通过CreateProcess()启动的进程如何获取PID?

14

首先声明,我不是C背景的开发者,而是一名PHP开发者。因此,我的所有编码都是通过借鉴其他示例并对其进行微调来满足我的需求。如果我提出了太基础或明显的问题,请多多包涵。

我正在使用CreateProcess()启动FFmpeg

int startFFmpeg()
{
    snprintf(cmd, sizeof(cmd), "D:\\ffpmeg\bin\ffmpeg.exe -i D:\\video.mpg -r 10 D:\\frames");

    PROCESS_INFORMATION pi;
    STARTUPINFO si={sizeof(si)};
    si.cb = sizeof(STARTUPINFO);
    int ff = CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    return ff;
}

我需要做的是获取该进程的PID,然后稍后检查是否仍在运行。基本上这就是我想要的:
int main()
{
    int ff = startFFmpeg();
    if(ff)
    {
       // great! FFmpeg is generating frames
       // then some time later
       if(<check if ffmpeg is still running, probably by checking the PID in task manager>) // <-- Need this condition
       {
            // if running, continue
       }
       else
       {
           startFFmpeg();
       }
    } 
  return 0;   
}

我做了一些研究,发现PIDPROCESS_INFORMATION中返回,但我找不到一个示例来展示如何获取它。

一些元数据

操作系统: Windows 7
编程语言: C
IDE: Dev C++


2
进程 ID 存储在作为 CreateProcess() 的最后一个参数传递的 PROCESS_INFORMATION 结构体中,在您的情况下,这将是 pi 变量,具体而言是:**pi.dwProcessId**。 - WhozCraig
2
真的吗?被踩了?我以为SO的目的是学习和分享。而且我不是刚来这里就发了这个问题。我确实先做了功课。 - asprin
@WhozCraig:确实,在这种情况下,这是首选的捷径...! - alk
2
下投票者可能想解释一下吗? - alk
@alk 谢谢。这个答案已经在我的回答中停留了10分钟,而且对他真正想要做的事情也已经给出了答案:查看进程是否已经终止。 - WhozCraig
哦,是的。不知何故,页面刷新没有起作用,当我坐在通勤火车上每分钟更改GMS单元格时。@WhozCraig - alk
2个回答

18
从您在CreateProcess()中作为最后一个参数传递的PROCESS_INFORMATION结构中提取它,在您的情况下是pi.dwProcessId
但是,要检查它是否仍在运行,您可能希望只需等待进程句柄即可。
static HANDLE startFFmpeg()
{
    snprintf(cmd, sizeof(cmd), "D:\\ffpmeg\bin\ffmpeg.exe -i D:\\video.mpg -r 10 D:\\frames");

    PROCESS_INFORMATION pi = {0};
    STARTUPINFO si = {0};
    si.cb = sizeof(STARTUPINFO);
    if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
    {
        CloseHandle(pi.hThread);
        return pi.hProcess;
    }
    return NULL;
}

在您的启动main()中,您可以这样做...
int main()
{
    HANDLE ff = startFFmpeg();
    if(ff != NULL)
    {
        // wait with periodic checks. this is setup for
        //  half-second checks. configure as you need
        while (WAIT_TIMEOUT == WaitForSingleObject(ff, 500))
        {
            // your wait code goes here.
        }

        // close the handle no matter what else.
        CloseHandle(ff);
    }
    return 0;
}

谢谢。让我试一下这个。 - asprin
3
不要忘记你在pi结构体中拥有进程句柄和相应的线程句柄。当完成操作后,你需要使用CloseHandle()关闭它们(不会终止进程,只是释放句柄)。 - WhozCraig
1
如果您想检查进程是否仍在运行,则必须使用进程句柄,而不是pid。 Pid可以被重用。 - Raymond Chen
@WhozCraig 在else部分中,我使用了printf("running"),输出正常。但是,在启动ffmpeg并使用任务栏关闭它后,我可以看到ffmpeg仍然将帧输出到输出文件夹中。 - asprin
@RaymondChen 在上面的例子中,它是进程句柄对吧? - asprin
显示剩余3条评论

4
你可能希望使用win32 api函数GetProcessId()
#include <windows.h>

...

BOOL bSuccess = FALSE;
LPTSTR pszCmd = NULL;
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(si);

pszCmd = ... /* assign something useful */

bSuccess = CreateProcess(NULL, pszCmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

if (bSuccess)
{
  DWORD dwPid = GetProcessId(pi.hProcess);
  ...
}
else
  ... /* erorr handling */

请查看此处以获取详细信息:http://msdn.microsoft.com/en-us/library/windows/desktop/ms683215%28v=vs.85%29.aspx

谢谢,这很有帮助。您能否给出一个示例,展示如何在任务管理器中搜索“dwPID”,以便我知道它仍在运行? - asprin
啊!现在它说 undefined reference to GetProcessId。我不太喜欢 C。 - asprin
你有包含 <windows.h> 吗?@asprin - alk
在Windows 8或Windows Server 2012上,可能需要包含Processthreadsapi.h。在Win7中,原型应该在<WinBase.h>中。无论如何,后者都应该随着包含<windows.h>而来。顺便说一句:这些都在我回答中添加的链接里。 - alk
没有运气。再次出现相同的消息。 - asprin
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接