使用 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: