程序设计领域里每一个人都想飞,但是在学会走之前,连跑都别想。
Windows程序的本质就是Message based,Event driven。
Message的结构:
/*Queued message structure */
typedef struct tagMSG
{
HWND hwnd;
UINT message; // WM_XXX
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
消息映射
首先定义一个MSGMAP_ENTRIES结构和dim宏
struct MSGMAP_ENTRIES{
UINT nMessage;
LONG (*pfn)(HWND, UINT, WPARAM, LPARAM);
};
#define dim(x) (sizeof (x) / sizeof (x[0]))
接下来,定义两个数组_messageEntries[] 和_commandEntries[],把程序中要处理的消息集消息处理常量的关联性建立起来。
//消息处理常量对照表
struct MSGMAP_ENTRY -messageEntries [] =
{
WM_CRATE, OnCreate,
WM_PAINT, OnPaint,
WM_SIZE, OnSize,
WM_COMMAND,OnCommand,
WM_SETFOCUS, OnSetFocus,
WM_CLOSE, OnClose,
WM_DESTROY, OnDestroy,
};
struct MSG_ENTRY _commandEntries [] =
{
IDM_ABOUT, OnAbout,
IDM_FILEOPEN, OnFileOpen,
IDM_SAVRAS, OnSaveAs,
};
因此,窗口函数可以设计成:
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
for (i = 0; i < dim (_messageEntries); i ++)
{
if (message == _messageEntries [i] .nMessage)
return ((* _messageEntries [i] .pfn)(hwnd, message, wParam, lParam));
}
return (DefWindowProc (hwnd, message, wParam, lParam));
}
LONG OnCommand(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
for (i = 0; i <dim(_commandEntries ); i ++)
{
if (LOWORD (wParam) == _commandEntries [i] .nMessage)
return ( (* _commandEntries[i].pfn)(hwnd, message, wParam, lParam));
}
return (DefWindowProc (hwnd, message, wParam, lParam));
}
LONG OnCreate (HWND hwnd, UINT uMsg, UINT wParam, LONG lParam)
{
….
}
一个进程从产生到灭亡的过程
1、shell调用CreateProcess启动.exe
2、系统产生一个[进程核心对象],将计数器设为1。
3、系统为此进程分配地址空间
4、载入器将必要的码载入地址空间,包括程序、资料及所需要的动态链接库
5、系统为此进程创建一个thread,称为primary thread。thread才是CPU分配时间的对象。
6、系统调用C runtime函数库的startup code。
7、Startup code 调用程序的WinMain函数
8、程序开始运行
9、用户关闭程序主窗口,使WinMain中的消息回路结束,于是WinMain结束
10、回到startup code
11、回到系统,系统呼叫ExitProcess结束进程。
CreateProcess
CreateProcess (
LPCSTR lpApplicationName,//应用程序名
LPSTR lpCommandLine,//传给进程的命令行参数
LPSECURITY_ATTRIBUTES lpProcessAttributes,//设定进程安全属性
LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程安全属性
BOOL bInheritHandles,//设定安全属性是否要被继承
DWORD dwCreationFlags,//多种常数的集合
LPVOID lpEnvironment,//指定环境变量区
LPCSTR lpCurrentDirectory,//工作目录
LPSTARTUPINFO lpStartupInfo,//
LPPROCESS_INFORMATION lpProcessInfomation)
如果指定了引用程序名,但没有指定扩展名,系统不会主动加上.exe扩展名。如果没有指定完整路径,系统就在当前目录中查找。如果设定lpApplicationName为NULL的话,系统会以lpCommandLine的第一个分割(token)作为应用程序的名称,如果没有指定扩展名,就用预设的.exe为扩展名。如果没有指定路径,Windows按照五个查找路径来查找应用程序,分别是:
1、 调用者应用程序所在目录
2、 调用者目前工作目录
3、 Windows目录
4、 Windows System目录
5、 环境变量中Path设定的目录
建立新进程之前,系统必须做出两个核心对象,也就是【进程对象】和【线程对象】
CreateProcess的第三个参数和第四个参数分别指定这两个核心对象的安全属性。
Typedef struct PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
VOID ExitProcess(UINT fuExitCode);//进程结束自己的生命
BOOL TerminateProcess (HANDLE hProcess, UINT fuExitCode);//进程结束另一个进程的生命。
一个线程的产生与消亡
1、 配置线程对象,其handle将成为CreateThread的返回值。
2、 设定计数值为1。
3、 配置线程的context
4、 保留线程的堆栈
5、 将context中的堆栈指针暂存器(SS)和指令指针寄存器(IP)设定完毕。
所谓的工作切换(context switch )其实就是对线程的context的切换。
CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes,//安全属性的设定及继承
DWORD dwStackSize,//设定堆的大小
LPTHREAD_START_ROUTINE lpStartAddress,//设定线程函数名称。
LPVOID lpParameter,//线程函数的参数
DWORD dwCreationFlags,//如果是0表示立即执行
LPDWORD lpTHreadId//
);
以_beginthreadex取代CreateThread
线程的优先权。第一步:给进程指定优先权等级;第二步:对该进程拥有的线程指定相对优先权。
等级 代码 优先权
idle IDLE_PRIORITY_CLASS 4
normal NORMAL_PRIORITY_CLASS 9(前台)或7(后台)
high HIGH_PRIORITY_CLASS 13
realtime REALTIME_PRIORITY_CLASS 24