DirectX5.0最新遊戲程式設計指南 DirectDraw篇 四、DirectDraw高階特性 (轉)

worldblog發表於2007-12-04
DirectX5.0最新遊戲程式設計指南 DirectDraw篇 四、DirectDraw高階特性 (轉)[@more@]

四、DirectDraw高階特性
1、直接訪問DMA
  有些顯示裝置能夠在記憶體表面支援位塊傳輸操作(或其它操作),這些操作就是直接記憶體訪問DMA(Direct Memory Access)。 你可以利用DMA的支援來加速一定的操作。例如,在這種裝置上你可以從系統記憶體位塊傳輸到影片記憶體上,同時還準備處理下一幀的畫面。
  在使用DMA操作之前,必須檢測裝置是否支援DMA及支援的程度。步驟是先用 IDirectDraw2::GetCaps方法來獲取裝置的能力,然後再檢視 DDCAPS結構中的dwCaps成員是否含有DDCAPS_CANBLTSYSMEM標誌,若是則表明裝置支援DMA。
  如果裝置支援DMA,還需要知道是如何支援的。這就需要檢視有關的結構成員,這些成員包含了有關係統記憶體——影片記憶體、影片記憶體——系統記憶體和系統記憶體——系統記憶體之間位塊傳輸操作的資訊。DDCAPS結構的幾個成員提供了這些資訊,如下表所示:
System-to-vo
Video-to-system
System-to-system
  dwSVBCaps
  dwVSBCaps
  dwSSBCaps
  dwSVBCKeyCaps
  dwVSBCKeyCaps
  dwSSBCKeyCaps
  dwSVBFXCaps
  dwVSBFXCaps
  dwSSBFXCaps
  dwSVBRops
  dwVSBRops
  dwSSBRops

  例如,系統記憶體到影片記憶體的位塊傳輸的標誌由dwSVBCaps、dwSVBCKeyCaps、dwSVBFXCaps和dwSVBRops提供。影片記憶體到系統記憶體的位塊傳輸效能標誌包含在以“dwVSB”開頭的成員中,系統記憶體到系統記憶體之間的位塊傳輸效能標誌包含在以“dwSSB”開頭的成員中。
  這些成員最關鍵的特性是對非同步DMA位塊傳輸操作的支援。如果驅動程式支援表面間的非同步DMA位塊傳輸操作,DDCAPS_BLTQUEUE 標誌將會設在dwSVBCaps、dwVSBCaps、和dwSSBCaps成員中。若該標誌不存在,就表明驅動程式不支援非同步DMA位塊傳輸操作。
  系統記憶體到影片記憶體之間的SRCCOPY傳輸是支援的最常見的位塊傳輸操作。因此,對這種操作最典型的應用是從系統表面記憶體將許多紋理移動到影片記憶體。系統記憶體到影片記憶體的DMA傳輸大約同處理器控制的傳輸速度一樣快,但具有更大的優點,因為這些操作可以同主機處理器並行執行。
  硬體傳輸使用實體記憶體地址而不是虛擬記憶體地址,某些裝置驅動程式要求提供實體記憶體地址。該機制是透過對IDirectDrawSurface3::PageLock方法的完成的。如果裝置驅動程式不要求頁鎖定,在用IDirectDraw2::GetCaps方法獲取硬體的能力時,DDCAPS2_NOPAGELOCKREQUIRED標誌將被 設定。
  頁鎖定一個表面可以防止系統將表面的實體記憶體再做她用,並且保持該表面的實體記憶體不變,直到呼叫IDirectDrawSurface3::PageUnlock方法為止。如果裝置驅動程式請求頁鎖定,DirectDraw只允許DMA操作在應用程式已經頁鎖定了的系統記憶體表面上。如果在這種情況下沒有呼叫IDirectDrawSurface3::PageLock,DirectDraw將用模擬傳輸工作。需要注意的是,鎖定的表面多了之後將會大大降低執行的。因此,最好只在全屏獨佔下處理較多數量的系統記憶體,並且當應用程式最小化時能夠對這些表面進行解鎖。當然,應用程式恢復後,應該重新對系統記憶體表面頁鎖定。

2、在視窗模式下使用DirectDraw調色盤
  顯示在全屏獨佔方式下時,IDirectDrawPalette介面方法是直接寫向硬體的。顯示在視窗模式下時,IDirectDrawPalette介面方法將呼叫GDI調色盤處理使得能與其它的Windows應用程式和諧地工作在一起。
