DircetDraw c/c++ 使用指導(一)
DircetDraw c/c++ 使用指導(一) DircetDraw c/c++ 使用指導
310cdt 譯
邊看邊譯,譯完就拿了上來,見笑了
這是一系列的DirectDraw的指南,教你一步步的去構建一個簡單的DirectDraw應用.這個指南用到了sdk包提供的很多DirectDraw的例子.這些例子展示了怎樣設置DirectDraw,怎樣用DirectDraw方法實現一般任務:
注意:這些指南中的例子是用c++寫的.如果你使用的是c編譯器,請進行適當的改變,以能進行成功的編譯.你需要把vtable和this指針添加到接口方法中.
1.DirectDraw基礎用法
要使用DirectDraw,你必須先創建一個代表計算機顯示接口的DirectDraw實例.然後,你就可以通過接口的方法來操縱這個對象.你可能會需要創建一個或更多的DirectDraw平面對象(DirectDraw surface object)的實例
來在圖形設備上顯示你的應用程序.
爲了演示這個,例子DDEx1 sample((SDK root)\Samples\Multimedia\DDraw\Src\Ddex1)演示了以下幾步:
step 1:創建一個DirectDraw對象
想創建一個DirectDraw對象的實例,你的應用程序必須在InitApp函數中使用DirectDrawCreateEx函數,就像例程ddex1中一樣.DirectDrawCreateEx函數包括4個參數.第一個是:顯示設備全局唯一標識(GUID).GUID大部分情況下是設爲NULL,選擇系統默認的顯示設備.第二個參數是:包含的是標示DirectDraw對象是否建立的指針的地址.第三個參數是IDirectDraw7接口的參考標示.必須設爲IID_IDirectDraw7.第四個參數是設置爲NULL的,是爲了將來的擴展做准備的.
以下的例子展示了怎樣創建DirectDraw對象,並判斷創建是否成功.
hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);
if(hRet == DD_OK)
{
// g_pDD is a valid DirectDraw object.
}
else
{
// The DirectDraw object could not be created.
}
step2:決定程序的行爲
在你改變顯示方法前,你必須至少在IDirectDraw7::SetCooperativeLevel函數中指定dwFlags參數(DDSCL_EXCLUSIVE 和 DDSCL_FULLSCREEN).這樣,你的應用程序就得到了顯示設備的全部控制權,其他的程序不能共享.DDSCL_FULLSCREEN讓你的應用程序在全屏幕模式下運行.你的程序覆蓋了桌面,並且只有你的程序能在屏幕上輸出.但是,桌面仍然是有效的.(按ALT+TAB切換到桌面)
下面的例子演示了SetCooperativeLevel函數的用法.
HRESULT hRet;
LPDIRECTDRAW7 g_pDD; // already created by DirectDrawCreateEx
hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if (hRet != DD_OK)
{
// Exclusive mode was successful.
}
else
{
// Exclusive mode was not successful.
// The application can still run, however.
}
如果 SetCooperativeLevel不返回DD_OK,你可以指定爲DDSCL_NORMAL繼續運行你的程序.但是,你的程序不再是獨占模式,而且,可能會無法完成你的一部分要求.在這種情況下,你最好顯示一個對話框讓用戶決定是否要繼續.
如果你設置的是全屏幕獨占合作級別,你必須把程序的窗口句柄傳遞給SetCooperativeLevel,這樣可以讓Windows有能力決定你的程序是否異常終止.
step3 :改變顯示模式
接下來,你可以用IDirectDraw7::SetDisplayMode函數來改變顯示模式.下面的例子將演示怎樣把顯示模式設置爲640 × 480 × 8 bits per pixel (bpp).
HRESULT hRet;
LPDIRECTDRAW7 g_pDD; // already created by DirectDrawCreateEx
hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);
if (hRet != DD_OK)
{
// The display mode changed successfully.
}
else
{
// The display mode cannot be changed.
// The mode is either not supported or
// another application has exclusive mode.
}
當你設置顯示模式的時候,你應該確定用戶的硬件是否支持這樣的模式.你可以設置一個能被大部分顯示適配器支持的標准的模式.例如:你的程序可以以640 × 480 × 8作爲備選模式,設計成爲可以在所有系統上運行.
注意:IDirectDraw7::SetDisplayMode返回一個DDERR INVALIDMODE錯誤值,如果顯示適配器無法切換到想要的模式時.你可以在試圖改變顯示模式前,用IDirectDraw7::EnumDisplayModes函數看一下用戶顯示適配器的能力.
step4:創建交換頁(flipping surface)
設置完顯示模式以後,你應該創建一個平面.例程:DDEx1用IDirectDraw7::SetCooperativeLevel 設置爲獨占模式.所以,你可以創建交換頁(flipping surfaces).如果你設置的是DDSCL_NORMAL模式,你可以創建一個可以塊移動(blit)的平面.創建交換頁(flipping surfaces)需要以下步驟:
(4.1)定義需求的平面:
第一步是以DDSURFACEDESC2結構定義一個需求的平面.下面的例子演示了結構的定義和標志位的設定:
// Create the primary surface with one back buffer.
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
在這個例子中,dwSize成員是DDSURFACEDESC2結構的大小.這是防止你用到的DirectDraw方法返回無效成員的錯誤.(dwSize是准備給將來的DDSURFACEDESC2結構的擴展用的)
dwFlags成員決定的DDSURFACEDESC2結構中那些成員將被填充有效的信息.例如在DDEx1中,dwFlags被設爲你想要用DDSCAPS結構(DDSD_CAPS)和你想創建一個後台緩沖(back buffer)(DDSD_BACKBUFFERCOUNT)
dwCaps成員在例子中標示一個將要在DDSCAPS結構中使用的標志位.在這種情況下,他指定一個主平面(primary surface DDSCAPS_PRIMARYSURFACE),一個交換頁(flipping surface DDSCAPS_FLIP),一個合成表面(complex surface DDSCAPS_COMPLEX).
最後,例子指定了一個後台緩沖.後台緩沖就是實際的繪圖操作先在那裏完成,然後,再快速的翻動(flip)到主平面(primary surface)上.在DDEx1中,後台緩沖的數目是1.其實,你要你的顯存允許,你想建幾個就建幾個.你想知道更多的關于創建大于1塊緩沖的信息,可以去看 "triple buffering".
創建的"平面"占用的存儲空間,可以是系統內存也可以是顯存.如果應用程序使用的空間超出了顯存,DirectDraw就會使用系統內存.(例如你指定多塊緩存在一個僅有1MB顯存的是配器上).你也可以這樣設置DDSCAPS結構的dwCaps成員,設成DDSCAPS_VIDEOMEMEORY或DDCAPS_SYSTEMMEMORY以達到只用顯存或只用內存.(如指定用顯存,而顯存不夠,IDirectDraw7::CreateSurface返回一個DDERR_OUTOFVIDEOMEMORY錯誤)
(4.2)創建平面
在填充完DDSURFACEDESC2結構後,你就可以用他和g_pDD指針(DirectDrawCreateEx函數創建的DirectDraw對象的指針)調用IDirectDraw7::CreateSurface方法,就像下面 :
hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
if (hRet != DD_OK)
{
// g_pDDSPrimary points to the new surface.
}
else
{
// The surface was not created.
return FALSE;
}
g_pDDSPrimary參數將指向由CreateSurface函數返回的主平面(primary surface)的地址,如果調用成功的話.
指向主平面(primary surface)的指針有效後,就可以調用IDirectDrawSurface7::GetAttachedSurface方法去得到一個指向緩沖的指針.如下:
ZeroMemory(&ddscaps, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);
if (hRet != DD_OK)
{
// g_pDDSBack points to the back buffer.
}
else
{
return FALSE;
}
如果IDirectDrawSurface7::GetAttachedSurface調用成功,g_pDDSBack參數將指向緩存區.
step5:在平面上輸出
在主平面(primary surface)和後台緩沖(back buffer)創建完成後,例子DDEx1用windows標准GDI函數輸出了一些文本在緩沖上.如下:
if (g_pDDSBack->GetDC(&hdc) == DD_OK)
{
SetBkColor(hdc, RGB(0, 0, 255));
SetTextColor(hdc, RGB(255, 255, 0));
if (phase)
{
GetClientRect(hWnd, &rc);
GetTextExtentPoint(hdc, szMsg, lstrlen(szMsg), &size);
TextOut(hdc, (rc.right - size.cx) / 2, (rc.bottom - size.cy) / 2,
szMsg, sizeof(szMsg) - 1);
TextOut(hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg));
phase = 0;
}
else
{
TextOut(hdc, 0, 0, szBackMsg, lstrlen(szBackMsg));
phase = 1;
}
g_pDDSBack->ReleaseDC(hdc);
}
這個例子使用the IDirectDrawSurface7::GetDC方法獲得設備上下文的句柄,並且,爲了准備寫入,將緩沖上鎖.如果你不准備用需要設備上下文句柄的windows函數,你可以使用IDirectDrawSurface7::Lock IDirectDrawSurface7::Unlock方法加解鎖.
接下來,phase變量決定了應該輸出到主緩存消息(primary buffer message)還是後台緩存消息(back buffer message).如果phase=1,輸出
主緩存消息,且設phase=0.如果phase=0,輸出後台緩存消息,且設phase=1.
當消息輸出到緩存區後,用IDirectDrawSurface7::ReleaseDC 方法將緩存區解鎖.
對創建平面的內存上鎖,是保證你的程序和系統不能同時對此內存進行存取.這防止你寫入"平面"內存事發生錯誤.另外,不對"平面"內存解鎖,你的程序將無法翻轉平面.
平面被加鎖之後,例子中用了標准windowsGDI函數:SetBkColor設置背景色,SetTextColor設置在背景上顯示的字的顔色,用TextOut在"表面"上輸出文字和背景色.
當文字被輸出到緩存之後,例子應用IDirectDrawSurface7::ReleaseDC方法解鎖"表面"並且釋放句柄.不論在什麽時候你的程序完成了對緩存的寫入,一定要調用IDirectDrawSurface7::ReleaseDC 或IDirectDrawSurface7::Unlock之一,具體用哪個,由你的程序而定.不解鎖,你的程序將不能翻轉平面.
注意:用IDirectDrawSurface7::Unlock對"平面"解鎖後,指向"平面"的指針將會無效.你必須再用IDirectDrawSurface7::lock去獲得一個有效的指針.
step:6 翻轉平面
在DDEx1中,WM_TIMER消息引發從緩存到主平面的翻轉.當"平面"內存解鎖後,你就可以用IDirectDrawSurface7::Flip方法實現從緩存到主平面的翻轉.如下:
case WM_TIMER:
// Update and flip surfaces
if (g_bActive && TIMER_ID == wParam)
{
UpdateFrame(hWnd);
while (TRUE)
{
hRet = g_pDDSPrimary->Flip(NULL, 0);
if (hRet == DD_OK)
break;
if (hRet == DDERR_SURFACELOST)
{
hRet = g_pDDSPrimary->Restore();
if (hRet != DD_OK)
break;
}
if (hRet != DDERR_WASSTILLDRAWING)
break;
}
}
break;
在例子中,g_pDDSPrimary參數指示主平面和與他連接的緩存.當IDirectDrawSurface7::Flip被調用,前後平面將會交換(只是交換指針,沒有實際的數據交換).如果翻轉成功,返回DD_OK,跳出循環.
如果翻轉返回的是DDERR_SURFACELOST值,就試圖用IDirectDrawSurface7::Restore 方法保存平面.如果保存成功,程序循環到調用IDirectDrawSurface7::Flip,再試一次.如果保存不成功,程序跳出循環,返回一個錯誤.
注意:當你調用IDirectDrawSurface7::Flip 時,翻轉動作並不能馬上完成.如果,前一個翻轉動作還沒有完成,IDirectDrawSurface7::Flip 會返回DDERR_WASSTILLDRAWING.在這個例子中,IDirectDrawSurface7::Flip會一直調用直到返回DD_OK.
step7:釋放DirectDraw對象
當你按下F12鍵時,例子DDEx1將在退出程序前處理WM_DESTROY消息.這個消息將調用ReleaseAllObjects函數,這個函數包括了多個Release調用.像下面一樣:
static void
ReleaseAllObjects(void)
{
if (g_pDD != NULL)
{
if (g_pDDSPrimary != NULL)
{
g_pDDSPrimary->Release();
g_pDDSPrimary = NULL;
}
g_pDD->Release();
g_pDD = NULL;
}
}
這個程序檢測DirectDraw對象的指針g_pDD和DirectDraw平面對象的指針g_pDDSPrimary是否爲NULL.然後,調用IDirectDrawSurface7::Release方法令DirectDraw平面對象的reference count(可以認爲是創建的對象的數目)數減1,這使得reference count減爲0,DirectDraw平面對象就釋放了.然後,還需將他的指針值設爲NULL.接下來,程序調用IDirectDraw7::Release,同樣是令DirectDraw的reference count減1,然後然後....全銷毀.
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
DircetDraw c/c++ 使用指導(一)
DircetDraw c/c++ 使用指導(一) DircetDraw c/c++ 使用指導
310cdt 譯
邊看邊譯,譯完就拿了上來,見笑了
這是一系列的DirectDraw的指南,教你一步步的去構建一個簡單的DirectDraw應用.這個指南用到了sdk包提供的很多DirectDraw的例子.這些例子展示了怎樣設置DirectDraw,怎樣用DirectDraw方法實現一般任務:
注意:這些指南中的例子是用c++寫的.如果你使用的是c編譯器,請進行適當的改變,以能進行成功的編譯.你需要把vtable和this指針添加到接口方法中.
1.DirectDraw基礎用法
要使用DirectDraw,你必須先創建一個代表計算機顯示接口的DirectDraw實例.然後,你就可以通過接口的方法來操縱這個對象.你可能會需要創建一個或更多的DirectDraw平面對象(DirectDraw surface object)的實例
來在圖形設備上顯示你的應用程序.
爲了演示這個,例子DDEx1 sample((SDK root)\Samples\Multimedia\DDraw\Src\Ddex1)演示了以下幾步:
step 1:創建一個DirectDraw對象
想創建一個DirectDraw對象的實例,你的應用程序必須在InitApp函數中使用DirectDrawCreateEx函數,就像例程ddex1中一樣.DirectDrawCreateEx函數包括4個參數.第一個是:顯示設備全局唯一標識(GUID).GUID大部分情況下是設爲NULL,選擇系統默認的顯示設備.第二個參數是:包含的是標示DirectDraw對象是否建立的指針的地址.第三個參數是IDirectDraw7接口的參考標示.必須設爲IID_IDirectDraw7.第四個參數是設置爲NULL的,是爲了將來的擴展做准備的.
以下的例子展示了怎樣創建DirectDraw對象,並判斷創建是否成功.
hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);
if(hRet == DD_OK)
{
// g_pDD is a valid DirectDraw object.
}
else
{
// The DirectDraw object could not be created.
}
step2:決定程序的行爲
在你改變顯示方法前,你必須至少在IDirectDraw7::SetCooperativeLevel函數中指定dwFlags參數(DDSCL_EXCLUSIVE 和 DDSCL_FULLSCREEN).這樣,你的應用程序就得到了顯示設備的全部控制權,其他的程序不能共享.DDSCL_FULLSCREEN讓你的應用程序在全屏幕模式下運行.你的程序覆蓋了桌面,並且只有你的程序能在屏幕上輸出.但是,桌面仍然是有效的.(按ALT+TAB切換到桌面)
下面的例子演示了SetCooperativeLevel函數的用法.
HRESULT hRet;
LPDIRECTDRAW7 g_pDD; // already created by DirectDrawCreateEx
hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if (hRet != DD_OK)
{
// Exclusive mode was successful.
}
else
{
// Exclusive mode was not successful.
// The application can still run, however.
}
如果 SetCooperativeLevel不返回DD_OK,你可以指定爲DDSCL_NORMAL繼續運行你的程序.但是,你的程序不再是獨占模式,而且,可能會無法完成你的一部分要求.在這種情況下,你最好顯示一個對話框讓用戶決定是否要繼續.
如果你設置的是全屏幕獨占合作級別,你必須把程序的窗口句柄傳遞給SetCooperativeLevel,這樣可以讓Windows有能力決定你的程序是否異常終止.
step3 :改變顯示模式
接下來,你可以用IDirectDraw7::SetDisplayMode函數來改變顯示模式.下面的例子將演示怎樣把顯示模式設置爲640 × 480 × 8 bits per pixel (bpp).
HRESULT hRet;
LPDIRECTDRAW7 g_pDD; // already created by DirectDrawCreateEx
hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);
if (hRet != DD_OK)
{
// The display mode changed successfully.
}
else
{
// The display mode cannot be changed.
// The mode is either not supported or
// another application has exclusive mode.
}
當你設置顯示模式的時候,你應該確定用戶的硬件是否支持這樣的模式.你可以設置一個能被大部分顯示適配器支持的標准的模式.例如:你的程序可以以640 × 480 × 8作爲備選模式,設計成爲可以在所有系統上運行.
注意:IDirectDraw7::SetDisplayMode返回一個DDERR INVALIDMODE錯誤值,如果顯示適配器無法切換到想要的模式時.你可以在試圖改變顯示模式前,用IDirectDraw7::EnumDisplayModes函數看一下用戶顯示適配器的能力.
step4:創建交換頁(flipping surface)
設置完顯示模式以後,你應該創建一個平面.例程:DDEx1用IDirectDraw7::SetCooperativeLevel 設置爲獨占模式.所以,你可以創建交換頁(flipping surfaces).如果你設置的是DDSCL_NORMAL模式,你可以創建一個可以塊移動(blit)的平面.創建交換頁(flipping surfaces)需要以下步驟:
(4.1)定義需求的平面:
第一步是以DDSURFACEDESC2結構定義一個需求的平面.下面的例子演示了結構的定義和標志位的設定:
// Create the primary surface with one back buffer.
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
在這個例子中,dwSize成員是DDSURFACEDESC2結構的大小.這是防止你用到的DirectDraw方法返回無效成員的錯誤.(dwSize是准備給將來的DDSURFACEDESC2結構的擴展用的)
dwFlags成員決定的DDSURFACEDESC2結構中那些成員將被填充有效的信息.例如在DDEx1中,dwFlags被設爲你想要用DDSCAPS結構(DDSD_CAPS)和你想創建一個後台緩沖(back buffer)(DDSD_BACKBUFFERCOUNT)
dwCaps成員在例子中標示一個將要在DDSCAPS結構中使用的標志位.在這種情況下,他指定一個主平面(primary surface DDSCAPS_PRIMARYSURFACE),一個交換頁(flipping surface DDSCAPS_FLIP),一個合成表面(complex surface DDSCAPS_COMPLEX).
最後,例子指定了一個後台緩沖.後台緩沖就是實際的繪圖操作先在那裏完成,然後,再快速的翻動(flip)到主平面(primary surface)上.在DDEx1中,後台緩沖的數目是1.其實,你要你的顯存允許,你想建幾個就建幾個.你想知道更多的關于創建大于1塊緩沖的信息,可以去看 "triple buffering".
創建的"平面"占用的存儲空間,可以是系統內存也可以是顯存.如果應用程序使用的空間超出了顯存,DirectDraw就會使用系統內存.(例如你指定多塊緩存在一個僅有1MB顯存的是配器上).你也可以這樣設置DDSCAPS結構的dwCaps成員,設成DDSCAPS_VIDEOMEMEORY或DDCAPS_SYSTEMMEMORY以達到只用顯存或只用內存.(如指定用顯存,而顯存不夠,IDirectDraw7::CreateSurface返回一個DDERR_OUTOFVIDEOMEMORY錯誤)
(4.2)創建平面
在填充完DDSURFACEDESC2結構後,你就可以用他和g_pDD指針(DirectDrawCreateEx函數創建的DirectDraw對象的指針)調用IDirectDraw7::CreateSurface方法,就像下面 :
hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
if (hRet != DD_OK)
{
// g_pDDSPrimary points to the new surface.
}
else
{
// The surface was not created.
return FALSE;
}
g_pDDSPrimary參數將指向由CreateSurface函數返回的主平面(primary surface)的地址,如果調用成功的話.
指向主平面(primary surface)的指針有效後,就可以調用IDirectDrawSurface7::GetAttachedSurface方法去得到一個指向緩沖的指針.如下:
ZeroMemory(&ddscaps, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);
if (hRet != DD_OK)
{
// g_pDDSBack points to the back buffer.
}
else
{
return FALSE;
}
如果IDirectDrawSurface7::GetAttachedSurface調用成功,g_pDDSBack參數將指向緩存區.
step5:在平面上輸出
在主平面(primary surface)和後台緩沖(back buffer)創建完成後,例子DDEx1用windows標准GDI函數輸出了一些文本在緩沖上.如下:
if (g_pDDSBack->GetDC(&hdc) == DD_OK)
{
SetBkColor(hdc, RGB(0, 0, 255));
SetTextColor(hdc, RGB(255, 255, 0));
if (phase)
{
GetClientRect(hWnd, &rc);
GetTextExtentPoint(hdc, szMsg, lstrlen(szMsg), &size);
TextOut(hdc, (rc.right - size.cx) / 2, (rc.bottom - size.cy) / 2,
szMsg, sizeof(szMsg) - 1);
TextOut(hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg));
phase = 0;
}
else
{
TextOut(hdc, 0, 0, szBackMsg, lstrlen(szBackMsg));
phase = 1;
}
g_pDDSBack->ReleaseDC(hdc);
}
這個例子使用the IDirectDrawSurface7::GetDC方法獲得設備上下文的句柄,並且,爲了准備寫入,將緩沖上鎖.如果你不准備用需要設備上下文句柄的windows函數,你可以使用IDirectDrawSurface7::Lock IDirectDrawSurface7::Unlock方法加解鎖.
接下來,phase變量決定了應該輸出到主緩存消息(primary buffer message)還是後台緩存消息(back buffer message).如果phase=1,輸出
主緩存消息,且設phase=0.如果phase=0,輸出後台緩存消息,且設phase=1.
當消息輸出到緩存區後,用IDirectDrawSurface7::ReleaseDC 方法將緩存區解鎖.
對創建平面的內存上鎖,是保證你的程序和系統不能同時對此內存進行存取.這防止你寫入"平面"內存事發生錯誤.另外,不對"平面"內存解鎖,你的程序將無法翻轉平面.
平面被加鎖之後,例子中用了標准windowsGDI函數:SetBkColor設置背景色,SetTextColor設置在背景上顯示的字的顔色,用TextOut在"表面"上輸出文字和背景色.
當文字被輸出到緩存之後,例子應用IDirectDrawSurface7::ReleaseDC方法解鎖"表面"並且釋放句柄.不論在什麽時候你的程序完成了對緩存的寫入,一定要調用IDirectDrawSurface7::ReleaseDC 或IDirectDrawSurface7::Unlock之一,具體用哪個,由你的程序而定.不解鎖,你的程序將不能翻轉平面.
注意:用IDirectDrawSurface7::Unlock對"平面"解鎖後,指向"平面"的指針將會無效.你必須再用IDirectDrawSurface7::lock去獲得一個有效的指針.
step:6 翻轉平面
在DDEx1中,WM_TIMER消息引發從緩存到主平面的翻轉.當"平面"內存解鎖後,你就可以用IDirectDrawSurface7::Flip方法實現從緩存到主平面的翻轉.如下:
case WM_TIMER:
// Update and flip surfaces
if (g_bActive && TIMER_ID == wParam)
{
UpdateFrame(hWnd);
while (TRUE)
{
hRet = g_pDDSPrimary->Flip(NULL, 0);
if (hRet == DD_OK)
break;
if (hRet == DDERR_SURFACELOST)
{
hRet = g_pDDSPrimary->Restore();
if (hRet != DD_OK)
break;
}
if (hRet != DDERR_WASSTILLDRAWING)
break;
}
}
break;
在例子中,g_pDDSPrimary參數指示主平面和與他連接的緩存.當IDirectDrawSurface7::Flip被調用,前後平面將會交換(只是交換指針,沒有實際的數據交換).如果翻轉成功,返回DD_OK,跳出循環.
如果翻轉返回的是DDERR_SURFACELOST值,就試圖用IDirectDrawSurface7::Restore 方法保存平面.如果保存成功,程序循環到調用IDirectDrawSurface7::Flip,再試一次.如果保存不成功,程序跳出循環,返回一個錯誤.
注意:當你調用IDirectDrawSurface7::Flip 時,翻轉動作並不能馬上完成.如果,前一個翻轉動作還沒有完成,IDirectDrawSurface7::Flip 會返回DDERR_WASSTILLDRAWING.在這個例子中,IDirectDrawSurface7::Flip會一直調用直到返回DD_OK.
step7:釋放DirectDraw對象
當你按下F12鍵時,例子DDEx1將在退出程序前處理WM_DESTROY消息.這個消息將調用ReleaseAllObjects函數,這個函數包括了多個Release調用.像下面一樣:
static void
ReleaseAllObjects(void)
{
if (g_pDD != NULL)
{
if (g_pDDSPrimary != NULL)
{
g_pDDSPrimary->Release();
g_pDDSPrimary = NULL;
}
g_pDD->Release();
g_pDD = NULL;
}
}
這個程序檢測DirectDraw對象的指針g_pDD和DirectDraw平面對象的指針g_pDDSPrimary是否爲NULL.然後,調用IDirectDrawSurface7::Release方法令DirectDraw平面對象的reference count(可以認爲是創建的對象的數目)數減1,這使得reference count減爲0,DirectDraw平面對象就釋放了.然後,還需將他的指針值設爲NULL.接下來,程序調用IDirectDraw7::Release,同樣是令DirectDraw的reference count減1,然後然後....全銷毀.