【问题标题】:C# COM Interop returning object of null causes 0x800A01A8 Object requiredC# COM Interop 返回 null 的对象导致 0x800A01A8 需要对象
【发布时间】:2012-05-02 05:23:30
【问题描述】:

我正在编写返回对象的 COM 包装器,如果该对象不存在,则返回 null。从 VBScript 调用时,返回 null 会引发错误“Object required: 'ComObj.Prop2'” Code 800A01A8...

C#

public class testCOM
{
    public object Func(int i)
    {
        if (i == 1) return new object();
        if (i == 2) return DBNull.Value;
        return null;
    }
}

VBScript

set ComObj = CreateObject("ClassLibrary1.testCOM")

set TestObj = ComObj.Func(1) 'This Works
set TestObj = ComObj.Func(2) 'Throws "Object required: 'ComObj.Func(...)'" Code 800A01A8
set TestObj = ComObj.Func(3) 'Throws "Object required: 'ComObj.Func(...)'" Code 800A01A8
set TestObj = Nothing        'This is what I want to occur with Func(2) and Func(3)

我尝试返回 DBNull.Value,它应该编组为 VT_NULL,但没有运气...

我真的不想用 .HasValue 和 .Value 编写类似于 Nullabe 的包装对象...我不喜欢的另一个选择是创建一个 Nothing 对象(在没有命名空间内),这样我就可以做到:

If TestObj Is Nothing And TestObj = "Nothing" Then
    'TestObj was nothing or "Nothing"
End If

如果我使用 Nothing 对象,那么我的 COM 对象必须重新输入 Object 类型而不是预期的类型化对象,这使得代码更难阅读,尽管功能上与我的目的相同。

通过 COM 将空对象返回给 VBScript 的最佳方法是什么?

【问题讨论】:

    标签: com vbscript null nothing


    【解决方案1】:

    检查界面中的签名并确保其正确无误。如果我执行以下操作:

    public object test(int i) {
        object retval = null;
        if (i == 1) {
            retval = new Object();
        } else if (i == 2) {
            retval = DBNull.Value;
        }
        return retval;
    }
    

    接口签名为:

    [DispId(1001)]
    object test(int i);
    

    然后,在 VBScript 中,执行:

    ' myObject is my instantiated COM class
    WScript.Echo TypeName(myObject.test(1))
    WScript.Echo TypeName(myObject.test(2))
    WScript.Echo TypeName(myObject.test(3))
    

    我回来了:

    Object
    Null
    Empty
    

    【讨论】:

    • 感谢您的回复。不幸的是,您的建议并未将返回的对象/值分配给变量。相反,它直接将其传递给另一个函数 TypeName。如果您的 vbscript 是:
    • 如果您的 vbscript 尝试使用 set TestObj = myObject.test(2)Echo TypeName(TestObj),则会出现代码 800A01A8 错误。显然,set 需要设置一个对象,所以我不能返回 null,它不是一个对象。如果您离开“设置”,它会起作用。我已经诉诸于在根命名空间中创建一个 Nothing 类并测试 If TypeName(TestObj) = "Nothing" Then
    • 您不能在尝试设置之前先使用 IsNull 进行测试吗?
    • 您可能会从我跟上这个线程的进度中猜到,我已经接受了返回 global::Nothing 对象的实例。但是,为了回应使用 IsNull,我假设您的意思是 If Not IsNull(ComObj.Func(2)) Then Set TestObj = ComObj.Func(2)。不幸的是,这将执行该函数两次,使工作加倍。但是,你确实给了我一个想法。我可以创建Function Wrapper(obj) If TypeName(obj) = "Empty" Then Set Wrapper = Nothing Else Set Wrapper = obj End If End Function。现在,这应该可以工作了:Set TestObj = Wrapper(CommObj.Func(2)))。感谢您的帮助!
    【解决方案2】:

    添加 MarshalAs 有帮助:

    [return:MarshalAs(UnmanagedType.IDispatch)]
    public object Func(int i)
    {
        if (i == 1) return new object();
        if (i == 2) return DBNull.Value;
        return null;
    }
    

    我不知道为什么。 如果你有一个接口,那么这个属性应该应用在接口级别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多