0

我有一个 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 引发的错误消息更改为包含错误代码作为文本的一部分有点像 hack。

4

3 回答 3

2

您将处理 COMException 并使用该异常对象的 ErrorCode 属性。通常在 Visual Basic DLL 中,如果您抛出自定义错误,您会使用以下命令引发错误:Err.Raise vbObjectError + 88, "Project1.Class1.Test3()", "Forced error test"

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

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

公共子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。

于 2008-09-30T23:06:54.107 回答
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); }
    }
于 2008-09-30T23:35:52.803 回答
2

只想提供对@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
}
于 2008-09-30T23:50:52.987 回答