简体   繁体   中英

How to track the completion of the program process in C/C++

I need to write a program that will do something after the program process is completed, such as a calculator. That is, I work with the calculator, and then I turned it off, respectively, its process is completed and my program does the actions I set. How do I do this? How do I track process completion? I googled and found tips that you need to create a separate process through the CreateProcess function , and then use WaitForSingleObject or GetExitCodeProcess, but this is not what I need, because I don't need to create a process it is already running, or I don't quite understand how it works.

You can use WMI to Monitor the Process Instance. Here is the complete steps that how to receive Event Notifications Through WMI.

And here is a code snippet that track the operation of notepad, you can refer to it:

#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();
}

It works perfectly for me:

在此处输入图片说明

This method seems not to be smart, Any way, You create process with CreateProcess, then you get process id and process name. Next, you monitor all process list and catch the moment when id is disappeard.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM