Alzer Casiño
Alzer Casiño

Reputation: 73

UIAutomation: AddAutomationEventHandler() returns E_INVALIDARG

Here's my code:

// Defines an event handler for general UI Automation events. It listens for
// tooltip and window creation and destruction events. 
#include <windows.h>
#include <stdio.h>
#include <UIAutomation.h>

class EventHandler :
    public IUIAutomationEventHandler
{
private:
    LONG _refCount;

public:
    int _eventCount;

    // Constructor.
    EventHandler() : _refCount(1), _eventCount(0)
    {
    }

    // IUnknown methods.
    ULONG STDMETHODCALLTYPE AddRef()
    {
        ULONG ret = InterlockedIncrement(&_refCount);
        return ret;
    }

    ULONG STDMETHODCALLTYPE Release()
    {
        ULONG ret = InterlockedDecrement(&_refCount);
        if (ret == 0)
        {
            delete this;
            return 0;
        }
        return ret;
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
    {
        if (riid == __uuidof(IUnknown))
            *ppInterface = static_cast<IUIAutomationEventHandler*>(this);
        else if (riid == __uuidof(IUIAutomationEventHandler))
            *ppInterface = static_cast<IUIAutomationEventHandler*>(this);
        else
        {
            *ppInterface = NULL;
            return E_NOINTERFACE;
        }
        this->AddRef();
        return S_OK;
    }

    // IUIAutomationEventHandler methods
    HRESULT STDMETHODCALLTYPE HandleAutomationEvent(IUIAutomationElement * pSender, EVENTID eventID)
    {
        _eventCount++;
        switch (eventID)
        {
        case UIA_AutomationFocusChangedEventId:
            wprintf(L">> Event FocusChanged Received! (count: %d)\n", _eventCount);
            break;
        case UIA_ToolTipOpenedEventId:
            wprintf(L">> Event ToolTipOpened Received! (count: %d)\n", _eventCount);
            break;
        case UIA_ToolTipClosedEventId:
            wprintf(L">> Event ToolTipClosed Received! (count: %d)\n", _eventCount);
            break;
        case UIA_Window_WindowOpenedEventId:
            wprintf(L">> Event WindowOpened Received! (count: %d)\n", _eventCount);
            break;
        case UIA_Window_WindowClosedEventId:
            wprintf(L">> Event WindowClosed Received! (count: %d)\n", _eventCount);
            break;
        default:
            wprintf(L">> Event (%d) Received! (count: %d)\n", eventID, _eventCount);
            break;
        }
        return S_OK;
    }
};

int main(int argc, char* argv[])
{
    HRESULT hr;
    int ret = 0;
    IUIAutomationElement* pTargetElement = NULL;
    EventHandler* pEHTemp = NULL;

    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    IUIAutomation* pAutomation = NULL;
    hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&pAutomation);
    if (FAILED(hr) || pAutomation == NULL)
    {
        ret = 1;
        goto cleanup;
    }
    // Use root element for listening to window and tooltip creation and destruction.
    hr = pAutomation->GetRootElement(&pTargetElement);
    if (FAILED(hr) || pTargetElement == NULL)
    {
        ret = 1;
        goto cleanup;
    }

    pEHTemp = new EventHandler();
    if (pEHTemp == NULL)
    {
        ret = 1;
        goto cleanup;
    }

    wprintf(L"-Adding Event Handlers.\n");
    hr = pAutomation->AddAutomationEventHandler(UIA_ToolTipOpenedEventId, pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationEventHandler*)pEHTemp);
    if (FAILED(hr))
    {
        ret = 1;
        goto cleanup;
    }
    hr = pAutomation->AddAutomationEventHandler(UIA_ToolTipClosedEventId, pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationEventHandler*)pEHTemp);
    if (FAILED(hr))
    {
        ret = 1;
        goto cleanup;
    }
    hr = pAutomation->AddAutomationEventHandler(UIA_Window_WindowOpenedEventId, pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationEventHandler*)pEHTemp);
    if (FAILED(hr))
    {
        ret = 1;
        goto cleanup;
    }
    hr = pAutomation->AddAutomationEventHandler(UIA_Window_WindowClosedEventId, pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationEventHandler*)pEHTemp);
    if (FAILED(hr))
    {
        ret = 1;
        goto cleanup;
    }
    // Error is here. hr returns E_INVALIDARG.
    hr = pAutomation->AddAutomationEventHandler(UIA_AutomationFocusChangedEventId, pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationEventHandler*)pEHTemp);
    if (FAILED(hr))
    {
        ret = 1;
        goto cleanup;
    }

    wprintf(L"-Press any key to remove event handlers and exit\n");
    getchar();

    wprintf(L"-Removing Event Handlers.\n");