2.1、視窗模式下調色盤實體的型別
  同全屏獨佔式的應用程式不一樣,視窗模式的應用程式必須同其它的應用程式共享桌面調色盤。用於同 DirectDrawPalette和GDI一同工作的PALETTEENTRY 結構包含了一個peFlags成員,該成員含有系統應該怎樣解釋PALETTEENTRY結構的資訊。peFlags成員描述了三種型別的調色盤實體。
2.1.1、視窗靜態實體
  在標準模式下,Windows保留調色盤實體0~9和實體246~255用於系統顏色、顯示選單條、選單文字和視窗邊界等等。為了使應用程式保持一致的外觀,避免破壞其它應用程式的外觀表現,你需要保護這些設給主表面的調色盤的實體。通常,程式設計師可以呼叫函式GetSystemPaletteEntries來獲取系統調色盤,然後顯式地在自定義調色盤中設定相同的調色盤,使之在分配給主表面前同系統調色盤匹配。儘管系統調色盤的實體複製到自定義調色盤中在最開始也可以工作,但在改變了桌面顏色的配色時,該自定義調色盤就會變的無效。
  為了避免使用者改變顏色配色後調色盤的效果很差,你可提供一個系統調色盤的來替代指定的顏色值,從而保護合適的實體。用這種方法,不管系統對所給的實體使用了什麼顏色,調色盤都會始終匹配,不需要做任何工作。用於 peFlags成員的PC_EXPLICIT標誌使你能夠直接索引到一個系統調色盤實體。使用了這一標誌後,系統就不再認為結構的其它成員包含了顏色資訊。你可以將peRed成員的值設定為需要的系統調色盤索引而將其它的顏色都設為0。例如,若想保證你的調色盤中的適當的實體總是同系統調色盤顏色配色匹配,可以使
用以下程式碼:
// Set the first and last 10 entries to match the system palette.
PALETTEENTRY pe[256];
ZeroMemory(pe, sizeof(pe));
for(int i=0;i<10;i++){
  pe[i].peFlags  = pe[i+246].peFlags = PC_EXPLICIT;
  pe[i].peRed = i;
  pe[i+246].peRed = i+246;
}
 
  你可以呼叫Win32函式SetSystemPaletteUse強制Windows只使用第一個和最後一個調色盤實體0和255。在這種情況下,應該在PALETTEENTRY結構中只將實體0和255設定為PC_EXPLICIT。
2.1.2、運動實體(Animated entries)
  你可在PALETTEENTRY結構中使用PC_RESERVED標誌來指定將用於運動是調色盤實體。Windows不允許其它的應用程式將它自己的邏輯調色盤實體對映到你指定的物理調色盤實體,從而在你的應用程式運動調色盤時,避免其它的應用程式改變它們的顏色。
2.1.3、非運動實體(Nonanimated entries)
  你可在PALETTEENTRY結構中使用PC_NOCOLLAPSE標誌來指定非運動調色盤實體。PC_NOCOLLAPSE標誌通知Windows不用已經分配了的調色盤實體替代該非運動實體。
2.2、在視窗模式下建立調色盤
  下面是在非獨佔視窗模式下建立DirectDraw調色盤的例子。為了使調色盤能夠正常的工作,最好在提交給 IDirectDraw2::CreatePalette方法的PALETTEENTRY結構中將256個實體都設定好。
LPDIRECTDRAW  lpDD; // Assumed to be initialized previously
PALETTEENTRY  pPaletteEntry[256];
int  index;
HRESULT  ddrval;
LPDIRECTDRAWPALETTE lpDDPal;
 
// First set up the Windows static entries.
for (index = 0; index < 10 ; index++)
{
  // The first 10 static entries:
  pPaletteEntry[index].peFlags = PC_EXPLICIT;
  pPaletteEntry[index].peRed = index;
  pPaletteEntry[index].peGreen = 0;
  pPaletteEntry[index].peBlue = 0;
 
  // The last 10 static entries:
  pPaletteEntry[index+246].peFlags = PC_EXPLICIT;
  pPaletteEntry[index+246].peRed = index+246;
  pPaletteEntry[index+246].peGreen = 0;
  pPaletteEntry[index+246].peBlue = 0;
}
 
