第4章 第一个窗口程序

1 了解窗口

2 窗口程序原理

事件驱动模式


image.png

窗口程序的运行过程


窗口程序的运行过程

DispatchMessage会在内部调用消息处理的回调函数
窗口程序的运行过程

应用程序之间也可互相发送消息
PostMessage 将一个消息放到其他程序的消息队列中
SendMessage 越过消息队列直接调用目标程序的窗口过程

RegisterClassEx 用来注册窗口过程 即用来注册处理窗口消息的回调函数

2 分析窗口程序

2.1 模块与句柄

exe dll装入内存后称为模块,每个模块都有一个唯一标识的句柄,在win32中,模块句柄在数值上等于内存中装入的起始地址,用来标识各种资源
使用GetModuleHandle来获取模块句柄
例子


获取user32.dll的句柄

当参数为NULL,会获取调用者本模块的句柄


image.png

在win32中实例句柄就是模块句柄
hInstance hModule
在C语言编程中 hInstance通过WinMain由系统传入
在win32汇编中,hInstance需要自己获取

windows中几乎所有的东西都是用句柄标识的,如文件句柄、窗口句柄、线程句柄、模块句柄等

2.2 创建窗口

窗口类中定义窗口的属性


窗口类的定义

初始化


窗口类的初始化
hIcon 窗口图标句柄 预定义 可通过LoadIcon指定
hCursor 光标句柄 预定义(IDC_ARROW...) 可通过LoadCursor指定
lpszMenuName 菜单字符串
hInstance 指定窗口类属于哪个模块 GetModuleHandle
cbSize 指定结构的长度
style 窗口风格 CS_HREDRAW CS_VREDRAW CS_DBLCLKS
hbrBackground  刷子句柄 指定窗口客户区的背景色  如BLACK_BRUSH、WHITE_BRUSH 使用 GetStockObject来获取刷子句柄 也可以指定颜色值 如 COLOR_BACKGROUND,COLOR_HIGHLIGHT,COLOR_MENU,COLOR_WINDOW等,需要加1
lpszClassName 指定类的名称
cbWndExtra cbClsExtra 预留的空间 用来存放自定义数据
lpfnWndProc 回调函数

使用CreateWindowEx来建立窗口

HWND CreateWindowEx(
    DWORD dwExStyle,    // extended window style WS_EX_* 可参考MSDN
    LPCTSTR lpClassName,    // pointer to registered class name
    LPCTSTR lpWindowName,   // pointer to window name
    DWORD dwStyle,  // window style 可参考MSDN WS_*
    int x,  // horizontal position of window
    int y,  // vertical position of window
    int nWidth, // window width
    int nHeight,    // window height
    HWND hWndParent,    // handle to parent or owner window 上级窗口,上级窗口销毁时,下级窗口也会被销毁
    HMENU hMenu,    // handle to menu, or child-window identifier 菜单句柄 可替换窗口类中的菜单 当dwStyle为WS_CHILD时,表示子窗口的ID
    HINSTANCE hInstance,    // handle to application instance 模块句柄
    LPVOID lpParam  // pointer to window-creation data 传给窗口的参数  这个参数在WM_CREATE消息中可以被获取
   );
style的预定义值
style的预定义组合
ExStyle的预定义值

常见的窗口样式


image.png

ShowWindow用来显示窗口

BOOL ShowWindow(
    HWND hWnd,  // handle of window
    int nCmdShow    // show state of window
   );
窗口的显示方式

UpdateWindow绘制客户区 向窗口发送了一条WM_PAINT消息

BOOL UpdateWindow(
    HWND hWnd   // handle of window  
   );

CreateWindowEx也可以创建子窗口 如Button Edit
创建一个button


创建一个button

注意 hMenu在这里表示子窗口的ID

2.3 消息循环

消息循环的一般形式

image.png

消息格式


image.png
image.png

lpMsg为指向MSG结构体的指针,接收返回消息
若获取的消息WM_QUIT eax中的返回值为0

TranslateMessage进行一些键盘消息的转换,将键盘消息的扫描码转换成ASC码在消息队列中插入WM_CHAR WM_SYSCHAR消息 遇到非键盘消息不处理

DispathMessage将消息发送到窗口处理过程,窗口过程返回后DispathMessage才返回

其它形式的消息循环

PeekMessage

BOOL PeekMessage(
    LPMSG lpMsg,    // pointer to structure for message
    HWND hWnd,  // handle to window
    UINT wMsgFilterMin, // first message
    UINT wMsgFilterMax, // last message
    UINT wRemoveMsg     // removal flags PM_NOREMOVE 取一条消息后在消息队列中删除该消息 PM_REMOVE 取一条消息不删除
   );   
 

无论应用程序消息队列是否有消息,PeekMessage函数都立即返回,程序得以继续执行后面的语句(无消息则执行其它指令,有消息时一般要将消息派发出去,再执行其它指令)。
GetMessage函数只有在消息队列中有消息时返回,队列中无消息就会一直等,直至下一个消息出现时才返回。在等的这段时间,应用程序不能执行任何指令。

2.4 窗口过程

窗口过程的一般结构


image.png

注意 proc后面的uses伪操作在子程序进入和退出时自动插上push和pop寄存器指令,来保护这些寄存器的值

uMsg的windows标准窗口预定义的值的范围为0-03ffh
用户自定义的消息可以从04ooh开始 一般为WM_USER+1,WM_USER+2,...

wParam和lParam为消息附带的参数,不同消息不一样

当窗口决定关闭时,需要程序调用DestoryWindow来摧毁窗口,并用PostQuitMessage向消息循环发送WM_QUIT消息来退出消息循环。

DefWindowProc来处理用户不管的消息,采取默认方式来处理窗口消息


DefWindowProc对一些消息的默认处理方式

附录 B实验

3 窗口间的通信

3.1 窗口间消息的互发

不同的应用程序之间可以使用SendMessage和PostMessage互相发送消息

LRESULT SendMessage(

    HWND hWnd,  // handle of destination window
    UINT Msg,   // message to send
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
   );
BOOL PostMessage(

    HWND hWnd,  // handle of destination window
    UINT Msg,   // message to post 
    WPARAM wParam,  // first message parameter
    LPARAM lParam   // second message parameter
   );

对于不同的msg, wParam和lParam的含义是不同的
wsprintf win32 api中用来格式化字符串输出的函数
windows在处理SendMessage时 传递字符串时使用了共享内容
注意 在用户自定义的消息中,不要在消息参数中传递指针 会引发非法访问内存

3.2 在窗口间传递数据

WM_COPYDATA消息用于在不同应用间传递数据

WM_COPYDATA  
wParam = (WPARAM) (HWND) hwnd;            // handle of sending window 
lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer to structure with data 

数据包含在COPYDATASTRUCT结构体中

typedef struct tagCOPYDATASTRUCT {  // cds  
    DWORD dwData; //Specifies up to 32 bits of data to be passed to the receiving application
    DWORD cbData; //Specifies the size, in bytes, of the data pointed to by the lpData member.
    PVOID lpData; //Points to data to be passed to the receiving application. This member can be NULL. 
} COPYDATASTRUCT; 

3.3 SendMessage和PostMessage的区别

SendMessage相当于直接调用其他窗口的窗口过程来处理某个消息,并等待窗口过程处理完成后返回
PostMessage则将某个消息放入目标窗口的消息队列中并直接返回,不能用于任何参数中用到指针的消息

你可能感兴趣的:(第4章 第一个窗口程序)