如何在 C/C++ 中跟踪程序过程的完成情况
Posted
技术标签:
【中文标题】如何在 C/C++ 中跟踪程序过程的完成情况【英文标题】:How to track the completion of the program process in C/C++ 【发布时间】:2020-10-22 14:07:45 【问题描述】:我需要编写一个程序,在程序过程完成后会做一些事情,比如计算器。也就是说,我使用计算器,然后分别将其关闭,它的过程完成,我的程序执行我设置的操作。我该怎么做呢?如何跟踪流程完成情况?我google了一下,发现提示需要通过CreateProcess函数创建一个单独的进程,然后使用WaitForSingleObject或者GetExitCodeProcess,但这不是我需要的,因为我不需要创建一个已经在运行的进程,或者我不太明白它是如何工作的。
【问题讨论】:
我不明白这个问题。什么“过程”是“完成”的,你的程序应该做的“事情”是什么? “过程”是你可以适应的吗? 进程还是a 进程?你自己的程序还是别人的程序? 作为起点,看看微软的例子:Enumerating all processes 第一部分听起来像是你想要int main () do_something(); do_more_when_something_is_finished();
这样的东西。第二部分听起来像是您想要进度条之类的东西。请澄清问题
我的主要目标是让程序能够跟踪我在程序中指定的进程是否已完成。不管是什么进程、游戏、记事本或计算器。我不创建这个过程,用户启动它。我需要我的程序了解用户定义的进程(例如计算器)何时完成。我有跟踪进程的代码。我需要程序了解用户启动的进程已经结束,然后采取必要的操作,例如替换文件或退出程序,例如: if(process_close(Calc.exe)) //doSomethingForExample exit(0) ;
【参考方案1】:
您可以使用WMI to Monitor
流程实例。 Here是如何通过WMI接收事件通知的完整步骤。
还有一个sn-p跟踪记事本操作的代码,大家可以参考一下:
#define CREATE 1
#define DELETE 0
using namespace std;
typedef function<void(void)> TNotificationFunc;
IWbemObjectSink* RegisterProcessCallback(IWbemServices* pSvc, TNotificationFunc callback, LPCWSTR ProcessName, BOOL flag);
class EventSink : public IWbemObjectSink
friend IWbemObjectSink* RegisterProcessCallback(IWbemServices* pSvc, TNotificationFunc callback, LPCWSTR ProcessName, BOOL flag);
CComPtr<IWbemServices> pSvc;
CComPtr<IWbemObjectSink> pStubSink;
LONG m_IRef;
TNotificationFunc m_callback;
public:
EventSink(TNotificationFunc callback) :m_IRef(0), m_callback(callback)
~EventSink()
virtual ULONG STDMETHODCALLTYPE AddRef()
return InterlockedIncrement(&m_IRef);
virtual ULONG STDMETHODCALLTYPE Release()
LONG IRef = InterlockedDecrement(&m_IRef);
if (IRef == 0)
delete this;
return IRef;
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv)
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
*ppv = (IWbemObjectSink*)this;
AddRef();
return WBEM_S_NO_ERROR;
else return E_NOINTERFACE;
virtual HRESULT STDMETHODCALLTYPE Indicate(
LONG lObjectCount,
IWbemClassObject __RPC_FAR* __RPC_FAR* apObjArray
)
for (int i = 0; i < lObjectCount; i++)
m_callback();
_variant_t vtProp;
HRESULT hr = S_OK;
hr = apObjArray[i]->Get(_bstr_t(L"TargetInstance"), 0, &vtProp, 0, 0);
if (!FAILED(hr))
IUnknown* str = vtProp;
hr = str->QueryInterface(IID_IWbemClassObject, reinterpret_cast<void**>(&apObjArray[i]));
if (SUCCEEDED(hr))
_variant_t cn;
hr = apObjArray[i]->Get(L"Handle", 0, &cn, NULL, NULL);
if (SUCCEEDED(hr))
if ((cn.vt == VT_NULL) || (cn.vt == VT_EMPTY))
wcout << "ProcessId : " << ((cn.vt == VT_NULL) ? "NULL" : "EMPTY") << endl;
else
wcout << "ProcessId : " << cn.bstrVal << endl;
VariantClear(&cn);
VariantClear(&vtProp);
return WBEM_S_NO_ERROR;
virtual HRESULT STDMETHODCALLTYPE SetStatus(LONG IFlags, HRESULT hResult, BSTR strParam, IWbemClassObject __RPC_FAR* pObjParam)
return WBEM_S_NO_ERROR;
;
void connect2WMI(IWbemServices** pSvc)
HRESULT hres;
CComPtr<IWbemLocator> pLoc;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
if (FAILED(hres))
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
throw std::exception("CreationEvent initialization failed");
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, pSvc);
if (FAILED(hres))
cout << "Could not connect. Error code = 0x" << hex << hres << endl;
throw std::exception("CreationEvent initialization failed");
hres = CoSetProxyBlanket(*pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hres))
cout << "Coult not set proxy blanket, Error code =0x" << hex << hres << endl;
throw std::exception("CreationEvent initialization failed");
IWbemObjectSink* RegisterProcessCallback(IWbemServices* pSvc, TNotificationFunc callback, LPCWSTR ProcessName, BOOL flag)
HRESULT hres;
CComPtr<EventSink> pSink(new EventSink(callback));
CComPtr<IUnsecuredApartment> pUnsecApp;
hres = CoCreateInstance(CLSID_UnsecuredApartment, NULL, CLSCTX_LOCAL_SERVER, IID_IUnsecuredApartment, (void**)&pUnsecApp);
CComPtr<IUnknown> pStubUnk;
pUnsecApp->CreateObjectStub(pSink, &pStubUnk);
IWbemObjectSink* pStubSink = NULL;
pStubUnk->QueryInterface(IID_IWbemObjectSink, (void**)&pStubSink);
wstring buffer = L"SELECT * FROM ";
if (flag == CREATE)
buffer += L"__InstanceCreationEvent";
else if (flag == DELETE)
buffer += L"__InstanceDeletionEvent";
buffer = buffer + L" WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = '" + ProcessName + L"'";
hres = pSvc->ExecNotificationQueryAsync(_bstr_t(L"WQL"), _bstr_t(buffer.c_str()), WBEM_FLAG_SEND_STATUS, NULL, pStubSink);
if (FAILED(hres))
cout << "ExecNotificationQueryAsync failed with = 0x" << hex << hres << endl;
throw std::exception("CreationEvent initialization failed");
return pStubSink;
void CreateEventCallBack() cout << "Create " << endl; /*connect()*/
void DeleteEventCallBack() cout << "Delete " << endl; /*disconnect()*/
int main()
CoInitializeEx(0, COINIT_MULTITHREADED);
IWbemServices* pSvc = NULL;
connect2WMI(&pSvc);
IWbemObjectSink* CreateSink = RegisterProcessCallback(pSvc, CreateEventCallBack, L"notepad.exe", CREATE);
IWbemObjectSink* DeleleSink = RegisterProcessCallback(pSvc, DeleteEventCallBack, L"notepad.exe", DELETE);
getchar();
cout << "Exit " << endl;
pSvc->CancelAsyncCall(CreateSink);
pSvc->CancelAsyncCall(DeleleSink);
CreateSink->Release();
DeleleSink->Release();
pSvc->Release();
CoUninitialize();
它非常适合我:
【讨论】:
@S1NGer-iwni- 嗨,如果这个答案对你有帮助,请随时标记它以帮助有同样问题的人,如果你有任何问题,请告诉我。谢谢。 【参考方案2】:这个方法好像不太聪明, 无论如何,您使用 CreateProcess 创建流程,然后您将获得流程 ID 和流程名称。 接下来,您监控所有进程列表并捕捉 id 消失的时刻。
DWORD hRetHandle = 0;
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot)
PROCESSENTRY32W pe = 0 ;
pe.dwSize = sizeof(PROCESSENTRY32W);
if (Process32FirstW(hSnapshot, &pe))
do
if (wcsstr(pe.szExeFile, pswProcName))
hRetHandle = pe.th32ProcessID;
break;
while(Process32NextW(hSnapshot, &pe));
CloseHandle(hSnapshot);
return hRetHandle;
【讨论】:
你的建议很酷,但它不适合我,原因之一,进程已经在运行我不需要创建它,即我有一个计算器进程 Calc。 exe,用户在他想要的时候启动,我的程序应该在进程结束时跟踪,例如退出程序或做其他事情 - 这并不重要,重要的是在进程结束时以编程方式跟踪 如果 calc.exe 已经在运行,您可以使用进程名称“caculator.exe”对其进行监控。 像任何基于抽样的解决方案一样,它无法提供第二部分来使这一点变得稳健:您何时对流程列表进行抽样?显然,这没有答案。因此,基于抽样的解决方案无法变得稳健。以上是关于如何在 C/C++ 中跟踪程序过程的完成情况的主要内容,如果未能解决你的问题,请参考以下文章