// Now set up private entries. In this example, the first 16
// available entries are animated.
for (index = 10; index < 26; index ++)
{
  pPaletteEntry[index].peFlags = PC_NOCOLLAPSE|PC_RESERVED;
  pPaletteEntry[index].peRed = 255;
  pPaletteEntry[index].peGreen = 64;
  pPaletteEntry[index].peBlue = 32;
}
 
// Now set up the rest, the nonanimated entries.
for (; index < 246; index ++) // Index is set up by previous for l
{
  pPaletteEntry[index].peFlags = PC_NOCOLLAPSE;
  pPaletteEntry[index].peRed = 25;
  pPaletteEntry[index].peGreen = 6;
  pPaletteEntry[index].peBlue = 63;
}
 
// All 256 entries are filled. Create the palette.
ddrval = lpDD->CreatePalette(DDPCAPS_8BIT, pPaletteEntry,
  &lpDDPal,NULL);
 
2.3、視窗模式下設定調色盤實體
  用於IDirectDraw2::CreatePalette方法的PALETTEENTRY中的規則同樣適用於IDirectDrawPalette::SetEntries方法。因此,你可以維持PALETTEENTRY結構組而不需要重建它。在需要的時候,更改結構組並呼叫IDirectDrawPalette::SetEntries方法。在大多數的環境中,處於視窗模式時,不要試圖來設定任何視窗靜態實體,否則將會出現無法預料的結果。只有在對實體復位時才允許設定視窗靜態實體。
  對應調色盤動畫,你只需要改變PALETTEENTRY結構組中的很少一部分實體,將這些實體提交給IDirectDrawPalette::SetEntries方法。
如果想對這些實體進行進行復位操作,只能復位那些用PC_NOCOLLAPSE標誌和PC_RESERVED標誌標記過的實體。試圖運動其它的實體會帶來不可預知的錯誤。下面的是非獨佔模式下的調色盤動畫的例子:
LPDIRECTDRAW  lpDD;  // Already initialized
PALETTEENTRY pPaletteEntry[256]; // Already initialized
LPDIRECTDRAWPALETTE lpDDPal;  // Already initialized
int  index;
HRESULT  ddrval;
PALETTEENTRY  temp;
 
// Animate some entries. Cycle the first 16 available entries.
// They were already animated.
temp = pPaletteEntry[10];
for (index = 10; index < 25; index ++)
{
  pPaletteEntry[index] = pPaletteEntry[index+1];
}
pPaletteEntry[25] = temp;
 
// Set the values. Do not pass a pointer to the entire palette entry
//structrue, but only to the changed entries.
ddrval = lpDDPal->SetEntries(
  0,  // Flags must be zero
  10,  // First entry
  16,  // Number of entries
  & (pPaletteEntry[10])); // Where to get the data
 
3、多顯示器系統
  (Memphis)和支援單一系統上的多個顯示裝置和顯示器。多顯示器系統(通常稱為 “MultiMon”)使得能夠使用兩個或兩個以上的顯示裝置和顯示器來建立單一的邏輯桌面。例如,在有兩臺顯示器的MultiMon系統中,使用者既能夠在其中一個顯示器上顯示應用程式,也能夠將視窗從一臺顯示器拖放到另一臺顯示器上。而DirectDraw支援這一體系結構。一個DirectDraw應用程式能夠列出硬體裝置,選擇一種裝置,然後利用該裝置的GUID為該裝置建立一個DirectDraw物件。這一技術可以保證不管是在MultiMon
系統還是在單一顯示器系統都能獲得最佳的效能表現。
  當前的活動顯示裝置被認為是“預設裝置”,或者是“空裝置”(Null Device,因為當前活動的顯示裝置在列出來時是以NULL作為它的GUID的)。已有的許多應用程式都可以為“空裝置”建立DirectDraw物件,假定該裝置是硬體加速的。但在MultiMon系統中,“空裝置”並不總是硬體加速的,它依賴於當時採用的協作等級。
  在全屏獨佔模式下,“空裝置”是硬體加速的,但系統並不知道其它已的裝置。這就意味著,全屏獨佔模式的應用程式執行在MultiMon系統上的速度同執行在其它系統上的速度一樣快,但不能使用內嵌的對跨越顯示裝置的圖象操作的支援。需要使用多個裝置的全屏獨佔模式的應用程式能為每一個要使用的裝置建立一個DirectDraw物件。注意,為指定的裝置建立DirectDraw物件,你必須提供該物件的GUID。呼叫DirectDrawEnumerate方法時可以列出每一個裝置的GUID。
  當設定了標準協作等級後,“空裝置”就不具有硬體加速能力,實際上,它只是將兩個物理裝置的資源結合在一起來模擬一個邏輯裝置。
