第十二章 Winform 框架

本文详细探讨了Win32应用程序结构,包括消息循环、窗口过程和多窗体创建。接着,对比了.NET Winform程序与传统Win32程序的关联,阐述了Windows Forms框架在消息处理、控件和事件模型上的优势。最后,深入介绍了Winform程序结构,包括UI线程、消息循环和窗口过程,以及模式窗体和非模式窗体的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 Win32 应用程序结构

1.1 Windows 消息循环

1.2 窗口过程

1.3 创建基于 Win32 的单窗体应用程序

1.4 创建基于 Win32 的多窗体应用程序

2 .NET Winform 程序与传统 Win32 程序的关联

3 Windows Forms 框架

4 Winform 程序结构

4.1 UI线程

4.2 消息循环

4.3 窗口过程

5 模式窗体与非模式窗体


1 Win32 应用程序结构

1.1 Windows 消息循环

Windows 消息循环结构类似下图:

C++ 中 Windows 消息循环代码类似如下:

MSG msg; // 代表一条消息
BOOL bRet;

// 从UI线程消息队列中取出一条消息
while ((bRet = GetMessage(&msg,NULL,0,0)) != 0)
{
    if (bRet == -1)
    {
        // 错误处理代码,通常是直接退出程序
    }
    else
    {
        TranslateMessage(&msg);   // 转换消息格式
        DispatchMessage(&msg);    // 分发消息给相应的窗体
    }
}

上图显示了 Windows 消息循环的结构,GetMessage 从操作系统中的消息队列(一种数据结构)获取 Windows 消息,(这些消息包括操作系统将用户输入转换而成的、操作系统本身发送给程序的以及其它程序发送给本程序的)。如果获取到的消息不为 WM_QUIT(表示退出含义),那么经过 TranslateMessage 方法进行预处理后,再由 DispatchMessage 将消息投递到指定的窗口过程(WndProc),窗口过程则负责处理消息。

注:GetMessage 方法有三种返回值,当取得 WM_QUIT 消息时,返回 0 值,While 循环退出;当有异常发生时,返回 -1 值;当获取非 WM_QUIT 的其它消息时,返回非 0 非 -1 的值。如果一个程序需要退出,那么 Windows 消息循环所在的线程必须结束,也就是说,While 循环中的 GetMessage 方法必须返回 0 值,由于 WM_QUIT 时 While 循环退出的条件,因此,消息队列中包含有一个 WM_QUIT 消息是程序退出的前提。

C++中 Windows 消息结构体的定义如下:

typedef struct tagMSG {
   HWND        hwnd;
   UINT        message;
   WPARAM      wParam;
   LPARAM      lParam;
   DWORD       time;
   POINT       pt;
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

如上代码所示,消息中包含有消息接收者的窗口句柄 hwnd,消息类型 message(一个数值,代码中常用 WM_PAINT、WM_QUIT 等代表),以及两个消息参数 wParam 和 IParam,还有发送消息时间 time 以及当前光标在屏幕中的坐标位置。消息投递方法 DispatchMessage 就是根据 hwnd 字段,将消息投递给指定窗口的窗口过程,最终由窗口过程处理这一消息。

1.2 窗口过程

消息处理的关键是 DispatchMessage 函数。这个函数根据取出的消息中所包含的窗体句柄,将这一消息转发给此句柄所对应的窗体对象。
而窗体负责响应消息的函数称为 “窗体过程(Window Procedure)”。

窗口过程用 C++ 代码声明类似如下:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   int wmId, wmEvent;
   switch (message)
   {
      case WM_COMMAND:
         wmId = LOWORD(wParam); // 发送消息的控件或菜单的ID
         wmEvent = HIWORD(wParam); // 通知消息
         // 分析菜单选择
         switch (wmId)
         {
            case IDM_ABOUT:
               DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
               break;
            case IDM_EXIT:
               DestroyWindow(hWnd);
               break;
            default:
               return DefWindowProc(hWnd, message, wParam, lParam);
         }
         break;
      case WM_PAINT:
         // draw something here with gdi win32 api
         break;
      case WM_DESTROY:
         PostQuitMessage(0);   // 给消息队列发送一个 WM_QUIT 消息,下一次消息循环时,GetMessage 从操作系统中的消息队列中取出 WM_QUIT 后,While 消息循环就会结束。
         break;
      default:
         return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

注:如果窗口为一个程序的主窗体,那么当这个窗口关闭后,程序应该退出(While 循环结束),又因为当关闭窗体后,系统会有一个 WM_DESTROY 消息发送给窗口过程(注意是直接发送给窗口过程),那我们完全可以在 switch/case 中拦截 WM_DESTROY 消息,然后调用 PostQuitMessage 这个 Win32 API 处理。

在 Windows 中,消息分成了两类:

1、队列消息:需要存入消息队列,然后由消息循环取出来之后才能被窗口过程处理。例如:WM_PAINT、WM_QUIT

2、非队列消息:不需要存入消息队列,也不经过消息循环,它们直接传递给窗口过程,由窗口过程直接处理。例如:WM_DESTROY

注:可以用 PostMessage() 或 SendMessage() 发送消息。PostMessage() 把一个消息放入消息队列后立即返回,也就是当调用 PostMessage(),函数执行完成返回时,很可能消息尚未处理。SendMessage() 直接将消息发送到窗口,直到这个消息处理完成才返回。如果要关闭一个窗口,可以给它发送一个 WM_CLOSE 消息,像PostMessage(hwnd,WM_CLOSE,0,0); 效果跟点击窗口右上角的关闭按钮是一样的。注意这里的 wParam 和 IParam 的值都是0,因为 WM_CLOSE 消息会忽略上述两个参数。

1.3 创建基于 Win32 的单窗体应用程序

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)    //NO.1 程序入口方法
{
   WNDCLASSEX wcex;
   wcex.style = CS_HREDRAW | C
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值