一、入口函数
任何平台任何形式的程序都需要入口函数。
一般C/C++程序的入口函数是main。
但Win32程序不是一般C程序。
所以Win32程序的入口函数不是main。
Win32的入口函数叫做WinMain()。
写在MSDN中的官方定义是这个样子:
hInstance:当前程序运行的实例句柄。int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // pointer to command line int nCmdShow // show state of window );
hPrevInstance:之前程序的的实例句柄,在Win32系统中永远赋值为NULL,为兼容旧版Win程序而保留的参数。
lpCmdLine:命令行参数。
nCmdShow:窗口显示的状态,隐藏/最大化/最小化之类的东西。
二、构建窗口
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { return 0; }
在这个Win32的入口函数里,我们完全可以和main函数一样,在return 0之前进行各种运算,定义变量,循环,选择,华丽的在函数外定义其他函数然后回来调用竭尽所能,最后单击编译——这都基本不会有任何的大问题——唯一一点的小瑕疵只不过是程序运行后跟个没运行一样而已。
之所以会这样不是程序没有正常运行,程序已经默默的运行完了主函数里的全部代码。
我们熟悉的C/C++程序在运行的时候是依赖于一个控制台或者终端这样的东西,我们的全部数据是借这个终端的平台来进行交互的。
在这个Win32程序中,系统创建了一个进程来执行代码里的全部内容,但不代表系统会自行创建一个窗口,所以在Win32程序中我们必须先创建一个窗口来进行这样的一个数据交互工作。
创建一个窗口大概有这样的几个步骤:
1、注册一个窗口的样式(RegisterClassEx())
2、利用刚创建的窗口样式创建一个窗口实例(CreateWindowEx())
3、消息循环(GetMessage()/TranslateMessage()/DispatchMessage())
每个步骤都对应一个或多个关键函数。
首先是注册窗口函数RegisterClassEx:
这个函数只需要一个类型为WNDCLASSEX的参数。
而WNDCLASSEX是一个结构体,所以我们仅需根据MSDN中的描述将所需创建窗口样式赋值给结构体实例相应变量,传入函数即可。
值得注意的几个属性变量:
cbSize:WNDCLASSEX结构体自身的大小,防止以后对该结构体的扩展
lpszClassName:该注册窗口样式的名称,后面创建窗口则根据该字符串找到该窗口样式
lpfnWndProc:函数指针,指向一个消息处理函数,消息处理函数在后面给出说明
窗口创建函数CreateWindowEx:
HWND CreateWindowEx( DWORD dwExStyle, // extended window style LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu, or child-window identifier HINSTANCE hInstance, // handle to application instance LPVOID lpParam // pointer to window-creation data );
消息处理相关函数:
消息获取函数GetMessage:
第一个参数是一个MSG结构体指针,MSG结构体记录了待处理消息的信息,该函数将得到的消息信息放入该指针指向的MSG结构体空间。BOOL GetMessage( LPMSG lpMsg, // address of structure with message HWND hWnd, // handle of window UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message );
后面三个参数起对消息过滤的作用,一般给定NULL,0,0即可,表示不作过滤。
消息翻译函数TranslateMessage:
将得到的消息传入该函数作一定处理,再由派发消息函数对该消息调用消息处理函数。BOOL TranslateMessage( CONST MSG *lpMsg // address of structure with message );
消息派发函数DispatchMessage:
LONG DispatchMessage( CONST MSG *lpmsg // pointer to structure with message );
三、消息处理函数
LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter );
这是一个回调函数,需要自行编写,然后将函数地址在注册窗口时赋值给相应的变量,在派发消息函数DispatchMessage中被系统调用。
hwnd是消息的来源窗口句柄。
uMsg是消息标志。
WPARAM与LPARAM则是消息发送时给定的两个参数,不同消息的含义有所不同。
四、代码实例
#include<windows.h> HINSTANCE g_hInstance=NULL; LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { if(uMsg==WM_DESTROY) { PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,uMsg,wParam,lParam); } ATOM InitApplication(HINSTANCE hInstance) { WNDCLASSEX wcex={0}; wcex.cbSize =sizeof(wcex); wcex.style =CS_HREDRAW|CS_VREDRAW; wcex.lpfnWndProc =WindowProc; wcex.cbClsExtra =0; wcex.cbWndExtra =0; wcex.hInstance =hInstance; wcex.hIcon =LoadIcon(NULL,IDI_APPLICATION); wcex.hIconSm =LoadIcon(NULL,IDI_APPLICATION); wcex.hCursor =LoadCursor(NULL,IDC_ARROW); wcex.hbrBackground=GetSysColorBrush(COLOR_3DFACE); wcex.lpszMenuName =NULL; wcex.lpszClassName="MAIN"; return RegisterClassEx(&wcex); } BOOL InitInstance(HINSTANCE hInstance,int nCmdShow) { g_hInstance=hInstance; HWND hwndMain=CreateWindowEx(WS_EX_CLIENTEDGE, "MAIN", "MyWin", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if(hwndMain==NULL) return 0; ShowWindow(hwndMain,nCmdShow); UpdateWindow(hwndMain); return 1; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if(!InitApplication(hInstance)) return 0; if(!InitInstance(hInstance,nCmdShow)) return 0; MSG Msg={0}; while(GetMessage(&Msg,NULL,0,0)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return 0; }