从通过反射调用的 COM 方法中检索原始错误号

Posted

技术标签:

【中文标题】从通过反射调用的 COM 方法中检索原始错误号【英文标题】:Retrieving the original error number from a COM method called via reflection 【发布时间】:2008-09-30 15:00:01 【问题描述】:

我有一个需要从我的 .Net 方法调用的 VB6 COM 组件。我使用反射来创建 COM 对象的实例并以下列方式激活它:

f_oType = Type.GetTypeFromProgID(MyProgId);
f_oInstance = Activator.CreateInstance(f_oType);

我需要使用 GetTypeFromProgID 而不是使用 tlbimp 来针对 COM DLL 创建一个库,因为我需要实例化的类型的 ProgId 可能会有所不同。然后我使用 Type.InvokeMember 在我的代码中调用 COM 方法,例如:

f_oType.InvokeMember("Process", BindingFlags.InvokeMethod, null, f_oInstance, new object[]  param1, param2, param3, param4 );

我捕获任何引发的 TargetInvocationException 进行日志记录,并且可以从 TargetInvocationException.InnerException 字段获取详细的错误描述。但是,我知道 COM 组件使用 Error.Raise 来生成错误号,我需要以某种方式在调用 .Net 应用程序中获取它。

问题似乎源于 TargetInvocationException 不包含错误号,如果它是一个正常的 COMException,我会期望它:

如何从我的 .Net 代码中的 COM 对象获取错误号?

当 COM 组件失败时,我能否以一种会导致 COMException(包含错误号)而不是 TargetInvocationException 的方式进行相同的调用?

还请注意,目标平台是 .Net 2.0,我确实可以访问 VB6 源代码,但会认为将 VB6 引发的错误消息更改为包含错误代码作为文本的一部分有点破解。

【问题讨论】:

【参考方案1】:

我仔细查看了您的代码,并通过反射处理 TargetInvocationException 并使用内部异常 COMException... 下面的代码示例(我也运行并测试了它):

    private void button1_Click(object sender, EventArgs e)
    
        try
        
            var f_oType = Type.GetTypeFromProgID("Project1.Class1");
            var f_oInstance = Activator.CreateInstance(f_oType);
            f_oType.InvokeMember("Test3", BindingFlags.InvokeMethod, null, f_oInstance, new object[] );
        
        catch(TargetInvocationException ex)
        
            //no need to subtract -2147221504 if non custom error etc
            int errorNumber = ((COMException)ex.InnerException).ErrorCode - (-2147221504);
            MessageBox.Show(errorNumber.ToString() + ": " + ex.InnerException.Message);
        
        catch(Exception ex)
         MessageBox.Show(ex.Message); 
    

【讨论】:

这明白了。最初被抛出,因为 InnerException 没有作为 COMException 返回,但调查显示 COM 组件错误地引发了错误。修复了这个问题,这是一种享受【参考方案2】:

您将处理 COMException 并使用该异常对象的 ErrorCode 属性。通常在 Visual Basic DLL 中,如果您抛出自定义错误,您将通过以下方式引发错误: Err.Raise vbObjectError + 88, "Project1.Class1.Test3()", "强制错误测试"

如果是这种情况,您需要从异常 ErrorCode 中减去 vbobjecterror (-2147221504) 以获得实际的错误编号。如果不只是使用 ErrorCode 值。

示例 VB dll 代码:(来自 Project1.Class1)

Public Sub Test3()

MsgBox "this is a test 3"
Err.Raise vbObjectError + 88, "Project1.Class1.Test3()", "Forced error test"

结束子

示例C#消费处理代码:

    private void button1_Click(object sender, EventArgs e)
    
        try
        
            var p = new Class1();
            p.Test3();
        
        catch (COMException ex)
        
            int errorNumber = (ex.ErrorCode - (-2147221504));
            MessageBox.Show(errorNumber.ToString() + ": " + ex.Message);
        
        catch(Exception ex)
         MessageBox.Show(ex.Message); 
    

我刚刚完成的这个测试中的ErrorCode按预期返回88。

【讨论】:

如原始问题所述,代码不会抛出 COMException,它会抛出没有错误号的 TargetInvocationException【参考方案3】:

只想对@sharvell 的捕获代码进行更新。除非您绝对确定 InnerException 是 COMException,否则最好先安全地测试它。否则,您的异常处理程序中将出现异常。哎呀!

catch(TargetInvocationException ex)

    if( ex.InnerException != null && ex.InnerException is COMException )
    
        COMException ce = (COMException)ex.InnerException;
        // do something with ce - e.g. logging the error
    
    // else InnerException not set, or it's not a COMException

【讨论】:

以上是关于从通过反射调用的 COM 方法中检索原始错误号的主要内容,如果未能解决你的问题,请参考以下文章

java反射的理解

vb.net制作的Excel文件 未捕获通过反射调用的方法而引发的异常

使用反射在外部JAR / CLASS上调用包含Hibernate事务的方法(Java EE)

从反射属性中检索反射类型中的值

使用反射机制调用属性和私有成员与代理模式的介绍

如何通过java 反射 调用一个 含有 可变参数的 方法呢 ??