花生肉泥 Blog

Win32基本程序概念

2016/05/26 Share
Win32程序开发流程

Windows程序分为[程序代码]和[UI(User Interface)资源]两大部分,两部分最后以RC编译器整合为一个完整的EXE文件,所谓UI资源是指功能菜单、对话框外貌、程序图标、光标形状等等东西。这些UI资源的实际内容(二进制代码)系借助各种工具产生,并以各种拓展名存在,如.ioc、.bmp、.cur等等。程序员必须在一个所谓的资源描述档(.rc)中描述他们。RC编译器(RC.EXE)读取RC档的描述后将所有UI资源档集中制作出一个.RES档,再与程序代码结合在一起,这才是一个完整的Windows可执行档。

需要什么函数库(.LIB)

LIBC.LIB - 这是C Runtime函数库动态联结版本。
MSVCRT.LIB - 这是C Runtime函数库动态联结(MSVCRT40.DLL)的import函数库。如果联结此一函数库,你的程序执行时必须有MSVCRT40.DLL在场。
另一组函数,WindowsAPI,由操作系统本身(主要是Windows三大模块GDI32.DLL和USER32.DLL和KERNEL32.DLL)提供。
32位Windows的三大模块所对应的import函数库分别为GUI32.LIB和USER32.LIB和KERNEL32.LIB。
Windows发展至今,逐渐加上的一些新的API函数,(例如Common Dialog、ToolHelp)并不放在GUI和USER和KERNEL三大模块中,而是放在诸如COMMDLG.DLL、TOOLHELP.DLL之中,如果要使用这些APIs,联结时还得加上这些DLLs所对应的import函数库,诸如COMDLG32.LIB和TH32.LIB

需要什么头文件(.H)

所有Windows程序都必须含有WINDOWS.H。
WINDOWS.H只照顾三大模块所提供的API函数,如果你用到其他system DLLs,例如COMMDLG.DLL或MAPI.DLL或TAPI.DLL等等,就得包含对应的头文件,例如COMMDLG.H或MAPI.H或TAPI.H等等。

以消息为基础,以事件驱动之 ( message based , event driven )

Windows程序的进行系依靠外部发生的事件来驱动。程序不断等待(利用一个while回路),等待任何可能的输入,然后做判断,然后再做适当的处理。输入是由操作系统捕捉到之后,以消息形式(一种数据结构)进入程序之中。USER模块长官各个外围的驱动程序,他们各有侦测回路。
Windows程序传送过来的消息,放在程序队列(application queue)中。以应用程序的眼光来看,消息就是消息,来自哪里或者放在哪里其实并没有太大区别。程序调用GetMessage API就取得一个消息,所有的GUI系统,包括UNIX的X Window以及OS/2的Presentation Manager,都像这样,是以消息为基础的事件驱动。
可想而知,每一个Windows 程序都应该有一个回路如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 以上出现的函数都是Windows API 函数
消息,也就是上面出现的MSG 结构,其实是Windows 内定的一种资料格式:
/* Queued message structure */
typedef struct tagMSG
{
HWND hwnd;
UINT message; // WM_xxx,例如WM_MOUSEMOVE,WM_SIZE...
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;

接受并处理消息的主角就是窗口,每一个窗口都应该有一个函数负责处理消息,程序员必须负责设计这个所谓的[窗口函数](window procedure,或称为window function),如果窗口获得一个消息,这个窗口函数必须判断消息的类别,决定处理的方式。

uploaded!
CreateWindow只产生窗口,并不显示窗口,所以稍后我们必须再利用ShowWindow将之显示在屏幕上。我们希望先传送个WM_PAITN给窗口,以驱动窗口的绘图动作,所以调用updateWindow。
在程序中,RegisterClass被包装在InitApplicaiton函数中,CreateWindow则被包装在InitInstance函数之中。
产生窗口,是每一个执行实例(instance)都得做的动作,所以把CreateWindow这个动作安排在[任何执行实例都会进入]的InitInstance函数中,由于Win32程序的每一个执行实例(instance)都有自己的地址空间,共享同一窗口类别已不可能,但是由于Win32系统令hPrevInstance永远为0,所以任然得把RegisterClass和CreateWindow按就习惯安排。

消息循环

初始化工作完成后,WinMain进入所谓的消息循环:

1
2
3
4
while (GetMessage(&msg,...)) {
TranslateMessage(&msg); // 转换键盘消息
DispatchMessage(&msg); // 分派消息
}

其中TranslateMessage是为了将键盘消息转化,DispatchMessage会将消息传给窗口函数去处理。DispatchMessage经过USER模块的协助,才把消息交到窗口函数手中。

窗口的生命中枢:窗口函数

消息循环中的DispatchMessage把消息通过USER模块的协助,送到该窗口的窗口函数。程序进行过程中,消息由输入装置,经由消息循环抓取,源源传送给窗口并进而送到窗口函数去。窗口函数的形式,一般是:

1
2
3
4
LRESULT CALLBACK WndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)

CATALOG
  1. 1. Win32程序开发流程
  2. 2. 需要什么函数库(.LIB)
  3. 3. 需要什么头文件(.H)
  4. 4. 以消息为基础,以事件驱动之 ( message based , event driven )
  5. 5. 消息循环
  6. 6. 窗口的生命中枢:窗口函数