Windows程序运行本质:Message based, Event driven
程序进入点WimMain
窗口类的注册 RegisterClass,放在InitApplication函数中。
窗口类的诞生 CreateWindow,放在InitInstance函数中。
初始化完成后,WinMain进入消息循环
DispatchMessage将消息送到窗口函数,窗口函数的形式为:
窗口函数通常利用switch/case方式判断消息种类,以决定处置方式,switch/case指令中的default:处必须调用DefWindowProc;这是Windows默认消息处理函数。
消息映射(Message Map):将数据和处理数据的方法封装起来。
对话框的运行:
1.modal对话框:令其父窗口无效,直到对话框结束。激活DialogBox,结束EndDialog。
2.modeless对话框:父窗口与对话框同时运行。
对话框包括:
1.对话框模块(dialog template)
2.对话框函数(dialog procedure) WM_INITDIALOG , WM_COMMAND
模块定义文件(.DEF)
资源描述文件(.RC)
【窗口的生命周期】
1.程序初始化过程中调用CreateWindow,为程序建立一个窗口,作为程序的屏幕舞台。CreateWindow产生窗口之后会送出WM_CREATE直接给窗口函数,后者于是可以在此时做些初始化操作(例如配置内存、打开文件、读初始数据……)
2.在程序活着的过程中,不断以GetMessage从消息队列中抓取消息。如果这个消息是WM_QUIT,GetMessage会传回0而结束while循环,进而结束整个程序。
3.DispatchMessage通过Windows USER模块的协助与监督,把消息分派至窗口函数。消息将在该处并判别并处理。
4.程序不断执行2.和3.的操作。
5.当使用者按下系统菜单中的Close命令项时,系统送出WM_CLOSE。通常程序的窗口函数不拦截此消息,于是DefWindowProc处理它。
6.DefWindowProc收到WM_CLOSE后,调用DestroyWindow把窗口清楚,DestroyWindow本身会送出WM_DESTROY。
7.程序对WM_DESTROY的标准反应是调用postQuitMessgae.
8.PostQuitMessage没什么其他操作,就只送出WM_QUIT消息,准备让消息循环中的GetMessage取得,如步骤2,结束消息循环。
空闲时间的处理:OnIdle
空闲时间(idle time):系统没有任何消息等待处理的时候。
传统SDK程序如果要处理空闲时间,可采用PeekMessage方式取代WinMain中传统高的消息循环:
GetMessage:遇Idle跳过。
PeekMessage:遇Idle取回控制权,执行一段时间。
Console程序:不牵扯任何窗口、对话框、控件的程序。
MFC Console程序的特点:
1.程序进入点仍为main
2.需载入所使用的类的头文件
3.可直接使用与GUI无关的MFC类。(如:CStdio,CString)
4.编辑时指定 /MT,表示使用多线程版本的C runtime函数库。
Visual C++提供6个C runtime函数库产品:
/ML Single-Threaded(static)
/MT Multithreaded(static)
/MD Multithreaded DLL(dynamic import library)
/MLd Debug Single-Threaded(static)
/MTd Debug Multithreaded(static)
/MDd Debug Multithreaded DLL(dynamic import library)
进程与线程(Process and Thread)
核心对象(kernel object):系统的一种资源,系统给予核心对象一个计数值(usage count)作为管理之用。
核心对象包括:event, mutex, semaphore, file, file-mapping, process, thread
以handle作为识别;handle每被使用一次,对应的计数加1.
核心对象的结束方式:调用CloseHandle.
一个进程的诞生与死亡:
1.shell 调用 CreateProcess 激活 App.exe.
2.系统产生一个“进程核心对象”,计数值为1.
3.系统为此进程建立一个4GB地址空间。
4.加载器将必要的代码加载到上述地址空间中,包括App.exe的程序、数据,以及所需的动态链接函数库(DLLs)。加载器如何知道要加载哪些DLLs呢?他们被记录在可执行文件(PE文件格式)的.idata section中。
5.系统为此行程建立一个线程,称为主线程(primary thread)。线程才是CPU时间的分配对象。
6.系统调用C runtime函数库的Startup code.
7.Startup code调用App程序的WinMain函数。
8.App程序开始运行。
9.使用者关闭App主窗口,使WinMain中的消息循环结束掉,于是WinMain结束。
10.回到Startup code.
11.回到系统,系统调用ExitProcess结束进程。
通过这种方式执行起来的所有Windows程序,都是shell的子进程。
产生子进程:CreateProcess
当系统为我们产生“进程对象”和“线程对象”时,它会把两个对象的handle填入此结构的相关字段中,应用程序从这里获得这些handles。
进程结束本身:
VOID ExitProcess(UINT fuExitCode);
进程结束另一进程:
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);
结束子进程:CloseHandle
一个线程的诞生与死亡:
调用CreateThread,系统会帮助完成:
1.配置“线程对象”,其handle将成为CreateThread的返回值。
2.设定计数值1.
3.配置线程的context。
4.保留线程的堆栈。
5.将context中的堆栈指针缓存器(SS)和指令指针缓存器(IP)设定妥当。
线程是CPU分配时间的单位。
工作切换(context switch)其实就是对线程的context的切换。
以_beginthreadex 取代 CreateThread
范例:
线程优先级(Priority)
0(最低)至31(最高) idle, normal, high, realtime.
SetThreadPriority 设定优先级
程序进入点WimMain
窗口类的注册 RegisterClass,放在InitApplication函数中。
窗口类的诞生 CreateWindow,放在InitInstance函数中。
初始化完成后,WinMain进入消息循环
while(GetMessage(&msg, ...)) {
TranslateMessage(&msg); //转换键盘消息
DispatchMessage(&msg); //分派消息
}
DispatchMessage将消息送到窗口函数,窗口函数的形式为:
LRESULT CALLBACK WndProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
窗口函数通常利用switch/case方式判断消息种类,以决定处置方式,switch/case指令中的default:处必须调用DefWindowProc;这是Windows默认消息处理函数。
消息映射(Message Map):将数据和处理数据的方法封装起来。
对话框的运行:
1.modal对话框:令其父窗口无效,直到对话框结束。激活DialogBox,结束EndDialog。
2.modeless对话框:父窗口与对话框同时运行。
对话框包括:
1.对话框模块(dialog template)
2.对话框函数(dialog procedure) WM_INITDIALOG , WM_COMMAND
模块定义文件(.DEF)
资源描述文件(.RC)
【窗口的生命周期】
1.程序初始化过程中调用CreateWindow,为程序建立一个窗口,作为程序的屏幕舞台。CreateWindow产生窗口之后会送出WM_CREATE直接给窗口函数,后者于是可以在此时做些初始化操作(例如配置内存、打开文件、读初始数据……)
2.在程序活着的过程中,不断以GetMessage从消息队列中抓取消息。如果这个消息是WM_QUIT,GetMessage会传回0而结束while循环,进而结束整个程序。
3.DispatchMessage通过Windows USER模块的协助与监督,把消息分派至窗口函数。消息将在该处并判别并处理。
4.程序不断执行2.和3.的操作。
5.当使用者按下系统菜单中的Close命令项时,系统送出WM_CLOSE。通常程序的窗口函数不拦截此消息,于是DefWindowProc处理它。
6.DefWindowProc收到WM_CLOSE后,调用DestroyWindow把窗口清楚,DestroyWindow本身会送出WM_DESTROY。
7.程序对WM_DESTROY的标准反应是调用postQuitMessgae.
8.PostQuitMessage没什么其他操作,就只送出WM_QUIT消息,准备让消息循环中的GetMessage取得,如步骤2,结束消息循环。
空闲时间的处理:OnIdle
空闲时间(idle time):系统没有任何消息等待处理的时候。
传统SDK程序如果要处理空闲时间,可采用PeekMessage方式取代WinMain中传统高的消息循环:
while(true) {
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GetMessage:遇Idle跳过。
PeekMessage:遇Idle取回控制权,执行一段时间。
Console程序:不牵扯任何窗口、对话框、控件的程序。
MFC Console程序的特点:
1.程序进入点仍为main
2.需载入所使用的类的头文件
3.可直接使用与GUI无关的MFC类。(如:CStdio,CString)
4.编辑时指定 /MT,表示使用多线程版本的C runtime函数库。
Visual C++提供6个C runtime函数库产品:
/ML Single-Threaded(static)
/MT Multithreaded(static)
/MD Multithreaded DLL(dynamic import library)
/MLd Debug Single-Threaded(static)
/MTd Debug Multithreaded(static)
/MDd Debug Multithreaded DLL(dynamic import library)
进程与线程(Process and Thread)
核心对象(kernel object):系统的一种资源,系统给予核心对象一个计数值(usage count)作为管理之用。
核心对象包括:event, mutex, semaphore, file, file-mapping, process, thread
以handle作为识别;handle每被使用一次,对应的计数加1.
核心对象的结束方式:调用CloseHandle.
一个进程的诞生与死亡:
1.shell 调用 CreateProcess 激活 App.exe.
2.系统产生一个“进程核心对象”,计数值为1.
3.系统为此进程建立一个4GB地址空间。
4.加载器将必要的代码加载到上述地址空间中,包括App.exe的程序、数据,以及所需的动态链接函数库(DLLs)。加载器如何知道要加载哪些DLLs呢?他们被记录在可执行文件(PE文件格式)的.idata section中。
5.系统为此行程建立一个线程,称为主线程(primary thread)。线程才是CPU时间的分配对象。
6.系统调用C runtime函数库的Startup code.
7.Startup code调用App程序的WinMain函数。
8.App程序开始运行。
9.使用者关闭App主窗口,使WinMain中的消息循环结束掉,于是WinMain结束。
10.回到Startup code.
11.回到系统,系统调用ExitProcess结束进程。
通过这种方式执行起来的所有Windows程序,都是shell的子进程。
产生子进程:CreateProcess
当系统为我们产生“进程对象”和“线程对象”时,它会把两个对象的handle填入此结构的相关字段中,应用程序从这里获得这些handles。
进程结束本身:
VOID ExitProcess(UINT fuExitCode);
进程结束另一进程:
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);
结束子进程:CloseHandle
一个线程的诞生与死亡:
调用CreateThread,系统会帮助完成:
1.配置“线程对象”,其handle将成为CreateThread的返回值。
2.设定计数值1.
3.配置线程的context。
4.保留线程的堆栈。
5.将context中的堆栈指针缓存器(SS)和指令指针缓存器(IP)设定妥当。
线程是CPU分配时间的单位。
工作切换(context switch)其实就是对线程的context的切换。
以_beginthreadex 取代 CreateThread
范例:
#include <windows.h>
#include <process.h>
unsigned __stdcall myfunc(void* p);
int main() {
unsigned long thd;
unsigned tid;
thd = _beginthreadex(NULL,
0,
myfunc,
0,
0,
&tid);
if(thd != NULL) {
CloseHandle(thd);
}
}
unsigned __stdcall myfunc(void* p) {
//do your job...
}
线程优先级(Priority)
0(最低)至31(最高) idle, normal, high, realtime.
SetThreadPriority 设定优先级