在创建DirectX应用程序之前我们要知道如何创建一个简单的Win32窗口程序. 在安装好 Microsoft Visual Studio .NET 2003 和 Microsoft DirectX 9.0c August 2006 后运行 Microsoft Visual Studio .NET 2003 建立一个Win32项目的空工程, 再新建一个C++源文件(建议名称使用Main.cpp或工程名.cpp), 我们以下的工作将在这个基础上实现. 要创建一个Win32窗口程序只需要以下几个步骤:
- 定义和注册一个窗口类, 描述我们想要创建的窗口类型.
- 创建窗口, 设定窗口风格.
- 创建消息循环更新窗口.
- 创建一个消息句柄或窗口处理器响应窗口消息.
以下为创建窗口程序的主要代码, 用于创建简单的Win32窗口, 你也可以扩展相应的功能. 详细使用说明见 MSDN .
//******************************************************************** // Filename: Main.cpp // Author: Chinafish // Modifier: Chinafish // Created: 2008-2-29 10:56 // Updated: 2008-2-29 10:56 // QQ: 149200849 // MSN: china_fish@msn.com // Purpose: Create a sample window. //==================================================================== // Copyright(C) 2004-2008 by Chinafish. All Rights Reserved. //******************************************************************** #define STRICT #define WIN32_LEAN_AND_MEAN #include "windows.h" #define WINDOW_TITLE "www.csinx.org - Creating A Sample Window (DX9+VC7)" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 //----------------------------------------------------------------------------- // GLOBALS //----------------------------------------------------------------------------- HWND g_hWnd = NULL; //----------------------------------------------------------------------------- // PROTOTYPES //----------------------------------------------------------------------------- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); //----------------------------------------------------------------------------- // Name: WinMain() // Desc: The application's entry point //----------------------------------------------------------------------------- int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX winClass; MSG uMsg; memset(&uMsg,0,sizeof(uMsg)); winClass.lpszClassName = "CLASS_CREATE_WINDOW"; winClass.cbSize = sizeof(WNDCLASSEX); winClass.style = CS_HREDRAW | CS_VREDRAW; winClass.lpfnWndProc = WindowProc; winClass.hInstance = hInstance; winClass.hIcon = LoadIcon(hInstance, NULL); winClass.hIconSm = LoadIcon(hInstance, NULL); winClass.hCursor = LoadCursor(NULL, IDC_ARROW); winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winClass.lpszMenuName = NULL; winClass.cbClsExtra = 0; winClass.cbWndExtra = 0; if( !RegisterClassEx(&winClass) ) return FALSE; g_hWnd = CreateWindowEx( NULL, "CLASS_CREATE_WINDOW", WINDOW_TITLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE,CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL ); if( g_hWnd == NULL ) return FALSE; // Adjust Window RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; AdjustWindowRect( &rect, GetWindowLong( g_hWnd, GWL_STYLE ), FALSE ); SetWindowPos( g_hWnd, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE ); // Show Window ShowWindow( g_hWnd, nCmdShow ); UpdateWindow( g_hWnd ); while( uMsg.message != WM_QUIT ) { if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &uMsg ); DispatchMessage( &uMsg ); } else { // Render a frame } } UnregisterClass( "CLASS_CREATE_WINDOW", winClass.hInstance ); return uMsg.wParam; } //----------------------------------------------------------------------------- // Name: WindowProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_KEYDOWN: { switch( wParam ) { case VK_ESCAPE: PostQuitMessage(0); break; } } break; case WM_CLOSE: { PostQuitMessage(0); } case WM_DESTROY: { PostQuitMessage(0); } break; default: { return DefWindowProc( hWnd, msg, wParam, lParam ); } break; } return 0; }
在以上代码中 WinMain 函数是Win32窗口程序的入口点. 首先我们要定义一个窗口类填充 WNDCLASSEX 结构, 这个结构告诉系统 我们要创建的窗口属性, 详见 MSDN 说明. 要注册一个窗口类只要调用 RegisterClassEx 即可, 注册的窗口类将用于创建窗口. 我们可以通过 CreateWindow 或 CreateWindowEx 创建一个窗口并指定 窗口风格 .
通常我们创建的窗口是包含标题, 菜单和窗口边框的大小, 实际上需要调整客户区为指定的大小. 可以通过 AdjustWindowRect 调节, 然后通过 SetWindowPos 更新窗口大小.
更新窗口大小后我们就可以通过调用 ShowWindow 和 UpdateWindow 显示窗口.
然后消息循环将一直更新消息直到用户想退出程序. 为了更新效率我们将在消息队列中没有消息时才更新和渲染物体. 通过 PeekMessage 检查是否有消息在队列中, 如果有消息我们就调用 TranslateMessage 和 DispatchMessage 转换虚拟键消息到字符消息并分配消息到窗口处理器.
窗口处理器 WindowProc 用于处理窗口收到的消息, 你可以定义为其他你想用的名称, 但是在 WNDCLASSEX 结构中的 lpfnWndProc 也要对应你定义的名称. 在窗口处理器中我们可能收到很多的消息, 在本例中我们只处理了 WM_KEYDOWN , WM_CLOSE , WM_DESTROY 消息并在收到 ESC 键按下, 窗口关闭消息和窗口销毁消息后通过调用 PostQuitMessage 通过应用程序关闭. 其他消息将通过调用 DefWindowProc 发送给系统处理.
下图为本例代码执行效果: