《Windows核心编程》笔记3 --- 进程

接上.......

二 进程
2.创建进程
    使用创建进程函数,即可创建相应的进程:
 
BOOL CreateProcess(
   PCTSTR pszApplicationName,
   PTSTR pszCommandLine,
   PSECURITY_ATTRIBUTES psaProcess,
   PSECURITY_ATTRIBUTES psaThread,
   BOOL bInheritHandles,
   DWORD fdwCreate,
   PVOID pvEnvironment,
   PCTSTR pszCurDir,
   PSTARTUPINFO psiStartInfo,
   PPROCESS_INFORMATION ppiProcInfo);

    注意几点,(1)调用创建进程函数肯定是在一个进程的线程中完成的。(2)系统会为该进程创建一个进程的内核对象。(3)由于进程创建后会自动创建一个该进程的主线程,所以,系统也会创建一个线程的内核对象。(4)系统会为进程分配相应的虚拟地址内存空间,并将可执行文件以及相应的DLL文件和代码加载到该虚拟内存空间中去。

    进程的主线程创建后,主线程便开始运行,如果成功的创建了进程,则CreateProcess返回TRUE。

    参数详解:
    pszApplicationName与pszCommandLine分别表示新进程使用的可执行文件名称与传递给新进程的命令行字符集。比如,用记事本打开一个文件文件:
TCHAR path[] = TEXT("MyText.txt");
CreateProcess(
"C:\\Windows\System32\\Notepad.exe",path,.....);

    下面PSECURITY_ATTRIBUTES psaProcess与PSECURITY_ATTRIBUTES psaThread则设定该进程与进程的主线程的安全性。如设置默认安全,则设置NULL即可。bInheritHandles则设定此进程所拥有内核对象的继承性。比如,ProcessA中创建一个进程ProcessB,且设定bInheritHandles为TRUE,则ProcessB就拥有了访问ProcessA的拥有内核对象的访问能力。在ProcessB中只要Open*打开相应的进程即可调用相应的内核对象。

    fdwCreate参数用于标识标志,以便规定用来如何创建新进程。详细的查看MSDN或《Windows核心编程》。

    pvEnvironment用来设定进程的环境参数,每个进程都有一个环境块,是进程地址空间中分配的一块内存。每个环境块都有一串字符串,作用跟系统中环境变量的作用差不多。一般来说设定NULL,以表示继承父进程的环境参数。可以用PVOID GetEnvironmentStrings()获得调用进程正在使用的环境字符串数据块的地址

    pszCurDir是设置新进程的驱动器与目录,如果是NULL,则工作目录将与本进程处于同目录中。

     psiStartInfo记录STARTUPINFO 结构的信息,大多数进程创只需要使用默认值,我们只需要定义该结构,然后初始化清零即可:
STARTUPINFO si = {sizeof(si)}
CreateProcess(..
&si,..)
    其它参数的详解可见MSDN或书本
    当然,在程序中可以获得其值,如:
   
STARTUPINFO si = {sizeof(si)};
GetStartupInfo(
&si);


ppiProcInfo参数用于指向你必须指定的PROCESS_INFORMATION结构。CreateProcess在返回之前要对该结构的成员进行初始化。该结构的形式如下面所示:

typedef struct _PROCESS_INFORMATION
{
   HANDLE hProcess;
   HANDLE hThread;
   DWORD dwProcessId;
   DWORD dwThreadId;
}
 PROCESS_INFORMATION;
如前所述,创建新进程可使系统建立一个进程内核对象和一个线程内核对象。在创建进程的时候,系统为每个对象赋予一个初始使用计数值1 。然后,在createProcess返回之前,该函数打开进程对象和线程对象,并将每个对象的与进程相关的句柄放入PROCESS_INFORMATION结构的hProcess和hThread 成员中。当CreateProcess 在内部打开这些对象时,每个对象的使用计数就变为2 。 
    以后,需要用到该进程或主线程的句柄时,即可用该变量的hProcess和hThread属性来获得。



3.终止进程
    1.主线程的返回退出(Best)
    2.使用函数ExitProcess(Not Use)
    3.使用函数TerminateProcess(Not Use)
    4.进程中的所有线程终止运行(impossibility)
    为什么说第一种方法最好,因为:(1)C++代码的析构函数能够被正确执行。(2)系统会正确的释放线程堆栈使用的内存。(3)系统会将进程的退出代码设置为进入点函数的返回值。(4)进程的内核对象会减
1。

    如果使用ExitProcess来退出进程,则该函数后的代码将不会被执行,比如C++代码中调用了ExitProcess,则很多对象创建完成之后,还没被析构进程就退出了,这样容易出现内存的泄漏。另外,进程中使用的资源也会汇漏。
    使用方法:在代码中使用 ExitProcess(0)即可终止进程运行。

    TerminateProcess函数也可以终止进程,但它与ExitProcess的区别是它不光可以终止本身的进程,亦可终止其它进程的运行。函数的原型是这样的:
   
BOOL TerminateProcess(HANDLE hProcess, UINT fuExitCode);

    它需要有个进程的句柄。以便结构该进程。

    TerminateProcess是个异步函数,什么是异步函数,就是说,当TerminateProcess返回时,我们无法保证该进程已经终止运行。如果要确定进程是否终止运行,需调用WaitForSingleObject函数或类似的函数。

4.创建子进程
    书本上提到,为何要创建子进程?它说:
    如果需要处理非常复杂的任务,我们也可以在进程中创建一个新的线程来执行这种操作,但是,进程中的线程都是共享进程的地址空间的,这样带来一个问题。线程可能更改地址空间中的内容,我们需要保护地址空间内容不被更改,那么,我们可以用创建新进程的方法来实现它。

    Windows进程间传递数据的问题。如何在Windows的进程中传递数据,系统提供了很多种方法。比如:动态数据交换DDE,OLE,邮箱,管道等,其中,最有用的非内存映射文件莫属。

    书中举了一例,使用WaitForSingleObject来获得子进程退出代码
PROCESS_INFORMATION pi;
DWORD dwExitCode;

//Spawn the child process.
BOOLfSuccess = CreateProcess(, π);

if(fSuccess)
{
   
//Close the thread handle as soon as it is no longer needed!
   CloseHandle(pi.hThread);

   
//Suspend our execution until the child has terminated.
   WaitForSingleObject(pi.hProcess,INFINITE);

   
//The child process terminated;get its exit code.
   GetExitCodeProcess(pi.hProcess,
      
&dwExitCode);

   
//Close the process handle as soon as it is no longer needed.
   CloseHandle(pi.hProcess);
}


posted @ 2005-08-25 11:12  shipfi  阅读(1007)  评论(0编辑  收藏  举报