CreateProcess使用注意事项

来源:互联网 发布:创建目录 linux 编辑:程序博客网 时间:2024/05/29 16:41
  1. BOOL CreateProcessCreateProcessA(
  2.     __in_opt    LPCSTR lpApplicationName,
  3.     __inout_opt LPSTR lpCommandLine,
  4.     __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
  5.     __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
  6.     __in        BOOL bInheritHandles,
  7.     __in        DWORD dwCreationFlags,
  8.     __in_opt    LPVOID lpEnvironment,
  9.     __in_opt    LPCSTR lpCurrentDirectory,
  10.     __in        LPSTARTUPINFOA lpStartupInfo,
  11.     __out       LPPROCESS_INFORMATION lpProcessInformation
  12.     );
复制代码
CreateProcess在进程完全初始化好之前就返回TRUE。这意味着操作系统加载器(loader)尚未尝试定位所有必要的DLL。如果一个DLL找不到或者不能正确初始化,进程就会终止。因为CreateProcess返回TRUE,所以父进程不会注意到任何初始化问题。

pszApplicationName和pszCommandLine参数分别指定新进程要使用的执行体文件的名称,以及要传给新进程的命令行字符串。先来谈谈pszCommandLine参数。注意,pszCommandLine参数被原型化为一个PTSTR。这意味着CreateProces期望你传入的是一个非“常量字符串”的地址。在内部,CreateProcess实际上会修改你传给它的命令行字符串。但在CreateProcess返回之前,它会将这个字符串还原为原来的形式。这是很重要的,因为如果命令行字符串包含在你的文件映像的只读部分,就会引起访问冲突(违例)。例如,以下代码就会导致冲突,因为Microsoft的C/C++编译器把"NOTEPAD"字符串放在只读内存中
  1. STARTUPINFO si = { sizeof(si) };
  2. PROCESS_INFORMATION pi;
  3. CreateProcess(NULL, TEXT("NOTEPAD"), NULL, NULL,FALSE, 0, NULL, NULL, &si, &pi);
复制代码
CreateProcess试图修改字符串时,会引起一个访问冲突(Microsoft C/C++编译器的早期版本把字符串放在可读/写内存中。所以对CreateProcess函数的调用不会引起访问冲突)。
解决这个问题的最佳方式是:在调用CreateProcess之前,把常量字符串复制到一个临时缓冲区,如下所示:
  1. STARTUPINFO si = { sizeof(si) };
  2. PROCESS_INFORMATION pi;
  3. TCHAR szCommandLine[] = TEXT("NOTEPAD");
  4. CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
复制代码
可以使用pszCommandLine参数来指定一个完整的命令行,供CreateProcess用于创建新进程。当CreateProcess解析pszCommandLine字符串时,它会检查字符串中的第一个标记(token),并假定此标记是你想运行的执行体文件的名称。如果执行体文件的名称没有扩展名,就会默认是.exe扩展名。CreateProcess还会按照以下顺序搜索执行体。
1. 主调进程.EXE文件所在的目录
2. 主调进程的当前目录
3. Windows系统目录,即GetSystemDirectory返回的System32子文件夹
4. Windows目录
5. PATH环境变量中列出的目录
当然,假如文件名包含一个完整路径,系统就会利用这个完整路径来查找执行体,而不会搜索目录。如果系统找到了执行体文件,就创建一个新进程,并将执行体的代码和数据映射到新进程的地址空间。然后,系统调用由链接器设为应用程序入口的C/C++运行时启动例程。

dwCreationFlags参数标识了影响新进程创建方式的标志(flag)。多个标志可以使用按位OR运算符来组合。可用的标志如下。
DEBUG_PROCESS标志向系统表明父进程希望调试子进程以及子进程将来生成的所有进程。该标志向系统表明,在任何一个子进程(现在的身份是被调试对象,或者说debugee)中发生特定的事件时,要通知父进程(现在的身份是调试器,或者说debugger)。
DEBUG_ONLY_THIS_PROCESS标志类似于DEBUG_PROCESS,但是,只有在关系最近的子进程中发生特定事件时,父进程才会得到通知。如果子进程又生成了新的进程,那么在这些新进程中发生特定事件时,调试器是不会得到通知的。要进一步了解如何利用这两个标志来写一个调试器,并获取被调试应用程序中的DLL和线程的信息,请阅读MSDN的一篇文章:“Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities, Part 2”,网址是http://msdn.microsoft.com/msdnmag/issues/02/08/EscapefromDLLHell/
CREATE_SUSPENDED标志造成系统创建新进程,但会挂起其主线程。这样一来,父进程就可以修改子进程地址空间中的内存,更改子进程的主线程的优先级,或者在进程执行任何代码之前,将此进程添加到一个作业(job)中。父进程修改好子进程之后,可以调用ResumeThread函数来允许子进程执行代码。欲知这个函数的详情,请参见第7章。
DETACHED_PROCESS标志阻止一个基于CUI(控制台用户界面)的进程访问其父进程的控制台窗口,并告诉系统将它的输出发送到一个新的控制台窗口,如果一个基于CUI的进程是由另一个基于CUI的进程创建的,那么在默认情况下,新进程将使用父进程的控制台窗口。(在命令提示符中运行C++编译器的时候,不会新建一个控制台窗口;输出将附加到现有控制台窗口的底部。)通过指定这个标志,新进程如果需要将输出发送到一个新的控制台窗口,就必须调用AllocConsole函数来创建它自己的控制台。
CREATE_NEW_CONSOLE标志指示系统为新进程创建一个新的控制台窗口。如果同时指定CREATE_NEW_CONSOLEDETACHED_PROCESS标志,会导致一个错误。
CREATE_NO_WINDOW标志指示系统不要为应用程序创建任何控制台窗口。可以使用这个标志来执行没有用户界面的控制台应用程序。
CREATE_NEW_PROCESS_GROUP标志修改用户按Ctrl+C或Ctrl+Break时获得通知的进程列表。按下这些组合键时,假如有多个CUI进程正在运行,系统将通知一个进程组中的所有进程,告诉它们用户打算中断当前操作。创建一个新的CUI进程时,假如指定了这个标志,就会创建一个新的进程组。组中的一个进程处于活动状态时,一旦用户按下Ctrl+C或Ctrl+Break,系统就只是向这个组的进程发出通知。
CREATE_DEFAULT_ERROR_MODE标志向系统表明新进程不会继承父进程所用的错误模式。(本章前面已经讨论了SetErrorMode函数。)
CREATE_SEPARATE_WOW_VDM标志只有在你运行16位Windows应用程序时才有用。它指示系统创建一个单独的虚拟DOS机(Virtual DOS Machine,VDM),并在这个VDM上运行16位Windows应用程序。默认情况下,所有16位Windows应用程序都在一个共享的VDM中执行。在独立的VDM中运行的好处是,假如应用程序崩溃,它只需要杀死这个VDM,在其他VDM中运行的其他程序仍然能正常工作。另外,在独立的VDM中运行的16位Windows应用程序有独立的输入队列。这意味着假如一个应用程序暂时挂起,独立VDM中运行的应用程序仍然能接收输入。运行多个VDM的缺点在于,每个VDM都要消耗较多的物理内存。Windows 98在单独一个虚拟机中运行所有16位Windows应用程序——你不能覆盖这个行为。
CREATE_SHARED_WOW_VDM标志只有在你运行16位Windows应用程序时才有用。默认情况下,所有16位Windows应用程序都在单独一个VDM中运行的,除非指定了CREATE_SEPARATE_WOW_VDM标志。不过,你也可以覆盖这个默认行为。办法是在注册表中将HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\WOW下DefaultSeparateVDM的值设为yes。在此之后,如果设置CREATE_SHARED_WOW_VDM标志,16位Windows应用程序就会在系统的共享VDM中运行。(修改了这个注册表设置后,必须重启电脑。)注意,为了检测在64位操作系统下运行的32位进程,你可以调用IsWow64Process函数,它的第一个参数是你要检测的进程的句柄,第二个参数则是指向一个Boolean值的指针;如果进程是在WOW64下运行,这个值就会设为TRUE;否则会设为FALSE。
CREATE_UNICODE_ENVIRONMENT标志告诉系统子进程的环境块应包含Unicode字符。进程的环境块默认包含的是ANSI字符串。
CREATE_FORCEDOS标志强制系统运行嵌入一个16位OS/2应用程序中的MS-DOS应用程序。
CREATE_BREAKAWAY_FROM_JOB标志允许一个作业中的进程生成一个和作业无关的进程。(详情参见第5章。)
EXTENDED_STARTUPINFO_PRESENT标志向操作系统表明一个STARTUPINFOEX结构被传给了psiStartInfo参数。

dwCreationFlags参数还允许你指定一个优先级类(priority class)。不过,这样做没有多大必要,而且对于大多数应用程序,都不应该这样做——系统会为新进程分配一个默认的优先级类。下列表格展示了可能的优先级类。
优先级类标志IdleIDLE_PRIORITY_CLASSBelow normalBELOW_NORMAL_PRIORITY_CLASSNormalNORMAL_PRIORITY_CLASSAbove normalABOVE_NORMAL_PRIORITY_CLASSHighHIGH_PRIORITY_CLASSRealtimeREALTIME_PRIORITY_CLASS

这些优先级类决定了相对于其他进程的线程,这个进程中的线程的调度方式,详情参见第 7 章的“优先级的抽象视图”一节。
0 0