Iva*_*lov 16 .net c# wpf ui-automation
假设我在自定义控件中实现了一些UIA模式.说,TablePattern
.如果出现任何问题,现有实现将返回null.但是调试起来不太方便.我可能在自动化同行中有更多的上下文.例如,因为GetItem(int row, int column)
我可能会说提供的参数超出范围而不是仅返回null.
如果我从自动化对等端抛出异常 - 在UIA客户端,我TargetInvocationException
从IUIAutomationPatternInstance
对象获得没有任何细节(InnerException属性为null).
有没有办法让UIA通过UIA-服务器端到UIA-客户端的一些附加信息传递错误?
UPD:经过一些调查并与评论中提供的示例@SimonMourier进行比较,我发现这TargetInvocationException
是我的错.在这里修复它.
现在我得到了正确的异常类型,但只有标准的异常消息.因为IndexOutBoundsException
它是"索引超出了数组的范围." 不管我在UIA服务器端试图将其置于例外状态.
不同之处在于我试图不通过标准的托管UIAutomationClient调用UIA方法,而是使用我自己的代码一直到COM调用(标准托管库不支持我想使用的自定义UIA模式).标准库传递异常消息就好了.我试图追踪差异,发现以下内容:
private static extern int RawGridPattern_GetItem(SafePatternHandle hobj, int row, int column, out SafeNodeHandle pResult);
.它返回HRESULT,由CheckError
方法通过调用来处理Marshal.ThrowExceptionForHR(hr);
.此时出现正确消息的异常,就像在UIA服务器端抛出一样.c:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\UIAutomationClient.idl
为HRESULT GetItem ([in] int row, [in] int column, [out, retval] IUIAutomationElement ** element );
.根据我对COM Interop的理解,重写返回值机制会自动检查HRESULT,必要时抛出异常,out result
否则返回参数.除了异常消息由于某种原因没有被翻译之外,它确实存在.要重现此问题,您可以尝试此项目.lib文件夹中的文件是从此存储库构建的.如果ConsoleApplication1引用UIAComWrapper库 - 异常带有默认消息.如果您更改引用以使用标准UIAutomationClient - 它会收到自定义的.
创建程序集的默认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 代码。前面还有很多工作要做。