Supponiamo che sto implementando alcuni pattern UIA nel mio controllo personalizzato. Dì, TablePattern
. Le implementazioni esistenti restituiscono null se qualcosa è andato storto. Ma non è molto comodo eseguire il debug. Potrei avere più di un contesto nel peer di automazione. Ad esempio, per GetItem(int row, int column)
potrei dire che gli argomenti forniti sono fuori limite anziché solo restituire null.Come restituire gli errori dal provider del pattern di automazione dell'interfaccia utente?
Se lancio un'eccezione dall'automazione peer - sul lato client UIA ottengo TargetInvocationException
dall'oggetto IUIAutomationPatternInstance
senza alcun dettaglio (la proprietà InnerException è null).
C'è un modo per far sì che l'UIA trasmetta l'errore con alcune informazioni aggiuntive dal lato UIA-server al lato client UIA?
UPD: Dopo alcune indagini e confronto con l'esempio @SimonMourier fornite nei commenti ho scoperto che TargetInvocationException
stata colpa mia. Risolto il problema here.
Ora sto ricevendo il tipo di eccezione corretto, ma solo un messaggio di eccezione standard. Per IndexOutBoundsException
è "L'indice era fuori dai limiti dell'array." indipendentemente da ciò che ho cercato di mettere in eccezione sul lato server UIA.
La differenza è che sto provando a chiamare il metodo UIA non tramite UIAutomationClient gestito standard, ma con il mio codice fino alla chiamata COM (la libreria gestita standard non supporta i modelli UIA personalizzati che vorrei usare). La libreria standard trasmette messaggi di eccezione in modo corretto. Ho cercato di tenere traccia di quale sia la differenza e trovato il seguente:
- standard gestito biblioteca rende chiamata a P/Invoke attraverso InternallCall here tramite metodo definito come
private static extern int RawGridPattern_GetItem(SafePatternHandle hobj, int row, int column, out SafeNodeHandle pResult);
. Restituisce HRESULT, che viene gestito dal metodoCheckError
tramite chiamata alloMarshal.ThrowExceptionForHR(hr);
. A questo punto appare un'eccezione con il messaggio corretto così come è stato lanciato sul lato server UIA. - UIAComWrapper che utilizzo sembra identico a COM call definito in
c:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\UIAutomationClient.idl
comeHRESULT GetItem ([in] int row, [in] int column, [out, retval] IUIAutomationElement ** element);
. Per quanto riguarda l'interoperabilità COM, il meccanismo del valore di ritorno della riscrittura controlla automaticamente HRESULT, genera un'eccezione se necessario e restituisce l'argomentoout result
altrimenti. Lo fa davvero eccetto che il messaggio di eccezione non viene tradotto per qualche motivo.
Per riprodurre il problema, provare this project. I file nella cartella lib sono stati creati da this repository. Se ConsoleApplication1 fa riferimento alla libreria UIAComWrapper, l'eccezione viene fornita con il messaggio predefinito. Se si modifica il riferimento per utilizzare lo standard UIAutomationClient, esso ne riceve uno personalizzato.
Avete controllato l'evento SystemAlert (UIA_SystemAlertEventId/20023)? https://msdn.microsoft.com/en-us/library/windows/desktop/ee671223(v=vs.85).aspx (solo per Windows 8+, non è supportato dalle DLL standard di UIAutomation .NET ma dal UIAComWrapper che sembra sapere :-) –
@SimonMourier eventi sono possibili, ma significherebbe che qualcuno dovrebbe essersi iscritto prima lì. E dovrebbe essere fatto prima di ogni chiamata per ottenere tali informazioni di errore. In modo simile, si potrebbe dichiarare la proprietà UIA standalone che restituisce i dettagli dell'ultimo errore - sarà qualcosa come "GetLastError". Soluzione non molto allettante (ma possibile da implementare ovviamente). –
Bene, non c'è altro da UIA in ciò che è in UIAutomationCore.idl e UIAutomationClient.idl dall'SDK di windows 8. Le interfacce non sono interfacce IDispatch, quindi non sono progettate per trasportare informazioni di eccezione extra (struttura EXCEPINFO che piace a .NET). Penso che dovrai escogitare un modo convenzionale per definire quali sono gli errori (dal punto di vista dell'interfaccia utente) e come si verificano. Si potrebbe anche usare IAnnotationProvider o IObjectModelProvider che sono piuttosto generica –