另一方面,“空裝置”自動具有跨越顯示器的圖形操作能力。所以,當第二個顯示器的邏輯位置處於主顯示器的左邊時,負的座標值就是合法的。
  如果應用程式在設定了標準協作等級後要求實現硬體加速功能,它就必須使用指定裝置的GUID建立一個單一的DirectDraw物件。如果不使用“空裝置”,就不能獲得跨越顯示裝置的圖象操作能力。也就是說,跨越主表面邊界的位塊傳輸操作將會被剪下(若使用了剪下板)或失敗(返回DDERR_INVALIDRECT)。
  不管在哪種系統下,都應該在獲取物件的能力和查詢其它的介面之前建立DirectDraw物件之後立即設定協作等級,還要避免在MultiMon系統中多次設定協作等級。如果需要從全屏模式切換到標準模式,最好建立新的DirectDraw物件,而不要繼續使用老的DirectDraw物件。

4、影片埠(Video Ports)
  DirectDraw影片埠擴充套件是一個低階介面,它的目的並不是用於目前的系統多程式設計。影片埠介面的物件是影片軟體公司,如開發DirectShow之類的公司。想要在自己的軟體中使用影片技術的程式設計師也可以使用影片埠擴充套件。不過,在很多軟體中提供的高階程式設計介面就足以滿足需要了。
  DirectDrawVideoPort物件表徵了某些系統中安裝了的影片埠硬體。一般來說,影片埠物件控制了影片埠硬體怎樣將從影片解碼器接受到的影片訊號直接應用到幀緩衝區。根據需要,可以建立多個DirectDrawVideoPort物件來控制多個影片通道。因為每個通道都可以分別列出和,所以,影片硬體不需要對每個通道做完全相同的處理。
  影片埠硬體能夠直接在幀緩衝區中對錶面進行存取,而繞過和PCI匯流排。直接對幀緩衝區的存取使得能有效地活動影片和錄製影片而不必裝載入CPU中。一旦存在於某個表面中,圖象就能在螢幕上如覆蓋一樣的顯示,它可用於 Direct3D紋理、CPU的截獲存取和其它的處理。
  在配備了影片埠裝置的計算機中,影片流中的資料能夠從影片源透過影片解碼器和影片埠直接流向幀緩衝區。這些部件通常和顯示介面卡連線在一起,也可以作為單獨的硬體互相連線在一起。下圖給出了資料流的處理過程:
 
  影片源是什麼呢?在影片埠技術範圍內,嚴格來說,影片源就是一個硬體影片輸入(Video Input)裝置,如Zoom影片埠、MPEG編碼器等。這些硬體源將訊號以不同的格式(包括NTSC、PAL和SECAM)透過連到影片解碼器的物理連線釋出出去。影片解碼器(Viceo Decoder)是另一個硬體部件。它的工作是翻譯影片源提供的資訊並將其用遵循的連線格式傳送到影片埠。解碼器保持同影片埠的物理連線,它還負責將影片資料、時針資訊和同步資訊送到影片埠。
  影片埠(Video-Port)也是一組硬體。它存在於顯示介面卡的VGA上,具有直接訪問幀緩衝區的能力。它處理來自於解碼器的資訊並放置於幀緩衝區中以備顯示。在對資料的處理過程中,影片埠能操作圖象資料以提供比例變化、拉伸、顏色控制和剪下等服務。
幀緩衝區(Frame Buffer)接受影片埠提供的影片資料,然後應用程式就可用程式設計的方法處理這些圖象資料,將其位塊傳輸到其它的位置或使用覆蓋將其顯示在螢幕上。
  DirectDraw影片埠擴充套件的實質是包含了DirectDrawVideoPort物件,可透過IDDVideoPortContainer和IDirectDrawVideoPort介面利用影片埠技術提供影片服務。DirectDrawVideoPort物件並不能控制影片解碼器,只能提供自己的服務。DirectDraw也不能控制影片源,因為影片源已經超出了影片埠的範圍。DirectDrawVideoPort物件只是表徵影片埠本身。它用介面方法設定的引數將輸入的訊號和圖象資料送到幀緩衝區執行翻轉或其它的處理。IDDVideoPortContainer介面(可透過IDirectDraw2::QueryInterface獲取)提供了查詢硬體建立影片埠物件的能力。你可以用IDDVideoPortContainer::CreateVideoPort方法建立一個影片埠物件,該物件透過IDirectDrawVideoPort介面顯示其功能。