cleanup:
    // Remove event handlers, release resources, and terminate
    if (pAutomation != NULL)
    {
        hr = pAutomation->RemoveAllEventHandlers();
        if (FAILED(hr))
            ret = 1;
        pAutomation->Release();
    }

    if (pEHTemp != NULL)
        pEHTemp->Release();

    if (pTargetElement != NULL)
        pTargetElement->Release();

    CoUninitialize();
    return ret;
}

This code comes from the examples from Microsoft about implementing Event classes for UIAutomation.

I edited the code a little bit so that it can support Focus events but I failed attempting to initialize one line of code.

I don't understand why hr = pAutomation->AddAutomationEventHandler(UIA_AutomationFocusChangedEventId, pTargetElement, TreeScope_Subtree, NULL, (IUIAutomationEventHandler*)pEHTemp) returns E_INVALIDARG.

Tried reading the docs and I can't find a reason why.

Please help.

Upvotes: 2

Views: 1437

Answers (1)

Wander3r
Wander3r

Reputation: 1881

There is a separate handler for handling FocusChanged, AddFocusChangedEventHandler which should be used for monitor focus changes. Since you are trying to send an EventHandler function pointer to handle FocusChanged, runtime error is coming.

To create that handler, need an instance of class that inherits from IUIAutomationFocusChangedEventHandler.

class FocusChangedEventHandler :
    public IUIAutomationFocusChangedEventHandler
{
private:
    LONG _refCount;

public:
    int _eventCount;

    //Constructor.
    FocusChangedEventHandler() : _refCount(1), _eventCount(0)
    {
    }

    //IUnknown methods.
    ULONG STDMETHODCALLTYPE AddRef()
    {
        ULONG ret = InterlockedIncrement(&_refCount);
        return ret;
    }

    ULONG STDMETHODCALLTYPE Release()
    {
        ULONG ret = InterlockedDecrement(&_refCount);
        if (ret == 0)
        {
            delete this;
            return 0;
        }
        return ret;
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
    {
        if (riid == __uuidof(IUnknown))
            *ppInterface = static_cast<IUIAutomationFocusChangedEventHandler*>(this);
        else if (riid == __uuidof(IUIAutomationFocusChangedEventHandler))
            *ppInterface = static_cast<IUIAutomationFocusChangedEventHandler*>(this);
        else
        {
            *ppInterface = NULL;
            return E_NOINTERFACE;
        }
        this->AddRef();
        return S_OK;
    }

    // IUIAutomationFocusChangedEventHandler methods.
    HRESULT STDMETHODCALLTYPE HandleFocusChangedEvent(IUIAutomationElement * pSender)
    {
        _eventCount++;
        wprintf(L">> FocusChangedEvent Received! (count: %d)\n", _eventCount);
        return S_OK;
    }
};

In main()

pFHTemp = new FocusChangedEventHandler();
hr = pAutomation->AddFocusChangedEventHandler(NULL, (IUIAutomationFocusChangedEventHandler*)pFHTemp);
if (FAILED(hr))
{
    ret = 1;
    goto cleanup;
}

Code snippets taken from MSDN link

Upvotes: 2

Related Questions