如何从UI自动化模式提供程序返回错误?

Iva*_*lov 16 .net c# wpf ui-automation

假设我在自定义控件中实现了一些UIA模式.说,TablePattern.如果出现任何问题,现有实现将返回null.但是调试起来不太方便.我可能在自动化同行中有更多的上下文.例如,因为GetItem(int row, int column)我可能会说提供的参数超出范围而不是仅返回null.

如果我从自动化对等端抛出异常 - 在UIA客户端,我TargetInvocationExceptionIUIAutomationPatternInstance对象获得没有任何细节(InnerException属性为null).

有没有办法让UIA通过UIA-服务器端到UIA-客户端的一些附加信息传递错误?


UPD:经过一些调查并与评论中提供的示例@SimonMourier进行比较,我发现这TargetInvocationException是我的错.在这里修复它.

现在我得到了正确的异常类型,但只有标准的异常消息.因为IndexOutBoundsException它是"索引超出了数组的范围." 不管我在UIA服务器端试图将其置于例外状态.

不同之处在于我试图不通过标准的托管UIAutomationClient调用UIA方法,而是使用我自己的代码一直到COM调用(标准托管库不支持我想使用的自定义UIA模式).标准库传递异常消息就好了.我试图追踪差异,发现以下内容:

  • 标准管理库使呼叫P /通过InternallCall调用这里通过定义方法private static extern int RawGridPattern_GetItem(SafePatternHandle hobj, int row, int column, out SafeNodeHandle pResult);.它返回HRESULT,由CheckError方法通过调用来处理Marshal.ThrowExceptionForHR(hr);.此时出现正确消息的异常,就像在UIA服务器端抛出一样.
  • 我使用的UIAComWrapper看似相同的COM调用定义c:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\UIAutomationClient.idlHRESULT GetItem ([in] int row, [in] int column, [out, retval] IUIAutomationElement ** element );.根据我对COM Interop的理解,重写返回值机制会自动检查HRESULT,必要时抛出异常,out result否则返回参数.除了异常消息由于某种原因没有被翻译之外,它确实存在.

要重现此问题,您可以尝试此项目.lib文件夹中的文件是从此存储库构建的.如果ConsoleApplication1引用UIAComWrapper库 - 异常带有默认消息.如果您更改引用以使用标准UIAutomationClient - 它会收到自定义的.

Sim*_*ier 3

创建程序集的默认TLB 导入器(或等效的 Visual Studio UI 操作)Interop.UIAutomationClient使用“ [out, retval]”签名布局而不是使用Preservesig属性(更多信息请参见http://blogs.msdn.com/b/adam_nathan/archive/2003/04 /30/56646.aspx)。

例如,这里声明IUIAutomationGridPattern如下(简化版本):

[Guid("414C3CDC-856B-4F5B-8538-3131C6302550"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IUIAutomationGridPattern
{
    UIAutomationClient.IUIAutomationElement GetItem(int row, int column);
    ...
}
Run Code Online (Sandbox Code Playgroud)

而不是这个:

[Guid("414C3CDC-856B-4F5B-8538-3131C6302550")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IUIAutomationGridPattern
{
    [PreserveSig]
    int GetItem(int row, int column, out UIAutomationClient.IUIAutomationElement element);
    ...
}
Run Code Online (Sandbox Code Playgroud)

尽管两者都有效,但如果您想仔细处理异常,则后一种更好。第一个做了一些魔法,不幸的是,它把这里有趣的东西变成了不太有趣的东西。因此,如果您使用该PreserveSig版本,您可以像这样替换 GridItem.cs 中的代码:

    public AutomationElement GetItem(int row, int column)
    {
        try
        {
            UIAutomationClient.IUIAutomationElement element;
            int hr = _pattern.GetItem(row, column, out element);
            if (hr != 0)
                throw Marshal.GetExceptionForHR(hr); // note this uses COM's EXCEPINFO if any

            return AutomationElement.Wrap(element).GetUpdatedCache(CacheRequest.Current);
        }
        catch (System.Runtime.InteropServices.COMException e)
        {
            Exception newEx; if (Utility.ConvertException(e, out newEx)) { throw newEx; } else { throw; }
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在您应该看到原始异常。

因此,要修复代码,您必须手动重新定义涉及的所有接口(或者这里有http://clrinterop.codeplex.com/releases/view/17579一个可以使用 PreserveSig 创建签名的较新的 tlbimp - 未测试) 。您还必须更改 UIAComWrapper 代码。前面还有很多工作要做。