Windows核心编程(四)进程-1

如何定义进程

进程一般定义为正在运行的程序的一个实例,由以下两部分组成:

  • 一个内核对象,用于保存进程统计信息并管理进程
  • 一的地址空间,其中包括所有可执行文件或动态链接库(DLL)模板的代码和数据,与此同时,还包含动态内存分配,比如线程堆栈和堆的分配

进程是惰性的,进程要做任何事情,都要让一个线程在它的上下文中运行,该线程负责指向进程地址空间包含的代码,当系统创建一个进程的时候,会自动为进程创建一个线程,称为主线程,然后这个主线程再创建更多的线程。
对于所有要运行的进程,操作系统会分配CPU时间片来运行这些进程,在宏观上并行,在微观上串行。
但是如果系统装备了多个CPU,就可以实现真正意义上的并发执行。

编写第一个Windows应用程序

GUI与CUI

GUI:图形用户界面
CUI:控制台用户界面

入口函数

_tmain与_tWinmain函数

应用程序类型入口点函数嵌入可执行文件的启动函数
处理ANSI字符和字符串的GUI应用程序_tWinMain(Winmain)WinmainCRTStartup
处理Unicode字符和字符串的GUI应用程序_tWinMain(wWinmain)wWinmainCRTStartup
处理ANSI字符和字符串的CUI应用程序_tmain(Main)mainCRTStartup
处理Unicode字符和字符串的CUI应用程序_tmain(Wmain)wmainCRTStartup

启动函数的用途:

  1. 获取指向新进程完整命令行的一个指针
  2. 获取指向新进程环境变量的一个指针
  3. 初始化C/C++运行库的全局变量,例如_osver(操作系统Build版本号)
  4. 初始化C运行库内存分配函数(malloc和calloc)和其他I/O利用使用的堆
  5. 调用所有全局和静态C++类对象的构造函数

入口函数返回后

入口函数返回后就会把返回值(nMainRetVal)传递给exit函数,然后会执行以下内容:

  1. 调用_onexit函数调用所注册的任何一个函数
  2. 调用所有全局和静态C++类对象的析构函数
  3. 如果是debug模式,设置了_CRTDBG_LEAK_CHECK_DF标志,会调用_CrtDumpMemoryLeaks函数生成内存泄露报告
  4. 调用API函数ExitProcess,传入nMainRetVal作为参数,操作系统会帮助结束进程,并且设置退出代码

进程实例句柄

加载到进程地址空间的每个可执行文件或动态链接库都被赋予了一个独一无二的实例句柄.。

在这里插入图片描述
在需要加载资源的函数调用中,一般都需要提供该句柄的值(LoadIcon函数的第一个参数)
在这里插入图片描述
在GetModuleFileName函数中,第一个参数的HMODULE类型实际上就是与前者就是一回事,之所以有两种数据类型,是因为在16位Windows中这两个类型表示的数据不同。
在这里插入图片描述
winmain函数中的HINSTANCE参数实际上就是一个内存基地址,系统将可执行文件的映像加载到了进程地址空间的这个位置,如果系统打开这个可执行文件,并将其加载到地址0x00400000,则winmain的HINSTANCE参数值位0x00400000。

可以通过GetModuleHandle函数返回可执行文件/动态链接库文件映像加载到的基地址,如果没找到就会返回NULL
在这里插入图片描述
还可以使用GetModuleHandleEx来获取:
在这里插入图片描述
第一个参数为GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,第二个参数为当前函数的地址,第三个参数是指向HMODULE的指针,该函数会使用第二个参数(传入函数所在的基地址)来填写该指针。
GetModuleHandle函数有两个重要特征:

  • 该函数只检查主调进程的地址空间,如果主调函数没有使用任何通用对话框函数,一旦调用GetModuleHandle,并向其传递ComDlg32,就会导致返回NULL
  • 调用该函数并向其传递NULL值,会返回进程的地址空间中的可执行文件的基地址

进程前一个实例的句柄

