《Windows程序设计》读书笔记------------->>窗口和消息 ---- 具体设定<<

本文深入剖析Windows程序结构,重点解读窗口注册与初始化过程,并通过详细示例解释如何处理消息循环及窗口消息。

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

以前在玩C编程的时候完全么有见过这么多参数的程序,Windows程序就是参数多,都不知道都是干些什么的。虽然有些参数可以简单的设定成NULL或者0,但是还是很麻烦就是了。那么就一句句分析好了。

前天说过了这个程序的结构,因为第一部分致使一些函数的调用,后面的才是关键,我就整理一下书上的内容好了。我实在搞不懂书上那个程序,只好以VC++的为准了。

 

//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释: 
//
//    仅当希望在已添加到 Windows 95 的
//    “RegisterClassEx”函数之前此代码与 Win32 系统兼容时,
//    才需要此函数及其用法。调用此函数
//    十分重要,这样应用程序就可以获得关联的
//   “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
 WNDCLASSEX wcex;

 wcex.cbSize 
= sizeof(WNDCLASSEX); 

 wcex.style   
= CS_HREDRAW | CS_VREDRAW;
 wcex.lpfnWndProc 
= (WNDPROC)WndProc;
 wcex.cbClsExtra  
= 0;
 wcex.cbWndExtra  
= 0;
 wcex.hInstance  
= hInstance;
 wcex.hIcon   
= LoadIcon(hInstance, (LPCTSTR)IDI_HELLOWIN);
 wcex.hCursor  
= LoadCursor(NULL, IDC_ARROW);
 wcex.hbrBackground 
= (HBRUSH)(COLOR_WINDOW+1);
 wcex.lpszMenuName 
= (LPCTSTR)IDC_HELLOWIN;
 wcex.lpszClassName 
= szWindowClass;
 wcex.hIconSm  
= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

 
return RegisterClassEx(&wcex);
}



来来来,一个个来,先看看这个,从数目上面看这里是最难的,参数多。不过一个个看就不这么难了。

 

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
    
/*首先是第一行,这里定义了一个WNDCLASSEX类型,不过我就不知道这个WNDCLASSEX和WNDCLASSA还有WNDCLASSW是什么关系了,反正就是一个参数的结构类型。*/

    wcex.cbSize 
= sizeof(WNDCLASSEX);
    
/*顾名思义,这个就是储存这个结构的大小咯*/
    
    wcex.style            
= CS_HREDRAW | CS_VREDRAW;
    
/*使用C的位「或」运算子结合了两个「窗口类别样式」标识符。如果看了书的话可以发现其实他们都是有预定义的。定义到数字上,我以前看书的时候似乎看到有说,这些数字为了可以任意多个进行合并,使用了分支的方法,就是有N个2位,每个2位代表一个类别(比如说A是001,B是010),这样合并的时候就互不干扰了!有兴趣试试这些数符合不符合?!*/

    wcex.lpfnWndProc    
= (WNDPROC)WndProc;
    
/*设定窗口消息处理程序,就是告诉Windows当这个窗口发生变化的时候,去找谁。“在C语言中,像这样在结构中使用函数名时,真正提供的是指向函数的指标。”*/

    wcex.cbClsExtra        
= 0;
    wcex.cbWndExtra        
= 0;
    
/*用于在窗口类别结构和Windows内部保存的窗口结构中预留一些额外空间,程序可以根据需要来使用预留的空间。HELLOWIN没有使用它们,所以设定值为0。*/

    wcex.hInstance        
= hInstance;
    
/*程序的执行实体句柄(它也是WinMain的参数之一)*/

    wcex.hIcon            
= LoadIcon(hInstance, (LPCTSTR)IDI_HELLOWIN);
    
/*设置一个图标*/

    wcex.hCursor        
= LoadCursor(NULL, IDC_ARROW);
    
/*设置一个指针样式*/

    wcex.hbrBackground    
= (HBRUSH)(COLOR_WINDOW+1);
    
/*依据这个类别建立的窗口背景颜色,GetStockObject呼叫将传回一个白色画刷的句柄,这意味着窗口显示区域的背景完全为白色。*/

    wcex.lpszMenuName    
= (LPCTSTR)IDC_HELLOWIN;
    
/*指定窗口类别菜单,当然,如果你不想要可以设置成NULL,这样就和书上那个一样了。*/

    wcex.lpszClassName    
= szWindowClass;
    
/*给出一个类别名称,就是窗口的名称,因为只有一个窗口,所以只要和程序名称一样就可以了。*/

    wcex.hIconSm        
= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
    
