最近不想用MFC写东西了,有没有安装Qt和其他图形化开发环境,只能捣鼓API了。于是乎,就有了以下的学习--
首先,老套的创建个Windows窗口,由于自己有点小懒,就直接用Hello Word的源码了。
#include <windows.h> #include <stdio.h> // 窗口过程函数 LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { // 窗口类 WNDCLASS wndcls; wndcls.cbClsExtra = 0; // 类附加内存 wndcls.cbWndExtra = 0; // 窗口附加内存 wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW); // 背景画刷句柄 wndcls.hCursor = LoadCursor(NULL, IDC_ARROW); // 窗口光标句柄 wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 窗口图标句柄 wndcls.hInstance = hInstance; // 包含窗口过程函数的程序实例 wndcls.lpfnWndProc = WinSunProc; // 只想窗口过程函数的指针 wndcls.lpszClassName = "CRoot"; // 窗口类名称 wndcls.lpszMenuName = NULL; // 菜单资源 wndcls.style = CS_HREDRAW | CS_VREDRAW; // 窗口样式 RegisterClass(&wndcls); // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄 HWND hwnd; hwnd = CreateWindow( // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL "CRoot", // 窗口类名 "Hello World", // 窗口名字 WS_CAPTION|WS_SYSMENU, // 窗口样式 CW_USEDEFAULT, CW_USEDEFAULT, // 窗口左上角坐标 200, 120, // 窗口宽高 NULL, // 父窗口句柄 NULL, // 窗口菜单句柄 hInstance, // 窗口所属应用程序实例 NULL // WM_CREATE消息附加参数lParam传入的数据指针 ); // 显示及刷新窗口 ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); // 定义消息结构体 MSG msg; while (GetMessage( // WM_QUIT消息返回0 错误返回-1 &msg, // 指向消息的结构体 NULL, // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息 0, // 获取消息的最小值 通常为0 0)) // 获取消息的最大值 都设为0表示接收所有消息 { TranslateMessage(&msg); // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出 DispatchMessage(&msg); // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理 } return msg.wParam; } // 窗口过程函数 LRESULT CALLBACK WinSunProc( HWND hwnd, // 窗口句柄 UINT uMsg, // 消息代码 WPARAM wParam, // 附加参数 LPARAM lParam ) { switch(uMsg) { case WM_CHAR: char szChar[20]; sprintf(szChar, "char code is %d", wParam); MessageBox(hwnd, szChar, "char", 0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }
然后,我们要在消息循环里面添加创建Button的代码,因为Button是一个子窗口,所以创建方式也如同创建窗口一样,使用CreateWindow()函数。
而,此窗口要一开始跟随父窗口出现,所以要在父窗口创建时创建该Button。嗯,所以要在窗口过程函数里面监听下WM_CREATE消息。
代码片段:
switch(uMsg) { case WM_CHAR: char szChar[20]; sprintf(szChar, "char code is %d", wParam); MessageBox(hwnd, szChar, "char", 0); break; case WM_CREATE: CreateWindowEx(0,"Button","按钮1",WS_VISIBLE|WS_CHILD,0,0,100,50,hwnd,(HMENU)0,0,0); default: return DefWindowProc(hwnd, uMsg, wParam, lParam); }
这里要说明一下啦,一开始我也搞得晕晕乎乎,不知道怎么搞Button的消息事件,这里我们用Button的ID啦。先看下微软的MSDN关于CreateWindow()函数
HWND WINAPI CreateWindow( _In_opt_ LPCTSTR lpClassName, _In_opt_ LPCTSTR lpWindowName, _In_ DWORD dwStyle, _In_ int x, _In_ int y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam );
关键点在参数HMENU hWndParent,第一眼一看是不是感觉像菜单?不错啦~确实在菜单中用到的。进一步看他的解释
hMenu [in, optional]
Type: HMENU
A handle to a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.
红色选中大体意思说,当在做一个子窗口的时候,这个参数就是一个整形表示,用于标识这个子窗口,提供父窗口的消息处理。总的来说就是所谓的控件ID啦~
既然有标识,就好办啦,我们就判断是不是他,若是这个按钮,我们就让他响应相应的操作啦~~
但是怎么知道按钮被Click了呢?我们又得监听另一个消息WM_COMMAND,它有两个参数,其中一个就传输了所谓的控件ID
wParam
For a description of this parameter.
lParam
For a description of this parameter.
我们可以判断他如果是这个按钮的ID,我们就让他干某些事情。我们首先要转换下wParam的类型,否则和我们写的ID的类型不一样的。
case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); switch (wmId) { case (0)://之前我们创建按钮时,写的ID为0
//功能代码 //....... break; //...更多代码 }
好了,整体框架差不多完工啦,自己再加下代码啥的就没问题了。在这里,我再次浪费下篇幅,给出完整代码:
关于wmId一开始写程序没有编译,因为逻辑错误,未有注意到,忘记声明他了。为了防止被default给忽略掉,我们把他写在switch(uMsg)之前。
1 #include <windows.h> 2 #include <stdio.h> 3 #include <Windef.h> 4 5 // 窗口过程函数 6 LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 7 8 int WINAPI WinMain( 9 HINSTANCE hInstance, // handle to current instance 10 HINSTANCE hPrevInstance, // handle to previous instance 11 LPSTR lpCmdLine, // command line 12 int nCmdShow // show state 13 ) 14 15 { 16 // 窗口类 17 WNDCLASS wndcls; 18 wndcls.cbClsExtra = 0; // 类附加内存 19 wndcls.cbWndExtra = 0; // 窗口附加内存 20 wndcls.hbrBackground = (HBRUSH) GetStockObject(COLOR_WINDOW); // 背景画刷句柄 21 wndcls.hCursor = LoadCursor(NULL, IDC_ARROW); // 窗口光标句柄 22 wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 窗口图标句柄 23 wndcls.hInstance = hInstance; // 包含窗口过程函数的程序实例 24 wndcls.lpfnWndProc = WinSunProc; // 只想窗口过程函数的指针 25 wndcls.lpszClassName = "CRoot"; // 窗口类名称 26 wndcls.lpszMenuName = NULL; // 菜单资源 27 wndcls.style = CS_HREDRAW | CS_VREDRAW; // 窗口样式 28 RegisterClass(&wndcls); 29 30 // 创建窗口, 定义一个变量用来保存成功创建窗口后返回的句柄 31 HWND hwnd; 32 hwnd = CreateWindow( // 窗口创建成功时返回为窗口分配的句柄 失败时返回NULL 33 "CRoot", // 窗口类名 34 "Hello World", // 窗口名字 35 WS_CAPTION|WS_SYSMENU, // 窗口样式 36 CW_USEDEFAULT, CW_USEDEFAULT, // 窗口左上角坐标 37 200, 120, // 窗口宽高 38 NULL, // 父窗口句柄 39 NULL, // 窗口菜单句柄 40 hInstance, // 窗口所属应用程序实例 41 NULL // WM_CREATE消息附加参数lParam传入的数据指针 42 ); 43 44 // 显示及刷新窗口 45 ShowWindow(hwnd, SW_SHOWNORMAL); 46 UpdateWindow(hwnd); 47 48 // 定义消息结构体 49 MSG msg; 50 while (GetMessage( // WM_QUIT消息返回0 错误返回-1 51 &msg, // 指向消息的结构体 52 NULL, // 指定接收属于哪一窗口的消息 通常设为NULL,用来接收属于调用线程的所有窗口的窗口消息 53 0, // 获取消息的最小值 通常为0 54 0)) // 获取消息的最大值 都设为0表示接收所有消息 55 { 56 TranslateMessage(&msg); // 将虚拟消息转换为字符消息 投递到调用线程的消息队列中 下次调用GetMessage时被取出 57 DispatchMessage(&msg); // 将消息传递给操作系统 由操作系统调用窗口过程函数对消息进行处理 58 } 59 return msg.wParam; 60 } 61 62 // 窗口过程函数 63 LRESULT CALLBACK WinSunProc( 64 HWND hwnd, // 窗口句柄 65 UINT uMsg, // 消息代码 66 WPARAM wParam, // 附加参数 67 LPARAM lParam 68 ) 69 { 70 WORD wmId = LOWORD(wParam); 71 //WORD wmEvent = HIWORD(wParam); 72 switch(uMsg) 73 { 74 /*case WM_CHAR: 75 char szChar[20]; 76 sprintf(szChar, "char code is %d", wParam); 77 MessageBox(hwnd, szChar, "char", 0); 78 break;*/ 79 case WM_CREATE: 80 CreateWindowEx(0,"Button","按钮1",WS_VISIBLE|WS_CHILD,0,0,70,40,hwnd,(HMENU)0,0,0); 81 break; 82 case WM_COMMAND: 83 switch (wmId) 84 { 85 case 0://(HMENU) 和创建中的id对应 86 //这里写你要让按钮实现的功能 87 MessageBoxA(NULL,"Hello Button!","My TestProject",MB_OK); 88 } 89 break; 90 91 default: 92 return DefWindowProc(hwnd, uMsg, wParam, lParam); 93 } 94 95 return 0; 96 }
目前已经在GNU GCC Compiler成功!