需求來源:項目上有用到需要擷取ffmpeg的指令輸出,進行解析,而後添加成進度條的形式表現出來
是以寫了個擷取子程序輸出的通用工具代碼
實作原理:
- 建立可繼承的匿名管道
- 将其中的寫管道,作為
的參數傳入,替換子程序的标準輸出createprocss
- 調用
從讀管道進行循環讀取内容readfile
代碼如下:
#include <windows.h>
#include <tchar.h>
#include <string>
typedef void (* FPTGETPROCESSOUT)(_In_ const char* szLineData, _In_ VOID *lpUser);
BOOL CreateProcessAndOutput(_In_ LPCTSTR szCommandLine, _In_ FPTGETPROCESSOUT CallBackFun, _In_ VOID *lpUser)
{
if (NULL == szCommandLine)
{
return FALSE;
}
BOOL bError = FALSE;
errno_t ErrorCode = 0;
LPTSTR szProcessCommand = NULL;
HANDLE hPipRead = NULL;
HANDLE hPipWrite = NULL;
SECURITY_ATTRIBUTES sa = { 0 };
STARTUPINFO Si = { 0 };
PROCESS_INFORMATION pi = { 0 };
char szRecvData[512] = { 0 };
DWORD dwRecvSize = 0;
std::string szOutputLine;
szProcessCommand = new TCHAR[_tcslen(szCommandLine) + 1];
ErrorCode = _tcscpy_s(szProcessCommand, _tcslen(szCommandLine) + 1, szCommandLine);
if (0 != ErrorCode)
{
goto FUN_CLEANUP;
}
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
bError = CreatePipe(&hPipRead, &hPipWrite, &sa, 0);
if (FALSE == bError || NULL == hPipRead || NULL == hPipWrite)
{
goto FUN_CLEANUP;
}
Si.cb = sizeof(Si);
Si.hStdOutput = hPipWrite;
Si.hStdError = hPipWrite;
Si.wShowWindow = SW_HIDE;
Si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
bError = CreateProcess(NULL, szProcessCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &Si, &pi);
if (FALSE == bError)
{
goto FUN_CLEANUP;
}
if (NULL != hPipWrite)
{
CloseHandle(hPipWrite);
hPipWrite = NULL;
}
while (FALSE != ReadFile(hPipRead, szRecvData, _countof(szRecvData) -1, &dwRecvSize, NULL))
{
szRecvData[dwRecvSize] = '\0';
char* szLinesBegin = szRecvData;
char* szLinesEnd = NULL;
while (true)
{
char* szFound = szLinesBegin + strcspn(szLinesBegin, "\r\n");
szLinesEnd = *szFound != '\0' ? szFound : NULL;
if (NULL == szLinesEnd)
{
szOutputLine += szLinesBegin;
break;
}
*szLinesEnd = '\0';
if (false == szOutputLine.empty())
{
szOutputLine += szLinesBegin;
CallBackFun(szOutputLine.c_str());
szOutputLine.clear();
}
else
{
if (*szLinesBegin != '\0')
{
CallBackFun(szLinesBegin);
}
}
szLinesBegin = szLinesEnd + 1;
}
}
WaitForSingleObject(pi.hProcess, INFINITE);
bError = TRUE;
FUN_CLEANUP:
if (NULL != hPipRead)
{
CloseHandle(hPipRead);
hPipRead = NULL;
}
if (NULL != hPipWrite)
{
CloseHandle(hPipWrite);
hPipWrite = NULL;
}
if (NULL != szProcessCommand)
{
delete[] szProcessCommand;
szProcessCommand = NULL;
}
if (NULL != pi.hProcess)
{
CloseHandle(pi.hProcess);
pi.hProcess = NULL;
}
if (NULL != pi.hThread)
{
CloseHandle(pi.hThread);
pi.hThread = NULL;
}
return bError;
}
使用方法:使用回調的形式,向回調函數傳回出每一行的輸出内容
1. 先定義一個回調函數,原型如下 (
lpUser
為使用者自定義指針,用于傳遞額外的參數)
void CallBackGetOutput(const char * szLineData, VOID *lpUser)
{
DWORD* Num = (DWORD*)lpUser;
printf("[line:%02d] %s\n", (*Num)++, szLineData);
}
2. 調用CreateProcessAndOutput,傳遞要調用的子程序指令行和回調函數位址