Problem bei UIAutomation



  • Hallo,
    mich plagt schon seit 2 Wochen ein Problem mit der Microsoft UIAutomation. In dem Testprojekt durchwandere ich immer den AutomationTree des Fensters das gerade im Fokus des Benutzers ist. Ich verwende dabei 1:1 den Beispiel FocusChangedHandler wie er auf MSDN beschrieben wird, und auch das Durchwandern des Automationtrees ist sehr stark an ein MSDN-Beispiel angelehnt.
    Da ich das Programm später noch um mehrere Handler erweitern will, und das Suchen im AutomationTree eigentlich ziemlich viel Zeit in Anspruch nimmt, läuft bei mir ein eigener Thread der das Suchen übernimmt und ständig überprüft, ob neue Events von den Handlern vorhanden sind. Kommt also ein Event während ein anderes noch in Abarbeitung ist, so beendet der Thread die Abarbeitung des alten Events, und startet mit der Abarbeitung des neuen Events.
    Das Testprogramm funktioniert eigentlich sehr gut, allerdings tritt nach mehreren Fokuswechseln mit der Maus irgendwann(manchmal sehr früh , manchmal später) einer von drei möglichen Fehlern immer an der selben Stelle auf. Hier der Code den ich soweit habe:

    #include "stdafx.h"
    #include <windows.h>
    #include "stdafx.h"
    #include "oleacc.h"
    #include <stdio.h>
    #include <UIAutomation.h>
    #include <vector>
    #include <process.h>
    
    //For thread controling:
    int     ThreadNr, running, stop, hasjob;
    
    HANDLE hMutex;
    
    IUIAutomation *g_pAutomation;
    //Global root element
    IUIAutomationElement *root;
    //Stores current focus element
    IUIAutomationElement *focusElement;
    void createJob(IUIAutomationElement *focus);
    
    //Focus Changed Handler
    class EventHandler1:
    public IUIAutomationFocusChangedEventHandler
    {
    private:
        LONG _refCount;
    
    public:
        int _eventCount;
    
        //Constructor.
        EventHandler1(): _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++;
    
    		//Create Job
    		createJob(pSender);
    
            return S_OK;
        }
    };
    
    //Gets all Descendants of an AutomationElement
    void ListDescendants(IUIAutomationElement* pParent)
    {
        if (pParent == NULL)
            return;
    
        IUIAutomationTreeWalker* pControlWalker = NULL;
        IUIAutomationElement* pNode = NULL;
    	try{
        g_pAutomation->get_ControlViewWalker(&pControlWalker);
        if (pControlWalker == NULL)
            goto cleanup;
    
        pControlWalker->GetFirstChildElement(pParent, &pNode); //<- Hier kommt es zu einem der beschriebenen Fehler.
        if (pNode == NULL)
            goto cleanup;
    
        while (pNode)
        {//Check if we should stop because of a new event.
    
    		if(running == 0){
    			stop = 1;
    			goto cleanup;
    		}
    
    		/*
    		Do something with the pNode Automationelement...
    		*/
    
            ListDescendants(pNode);
            IUIAutomationElement* pNext;
            pControlWalker->GetNextSiblingElement(pNode, &pNext);
            pNode->Release();
            pNode = pNext;
        }
    }catch(char * str ){
    
    }
    
    cleanup:
        if (pControlWalker != NULL)
            pControlWalker->Release();
    
        if (pNode != NULL)
            pNode->Release();
    
        return;
    }
    
    //Inits UI-Automation and the Eventhandler and then waits for jobs to arrive....
    void DoWork( void *pMyID )
    {
    	//Init UIAutomation
    	CoInitializeEx(NULL,COINIT_MULTITHREADED);
    	HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
            CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), 
            (void**)&g_pAutomation);
    
    	hr = g_pAutomation->GetRootElement(&root);
    	EventHandler1* pEHTemp1 = NULL;
    
    	//Add EventHandler
    	pEHTemp1 = new EventHandler1(); 
    	hr = g_pAutomation->AddFocusChangedEventHandler(NULL, (IUIAutomationFocusChangedEventHandler*) pEHTemp1); 
    
    	//Enter Loop
    	while(true){
    
    		if(hasjob == 1){
    			WaitForSingleObject(hMutex, INFINITE);
    			running = 1;
    			ReleaseMutex(hMutex);
    
    			ListDescendants(focusElement);
    			if(stop == 1){
    				WaitForSingleObject(hMutex, INFINITE);
    				running = 1;
    				stop = 0;
    				ReleaseMutex(hMutex);
    			}else{
    				WaitForSingleObject(hMutex, INFINITE);
    				hasjob = 0;
    				ReleaseMutex(hMutex);
    			}
    
    		}
    
    	}
    
    }
    
    //Creates a Job
    void createJob(IUIAutomationElement *focus){
    
    	IUIAutomationElement *x = focus;
    
    	HRESULT hr;
    	IUIAutomationTreeWalker *pWalk;  
    	g_pAutomation->get_ControlViewWalker(&pWalk);
    
    	IUIAutomationElement *result = root;
    
    	//Go up the tree and find the windowelement of the focues element.
    	BOOL equal;
    	g_pAutomation->CompareElements(x,root,&equal);
    	while(!equal){
    	result = x;
    	hr = pWalk->GetParentElement(x, &x);
    	g_pAutomation->CompareElements(x,root,&equal);
    
    	}
    	if(result == NULL){
    		result = focus;
    	}
    
    	//Start job
    	WaitForSingleObject(hMutex, INFINITE);
    	hasjob = 1;
    	running = 0;
    	focusElement = result;
    	ReleaseMutex(hMutex);
    
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    //Create Mutex
    hMutex = CreateMutex(NULL,  FALSE, "MyMutex"); 
    
    hasjob = 0;
    stop = 0;
    running = 0;
    //Starte Thread
    _beginthread( DoWork, 0, &ThreadNr );
    
    getchar();
    
    return 0;
    }
    

    Hier nun kurz die Fehler(sie treten immer in Zeile 97 auf):

    Windows has triggered a breakpoint in Testiii.exe. This may be due to a corruption of the heap, which indicates a bug in Testiii.exe or any of the DLLs it has loaded. This may also be due to the user pressing F12 while Testiii.exe has focus. The output window may have more diagnostic information.

    First-chance exception at 0x008e00c4 in Testiii.exe: 0xC0000005: Access violation. Unhandled exception at 0x008e00c4 in Testiii.exe: 0xC0000005: Access violation.

    First-chance exception at 0x640a3529 in Testiii.exe: 0xC0000005: Access violation reading location 0xfeeefeee. Unhandled exception at 0x640a3529 in Testiii.exe: 0xC0000005: Access violation reading location 0xfeeefeee.

    Als relativer C-Neuling überfordern mich diese Fehlermeldungen etwas. Laut meinen Nachforschungen im Internet bedeutet zum Beispiel: 0xfeeefeee dass ich versuche irgendwo Memory zu lesen die vorher schon deallocated wurde. Aber ich mache eigentlich kein free() etc.
    Hat hier vielleicht wer einen kleinen Tipp was ich da falsch mache, oder einen Link der weiterhelfen würde?
    Bin für jede Hilfe dankbar.
    Mfg
    Pezibär


Anmelden zum Antworten