windows编程(二)——第一个窗口程序与消息机制

时间:2021-10-13 05:41:05

windows编程(二)——第一个窗口程序与消息机制

第一个窗口程序我们附上两段代码,一段是用 c语言实现的,一段是用win32汇编实现的。要说理解第一个窗口程序的代码还是有点困难的。理解之后,实际过程当中我们没有必要自己去写这个窗口的框架。直接拿别人的用,然后再去改 就行了。因为接近一百多行的代码,写起来还是有点费劲的。 先上比较容易理解的c言吧。上我自己正在写的一个工具的主窗口框架,效果如如下 windows编程(二)——第一个窗口程序与消息机制
我们程序的效果图和这个还是有差距的,本人把状态栏和菜单都给去掉了。代码实现如下。
#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;

wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow (szAppName, // window class name
TEXT ("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
LOGFONT logfont;//字体
HFONT hFont;
     static TCHAR Welcome[] = "WELCOME";     switch (message)     {          case WM_PAINT:         hdc = BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect);//设置字体和背景色,字体大小变大一些,背景色改成与窗口背景色一样就行ZeroMemory(&logfont, sizeof(LOGFONT)); logfont.lfHeight = 50;logfont.lfPitchAndFamily = FF_ROMAN;hFont = CreateFontIndirect(&logfont);//直接创建字体//SetTextColor(hdc,GetStockObject(GRAY_BRUSH));SetBkColor(hdc,GetSysColor(COLOR_WINDOW));SetTextColor(hdc,RGB(255,255,255));SetBkMode(hdc,TRANSPARENT);//透明SelectObject(hdc,hFont);DrawText(hdc,Welcome,-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);EndPaint(hwnd,&ps);return 0 ;               case WM_DESTROY:          PostQuitMessage (0) ;          return 0 ;     }     return DefWindowProc (hwnd, message, wParam, lParam) ;}
下面是win32汇编实现的

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
includewindows.inc
includegdi32.inc
includelibgdi32.lib
includeuser32.inc
includelibuser32.lib
includekernel32.inc
includelibkernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstancedd?
hWinMaindd?

.const
szClassNamedb'MyClass',0
szCaptionMaindb'windows编程——Change By:ICKelin!',0
szTextdb'使用win32汇编进行windows编程',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMainprocuses ebx edi esi hWnd,uMsg,wParam,lParam
local@stPs:PAINTSTRUCT
local@stRect:RECT
local@hDc

moveax,uMsg
;********************************************************************
.ifeax ==WM_PAINT
invokeBeginPaint,hWnd,addr @stPs
mov@hDc,eax

invokeGetClientRect,hWnd,addr @stRect
invokeDrawText,@hDc,addr szText,-1,\
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER

invokeEndPaint,hWnd,addr @stPs
;********************************************************************
.elseifeax ==WM_CLOSE
invokeDestroyWindow,hWinMain
invokePostQuitMessage,NULL
;********************************************************************
.else
invokeDefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;********************************************************************
xoreax,eax
ret

_ProcWinMainendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMainproc
local@stWndClass:WNDCLASSEX
local@stMsg:MSG

invokeGetModuleHandle,NULL
movhInstance,eax
invokeRtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;********************************************************************
; 注册窗口类
;********************************************************************
invokeLoadCursor,0,IDC_ARROW
mov@stWndClass.hCursor,eax
pushhInstance
pop@stWndClass.hInstance
mov@stWndClass.cbSize,sizeof WNDCLASSEX
mov@stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov@stWndClass.lpfnWndProc,offset _ProcWinMain
mov@stWndClass.hbrBackground,COLOR_WINDOW+1
mov@stWndClass.lpszClassName,offset szClassName
invokeRegisterClassEx,addr @stWndClass
;********************************************************************
; 建立并显示窗口
;********************************************************************
invokeCreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100,100,600,400,\
NULL,NULL,hInstance,NULL
movhWinMain,eax
invokeShowWindow,hWinMain,SW_SHOWNORMAL
invokeUpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
.whileTRUE
invokeGetMessage,addr @stMsg,NULL,0,0
.break.if eax== 0
invokeTranslateMessage,addr @stMsg
invokeDispatchMessage,addr @stMsg
.endw
ret

_WinMainendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call_WinMain
invokeExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
endstart

两段代码实现的效果不一样,但是总体框架基本相同,我们要学的就是这个窗口框架。代码太多,但是真正要掌握的就一个——消息机制。API编程包括一大堆的消息处理,消息处理的时候又调用一大堆API。API我们不用记。更不要去记API的参数。要用的时候,再去找MSDN就行了。
我们来分析一下c语言版的windows框架。其实本人也在纠结到底要不要贴上win32汇编的代码。win32实现起来比较麻烦。不过本人是由win32汇编转向c的。也不知道这算不算弯路。没有汇编基础的如果有兴趣就看win32汇编的代码,没有的可以直接跳过汇编代码,看c语言实现就行了。 走一遍程序 RegisterClass→CreateWindow→ShowWindow→UpdateWindow→GetMessage→TranslateMessage→DispatchMessage→回到GetMessage循环 我们还有一个函数LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;这似乎跟我们常见的函数不太一样。这叫回调函数。windows编程里面有句很经典的话。叫Don't Call Me,I Will Call You!!这也是我比较喜欢的一句话。挺装逼的。

窗口运行的过程

过程就是我们刚刚说的几个API调用的过程。还是那句话,不管博客写得好不好,但有自己的风格。什么该写什么不该写。我不会写API的参数和解释API参数的取值,那是MSDN的事。想知道就去查,而且必须得自己去查一查。如果懒得去查,那我无能为力。回到正题。LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;这个函数是给操作系统调用的,但是在注册窗口类的时候,要给WNDCLASS的参数赋值  wndclass.lpfnWndProc   = WndProc ;窗口就告诉操作系统。Tmd,WINDOWS,我被点击了。然后windows就调用这个函数去处理窗口被点击的事件。也就是说WndProc是处理消息的。我们也暂且不说WndProc的执行过程。我们看windows的消息处理机制

windows 消息机制

《windows 环境下32位汇编语言程序设计》这本书上的一个图很好的解释了消息机制。虽然不是很晦涩,但是我当时看的时候还是看了一段时间的。 windows编程(二)——第一个窗口程序与消息机制
当我们按下键盘或者鼠标的时候,windows会产生一个消息放到消息系统消息队列中,每个应用程序又会维护一个消息队列队列。所以windows会将消息队列里面的消息发送到对应的应用程序的消息队列中去,当应用程序执行到GetMessage的时候。GetMessage所在的动态链接库,也就是user32.dll,然后从应用程序的消息队列中获取消息,队列嘛,早早就排好队去伺候你了。获得消息之后。下面有个TranslateMessage的API,这就有点不理解了。按照正常思维应该是叫那个叫WndProc的消息处理回调函数去帮我干事啊。TranslateMessage是相对键盘来说的,如果按下键盘会产生一个扫描码,但是windows不认,所以就用一个TranslateMessage来转换成windows认识的东西。然后在DispatchMessage来分派消息。将消息的类型和相关参数传递给消息处理函数。我们windows编程最重要的一点个人觉得,是要处理的消息和消息的参数。
好好看看上面的消息处理过程。或许没有多难。至于消息回调函数。感觉这篇文章太多东西了。留着下一篇再写。欢迎指正,写博客的意义就在于写出来的东西,给懂的人看,能指出你的错误,给不懂的人看,可以指点方向。
未完待续^_^——————————————————————————————————