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

时间:2008-09-30 15:00:01

标签: c# .net com interop

我有一个VB6 COM组件,我需要从我的.Net方法调用。我使用反射来创建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引发的错误消息,以包含错误代码作为文本的一部分有点像破解。

3 个答案:

答案 0 :(得分: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"

End Sub

示例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.

答案 1 :(得分:2)

我仔细查看了你的代码并使用反射处理了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); }
    }

答案 2 :(得分:2)

只想提供@ sharvell的catch代码的更新。除非你绝对确定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
}