相关文章推荐
苦闷的生姜  ·  NSIS ...·  3 月前    · 
淡定的蚂蚁  ·  GroupBox - WPF .NET ...·  1 年前    · 

使用 CreateProcess 函数创建进程(调用外部程序)算是很常用的操作了,最近在工作中却遇到一个少见的怪现象,经常使用的一段代码(调用外部程序并等待其结束,主要就使用了 CreateProcess 函数),在少数某些机器上会失败(目前只在某一个 Win8.1 和某一个 Win10 机器遭遇失败)。

经调查分析,发现正是 CreateProcess 调用失败,GetLastError 返回 0x05 错误( ERROR_ACCESS_DENIED ),凭经验知道这是权限不足的问题,但具体是什么原因?一时无解。继续排查,发现原先有另一处调用外部程序的代码是不存在该问题的,仔细对比两处代码,发现调用 CreateProcess 时的第6个参数(dwCreationFlags)不一样!问题代码中使用了 CREATE_BREAKAWAY_FROM_JOB 值(和 Job Object 有关),马上去掉该值再测试,问题果然没有了!

抱着「知其然,还要知其所以然。」的一惯态度,继续寻找导致该问题的原因,历程如下:

1. 先是深入解读了 MSDN 相关部分,了解到使用 CREATE_BREAKAWAY_FROM_JOB 参数是需要前提条件的:需要其关联的 Job 对象具有 JOB_OBJECT_LIMIT_BREAKAWAY_OK 属性,否则就会失败,但 MSDN 中并未明确指出失败码为 0x05。

2. 网上求解过程中,意外地在 Chrome Issues 列表中发现同样的问题:「 WinAPI  CreateProcessAsUserW() with CREATE_BREAKAWAY_FROM_JOB flag which fails with 0x5 (access denied) error. 」。

3. 翻书《Windows核心编程》也找到了对 CREATE_BREAKAWAY_FROM_JOB 的相关说明(如下图):

总结一下:
我使用的这段代码是从以前的工程里拷贝来的,至于为什么带上了 CREATE_BREAKAWAY_FROM_JOB 参数,属于历史问题就不得而知了,这个参数的目的是让子进程脱离父进程的 Job,如果本没有这个需求的话,可以不用考虑直接去掉,如果确实需要该特性的话,那就得按官方的要求来,要确保其 Job 对象具有 JOB_OBJECT_LIMIT_BREAKAWAY_OK 属性(具体怎么实现不属于本文的范畴了)。个别机器上可能由于系统环境的某些特殊原因,造成相关 Job 对象不具有 JOB_OBJECT_LIMIT_BREAKAWAY_OK 属性,因此导致了该问题的出现,图证如下:

所以,以后遇到 CreateProcess 失败,错误码为 0x05 时,去检查一下参数里是否有 CREATE_BREAKAWAY_FROM_JOB 吧!

参考:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684147(v=vs.85).aspx
https://code.google.com/p/chromium/issues/detail?id=79091#c45
《Windows核心编程》

使用 CreateProcess 函数创建进程(调用外部程序)算是很常用的操作了,最近在工作中却遇到一个少见的怪现象,经常使用的一段代码(调用外部程序并等待其结束,主要就使用了 CreateProcess 函数),在少数某些机器上会失败。经调查分析,发现正是 CreateProcess 调用失败,GetLastError 返回 0x05 错误(ERROR_ACCESS_DENIED) STARTUPINFO si={sizeof(si)}; PROCESS_INFORMATION pi; si.dwFlags=STARTF_USESHOWWINDOW; //制定wShowWindow成员 si.wShowWindow=TRUE;
进程 (Process)和线程(Thread) 进程 通常被定义为一个正在运行的程序的实例。简单来说,磁盘上的可执行文件被载入内存执行之后,就变成“ 进程 ”了。在 SDK 文档中有关于 进程 的更精确的描述: 进程 是一个正在运行的程序,它拥有自己的虚拟地址空间,拥有自己的代码、数据和其 他 系统 资源,如 进程 创建 的文件、管道、同步对象等。一个 进程 也包含了一个或者多个运行在 此 进程 内的线程。 虽然程序和 进程 在表面上很相似,但是它们有着根本的区别。程序是一连串静态的指令,而 进程 是一个容器,它包含了一系列运行在这个程序实例上下
调用 CreateProcess ()函数时, 系统 所做的工作: 系统 创建 一个 进程 内核对象,初始使用计数为1;( 进程 内核对象并不代表 进程 本身,而是操作 系统 用来管理这个 进程 的一个数据结构) 系统 为新 进程 创建 一个虚拟地址空间,并且将可执行文件的代码及数据加载到 进程 的地址空间; 系统 为新 进程 创建 一个主线程内核对象,使用计数为1;(线程内核对象是操作 系统 用来管理线程的数据结构) 注释:内核对象 #include <windows> CreateProcess ()函数原型 BOOL C
CreateProcess 函数用来 创建 一个 进程 ,在参数中有一个就是执行的命令。这个值在 createprocess 函数内部是会被改变的,所以在传递参数的时候不允许传const类型常量。 如以下方法不允许 1: CreateProcess (NULL,_T("calc.exe'),NULL,NULL,TRUE,0,NULL,NULL,&si,&pi); const TCHAR sCmd[
LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes。 LPSECURITY_ATTRIBUT
转载请您注明出处:http://www.cnblogs.com/lsh123/p/7405796.html 0x01 CreateProcess W CreateProcess 的使用有ANSI版本的 CreateProcess A和UNICODE版本的 CreateProcess W:   不过查看源码就可以发现其实 CreateProcess A内部 调用 的还是 CreateProcess W: