【文起】豆子爱蟹儿,没有你,我不可能每天坚持下去,为了你和我们的爱
进程
1、 进程和线程:
进程通常被定义为一个正在运行的程序实例。由两个部分组成:
*操作系统用来管理进程的内核对象;
*地址空间,包含所有可执行模块或DLL模块的代码和数据,还包含动态内存分配的空间。
进程是不活泼的,必须拥有线程来执行包含在进程的地址空间中的代码。创建一个进程时,系统将会自动创建一个线程,称为主线程。该线程可以再创建其他线程。
2、 Windows的应用程序:
Windows支持两种应用程序:1、基于图形用户界面(GUI)的应用程序;2、基于控制台用户界面(CUI)的应用程序。
CUI链接程序开关是/SUBSYSTEM:CONDOLE;GUI链接程序开关是:/SUBSYSTEM:WINDOWS
Windows应用程序都有一个接入点函数,也就是我们通常称为的main函数。
int WINAPI WinMain(HINSTANCE hinstExe,HINSTANCE,PSTR pszCmdLine,int nCmdShow);
int WINAPI wWinMain(HINSTANCE hinstExe,HINSTANCE,PWSTR pszCmdLine,int nCmdShow);
int __cdel main(int argc,char *argv[], char *envp[]);
int __cdecl wmain(int argc,wchar_t *argv[],wchar_t *envp[]);
如果链接程序开关为/SUBSYSTEM:CONDOLE,那么链接程序希望找到一个main或者wmian开头的程序,如果没有找到,那么就会返回一条“未转换外部符号”的信息;同样,如果链接程序开关为/SUBSYSTEM:WINDOWS,那么链接程序希望找到一个WinMain或者wWinMain开头的程序。
当然有一个最好的办法来解决链接程序开关,那就是全部删除链接程序开关,这样系统会去寻找4个接入点函数,然后自动确定使用哪一个。
程序执行的步骤:
A、 检索指向新进程的完整命令行的指针;
B、 检索指向新进程的环境变量的指针;
C、 对C/C++运行期的全局变量进程初始化;
D、 对C运行期间内存单元分配函数和其他底层输入/输出例程使用的内存栈进程初始化;
E、 为所有全局和静态C++类对象调用构造函数
F、 进入接入点函数,执行、退出
G、 调用由_onexit函数的调用而注册的任何函数
H、 为所有全局和静态C++类对象调用析构函数;
I、 调用操作系统的ExitProcess函数
3、 进程的实例句柄
3.1使用GetModuleHandle函数,将返回可执行文件或DLL文件加载到进程的地址空间时所用的句柄/基地址 HMODULE GetModuleHandle(PCTSTR pszModule);
3.2修改环境变量
3.3当前目录:如GetCurrentDirectory(DWORD cchCurDir,PTSTR pszCurDir);
BOOL SetCurrentDirectory(PCTSTR pszCurDir);
3.4系统版本号:
举例检查一个系统是Windows xp
#include <windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
OSVERSIONINFOEX osver = {0};
osver.dwOSVersionInfoSize = sizeof(osver);
osver.dwMajorVersion = 5;
osver.dwMinorVersion = 1;
osver.dwPlatformId =VER_PLATFORM_WIN32_NT;
DWORDLONG dwlConditionMask = 0;
VER_SET_CONDITION(dwlConditionMask,VER_MAJORVERSION,VER_EQUAL);
VER_SET_CONDITION(dwlConditionMask,VER_MINORVERSION,VER_EQUAL);
VER_SET_CONDITION(dwlConditionMask,VER_PLATFORMID,VER_EQUAL);
if (VerifyVersionInfo(&osver,VER_MAJORVERSION|VER_MINORVERSION|VER_PLATFORMID,dwlConditionMask))
{
printf("The host system is Windows xp");
}
else
{
printf("The host system is not Windows xp");
}
/* 调用另一个函数来看看*/
GetVersionEx((LPOSVERSIONINFOW)&osver);
printf("MajorVersion = %u,MinorVersion = %u",
osver.dwMajorVersion,osver.dwMinorVersion);
return 0;
}
4、 CreateProcess函数
当一个线程调用该函数时,系统会自动生成一个进程内核对象,初始计数为1.然后系统为该进程创建一个虚拟地址空间,将可执行文件或者DLL文件的代码、数据拷入,系统会为该进程的主线程创建一个线程内核对象,最终调用main函数开始执行。
CreateProcess函数参数所需要注意的地方:
4.1参数pszCommandLine必须是一个和修改的参数。虽然函数不会修改,但是不能传入只读的。如
STARTUPINFO si = {sizeof(si)};
PROCESS_INFORMATION pi;
CreateProcess(NULL,_T("NOTEPAD"),NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
就会报错,而这样操作,就可以通过
TCHAR szCommandLine[] = _T("NOTEPAD");
CreateProcess(NULL,szCommandLine,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
5、 进程终止
5.1主线程的进入点函数返回;(最好使用这个方法)
Ø 该线程创建的任何C++对象将能使用它们的析构函数正确的撤销;
Ø 操作系统能正确的释放该线程的堆栈使用的内存;
Ø 系统将进程的退出代码设置为进入点函数的返回值;(调用ExitProcess)
Ø 系统将进程内核对象的返回值减一
5.2进程中的一个线程调用ExitProcess函数;(避免使用)
与5.1相比,跳过了析构函数的撤销等,直接调用ExitProcess函数。
所以这种情况C++的类对象没有机会去调用析构函数。(如果使用VS2008的话,会发现全局变量还是被释放了,只有局部变量没有释放,这个我会再总结一份)
5.3另一个进程中的线程,调用TerminateProcess函数;(避免使用)
该函数是一个异步函数,也就是说,它会通知操作系统,想要终止运行一个进程,但是这个函数无法知道也无法保证进程是否已经终止运行。如果想要知道,必须调用WaitForSingleObject函数。
5.4进程中的所有线程自行终止运行。(几乎从未发生)
【文尾】如果文章对您有帮助,请留下对我和蟹儿的祝福,谢谢~~