Windwos 进程
进程通常被定义为一个正在运行的程序实例 , 它由两个部分组成 :
1 操作系统用来管理进程的内核对象 。 内核对象也是系统用来存放关于进程的统计信息的地方
2 另一个是地址空间 , 它包含所有可执行模块 或 DLL 模块的代码和数据 。 它还包含动态内存分配的空间 。 如 线程堆栈 和 堆分配的空间
进程可能包含若干个线程 , 每个线程都有它自己的一组 CPU寄存器 和 它自己的堆栈 .
CUI 应用程序的连接程序开关是 /SUBSYSTEM : CONDOLE
GUI 应用程序的连接程序开关是 /SUBSYSTEM : WINDOWS
操作系统实际上并不调用用户编写的进入点函数 , 它调用的是 C/C++ 运行期启动函数 。 该函数负责对 C/C++ 运行期库进行初始化 , 这样就可以调用 malloc 和 free 之类的函数 。 它还能够确保已经声明的任何全局精通对象 和 精通 C++ 对象能够在代码执行前正确的创建 。
应用程序的进入点 :
----------------------------------------------------------------------------------------------------------
应用程序类型 进入点 嵌入可执行文件的启动函数
----------------------------------------------------------------------------------------------------------
需要 ANSI 字符和字符串的 GUI 应用程序 WinMain WinMainCRTStartup
需要 Unicode 字符和字符串的 GUI 应用程序 wWinMain wWinMainCRTStartup
需要 ANSI 字符和字符串的 CUI 应用程序 main mainCRTStartup
需要 Unicode 字符和字符串的 CUI 应用程序 wmain wmainCRTStartup
连接程序负责在它连接可执行文件时选择相应的 C/C++ 运行期启动函数 。如果设定了 /SUBSYSTEM:WINDOWS 连接程序开关 , 那么该连接程序期望找到一个 WinMain 或 wWinmain 函数 。 如果这两个函数都不存在 , 连接程序便返回一个 "为转换的外部符号" 的错误信息 . 否则它可以分别选择 WinMainCRTStartup 函数 或 wWinMainCRTStartup 函数 。
同样,如果设定了/SUBSYSTEM:CONSOLE 链接程序开关,那么该链接程序便期望找到 main 或 wmain函数,并且可以分别选择mainCRTStartup 函数或 wmainCRTStartup 函数。同样,如果 main 或 wmain 都不存在,那么链接程序返回一条“未转换外部符号”的消息。
VC++ 配有 C 运行库的源代码 。 可以在 CR t0.c 文件中找到这 4 个启动函数的代码 。现在将启动函数的功能归纳如下
1 检索指向新进程的完整命令行的指针
2 检索指向新进场的环境变量的指针
3 对 C/C++ 运行期的全局变量进行初始化 。如果包含了 StdLib.h 文件 , 代码就能访问这些变量 。
4 对 C 运行期内存单元分配函数(malloc 和 calloc) 和 其他底层 输入/输出 例程使用的内存栈进行初始化
5 为所有全局和镜态 C++ 类对象调用构造函数
当所有这些初始化操作完成后 , C/C++ 启动函数就调用应用程序的进入点函数 。
当进入点函数返回时 , 启动函数便调用 C 运行期的 exit 函数 , 将返回值 (nMainRetVal) 传递给它 . Exit 函数负责的操作 :
1 调用由 _onexit 函数的调用而注册的任何函数 。
2 为所有全局的和镜头的 C++ 类对象调用析构函数 。
3 调用操作系统的 ExitProcess 函数 , 将 nMainRetVal 传递给它 。 这使得该操作系统能够撤销进程并设置它的 exit 代码
进程的实例句柄 :
若要从可执行文件的映像来加载图标资源 , 需要调用函数 HICON LoadIcon(HINSTANCE hInst,PCTSTR pszIcon);
VC++ 连接程序使用的默认基址是 0x00400000 。 因为这使在运行 windows 98 时可执行文件的映像可以加载到的最低地址
HMODULE GetModuleHandle(PCTSTR pszModule); //返回可执行文件或DLL问津加载到进程的地址空间时所使用的句柄/基地址
如果传递的参数 pszModule 是 NULL , 返回调用的可执行文件的基地址 。
进程的命令行 :
当一个新的进程创建时 , 它要传递一个命令行 。 该命令行几乎永远不会为空的 , 创建新进程的可执行文的名字命令行上的第一个标记。
PTSTR GetCommandLine() 函数 :
返回一个指向包含完整命令行的缓存的指针 , 该命令行包括执行文件的完整路径名
PWSTR CommandLineToArgvW(PWSTR pszCmdLine,int* pNumArgs); 函数 :
将命令行的 Unicode 字符串分隔成它的各个标记
pszCmdLine 参数是 GetCommandLine() 函数的返回值
pNumArgs 参数是个整数地址 , 该整数被设置为命令行中的参数个数
CommandLineToArgvW() 函数负责在内部分配内存 , 大多数的应用程序不释放该内存 , 它们在进程运行终止时依靠操作系统来释放内存 。
HeapFree() 函数 : 手动的释放内存
PWSTR *ppArgv = CommandLineToArgvW(GetCommandLineW(),&nNumArgs);
HeapFree(GetProcessHeap(),0,ppArgv);
进程的环境变量 :
每个进程都有一个与它相关的环境块 。 环境块是进程的地址空间中分配的一个内存块 。 每个环境块都包含一组字符串 。
环境变量中的空格是很严谨的 。环境变量的结尾处必须是一个 0 字符 , 表示环境变量块的结束
子进程可以继承一组与父进程相同的环境变量 。 父进程能够控制子进程继承什么环境变量 。
//环境变量名 //指向存放变量值的缓存 //缓存的大小
DWORD GetEnvironmentVariable(PCTSTR pszName,PTSTR pszValue,DWORD cchValue) 函数 :
能够确定某个环境变量是否存在以及它的值 。返回值是拷贝到缓存的字符数 , 如果在环境中找不到该变量名 , 返回 0
DWORD ExpandEnvironmentString(PCSTR pszSrc,PSTR pszDst,DWORD nSize) 函数 : 替换字符串变量
BOOL SetEnvironmentVariable(PCTSTR pszName , PCTSTR pszValue) 函数 : 添加 ,删除 环境变量或者修改环境变量的值
进程的错误模式 :
UINT SetErrorMode(UINT fuErrorMode) 函数 : 进程用来告诉系统如何处理每一种错误 。
fuErrorMode 参数的标志 :
-------------------------------------------------------------------------------------------------
SEM_FAILCRITICALERRORS 系统不显示关键错误句柄消息框 , 并将错误返回给调用进程
SEM_NOGOFAULTERRORBOX 系统不显示一般保护故障消息框 。本标志只应该由采用异常情况处理程序来处理一般保护(GP) 故障的调试应用程序来设定
SEM_NOOPENFILEERROEBOX 当系统找不到文件时 , 它不显示消息框 。
SEM_NOALIGNMENTFAULTEXCEPT 系统自动排除内存没有对其的故障 ,并使应用程序看不到这些故障 。本标志对x86处理器不起作用
进程的当前驱动器和目录 :
DWORD GetCurrentDirectory(DWORD cchCurDir , PTSTR pszCurDir) 函数 : 获取当前进程的当前驱动器和目录
BOOL SetCurrentDirectory(PCTSTR pszCurDir) 函数 : 设置当前进程的当前驱动器和目录
可以使用C运行期函数 _chdir,而不是使用 Windows 的 SetCurrentDirectory 函数来变更当前目录。_chdir 函数从内部调用 SetCurrentDirectory,但是 _chdir 也能够添加或修改该环境变量,这样,不同驱动器的当前目录就可以保留。
DWORD GetFullPathName(PCTSTR pszFile,DWORD cchPath,PTSTR pszPath,PTSTR *ppszilePart) 函数 : 父进程可以获得它的当前目录
系统版本 :
DWORD GetVersion() 函数 : 获得系统版本
BOOL GetVersionEx(POSVERSIONINFO pVersionInformation) 函数 :
typedef struct{
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
TCHAR szCSDVersion[128];
WORD wServicePackMajor;
WORD wServicePackMinor;
WORD wSuiteMask;
BYTE wProductType;
BYTE wReserved;
}OSVERSIONINFOEX *posversioninfoex;
CreateProcess 函数 : 用于创建一个进程
BOOL CreateProcess(
PCTSTR pszApplicationName ,
PTSTR pszCommandLine ,
PSECURITY_ATTRIBUTES pszProcess ,
PSECURITY_ATTRIBUTES pszThread ,
BOOL bInheritHandles ,
DWORD fdwCreate ,
PVOID pvEnvironment ,
PCTSTR pszCurDir ,
PSTARTUPINFO psiStartInfo ,
PPROCESS_INFORMATION ppiProcInfo);
注意 : pszCommandLine 参数的原型是 PTSTR 。这意味着 CreateProcess 期望你将传递一个非常量字符串的地址 。
可以使用 pszCommandLine 参数设定一个完整的命令行 , 以便 CreateProcess 用来创建新进程 。 当 CreateProcess 分析 pszCommandLine 字符串时 , 它将查看字符串中的第一个标记 , 并假设该标记是想运行的可执行文件的名字 。 如果可执行文件没有扩展名 , 便假设它的扩展名为 .exe
CreateProcess 函数按以下的顺序搜索该可执行文件 :
1 包含调用进程的 .exe 文件的目录
2 调用进程的当前目录
3 Windows 的系统目录
4 Windows 目录
5 PATH 环境变量中列出的目录
pszProcess pszThread 和 binheritHandles 参数 :
psaProcess 和 psaThread 参数分别设定进程对象和线程对象需要的安全性 。如果传递 NULL 则赋予默认的安全性描述符 , 也可以指定
SECURITY_ATTRIBUTES 结构 , 并对它们进行初始化 , 以便创建自己的安全性权限 , 并将它们赋予进程对象和线程对象 。
fdwCreate 参数 :
用于标识标志 , 以便用于规定如何来创建新进程 。 如果将标志逐位用 OR 操作符组合起来的话 , 就可以设定多个标志 。
pvEnvironment 参数 :
指向包含新进程将要使用的环境字符串的内存块 。
PVOID GetEnvironmentString() 函数 :
该函数用于获得调用进程正在使用的环境字符串数据块的地址 。可以使用该函数的返回地址 , 作为 CreateProcess 的 pvEnvironment 参数 。
BOOL FreeEnvironmentStrings(PTSTR pszEnvironmentBlock) 函数 : 释放内存块。
pszCurDir 参数 :
允许父进程设置子进程的当前驱动器和目录 。 如果本参数是 NULL , 则新进程的工作目录将与生产新进程的应用程序的目录相同 。 如果本参数不是 NULL , 那么 pszCurDir 必须指向包含需要的工作驱动器 和 工作目录的以 0 结尾的字符串 。
注意 : 必须设定路径中的驱动器名 。