/*这个干什么的呢?书上没有的呀?不知道了。。。。*/

    
return RegisterClassEx(&wcex);
}

下面就是函数: InitInstance(HANDLE, int)了:

 

//
//   函数: InitInstance(HANDLE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释: 
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst 
= hInstance; // 将实例句柄存储在全局变量中

   hWnd 
= CreateWindow(
       szWindowClass,         
//Windows类别名称
       szTitle,                /*Windows窗口名称,不要和上面那个搞混了!不一样的,上面的只是起指示作用,这个才会真正地显示出来。*/
       WS_OVERLAPPEDWINDOW,
//风格
       CW_USEDEFAULT,        //指定了窗口左上角相对于屏幕左上角的初始位置,这里是默认的迭代方式
       0
       CW_USEDEFAULT,        
//制定窗口大小,这里使用默认设定
       0
       NULL,                
//父窗口句柄,这里使直接建立一个窗口,所以不用
       NULL,                //窗口菜单句柄,按道理这里应该是有菜单的,就不知道为什么这里没有了
       hInstance,            //「程序执行实体句柄」设定为执行实体句柄,它是作为WinMain的参数传递给这个程序的。
       NULL);                //「建立参数」指标设定为NULL,可以用这个参数存取稍后程序中可能引用到的数据。不知道怎么用。。。。


   
if (!hWnd)
   {
      
return FALSE;            //建立失败
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   
return TRUE;
}

 

 

    // 主消息循环:
    while (GetMessage(&msg, NULL, 00))        //从消息队列中取出一个消息,传给Windows一个指标,指向名为msg的MSG结构。
    {
        
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
        {
            TranslateMessage(
&msg);            //将msg结构传给Windows,进行一些键盘转换。
            DispatchMessage(&msg);            //将msg结构回传给Windows。然后,Windows将该消息发送给适当的窗口消息处理程序,让它进行处理。
        }
    }

    
return (int) msg.wParam;
}

 

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
/*窗口消息处理程序的四个参数与MSG结构的前四个字段是相同的。第一个参数hwnd是接收消息的窗口的句柄,它与CreateWindow函数的传回值相同。对于与HELLOWIN相似的程序(只建立一个窗口),这个参数是程序所知道的唯一窗口句柄。如果程序是依据同一窗口类别(同时也是同一窗口消息处理程序)建立多个窗口,则hwnd标识接收消息的特定窗口。*/

{
    
int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    RECT rect;

    
switch (message) 
    {
    
case WM_COMMAND:
        wmId    
= LOWORD(wParam); 
        wmEvent 
= HIWORD(wParam); 

        
// 分析菜单选择:
        
//这个地方书上是没有的,因为人家的没有菜单咯,那就不管先:)
        switch (wmId)
        {
        
case IDM_ABOUT:
            DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
            
break;
        
case IDM_EXIT:
            DestroyWindow(hWnd);
            
break;
        
default:
            
return DefWindowProc(hWnd, message, wParam, lParam);
        }
        
break;

    
case WM_PAINT:            //处理WM_PAINT消息
        hdc = BeginPaint(hWnd, &ps);
        
//TODO: 在此添加任意绘图代码:

        MessageBox(NULL,TEXT (
"我重绘窗口了!"),TEXT ("Hei here"), 0);
        
/*开始的时候绘制,大小改变的时候绘制,甚至有东西覆盖也要重新绘制。运行一下就知道了。*/
        GetClientRect (hWnd, 
&rect) ;
        DrawText (hdc, TEXT (
"Hello, Windows 98!"), -1&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;

        EndPaint(hWnd, 
&ps);
        
break;

    
case WM_DESTROY:        // 处理WM_DESTROY消息
        MessageBox(NULL,TEXT ("我退出了!"),TEXT ("Hei here"), 0);                //窗口关闭
        PostQuitMessage(0);
        
break;
    
default:
        
return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
return 0;
}

 

好了,基本就这么多了,写了前面的我就已经头大了,所以后面基本上就抄书上的了,我在消息处理函数那里加入了一些MessageBox,这样在运行的时候就可以知道什么时候会调用这个消息了。

-----------------------------------------------

我发现的一个问题:一开始我老找不到

TCHAR szTitle[MAX_LOADSTRING];                    // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

这个在怎么地方被定义成了HELLOWIN,其实这个在下面这个函数中真正被定义了:

    // 初始化全局字符串
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_HELLOWIN, szWindowClass, MAX_LOADSTRING);

那么我看呀看,终于在资源列表里面发现了IDS_APP_TITLE和IDC_HELLOWIN的踪影,看图:

就是这了,进去以后你会发现这样的好处是方便集中修改,不过要以后才用得到了。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值