在vs2010中,建立一個新的win32工程,名字是: myTutorialD3D11, 注意:同時勾選Create directory for solution,我們同時建立一個solution,后面教程的所有的工程文件,我們都建立在這個solution中。
勾選 Emtpy project
增加source files->add new item->main.cpp
創建一個windows應用程序需要以下步驟:
1、在入口Main函數中注冊窗口類
2、調用CreateWindowEx函數創建窗口
3、處理調度消息循環
4、編寫回調函數,在回調函數中響應處理各種消息事件
在main.cpp中,逐步增加以下的代碼:
首先增加
#include <windows.h>
這樣,我們就能夠使用windows中的API函數、structure,類對象等。
//窗口類的名字
LPCWSTR m_applicationName;
//應用程序實例句柄
HINSTANCE m_hinstance;
定義一個全局的windows窗口句柄,這個句柄用來表示應用程序的主窗口句柄。
//窗口句柄
HWND m_hwnd;
//用來判斷是否按ESC鍵,按下ESC鍵,則退出程序
bool bexit = false;
//初始化窗口類,創建應用程序窗口
void InitializeWindows(int& screenWidth, int& screenHeight);
//調用初始化窗口函數,以及其它的接口類的初始化函數
bool Initialize();
//處理消息循環
void Run();
//關閉窗口
void ShutdownWindows();
//這兩個函數是窗口的回調函數
static LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//判斷是否全屏,全屏模式和窗口模式下使用不同的創建窗口參數
const bool FULL_SCREEN = false;
下面的函數WinMain,是windows應用程序的入口函數。
四個參數簡單提一下,HInstance表示當前應用程序的實例句柄,它實際上是一個內存基地址,系統將可執行程序的映像加載到進程地址空間中的這個位置。
HPrevInstance表示進程前一個實例句柄,比如對於同一個程序打開兩次,出現兩個窗口,第一次打開的窗口就是先前實例的窗口。該參數用於16位Windows系統,對於一個32位程序,該參數總為NULL,現在仍然保留該參數主要是為了和16位windows系統兼容。
pSCmdLine是指向應用程序命令行的字符串的指針,不包括執行文件名。獲得整個命令行,使用函數GetCommandLine。
nCmdShow:指明窗口如何顯示,比如SW_HIDE(隱藏),SW_MINIMIZE(最小化)等等,默認情況為SW_SHOW。
//應用程序入口main函數
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
Initialize();
Run();
ShutdownWindows();
return 0;
}
該函數首先調用初始化函數,初始化函數中將會設置窗口的高度、寬度,然后調用初始化窗口函數。
//調用窗口初始化函數和其它一些類的初始化函數
//本例子中,只調用初始化窗口函數
bool Initialize()
{
int screenWidth = 0, screenHeight = 0;
// 初始化窗口
InitializeWindows(screenWidth, screenHeight);
return true;
}
void InitializeWindows(int& screenWidth, int& screenHeight)
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
// 得到應用程序實例句柄
m_hinstance = GetModuleHandle(NULL);
// 應用程序名字
m_applicationName = L"Engine";
// 設置窗口類參數.
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
指定回調函數后,windows會自動調用回調函數處理各種消息事件
wc.lpfnWndProc = WndProc; //指定回調函數
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hinstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //默認黑色窗口黑色背景
wc.lpszMenuName = NULL;
wc.lpszClassName = m_applicationName;
wc.cbSize = sizeof(WNDCLASSEX);
// 注冊窗口類
RegisterClassEx(&wc);
// 得到windows桌面分辨率
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 根據是否全屏設置不同的分辨率.
if(FULL_SCREEN)
{
//全屏模式下,設置窗口大小為windows桌面分辨率.
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// 臨時設置顯示設備為全屏模式,注意:應用程序退出時候,將恢復系統默認設置。
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
// 設置窗口的左上角坐標位置為(0,0).
posX = posY = 0;
}
else
{
// 窗口模式:800*600.
screenWidth = 800;
screenHeight = 600;
// 窗口左上角坐標位置,posX, posY
posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
}
// 全屏和窗口使用不同的參數.
if( FULL_SCREEN)
{
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
}
else
{
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW, m_applicationName, m_applicationName,
WS_OVERLAPPEDWINDOW,
posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
}
// 顯示窗口並設置其為焦點.
ShowWindow(m_hwnd, SW_SHOW);
SetForegroundWindow(m_hwnd);
SetFocus(m_hwnd);
// 隱藏鼠標.
//ShowCursor(false);
return;
}
在Run函數中,我們響應調度windows消息以及調用我們的render函數。
//處理消息
void Run()
{
MSG msg;
bool done, result = 1;
// 初始化消息結構.
ZeroMemory(&msg, sizeof(MSG));
// 循環進行消息處理
done = false;
while(!done)
{
// 處理windows消息.
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 接收到WM_QUIT消息,退出程序.
if(msg.message == WM_QUIT)
{
done = true;
}
else
{
result = bexit; //如果按了ESC,也退出程序
//我們的渲染或者其它處理,可以放在這兒
//....
//.....
if(result)
{
done = true;
}
}
}
return;
}
WndProc函數為窗口回調函數,程序中的消息處理都在這個函數中。
LRESULT CALLBACK WndProc(HWND hwnd, UINT umessage, WPARAM wparam, LPARAM lparam)
{
switch(umessage)
{
// 窗口銷毀消息.
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
// 窗口關閉消息.
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
//MessageHandle過程處理其它所有消息.
default:
{
return MessageHandler(hwnd, umessage, wparam, lparam);
}
}
}
LRESULT CALLBACK MessageHandler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch(umsg)
{
// 檢測按鍵消息.
case WM_KEYDOWN:
if(wparam==VK_ESCAPE)
bexit = true;
return 0;
//任何其它消息發送到windows缺省處理.
default:
{
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
}
}
ShutdownWindows函數主要用來在程序結束后,釋放一些資源。
void ShutdownWindows()
{
//顯示光標.
//ShowCursor(true);
// 恢復默認顯示設置.
if(FULL_SCREEN)
{
ChangeDisplaySettings(NULL, 0);
}
//釋放窗口句柄.
DestroyWindow(m_hwnd);
m_hwnd = NULL;
// 釋放應用程序實例.
UnregisterClass(m_applicationName, m_hinstance);
m_hinstance = NULL;
return;
}
程序執行后,界面如下,窗口是黑色,我們按下ESC,程序會退出:
完整的代碼請參考:
工程文件myTutorialD3D11
代碼下載:




