《Windows程序设计》读书笔记------------->>窗口和消息 -- 代码结构和消息机制<<

本文深入剖析了Windows编程的基础,包括窗口程序结构、关键函数的作用及调用顺序等核心内容,为初学者提供了清晰的学习路径。

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

这一节内容真正进入到了Windows编程最重要的部分,我以前老看不懂的地方就是这了。写程序,语言至少看得懂,但是代码放在在什么地方也是一个很重要的问题。现在终于有时间静下心来读一读,终于弄清楚了基本的Windows窗口程序的结构,这下放代码就有地方放咯!

这一节内容真是太多了,为了简单,抛开具体的设定不说,从结构上分析代码。

大多数结构VC都写好了注释了,其他的我都添加到到注释里面好了。

 

// HELLOWIN.cpp : 定义应用程序的入口点。
//

#include 
"stdafx.h"
#include 
"HELLOWIN.h"
#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;                                // 当前实例
TCHAR szTitle[MAX_LOADSTRING];                    // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, 
int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

/*
上面这部分就是些定义咯,没有什么好看的,就是看看每个变量干什么用的,不过那也要等到下一节慢慢分析代码的时候才有用。
*/


int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     
int       nCmdShow)
{
     
// TODO: 在此放置代码。

    MSG msg;
    HACCEL hAccelTable;

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

    
// 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow)) 
    
{
        
return FALSE;            
        
/*
        初始化失败的解决办法,也就是书上能加上    [MessageBox (  NULL, TEXT ("This program requires Windows NT!"),szAppName, MB_ICONERROR) ;的地方(我猜的:)
        
*/


    }


    hAccelTable 
= LoadAccelerators(hInstance, (LPCTSTR)IDC_HELLOWIN);

/*
到这里程序已经完成了窗口的设定,注册还有创建的工作,这个地方和书上的不同的地方在于,这里完全结构化了,没有出现具体的代码,都是通过不同的函数一步步完成了一系列工作。具体每个函数是干什么的,往下看,那里的解释还是非常详细的。这么做可以方便程序员该程序,迅速找到要改的地方。
*/



    
// 主消息循环:
    while (GetMessage(&msg, NULL, 00)) 
    
{
        
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
        
{
            
//MessageBox(NULL,TEXT ("I got message!"),TEXT ("Hei here"), 0);

            TranslateMessage(
&msg);
            DispatchMessage(
&msg);
        }

    }


/*
这里就是Windows程序和以前的控制台程序最大的不同了,通过消息队列的方式处理对窗口的操作。
*/


    
return (int) msg.wParam;
}




//
//  函数: 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);
}


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

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

   hWnd 
= CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 
0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   
if (!hWnd)
   
{
      
return FALSE;
   }


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

   
return TRUE;
}


//
//  函数: WndProc(HWND, unsigned, WORD, LONG)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND    - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY    - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
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:            //窗口绘制就是这了
        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:
        MessageBox(NULL,TEXT (
"我退出了!"),TEXT ("Hei here"), 0);                //窗口关闭
        PostQuitMessage(0);
        
break;
    
default:
        
return DefWindowProc(hWnd, message, wParam, lParam);
    }

    
return 0;
}


// “关于”框的消息处理程序。
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    
switch (message)
    
{
    
case WM_INITDIALOG:
        
return TRUE;

    
case WM_COMMAND:
        
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
        
{
            EndDialog(hDlg, LOWORD(wParam));
            
return TRUE;
        }

        
break;
    }

    
return FALSE;
}

 

嗯嗯,不错看来我自学真是天才,都会举一反三了,哈哈。下面就是程序运行的机理了:

最直观的方法是看这个程序运行函数的顺序,<Windows程序设计>已经列出来了:

 

Windows函数呼叫


HELLOWIN至少呼叫了18个Windows函数。下面以它们在HELLOWIN中出现的次序列出这些函数以及各自的简明描述:

LoadIcon 加载图标供程序使用。
  
LoadCursor 加载鼠标光标供程序使用。
  
GetStockObject 取得一个图形对象(在这个例子中,是取得绘制窗口背景的画刷对象)。
  
RegisterClass 为程序窗口注册窗口类别。
  
MessageBox 显示消息框。
  
CreateWindow 根据窗口类别建立一个窗口。
  
ShowWindow 在屏幕上显示窗口。
  
UpdateWindow 指示窗口自我更新。
  
GetMessage 从消息队列中取得消息。
  
TranslateMessage 转译某些键盘消息。
  
DispatchMessage 将消息发送给窗口消息处理程序。
  
PlaySound 播放一个声音文件。
  
BeginPaint 开始绘制窗口。
  
GetClientRect 取得窗口显示区域的大小。
  
DrawText 显示字符串。
  
EndPaint 结束绘制窗口。
  
PostQuitMessage 在消息队列中插入一个「退出程序」消息。
  
DefWindowProc 执行内定的消息处理。

 

去除一些关系不是很大的,发现了运行的顺序是这样的:

 

所以,以后要在不同的情况下疳不同的事情应该就是在处理主窗口的消息的函数这里修改了。

 

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

关于“匈牙利表示法”实在是。。。。盗版书的了:

读者可能注意到,HELLOWIN.C中有一些变量的名字显得很古怪。如szCmdLine,它是传递给WinMain的参数。

许多Windows程序写作者使用一种叫做「匈牙利表示法」的变量命名通则。这是为了纪念传奇性的Microsoft程序写作者Charles Simonyi。非常简单,变量名以一个或者多个小写字母开始,这些字母表示变量的数据型态。例如,szCmdLine中的sz代表「以0结尾的字符串」。在hInstance和hPrevInstance中的h前缀表示「句柄」;在iCmdShow中的i前缀表示「整数」。WndProc的后两个参数也使用匈牙利表示法。正如我在前面已经解释过的,尽管wParam应该更适当地被命名为uiParam(代表「无正负号整数」),但是因为这两个参数是使用数据型态WPARAM和LPARAM定义的,因此保留它们传统的名字。

在命名结构变量时,可以用结构名(或者结构名的一种缩写)的小写作为变量名的前缀,或者用作整个变量名。例如,在HELLOWIN. C的WinMain函数中,msg变量是MSG型态的结构;wndclass是WNDCLASSEX型态的一个结构。在WndPmc函数中,ps是一个PAINTSTRUCT结构,rect是一个RECT结构。

匈牙利表示法能够帮助程序写作者及早发现并避免程序中的错误。由于变量名既描述了变量的作用,又描述了其数据型态,就比较容易避免产生数据型态不合的错误。

表3-4列出了在本书中经常用到的变量前缀。

表3-4

前缀

数据型态

c

char或WCHAR或TCHAR

by

BYTE (无正负号字符)

n

short

i

int

x, y

int分别用作x坐标和y坐标

cx, cy

int分别用作x长度和y长度;C代表「计数器」

b或f

BOOL (int);f代表「旗标」

w

WORD (无正负号短整数)

l

LONG (长整数)

dw

DWORD (无正负号长整数)

fn

function(函数)

s

string(字符串)

sz

以字节值0结尾的字符串

h

句柄

p

指标

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值