【问题标题】:Is there any way GetExitCodeProcess could set the exit code to the wrong value?有什么方法 GetExitCodeProcess 可以将退出代码设置为错误的值?
【发布时间】:2013-06-01 00:19:17
【问题描述】:

我正在维护某人只是在他们退休之前编写的代码,这意味着我找不到他们来提问。 :-) 这基本上是一个用于启动程序的 C++ 包装器。有问题的代码块是这样的:

BOOL bSuccess = CreateProcess(NULL, (char *)strBatFile.c_str(),
    NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, strLocalWorkingDir.c_str(), &si,  &pi );

   if( bSuccess )
   {
      DWORD dwMillisec = INFINITE;      
      DWORD dwWaitStatus = WaitForSingleObject( pi.hProcess, dwMillisec );

      if( dwWaitStatus == WAIT_OBJECT_0 )
      {
         DWORD dwExitCode = NULL;
         GetExitCodeProcess( pi.hProcess, &dwExitCode );
         nRet = (int)dwExitCode;
        }

      CloseHandle( pi.hThread );
      CloseHandle( pi.hProcess );
   }
   else
      nRet = START_PROCESS_FAILED;

如果一次只运行一个实例,它总是可以正常工作。但是,如果在很短的时间范围内运行多个,则其中大约一半的 dwExitCode 设置为 1 而不是 0,即使进程没有崩溃,并且内部程序写入的日志文件正在完成。

所以澄清一下,这个过程总是开始正常,它总是进入 if 语句,但它是由 GetExitCodeProcess 设置的 dwExitCode 的值,它不包含预期的内容。由于我们对此进行了错误检查,因此我们将其中一些运行标记为不完整,而实际上它们都很好。

有什么方法可以将此值设置为与进程退出代码不同的值?和/或是否有我可以同时运行的实用程序来确认退出代码是我认为的那样?

谢谢!

ETA: 刚刚意识到这是将内部程序调用放在一个 .bat 文件中 - “C:\\ --flags etc...”,然后在第二个参数,而不是直接使用 lpApplicationName 调用它。不知道这是否有所作为!但是当我打印进程的 PID 时,我可以看到它是 cmd.exe 进程的 PID,然后我们的程序有一个子 PID。但是,当我在 Process Monitor 中进行跟踪时,我可以看到父母和孩子都以退出代码 0 退出。

【问题讨论】:

  • 您是否偶然在多个线程中同时共享pi?否则,此代码返回 1 的 ExitCode 的唯一方法是生成的进程确实返回值 1,或者 nRet 未正确初始化(因为 dwWaitStatus 值不是 WAIT_OBJECT_0更新nRet)。
  • GetExitCodeProcess 似乎不太可能被破坏 - 它经常被 Windows 和第三方代码用于命令提示符和 GUI 程序。您确定将正确的 hProcess 值传递给GetExitCodeProcess
  • 您没有检查GetExitCodeProcess 的返回值。来自文档:“如果函数成功,则返回值非零。如果函数失败,则返回值为零。要获取扩展错误信息,请调用 GetLastError。”。您的代码不知道它是成功还是失败,因为它不检查。
  • 除了缺少的检查之外,该代码片段看起来很合理,但是如果不查看已启动的程序或不知道它的作用,很难给出明确的答案:您确定它总是正确设置退出成功代码为0,错误代码为1? MSDN GetExitCodeProcess() 文档中列出了进程设置其退出代码的不同方式。
  • @RemyLebeau - nRet 已提前初始化,在这方面看起来一切正常。我必须进一步研究线程(我对这种类型的编码很陌生),但这会产生什么影响?

标签: c++ kernel32


【解决方案1】:

找到了!应用程序本身实际上返回了 0 错误代码……它周围的外壳返回了 1。这是由于第二个参数中的 .bat 文件。该名称是从时间生成的,因此如果多个实例过于紧密地一起运行,它最终会成为完全相同的名称。这就是内部应用程序运行良好的原因……那里总是有一个具有该名称的 bat 文件。但是据我所知,当不同的实例试图生成或清理 bat 时,会发生访问冲突。

作为一个概念验证黑客,我只是将当前 PID 添加到文件名的末尾,并且一切正常。现在我只需要决定真正的修复,我认为这可能会完全摆脱整个 bat 文件机制并直接调用应用程序。

哇!谢谢各位的帮助!可悲的是,我包含的那段代码没有违规行,但上面每个人的提示帮助我缩小了问题的范围。 :-)

【讨论】:

  • 如果批处理文件仍然需要,Windows API 提供了一个函数 (GetTempFileName) 用于生成唯一的临时文件名:msdn.microsoft.com/en-us/library/windows/desktop/…
  • 老实说,我不知道为什么要使用批处理文件。有一个变量保存进入批处理文件的命令,如果我使用它作为第二个参数,它似乎工作得很好。如果有人知道为什么批处理文件可能会更好,我会全力以赴,但目前我只是想把它拿出来。
  • CreateProcess 使用起来可能有点吓人(有关可能出错的一些示例,请参阅此问题 stackoverflow.com/questions/1135784/…)。批处理文件可能只是以前的维护者为自己省去一些麻烦的一种方式。如果您的解决方案在没有批处理文件的情况下工作,那么最好没有它。
猜你喜欢
  • 2021-01-12
  • 1970-01-01
  • 2017-01-04
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-12
相关资源
最近更新 更多