windows 核心编程(进程)

本文详细介绍了Windows环境下进程的概念、创建过程及生命周期管理。包括进程实例、环境变量存储位置、创建与结束进程的不同方法及其影响等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、进程:一个正在运行的程序的实例,它由两部分组成:

(1) 一个内核对象,操作系统用它来管理进程。内核对象也是系统保存进程统计信息的地方。

(2) 一个地址空间,其中包含所有可执行文件或DLL模块的代码和数据,此外,它还包含动态分配内存,比如线程堆栈和堆的分配。

2、windows应用程序必须有一个入口点函数,应用程序开始运行时,这个函数会被调用。操作系统实际并不调用我们所写的入口点函数。相反,它会调用由C/C++运行库实现并在链接时使用-entry:命令行选项来设置一个C/C++运行时启动函数。该函数讲初始化C/C++运行库,使我们能调用malloc和free之类的函数。它还确保了我们的代码开始执行之前,我们声明的任何全局和静态C++对象都被正确的构造。

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

                 应用程序类型                                      入口点函数(入口)                              嵌入可执行文件的启动函数

处理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链接器开关,链接器就会寻找main或wmain函数,并根据情况分别选择mainCRTStartup或wmainCRTStartup函数。

 

Visual C++自带C运行库的源代码。可以在crtexe.c文件中找到4个启动函数的源代码。这些启动函数的用途简单总结如下:

(1)         取得指向进程的命令行(command line)的指针

(2)         取得指向进程的环境变量的指针

(3)         初始化C/C++ Run Time的全局变量,这此变量放在StdLib.h

(4)         初始化C Run Time 内存分配函数所用的堆,从而使malloc/free 函数可用。

(5)         调用程序中的静态变量和全局变量的构造函数

(6)         调用程序中的Main/WinMain函数

(7)         当从Main中返回后,取得Main的返回值Ret,调用C Run-Time exit(Ret) 函数,参数是Ret

(8)         调用_onexit注册的函数

(9)         为所有全局和静态变量调用析构函数

(10)      若是Debug Build,如果_CRTDBG_LEAK_CHECK_DF 宏被设置了,系统会调用_CrtDumpMemoryLeaks函数 输出程序中的内存泄露的地方

(11)      Ret参数调用操作系统的ExitProcess函数,操作系统会杀掉当前进程并设置进程的Exit Code.

 注:第11条说明在Windows中主线程退出会执行ExitProcess,即使有未执行完的线程进程也会退出。这种做法与Linux不同。

         若将ExitProcess改为ExitThread 那么主线程退出时 若还有其它线程在运行,进程不会退出。

3、一个进程的实例句柄

  1Handle/HMODULE/HINSTANCE

Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。

HMODULE 是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。

HINSTANCE win32下与HMODULE是相同的东西,在Win32下还存在主要是因为win16 程序使用HINSTANCE来区别task

HWND 是窗口句柄。

2)进程的环境变量

     环境初始值存储位置:

系统环境变量

HKEY_LOCAL_MACHINE"SYSTEM"CurrentControlSet"Control"Session Manager"Environment

用户环境变更

HKEY_CURRENT_USER"Environment

 

3)创建进程

     CreateProcess()函数可以创建一个进程,在创建进程时两个内核对象会被创建,一个是进程内核对象,一个是线程内核对象。

4.       结束进程(Terminating a Process)   

四种结束进程的方法:

(1)     从主线程的入口函数返回----------推荐此方法。

(2)     进程中的任一线程调用ExitProcess()----------避免使用该方法

(3)     其它进程中的任一线程调用TerminateProcess()----------避免使用该方法

(4)     进程中的所有线程执行完毕后, 进程会自动结束----------这种情况很少发生。

 

ExitProcess & ExitThread

调用以上两个函数的线程会使线程或进程立刻退出,写在以上两个函数后面的代码永远都不可能被执行。如:

                    ExitThread(0);

                Printf(“"nYou will never see this!”);

 

进程结束与资源释放

无论进程以何种方式结束, 正常退出或异常退出,系统会保证释放掉进程所占用及分配的任何资源,就好像进程从没运行过一样。也就是说进程结束后不会泄露任何资源。

5.子进程

子进程有自已的进程地址空间,它不依附于父进程而独立存在。即使父进程终止了 子进程仍可以运行。

除非父进程给子进程共享了某些数据或资源 否则子进程无法操作父进程的数据。

 

父进程在创建完子进程后 根据需要 适时调用CloseHandle()函数 关闭子进程的Thread句柄和Process句柄。否则父进程会一直持有子进程的ThreadProcess句柄 从而导致系统无法释放子进程的ProcessThread所占用的资源。父进程也可以通过 WaitForSingleObject 函数等待子进程结束。然后再关闭Process 句柄。

 

 

分离的子进程

     在创建完子进程后, 父进程不需要与子进程有任何交互或不需要等待子进程执行完后再继续做其它的事,

      那么在创建完子进程可立刻关闭父进程所持有的子进程的Process句柄和Thread句柄,从而将子进程分离出来。

 

     例子如下:

     PROCESS_INFORMATION pi;

  // Spawn the child process.

  BOOL fSuccess = CreateProcess(..., &pi);

  if (fSuccess)

 {

   // Allow the system to destroy the process & thread kernel

   // objects as soon as the child process terminates.

   CloseHandle(pi.hThread);

   CloseHandle(pi.hProcess);

 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值