在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
代码下载: