Windows程序设计相关参数理解
| WinMain入口函数 |
| |
| int APIENTRY WinMain(HINSTANCE hInstance, |
| HINSTANCE hPrevInstance, |
| LPSTR lpCmdLine, |
| int nCmdShow) |
| |
| 窗口回调函数(消息处理函数) |
| |
| LRESULT CALLBACK WindowProc( |
| IN HWND hwnd, |
| IN UINT uMsg, |
| IN WPARAM wParam, |
| IN LPARAM lParam |
| ); |
HINSTANCE理解
- 1.变量类型 HINSTANCE
- (1) HINSTANCE是Windows里面的一种数据类型,其实她本质就是个无符号长整型,针对32位的Windows操作系统,她用于标记或者说记录一个程序的实例,她与HMODULE是一样的,这两种类型最终都是无符号长整型;
- (2) HINSTANCE,如果分开看的话,就是H+INSTANCE,其中H代表HANDLE(翻译为"句柄"),INSTANCE翻译就是"实例"的意思
- (3) 实例HINSTANCE在VC++6.0上查找对应定义的具体代码选中HINSTANCE,且包含Windows的头文件然后F12找到对应定义的位置在C:\Program Files\Microsoft Visual Studio\VC98\Include\WINDEF.H
| DECLARE_HANDLE(HINSTANCE); |

- (4) 看到前面定义的是DECLARE_HANDLE,再次F12进去看看具体代码,得到如下位置:C:\Program Files\Microsoft Visual Studio\VC98\Include\WINNT.H
| #ifdef STRICT |
| typedef void *HANDLE; |
| #define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name |
| #else |
| typedef PVOID HANDLE; |
| #define DECLARE_HANDLE(name) typedef HANDLE name |
| #endif |
| typedef HANDLE *PHANDLE; |

- (5) 通过上面的代码发现DECLARE_HANDLE()是一个条件预定义,那么根据这个条件STRICT查看是否成立,再次选中STRICT按住F12进行查看
| #ifndef _WINDEF_ |
| #define _WINDEF_ |
| |
| #ifndef NO_STRICT |
| #ifndef STRICT |
| #define STRICT 1 |
| #endif |
| #endif |

- (6) 通过上面的STRICT的定义为1,得知其是默认被定义的,这样我们再回头看看上面的代码
| #define DECLARE_HANDLE(name) struct name##__ ; typedef struct name##__ *name |
- (7) 上面代码其中##在宏里面是表示字符连接的作用,所以回到上面DECLARE_HANDLE(name)代码我们就可以有如下理解
| DECLARE_HANDLE(name) 根据实例WinMain实例函数,就变成了DECLARE_HANDLE(HINSTANCE) |
| 再开始宏扩展 |
| DECLARE_HANDLE(HINSTANCE)变成如下: |
| |
| struct HINSTANCE__ { int unused; }; typedef struct HINSTANCE__ *HINSTANCE |
| |
| struct HINSTANCE__ |
| { |
| int unused; |
| }; |
| typedef struct HINSTANCE__ *HINSTANCE |
| |
| 得到上面的结果,然后我们可以这样理解: |
| |
| 定义了一个结构体HINSTANCE__,这个结构体里面就只有一个int类型的变量; |
| 然后将这个结构体HINSTANCE__变成结构体指针类型:HINSTANCE__* ; |
| 最后才将HINSTANCE__*这个结构体指针类型别名为HINSTANCE; |
| |
总结:HINSTANCE是个数据类型,本质就是个结构体指针,里面结构体成员只有一个int类型变量,指向的是PE结构中讲到的ImageBase,仅此而已;
HWND理解
- 2.变量类型 HWND
- (1) HWND同样是个数据类型,可以把她看作像是身份证号一样,是唯一的标识,当窗口被创建的时候会分配一个句柄,这个句柄是唯一的,可以通过这个句柄找到窗口的各种属性;
- (2) HWND可以拆分为H和WND,其中H是Handle,就会是句柄的一些,而WND就是变量对象的描述,全称就是Windows,合起来就是Handle of Windows,缩写就是上面我们所的HWND,翻译为窗口句柄;
- (3) 同样的操作,包含Windows头文件,选中HWND按住F12进入定义的代码,如下:
| 路径:C:\Program Files\Microsoft Visual Studio\VC98\Include\WINDEF.H |
| DECLARE_HANDLE (HWND); |

- (4) 看到上面的代码同样定义了DECLARE_HANDLE,而这跟上面HINSTANCE的定义是一样的,所以这里不就再查看重复的代码定义内容,也因为如此,可以得出同样的结论,HWND也是个结构体类型指针,里面定义的类型同样是int类型,只是她这个结构体指针指向的是Windows给其分配的一个唯一的ID而已;
总结:HWND同样是个数据类型,只是改了名称叫法而已,叫做窗口句柄,将其实例化后,就是个整型int类型的数据,只是是用指针的方式指向她,其本质是个结构体指针,里面结构体成员只有一个int类型变量,所以HWND是个带有int类型成员的结构体指针,指向每个不同的窗口,并且给不同的窗口分配唯一的编号,通过这个编号就能找到不同的窗口,仅此而已;
根据实例代码理解
| #include "stdafx.h" |
| |
| HINSTANCE hAppInstance |
| |
| LRESULT CALLBACK WindowProc( |
| IN HWND hwnd, |
| IN UINT uMsg, |
| IN WPARAM wParam, |
| IN LPARAM lParam |
| ) |
| |
| void __cdecl OutputDebugStringF(const char *format, ...) |
| { |
| va_list vlArgs; |
| char *strBuffer = (char*)GlobalAlloc(GPTR, 4096) |
| |
| va_start(vlArgs, format) |
| _vsnprintf(strBuffer, 4096 - 1, format, vlArgs) |
| va_end(vlArgs) |
| strcat(strBuffer, "\n") |
| OutputDebugStringA(strBuffer) |
| GlobalFree(strBuffer) |
| return |
| } |
| |
| void CreateButton(HWND hwnd) |
| { |
| HWND hwndPushButton |
| HWND hwndCheckBox |
| HWND hwndRadio |
| |
| hwndPushButton = CreateWindow( |
| TEXT("button"), |
| TEXT("普通按钮"), |
| //WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_DEFPUSHBUTTON, |
| //WS_CHILD 表示当前按钮是子窗口 |
| WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON| BS_DEFPUSHBUTTON, |
| 10, |
| 10, |
| 80, |
| 20, |
| hwnd, |
| (HMENU)1001, //子窗口ID |
| hAppInstance, |
| NULL |
| ) |
| |
| //获取button的WNDCLASS |
| TCHAR szBuffer[0x20] |
| GetClassName(hwndPushButton, szBuffer, 0x20) |
| |
| WNDCLASS wc |
| GetClassInfo(hAppInstance, szBuffer, &wc) |
| OutputDebugStringF("-->%s\r\n", wc.lpszClassName) |
| OutputDebugStringF("-->%x\r\n", wc.lpfnWndProc) |
| |
| hwndCheckBox = CreateWindow ( |
| TEXT("button"), |
| TEXT("复选框"), |
| //WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BS_AUTOCHECKBOX, |
| WS_CHILD | WS_VISIBLE | BS_CHECKBOX |BS_AUTOCHECKBOX, |
| 10, 40, |
| 80, 20, |
| hwnd, |
| (HMENU)1002, //子窗口ID |
| hAppInstance, |
| NULL) |
| |
| hwndRadio = CreateWindow ( |
| TEXT("button"), |
| TEXT("单选按钮"), |
| //WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON | BS_AUTORADIOBUTTON, |
| WS_CHILD | WS_VISIBLE | BS_RADIOBUTTON, |
| 10, 70, |
| 80, 20, |
| hwnd, |
| (HMENU)1003, //子窗口ID |
| hAppInstance, |
| NULL) |
| } |
| |
| int APIENTRY WinMain(HINSTANCE hInstance, |
| HINSTANCE hPrevInstance, |
| LPSTR lpCmdLine, |
| int nCmdShow) |
| { |
| hAppInstance = hInstance |
| TCHAR className[] = TEXT("My First Windows") |
| |
| WNDCLASS wndclass = {0} |
| wndclass.hbrBackground = (HBRUSH)COLOR_MENU |
| wndclass.lpfnWndProc = WindowProc |
| wndclass.lpszClassName = className |
| wndclass.hInstance = hInstance |
| |
| RegisterClass(&wndclass) |
| |
| HWND hwnd = CreateWindow( |
| className, |
| TEXT("我的第一个窗口"), |
| WS_OVERLAPPEDWINDOW, |
| 10, |
| 10, |
| 600, |
| 300, |
| NULL, |
| NULL, |
| hInstance, |
| NULL) |
| |
| if(hwnd == NULL) |
| return 0 |
| |
| CreateButton(hwnd) |
| |
| ShowWindow(hwnd, SW_SHOW) |
| |
| MSG msg |
| while(GetMessage(&msg, NULL, 0, 0)) |
| { |
| TranslateMessage(&msg) |
| DispatchMessage(&msg) |
| } |
| |
| return 0 |
| } |
| |
| LRESULT CALLBACK WindowProc( |
| IN HWND hwnd, |
| IN UINT uMsg, |
| IN WPARAM wParam, |
| IN LPARAM lParam |
| ) |
| { |
| //OutputDebugStringF("%d \r\n", uMsg) |
| switch(uMsg) |
| { |
| case WM_CREATE: |
| { |
| // CREATESTRUCT* p = (CREATESTRUCT*) lParam |
| // OutputDebugStringF("WM_CREATE: %s \r\n", p->lpszClass) |
| // OutputDebugStringF("WM_CREATE: %d \r\n", uMsg) |
| return 0 |
| } |
| case WM_MOVE: |
| { |
| //OutputDebugStringF("WM_MOVE: %d \r\n", uMsg) |
| |
| // DWORD xPos = (int)(short) LOWORD(lParam) |
| // DWORD yPos = (int)(short) HIWORD(lParam) |
| // |
| // OutputDebugStringF("%d - %d \r\n", xPos, yPos) |
| |
| return 0 |
| } |
| case WM_SIZE: |
| { |
| // DWORD xWidth = (int)(short) LOWORD(lParam) |
| // DWORD yHigh = (int)(short) HIWORD(lParam) |
| // OutputDebugStringF("%d - %d \r\n", xWidth, yHigh) |
| return 0 |
| } |
| case WM_KEYUP: |
| { |
| // OutputDebugStringF("WM_KEYUP %d %d \r\n", wParam, lParam) |
| return 0 |
| } |
| case WM_KEYDOWN: |
| { |
| // OutputDebugStringF("WM_KEYDOWN %d %d \r\n", wParam, lParam) |
| return 0 |
| } |
| case WM_LBUTTONDOWN: |
| { |
| OutputDebugStringF("WM_LBUTTONDOWN %d %d \r\n", wParam, lParam) |
| return 0 |
| } |
| case WM_COMMAND: |
| { |
| switch(LOWORD(wParam)) //LOWORD取低两位的2个字节 |
| { |
| case 1001: |
| MessageBox(hwnd,"Hello Button 1","Demo",MB_OK) |
| return 0 |
| case 1002: |
| MessageBox(hwnd,"Hello Button 2","Demo",MB_OK) |
| return 0 |
| case 1003: |
| MessageBox(hwnd,"Hello Button 3","Demo",MB_OK) |
| return 0 |
| } |
| return DefWindowProc(hwnd,uMsg,wParam,lParam) |
| } |
| case WM_DESTROY://这个是销毁窗口的消息 |
| { |
| //OutputDebugStringF("WM_DESTROY %d %d \r\n",wParam,lParam) |
| PostQuitMessage(0) |
| |
| return 0 |
| } |
| } |
| return DefWindowProc(hwnd, uMsg, wParam, lParam) |
| } |
参考
https://www.cnblogs.com/furzoom/p/hinstance.html
https://blog.csdn.net/ljsr123/article/details/104491368
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?