D3D創(chuàng)建(一)
- 從Windows普通窗口到D3D窗口
在windows中智末,幾乎所有程序都要依賴(lài)于窗口。今天就分析如何從Windows窗口創(chuàng)建到D3D窗口創(chuàng)建商虐。 - 普通Windows窗口
為了使代碼明了可控何荚,我們應(yīng)從底層實(shí)現(xiàn)一個(gè)Windows窗口,每一條屬性都由我們自己填充剃毒。而不是使用快速創(chuàng)建。主要實(shí)現(xiàn)過(guò)程如下
首先創(chuàng)建一個(gè)空白工程搂赋,并自己建立一個(gè)入口點(diǎn)函數(shù)赘阀。既然是創(chuàng)建窗口程序,那么首先我們應(yīng)該包含windows.h頭文件脑奠。值得注意的是窗口程序入口函數(shù)為WinMain基公,而非控制臺(tái)程序的入口函數(shù)Main。
#include "windows.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return 0;
}
其次使用窗口類(lèi) WNDCLASS或WNDCLASSEX 并用API創(chuàng)建窗口宋欺,這里我們使用WNDCLASSEX以便于支持更多拓展特性轰豆,觀察類(lèi)原型
typedef struct tagWNDCLASSEXA {
UINT cbSize;
/* Win 3.x */
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
/* Win 4.0 */
HICON hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, NEAR *NPWNDCLASSEXA, FAR *LPWNDCLASSEXA;
這里很多參數(shù)并不是必要的,但是cbSize迄靠,lpfnWndProc秒咨,hInstance是必須填寫(xiě)的
這里我使用{ }進(jìn)行初始化,以便使所有未指定的值以0填充掌挚,這樣我們就不必一一進(jìn)行重復(fù)的初始化雨席;
WNDCLASSEX wcex = {};
wc.cbSize = sizeof(WNDCLASSEX);
//類(lèi)大小,讓API幫我計(jì)算
wc.hInstance = hInstance;
//實(shí)例句柄吠式,這里填WinMain句柄
wc.lpfnWndProc = WndPro;
//窗口處理函數(shù)陡厘,是一個(gè)回調(diào)函數(shù)
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
//設(shè)置窗口背景顏色
這里就已經(jīng)填充好了抽米,但是其中有一個(gè)函數(shù)WndPro還沒(méi)有實(shí)現(xiàn)。現(xiàn)在我們就實(shí)現(xiàn)它糙置,首先查看手冊(cè)是怎么說(shuō)的云茸。
LRESULT CallWindowProcA(
WNDPROC lpPrevWndFunc,
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
首先第一個(gè)參數(shù)lpPrevWndFunc,這個(gè)參數(shù)是歷史遺留下來(lái)谤饭,在我們現(xiàn)在的系統(tǒng)已經(jīng)棄用了标捺,原用于指向上一個(gè)窗口過(guò)程的句柄。hWnd:既是對(duì)應(yīng)的窗口句柄揉抵,Msg:窗口的消息結(jié)構(gòu)體亡容,這里留到下面討論。wParam冤今、lParam:這是因?yàn)閃indows消息復(fù)雜繁多闺兢,有時(shí)候Msg的容量并不能完全滿(mǎn)足消息大小,這時(shí)候就輪到了wParam戏罢、lParam這兩個(gè)附加消息屋谭。了解完了參數(shù)功能,現(xiàn)在就實(shí)現(xiàn)它龟糕。
LRESULT WINAPI WndPro(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
}
接下來(lái)在此函數(shù)內(nèi)寫(xiě)入處理細(xì)節(jié)桐磁。這里并沒(méi)有什么要做的,那么先加入關(guān)閉窗口的處理吧讲岁。如果你不想你的程序無(wú)法被關(guān)閉的話所意,這也是必須加入的。當(dāng)窗口被點(diǎn)擊關(guān)閉時(shí)發(fā)出的消息是WM_DESTROY催首,這個(gè)你可以看MSG結(jié)構(gòu)的相關(guān)文檔知道,我們要做的就是當(dāng)接收到消息時(shí)泄鹏,選擇性的將某些消息與某些動(dòng)作聯(lián)系起來(lái)郎任,而選擇之外的消息我們并不關(guān)心,則留給Windows幫我們處理备籽,這里使用switch選擇舶治。當(dāng)接收到WM_DESTROY,就發(fā)出退出消息车猬,告訴Windows替我銷(xiāo)毀當(dāng)前窗口霉猛。其他的消息就return DefWindowProc(hwnd, msg, wParam, lParam),讓W(xué)indows忙去珠闰。
LRESULT WINAPI WndPro(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
這樣就完成了最基礎(chǔ)的窗口過(guò)程處理函數(shù)惜浅。接下來(lái)我們回到前面的代碼。窗口類(lèi)填充完畢伏嗜,類(lèi)所需的函數(shù)也實(shí)現(xiàn)完畢坛悉。下一步就要告訴Windows我們的類(lèi)——注冊(cè)窗口類(lèi)伐厌,這個(gè)函數(shù)很簡(jiǎn)單,傳入類(lèi)指針就行了裸影。注冊(cè)成功后就是用這個(gè)類(lèi)創(chuàng)建窗口了挣轨。創(chuàng)建窗口函數(shù)就比較復(fù)雜了,老規(guī)矩轩猩,原型伺候卷扮。
HWND CreateWindowExA(
DWORD dwExStyle,
LPCSTR lpClassName,
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
dwExStyle——窗口拓展風(fēng)格 這里我們只創(chuàng)建最基礎(chǔ)的窗口不需要風(fēng)格 填入NULL即可
lpClassName ——類(lèi)名 填入你自己定義的類(lèi)名 我這里寫(xiě)入 "ClassName"
lpWindowName——窗口名 窗口名 我寫(xiě)入"WindowName"
dwStyle——風(fēng)格 這里我創(chuàng)建一個(gè)層疊窗口
x,y ——窗口位置 隨意一個(gè)屏幕坐標(biāo)都可以,這里我使用默認(rèn)的值CW_USEDEFAULT
nWidth均践,nHeight——要?jiǎng)?chuàng)建的窗口的寬高 也可以任意指定晤锹,這里我依舊使用默認(rèn)CW_USEDEFAULT
hWndParent——父窗口句柄 這個(gè)窗口沒(méi)有父窗口 NULL
hMenu——菜單句柄 沒(méi)有菜單,NULL
hInstance——示例句柄 填WinMain句柄hInstance
lpParam——指向窗口的創(chuàng)建數(shù)據(jù) 并沒(méi)有 NULL
最后浊猾,函數(shù)返回一個(gè)HWND抖甘,此句柄指向我們創(chuàng)建的窗口,我們需要保存下來(lái)葫慎。
實(shí)現(xiàn)代碼:
HWND hWnd=CreateWindowEx(NULL,ClassName,WindowName,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL,NULL, hInstance,NULL);
創(chuàng)建窗口之后當(dāng)然是顯示窗口啦
ShowWindow(hWnd, SW_SHOWDEFAULT);
為了我們的窗口能立即顯示必須立即更新窗口
UpdateWindow(hWnd);
這樣我們的窗口就做好啦衔彻,但是他并不是一個(gè)完全意義上的窗口,因?yàn)樗€沒(méi)有與相關(guān)操作交互的能力偷办,既然我們之前做好了接收相關(guān)操作產(chǎn)生消息的函數(shù)艰额,同樣的,這里應(yīng)該發(fā)出消息讓它處理椒涯。
MSG msg;
ZeroMemory(&msg, sizeof(msg));
創(chuàng)建消息結(jié)構(gòu)msg柄沮,并初始化內(nèi)存,防止使用到遺留數(shù)據(jù)废岂。
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
如果接收到消息祖搓,則翻譯消息,然后分發(fā)消息湖苞。這樣這才是一個(gè)基礎(chǔ)的窗口程序拯欧。
- 完整代碼
#include "windows.h"
#define ClassName "DX"
#define WindowName "Win_DX"
#define MenuName NULL
LRESULT WINAPI WndPro(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wc = { sizeof(WNDCLASSEX),0,WndPro,NULL,NULL,hInstance,NULL,NULL,
NULL,MenuName,ClassName };
wc.cbSize = sizeof(WNDCLASSEX);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndPro;
RegisterClassEx(&wc);
HWND hWnd = CreateWindowEx(NULL, ClassName, WindowName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}