C/C++运行库启动代码总是向WinMain的hPrevInstance参数传递NULL,该参数用于16位Windows系统,因此仍然将其保留为Winmain的一个参数,在实际使用过程中千万不能引用该参数。

进程的命令行

系统在创建一个新进程时,会传给一个命令行给它,这个命令行基本上不会为空:命令行上的第一个标记(token)就是用于创建新进程的可执行文件的名称。
在这里插入图片描述
通过调用GetCommandLine函数来获得一个指向进程完整命令行的指针:
在这里插入图片描述

进程的环境变量

每个进程都有与它相关联的环境块,这是在进程地址空间内分配的一块内存,其中包含字符串类似:

=::=\...
VarName1=VarValue1\0
VarName1=VarValue2\0
VarName1=VarValue3\0
VarName1=VarValueN\0
\0

每个字符串的第一部分是一个环境变量的名称,等号之后是希望赋给此变量的值
获取完整的环境块:
在这里插入图片描述
释放环境块:
在这里插入图片描述

系统环境变量和用户环境变量

  • 系统环境变量:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
  • 用户环境变量:
    HKEY_CURRENT_USER\Environment
    在这里插入图片描述

添加环境变量

可替换字符串:
原始:%USERPROFILE%
替换:C:/Users/…
用于添加环境变量:
在这里插入图片描述

进程的错误格式

进程可以调用一个名为SetErrorMode的API来告诉系统如何处理错误:
在这里插入图片描述
通过四个宏来对其定义处理错误方式的标志

SEM_FAILCRITICALERRORS   //系统不显示严重错误处理程序消息框,并将错误返回主调进程

SEM_NOGPFAULTERRORBOX      //系统不显示常规保护错误消息框,此标志只应该由调试程序设置;
						   //该调试程序用一个异常处理程序来自行处理常规保护错误
						  
SEM_NOOPENFILEERRORBOX     //系统查找文件失败时,不显示消息框

SEM_NOALIGNMENTFAULTEXCEPT //系统自动修复内存对齐错误,并使应用程序看不到这些错误.此标准对x86/x64处理器无效

进程当前所在的驱动器和目录

如果不提供完整的路径名,各种Windows函数会在当前驱动器的当前目录查找文件和目录
一个线程可以调用两种函数来获取和设置当前所在位置的驱动器和目录:
在这里插入图片描述
在这里插入图片描述
如果提供的缓冲区不够大,GetCurrentDirectory函数就会返回保存文件夹所需要的字符数,而且不会往缓冲区复制任何内容,此时将缓冲区设置为NULL,就会返回字符串的长度(字符数),不包括结尾的’\0’

进程的当前目录

系统跟踪记录着进程的当前驱动的驱动器和目录,但是未记录每个驱动器的当前目录,而这些目录是通过环境变量来提供的,一个进程可以有如下所示的两个环境变量:

=C:=C:\Utilty\Bin
=D:=D:\Program Files

如果调用一个函数,且传入的路径名限定的是当前驱动器意外的驱动器,系统会在进程的环境块中查找与指定的驱动器相关联的变量如果找到,就当成当前目录使用,如果没有就是假定指定驱动器的当前目录是它的根目录.

可以通过GetFullPathName函数来得到当前目录:
在这里插入图片描述

系统版本

通过GetVersionExW函数获得所运行的版本信息:

在这里插入图片描述
LPOSVERSIONINFOW参数结构如下:
在这里插入图片描述

typedef struct _OSVERSIONINFOW {
    DWORD dwOSVersionInfoSize;      //初始化结构大小
    DWORD dwMajorVersion;           //主版本号
    DWORD dwMinorVersion;           //次版本号
    DWORD dwBuildNumber;            //构建版本号
    DWORD dwPlatformId;             //标识当前系统支持的套件
    WCHAR  szCSDVersion[ 128 ];     // Maintenance string for PSS usage,额外信息
} OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW, RTL_OSVERSIONINFOW, *PRTL_OSVERSIONINFOW;

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页