利用這些介面,你能夠檢查影片埠的能力,分配覆蓋表面以接收圖象資料、開始和停止影片播放、設定硬體引數處理圖象資料使產生剪下、顏色轉換、比例縮放和拉伸壓縮效果。DirectDraw影片埠擴充套件支援同一臺計算機上的多個影片埠,允許建立多個影片埠物件。

5、獲取翻轉和位塊傳輸狀態
  我們已經知道,呼叫IDirectDrawSurface3::Flip方法之後,主表面和後臺緩衝區就會互相。但交換的動作並不是立即就會發生。例如,若前面的一個翻轉任務還未完成時,該方法就返回DDERR_WASSTILLDRAWING,DirectDraw繼續對IDirectDrawSurface3::Flip進行呼叫直到返回DD_OK為止。如果應用程式在呼叫IDirectDrawSurface3::Flip方法返回DD_OK之前一直處於等待狀態,那麼該程式的效率就會非常低。取而代之的是,你可以建立一個函式在後臺緩衝區呼叫
  IDirectDrawSurface3::GetFlipStatus方法檢測前面的翻轉工作是否完成。如果未完成,返回的還是DDERR_WASSTILLDRAWING,應用程式就可以在下一次檢查該狀態之間的一段時間內執行其它的任務。下面是這一思想的例子:
while(lpDDSBack->GetFlipStatus(DDGFS_ILIPDONE) == DDERR_WASSTILLDRAWING);
 
  // Waiting for the previous flto finish. The application can
  // perfoanother task here.
 
ddrval = lpDDSPrimary->Flip(NULL, 0);
 
  你也可以用同樣的方法呼叫IDirectDrawSurface3::GetBltStatus來檢測一次位塊傳輸是否完成。因為IDirectDrawSurface3::GetFlipStatus和IDirectDrawSurface3::GetBltStatus能夠立即返回應用程式目前所處的狀態,所以可以在程式中週期地使用它們而不至於太影響程式的執行速度。
  執行顏色填充的工作需要呼叫IDirectDrawSurface3::Blt方法。例如,若程式中最常顯示的顏色是蘭色,你就可以以蘭色呼叫 IDirectDrawSurface3::Blt方法,利用DLT_COLORFILL標誌首先填充表面,然後再將其它的物體寫到上面。該方法允許你非常地填充最常用的顏色,然後只需要向表面寫很少數量的顏色。下面是執行顏色填充的例子:
DDBLTFX ddbltfx;
ddbltfx.dwSize = sizeof(ddbltfx);
ddbltfx.dwFillColor = 0;
ddrval = lpDDSPrimary->Blt(
  NULL,  // Destination
  NULL, NULL,  // rectangle
  DDBLT_COLORFILL, &ddbltfx);
 
switch(ddrval)
{
  case DDERR_WASSTILLDRAWING:
  .
  .
  .
  case DDERR_SURFACELOST:
  .
  .
  .
  case DD_OK:
  .
  .
  .
  default:
}
 
6、檢測顯示硬體的能力
  DirectDraw使用軟體模擬來執行那些不被使用者的硬體支援的DirectDraw功能。為了提高DirectDraw應用程式的執行速度,應該在建立DirectDraw物件後馬上檢測顯示硬體的能力,然後再儘可能地利用硬體提供的特性構件程式。你可以利用IDirectDraw2::GetCaps方法檢測硬體的效能。並不是所有的硬體特性都可以用軟體來模擬。如果你想使用一種僅僅被一些硬體支援的特性,最好還是作好系統可能不支援這種硬體的準備,也就是要提供如果硬體不支援這種硬體的解決方法。

