今天看Windows Program Via c/c++;突然想看一下Windows加载EXE文件或者可执行文件的过程。于是就建立了一个
项目进行测试:
代码很简单,就是建立一个窗口。
/* windows program via c/c++ exp: chapter 1 */ #include <windows.h> LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) { TCHAR szAppName[]=TEXT("ErrorWin"); HWND hwnd; //窗口句柄 WNDCLASS wndclass; //窗口类 MSG message; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); wndclass.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hInstance =hInstance; wndclass.lpfnWndProc=WndProc; wndclass.lpszClassName=szAppName; wndclass.lpszMenuName=NULL; wndclass.style = CS_HREDRAW | CS_VREDRAW; if(!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("You need Windows NT to run this program"), TEXT("ErrorWin"), MB_ICONERROR); return 0; } hwnd=CreateWindow(szAppName, //窗口类名 TEXT("ErrorWin"), //窗口标题 WS_OVERLAPPEDWINDOW, //窗口层叠类型 CW_USEDEFAULT,//x CW_USEDEFAULT, //y 480, //hight 240, //width NULL, //父窗口句柄 NULL, //菜单句柄 hInstance, //实例句柄 NULL //附加参数 ); ShowWindow(hwnd,nShowCmd); UpdateWindow(hwnd); while(GetMessage(&message,hwnd,0,0)) { TranslateMessage(&message); DispatchMessage(&message); } return message.wParam; } LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { switch(message) { case WM_CLOSE: case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); }
下面是程序执行过程VS 2008 Output窗口显示的调试信息:
'chapter1_01.exe': Loaded 'G:\13_Windows_Program_Via_C\chapter1_01\Debug\chapter1_01.exe', Symbols loaded. 'chapter1_01.exe': Loaded 'C:\Windows\System32\ntdll.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\kernel32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\KernelBase.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\user32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\gdi32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\lpk.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\usp10.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\msvcrt.dll' 'chapter1_01.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.vc90.debugcrt_1fc8b3b9a1e18e3b_9.0.21022.8_none_96748342450f6aa2\msvcr90d.dll', Symbols loaded. 'chapter1_01.exe': Loaded 'C:\Windows\System32\imm32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\msctf.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\uxtheme.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\apphelp.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\baiducn.ime' 'chapter1_01.exe': Loaded 'C:\Windows\System32\oleacc.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\ole32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\rpcrt4.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\advapi32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\sechost.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\shell32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\shlwapi.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\oleaut32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.7601.17514_none_ec83dffa859149af\comctl32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\version.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\profapi.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\dwmapi.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\cryptbase.dll' 'chapter1_01.exe': Loaded 'C:\Program Files\Baidu\BaiduPinyin\2.4.2.281\uipfull.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\winmm.dll' 'chapter1_01.exe': Loaded 'C:\Windows\System32\msimg32.dll' 'chapter1_01.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.windows.gdiplus_6595b64144ccf1df_1.1.7601.17514_none_72d18a4386696c80\GdiPlus.dll' 'chapter1_01.exe': Loaded 'C:\Program Files\Baidu\BaiduPinyin\2.4.2.281\imefreetype.dll', Binary was not built with debug information. 'chapter1_01.exe': Loaded 'C:\Program Files\Baidu\BaiduPinyin\2.4.2.281\imepng.dll', Binary was not built with debug information. 'chapter1_01.exe': Loaded 'C:\Program Files\Baidu\BaiduPinyin\2.4.2.281\imezlib.dll', Binary was not built with debug information. 'chapter1_01.exe': Loaded 'C:\Windows\System32\sspicli.dll' The thread 'Win32 Thread' (0x7fc) has exited with code 0 (0x0). The thread 'Win32 Thread' (0xb74) has exited with code 0 (0x0). The thread 'Win32 Thread' (0x210) has exited with code 0 (0x0). The thread 'Win32 Thread' (0xd34) has exited with code 0 (0x0). The program '[3940] chapter1_01.exe: Native' has exited with code 0 (0x0).
我们可以看各行的信息:
【1】
Loaded 'G:\13_Windows_Program_Via_C\chapter1_01\Debug\chapter1_01.exe', Symbols loaded.
这一行的内容: 显示加载可执行文件到内存,并且加载程序的符号,毫无疑问,第一步必须将文件从硬盘加载到内存,才有可能执行。
【2】
'chapter1_01.exe': Loaded 'C:\Windows\System32\ntdll.dll'
加载ntdll.dll中的内容,这个动态链接库文件,应该是一直常驻内存的;这个地方既然不是加载,那么就必然是调用函数,那么这个时候调用的会
是那个API函数呢?
我们可以通过查看ntdll.dll文件的导出符号表,发现里面有一个NtCreateProcess函数,如下图所示:
虽然我们在Windows API中有CreateProcess函数可以使用;但是函数CreateProcess最终都会调用NtCreateProcess函数来创建进程;这个函数
的作用就是创建内核进程对象,具体是:
所谓创建内核中的进程对象,实际上就是创建以EPROCESS为核心、为基础的相关数据结构,这就是系统调用NtCreateProcess()要做的事情,主要包括:
● 分配并设置EPROCESS数据结构。
● 其他相关的数据结构的设置,例如“打开对象表”。
● 为目标进程创建初始的地址空间。
● 对目标进程的“内核进程块”KPROCESS进行初始化。
● 将系统DLL的映像映射到目标进程的(用户)地址空间。
● 将目标进程的映像映射到其自身的用户空间。
● 设置好目标进程的“进程环境块”PEB。
● 映射其他需要映射到用户空间的数据结构,例如与“当地语言支持”、即NLS有关的数据结构。
● 完成EPROCESS创建,将其挂入进程队列(注意受调度的是线程队列而不是进程队列)。
当然这个过程也会进行一次线程的创建,如果是单线程的话,那么这个线程就是进程的主线程。
但是这个函数并没有进行真正的进程创建工作,真正的工作是PspCreateProcess完成的。但是我找了好久的资料都没发现这个PspCreateProcess函数
存在于那个动态链接库文件中。
【3】
'chapter1_01.exe': Loaded 'C:\Windows\System32\kernel32.dll'
这一行,表示进程执行过程中,调用了Kernel32.dll文件,在《Windows程序设计》里面,作者将kernel32.dll作为一个子系统来作用,这里我们可以看一下
这个动态链接库文件与其他链接库文件的依存关系:
通过上面的图可以看出:kernel32.dll 调用了ntdll.dll中提供的函数;而在整个dll链中ntdll.dll,我们没有发现其有依存关系(迷惑中....ing)。
而在kernel32.dll中,我们可以看到CreateProcess函数
创建进程后,需要初始化内核对象。
【4】
'chapter1_01.exe': Loaded 'C:\Windows\System32\user32.dll'
当进程内核对象创建完成,并完成初始化。
进程内核对象初始化完成后,就需要进行一些界面上处理工作了,这个时候就需要注册窗口类了,
RegisteClass函数是user32.dll提供的系统API函数。注册完就是创建窗口。
这就是CreateWindow这些函数的事情了,在dll中可以查看
其函数有
这就是我们的CreateWindows函数,创建窗口,很显然这个属于用户界面的范畴。
创建完窗口,就是显示和更新窗口,这个也是属于用户界面的范畴。
最终进入消息循环队列,这个还是属于user32.dll动态链接库的范畴,由用户子系统来处理消息。
大体就是这么一个过程,可以发现执行一个Windows程序,系统需要做的工作非常之多。
凌晨0点了,累了,有机会再说吧。