进程(1)

来源:互联网 发布:行楷 知乎 编辑:程序博客网 时间:2024/05/20 18:41

进程构成:

  • 一个内核对象用于管理进程,保存进程的统计信息。
  • 一个地址空间包括可执行文件以及DLL模块的代码和数据,还包括动态分配的内存。

线程负责执行进程空间所包含的代码。创建进程事,系统会自动创建一个主线程。

windows应用程序:

  • GUI程序(图形用户见面,Graphical User Interface)链接器开关:/SUBSYSTEM:WINDOWS

  • CUI程序(控制台用户界面,Console User Interface)链接器开关:/SUBSYSTEM:CONSOLE
用Microsoft Visual Studio 创建应用项目时,集成开发环境会设置各种链接器开关,使链接器将子系统的正确类型嵌入可执行文件中。

windows应用程序必须有一个入口点函数,有两种:

  • int WINAPI _tWinMain(HINSTANCE hInstanceExe , HINSTANCE , PTSTR  pszCmdLine , intnCmdShow ) ;
  • int _tMain(int  argc , TCHAR  *argv[] , TCHAR  *envp[] ) ;

操作系统并不调用入口函数。它会调用一个C/C++运行时启动函数(由C/C++运行库实现  并  在链接时使用-entry:命令行选项设置的)。这函数初始化C/C++运行库,使我们能调用库中的标准函数。

应用程序类型和相应的入口点函数

应用程序类型入口点函数
嵌入式可执行
文件的启动函数
处理ANSI和字符串的GUI_tWinMain(WinMain)WinMainCRTStartup处理Unicode和字符串的GUI_tWinmain(wWinmain)wWinMainCrtStartup处理ANSI和字符串的CUI_tmain(Main)mainCRTStartup处理Unicode和字符串的CUI_tmain(wMain)wmainCRTStartup

在链接可执行文件时,链接器将选择正确的C/C++运行库启动函数。如果执行/SUBSYSTEM:WINDOWS 链接器开关,链接器就会寻找WinMain或者wWinMain函数,找不到就返回“unresolved external symbol ”。找到后,则根据情况分别选择WinMainCRTStartup或者wWinMainCRTStartup函数。/SUBSYSTEM:CONSOLE 同理。

所有C/C++运行库启动函数所做的基本一样,区别在于所用的字体;以及初始化C运行库之后所调用的入口函数。VC自带C运行库源代码,可以在crtexe.c文件中找到4个启动函数的源代码。

这些启动函数的用途简单总结如下:

  • 获取指向新进程的完整命令行的指针。
  • 获取指向新进程的环境变量的指针。参照表4-2
  • 初始化C/C++运行库的全局变量,<stdlib.h>
  • 初始化C运行库内存分配函数
  • 调用所有全局函数和静态C++类对象的构造函数

完成这些初始化工作后,C/C++启动函数就会调用应用程序的入口点函数。
如果调用了_tWinMain 函数,而且定义了_UNICODE,调用过程:
GetStartupInfo(&StartupInfo);int nMainRetVal=wWinMain( (HINSTANCE)&__ImageBase , NULL , pszCommandLineUnicode,(StartupInfo.dwFlags & STARTF_USERHOWWINDOW)?StartupInfo.wShowWindow:SW_SHOWDEFAULT  );


__ImageBase是链接器定义的伪变量。表明可执行文件被映射到应用程序内存的位置4.1.1进一步讨论。
int _tmain(int argc,TCHAR* argv[],TCHAR* env[])

env指向一个数组,包含了素有“环境变量 ”。

入口点函数返回后,启动函数会调用exit,向其传递返回值(nMainRetVal

exit函数执行的任务:

  • 调用_onexit函数调用所注册的任何一个函数。
  • 调用全局和静态C++类对象的析构函数。
  • DEBUG生成中,如果设置了_CRTDBG_LEAK_CHECK_DF标志,就通过调用_CrtDumpMemoryLeaks函数来生成内存泄露报告。
  • 调用操作系统的ExitProcess函数,向其传入nMainRetVal。操作系统终结进程,并设置退出代码。