C++ 什么可能导致ShellExecute返回SE_ERR_OOM(错误8)?

C++ 什么可能导致ShellExecute返回SE_ERR_OOM(错误8)?,c++,windows,winapi,out-of-memory,shellexecute,C++,Windows,Winapi,Out Of Memory,Shellexecute,我经常从本机C++/Win32应用程序调用ShellExecute,以执行最终用户从GUI中选择的任何shell项。项目是可执行文件/脚本或链接(.lnk)。在一些我仍然不清楚的情况下,下面的函数有时返回8(SE_ERR\u OOMerror;仅简要说明)。因此,不会执行该项。什么可能导致此错误 int doExecute(LPCTSTR file, LPCTSTR args, LPCTSTR workDir) { assert(file && *file); H

我经常从本机C++/Win32应用程序调用ShellExecute,以执行最终用户从GUI中选择的任何shell项。项目是可执行文件/脚本或链接(.lnk)。在一些我仍然不清楚的情况下,下面的函数有时返回
8
SE_ERR\u OOM
error;仅简要说明)。因此,不会执行该项。什么可能导致此错误

int doExecute(LPCTSTR file, LPCTSTR args, LPCTSTR workDir)
{
    assert(file && *file);
    HRESULT hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    assert(hRes == S_OK || hRes == S_FALSE);
    int code = (int)ShellExecute(NULL, NULL, file, args, workDir, SW_SHOWNORMAL);
    doLog("ShellExecute returned: %d, %u", code, GetLastError()); // EDIT
    CoUninitialize();
    return code;
}
背景:

  • Windows8 64位,应用程序为32位,无法在任何其他计算机上尝试
  • 应用程序是多线程的
  • 根据设计,总是专门创建一个新线程来执行此调用
  • 此代码中的断言在调试会话期间从不中断
  • 应用程序本身不直接使用COM,但可能必须调用间接使用COM的Win32 API,因为它与shell交互非常频繁。在这些情况下,COM总是使用与上面所示相同的标志进行初始化
  • 传递给
    CoInitializeEx
    的标志是在MSDN推荐后盲目选择的(参见文档),而不是因为个人选择
到目前为止对该缺陷的观察:

  • 这很少见
  • 它只在一次或几次休眠后发生(我的应用程序总是在我的笔记本电脑上运行,我经常使用它)
  • 调用
    ShellExecute
    后立即调用始终返回
    0
  • 就我记忆所及,它总是在尝试执行
    .lnk
    文件时发生,但并不总是同一个文件
  • 快速查看机器上运行的
    Process Explorer
    (sysinternals.com),不会显示任何内存使用峰值
  • edit:我在这里发布之前做了最后一次测试,连续调用
    doExecute
    200次。所有进程都是无错误生成的

经过长时间的测试,在我按照@DavidHeffernan和@RossRidge的建议对代码进行了一些更改之后,这个错误再也没有出现过。虽然我真的不能认为这是一个明确的答案本身,因为我仍然不知道到底发生了什么在引擎盖,我还没有能够复制错误至今。 适用的修改:

  • ShellExecuteEx
    调用替换为
    ShellExecuteEx
  • 为每个新线程调用一次
    CoInitializeEx
    ,而不使用其
    counInitializeEx
    计数器部分。但保留了以下嵌套的
    CoInitializeEx
    -
    CoUninitialize

编辑:如果有人需要,只是为了确认问题不再发生,即使经过几个月的测试,应用了这些修改。

如果需要正确的错误处理,请使用ShellExecuteEx。“我经常调用ShellExecute”。如果你不检查你启动和节流的过程发生了什么,那么这就在某个地方停止了。进程是迄今为止可以创建的最昂贵的操作系统对象。通常会耗尽的资源是内核的未分页内存池,当这种情况发生时,您确实会得到OOM。“系统内存不足”,尽可能描述。如果您仍然可以启动任务管理器,它应该显示许多活动进程。
doExecute
不调用。因此,在
doExecute
返回后调用是没有意义的(请参见备注部分)。如果每个线程调用
CoInitializeEx
coInitialize
不止一次,我会尽量避免。大多数应用程序每个线程只调用一次
coInitializeX
,许多应用程序从未调用
coInitialize
@HansPassant,我忘了提到这一点,在这里发布之前,我做了一个测试,循环调用了200个
doExecute
。所有进程都是在没有任何错误的情况下生成的。谢谢,我编辑了我的帖子。