Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何从UI自动化模式提供程序返回错误?_C#_.net_Wpf_Ui Automation - Fatal编程技术网

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

C# 如何从UI自动化模式提供程序返回错误?,c#,.net,wpf,ui-automation,C#,.net,Wpf,Ui Automation,假设我正在自定义控件中实现一些UIA模式。比如说,TablePattern。如果出现任何错误,现有实现将返回null。但是调试起来不是很方便。我可能在自动化领域有更多的背景知识。例如,对于GetItem(int行,int列)我可能会说提供的参数超出了范围,而不仅仅是返回null 如果我从automation peer引发异常-在UIA客户端,我从IUIAutomationPatternInstance对象中获得targetingException,但没有任何详细信息(InnerException

假设我正在自定义控件中实现一些UIA模式。比如说,
TablePattern
。如果出现任何错误,现有实现将返回null。但是调试起来不是很方便。我可能在自动化领域有更多的背景知识。例如,对于
GetItem(int行,int列)
我可能会说提供的参数超出了范围,而不仅仅是返回null

如果我从automation peer引发异常-在UIA客户端,我从
IUIAutomationPatternInstance
对象中获得
targetingException
,但没有任何详细信息(InnerException属性为null)

有没有一种方法可以让UIA通过一些附加信息将错误从UIA服务器端传递到UIA客户端


UPD:经过调查并与评论中提供的@SimonMourier示例进行比较后,我发现
targetingException
是我的错。修好了

现在我得到了正确的异常类型,但只有一条标准的异常消息。对于
IndexOutBoundsException
来说,它是“索引超出了数组的边界”。不管我一直试图在UIA服务器端设置什么异常

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

  • 标准托管库通过定义为
    private static extern int RawGridPattern_GetItem(SafePatternHandle hobj、int行、int列、out SafeNodeHandle pResult)的方法通过内部调用调用P/Invoke。它返回HRESULT,由
    CheckError
    方法通过调用
    Marshal.throweExceptionForHR(hr)来处理。此时,带有正确消息的异常显示为UIA服务器端抛出的异常
  • 我使用的UIAComWrapper与
    c:\ProgramFiles(x86)\Microsoft SDK\Windows\v7.1A\Include\UIAutomationClient.idl
    as
    HRESULT GetItem([in]int行,[in]int列,[out,retval]IUIAutomationeElement**元素)中定义的似乎相同。据我对COM互操作的理解,重写返回值机制会自动检查HRESULT,必要时抛出异常,否则返回
    out结果
    参数。它确实是这样的,只是由于某种原因,异常消息没有被翻译
要重现问题,您可以尝试。lib文件夹中的文件是从中生成的。如果ConsoleApplication1引用UIAComWrapper库,则默认消息会出现异常。如果将引用更改为使用标准UIAutomationClient,则它将接收自定义引用。

创建互操作的默认或等效Visual Studio UI操作。UIAutomationClient程序集使用“
[out,retval]
”签名布局,而不是使用
Preservesig
属性(这里有更多信息)

例如,这里它声明了
IUIAutomationGridPattern
,如下所示(简化版):

与此相反:

[Guid("414C3CDC-856B-4F5B-8538-3131C6302550")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IUIAutomationGridPattern
{
    [PreserveSig]
    int GetItem(int row, int column, out UIAutomationClient.IUIAutomationElement element);
    ...
}
虽然这两种方法都是有效的,但如果你想仔细处理异常,后一种方法会更好。第一种方法会做一些神奇的事情,不幸的是,它会将这里感兴趣的东西转换成不那么有趣的东西。 因此,如果您使用
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; }
        }
    }
现在您应该看到原始的异常


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

您检查过SystemAlert事件(UIA_SystemAlertEventId/20023)吗?(仅适用于Windows 8+,标准的.NET UIAutomation DLL不支持它,但您似乎知道的UIAComWrapper支持它:-)@SimonMourier事件是可能的,但这意味着应该先有人订阅。并且应该在每次调用之前完成,以获取此类错误信息。类似地,可以声明独立的UIA属性,返回上一个错误的详细信息—类似于
GetLastError
。这不是很吸引人的解决方案(当然可以实现)。好吧,除了windows 8 SDK中的UIAutomationCore.idl和UIAutomationClient.idl中的内容之外,UIA没有更多内容。这些接口没有IDispatch接口,因此设计时不会携带额外的异常信息(除了.NET喜欢的结构).我认为你必须想出一个常规的方法来定义什么是错误(从UI的角度)以及它们是如何发生的。你也可以使用IAnnotationProvider或IObjectModelProvider,它们都很漂亮generic@SimonMourier如果我理解正确,UIA客户端会在调用后查看HRESULT,如果存在适当的异常(例如
ElementNotAvailableException
).但我不明白UIA服务器端如何在那里设置HRESULT-即使在自动化对等中我抛出
ElementNotAvailableException
-客户端仍然看到
TargetingException
。也许我做错了什么,但实际上不知道如何调试它。事实上,我无法重现您的问题。这是一个示例WPFUserControl引发了一个异常,该异常显示在示例控制台应用程序服务器中:因此,无法说服marshaller为我做这项工作。我希望得到一些神奇的特性,就像通常的情况一样:)但是谢谢,如果PreserveSig是唯一的方法,我会尝试一下。正如你所看到的,我已经在做一些原始的tlbimp结果重写了,所以添加新属性可能不像一开始看起来那么痛苦…有很多
    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; }
        }
    }