如何在 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++ 中跟踪程序过程的完成情况的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用跟踪句柄的情况下等待未知数量的 Rust 线​​程完成?

在资产跟踪设备研发中,如何进行固件升级

在SQLSERVER里面,如何写一个存储过程来创建跟踪?

如何在 GDB 中使用跟踪

在Linux中如何利用backtrace信息解决问题

如何在不删除任何文件的情况下从跟踪中分离文件夹?