7、在顯示記憶體中點陣圖
  通常,從顯示記憶體到顯示記憶體之間的位塊傳輸比從系統記憶體到顯示記憶體之間的位塊傳輸效率要高。因此,最好在顯示記憶體中儘可能多地儲存將要用到的精靈點陣圖。大多數的顯示介面卡都包含了足夠的額外記憶體以儲存不止一個主表面和後臺緩衝區。你可以利用 DDCAPS結構中的dwVidMemTotal和dwVidMemFree成員來檢測顯示記憶體中還有多少記憶體可用來儲存點陣圖。包含在 SDK中的DirectX Viewer範例程式給出了這一過程。

8、三緩衝(Triple Buffering)
  在某些情況下,顯示介面卡可能有比較多的顯示記憶體,這就有可能使用三緩衝來提高顯示速度。三緩衝使用一個主表面和兩個後臺緩衝區。下面是初始化一個三緩衝的例子:
// The lpDDSPrimary, lpDDSMiddle, and lpDDSBack are globally
// declared, uninitialized LPDIRECTDRAWSURFACE variables.

DDSURFACEDESC ddsd;
ZeroMemory (&ddsd, sizeof(ddsd));

// Create the primary surface with two back buffers.
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
  DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 2;
ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);

// If we successfully created the flip chain,
// retrieve pointers to the surfaces we need for
// flipping and blitting.
if(ddrval == DD_OK)
{
  // Get the surface directly attached to the primary (the back buffer).
  ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
  ddrval = lpDDSPrimary->GetAttachedSurface(&ddsd.ddsCaps,
  &lpDDSMiddle);
  if(ddrval != DD_OK) ;
  // Display an error message here.
}
 
  你不需要保留三緩衝翻轉鏈中所有表面的軌跡,只需要保留主表面和後臺緩衝表面的指標。主表面指標用來翻轉處於翻轉鏈中的主表面,後臺緩衝的指標則是用於位塊傳輸。三緩衝允許應用程式繼續位塊傳輸到後臺緩衝區,只要後臺緩衝的上一次位塊傳輸已經完成,即使翻轉未完成也沒有關係。執行翻轉並不是一個同步事件,一次翻轉可能比另一次翻轉的時間還要長。因此,如果只使用了一個後臺緩衝區,當
IDirectDrawSurface3::Flip方法返回DD_OK之前,程式可能會耗用不少時間處於等待狀態。

9、DirectDraw應用程式和視窗風格
  如果應用程式在視窗模式下使用DirectDraw,就可以使用任何的風格建立視窗。全屏獨佔模式的出現不能用 WS_EX_TOOLWINDOW風格建立視窗,它應該用WS_EX_TOPMOST擴充套件視窗風格和WS_VISIBLE視窗風格確保圖象正確顯示。這兩種風格可將應用程式保持在視窗Z方向的最前端,避免GDI向主表面畫圖。下面的例子顯示瞭如何使獨佔全屏模式的應用程式執行:
// Register the window class, display the window, and init all DirectX and graphic s.
BOOL WIN InitApp(INT nWinMode)
{
  WNDCLASSEX wcex;

  wcex.cbSize  =  sizeof(WNDCLASSEX);
  wcex.hInstance  =  g_hinst;
  wcex.lpszClassName  =  g_szWinName;
  wcex.lpfnWndProc  =  WndProc;
  wcex.style  =  CS_VREDRAW|CS_HREDRAW|CS_DBLCLKS;
  wcex.hIcon  =  LoadIcon (NULL, IDI_APPLICATION);
  wcex.hIconSm  =  LoadIcon (NULL, IDI_WINLOGO);
  wcex.hCursor  =  LoadCursor (NULL, IDC_ARROW);
  wcex.lpszMenuName  =  MAKEINTRESOURCE(IDR_APPMENU);
  wcex.cbClsExtra  =  0 ;
  wcex.cbWndExtra  =  0 ;
  wcex.hbrBackground  =  GetStockObject (NULL_BRUSH);

  RegisterClassEx(&wcex);

  g_hwndMain = CreateWindowEx(
  WS_EX_TOPMOST,
  g_szWinName,
  g_szWinCaption,
  WS_VISIBLE|WS_POPUP,
  0,0,CX_SCREEN,CY_SCREEN,
  NULL,
  NULL,
  g_hinst,
  NULL);

  if(!g_hwndMain)
  return(FALSE);

  SetFocus(g_hwndMain);
  ShowWindow(g_hwndMain, nWinMode);
  UpdateWindow(g_hwndMain);

  return TRUE;
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987903/,如需轉載,請註明出處,否則將追究法律責任。

相關文章