现在的位置: 首页 > 综合 > 正文

Windows程序设计_18_程序加载过程

2013年01月27日 ⁄ 综合 ⁄ 共 5939字 ⁄ 字号 评论关闭

  今天看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点了,累了,有机会再说吧。

抱歉!评论已关闭.