在C#COM中处理NULL指针输出参数

时间:2011-07-09 01:25:59

标签: c# com null idl typelib

我正在使用具有以下函数定义的COM插件接口:

HRESULT foo ( [out, ref] VARIANT* a, [out, ref] VARIANT* b );

当使用tlbimp(来自codeplex的tlbimp2.exe)时,.NET库具有以下接口函数:

int foo ( out object a, out object b );

问题是调用应用程序将进行函数调用:

VARIANT a;
::InitVariant( &a );

plugin->foo( &a, NULL );

在C#中我实现了函数:

int foo ( out object a, out object b )
{
    a = 1;
    b = 2;

    return 0; // S_OK
}

当完成所有操作时,应用程序实际上获得了E_POINTER返回而不是S_OK。我假设是因为NULL传递了out参数。

有没有办法检查C#实现中的地址指针是否为NULL?

注意:out参数未初始化,因此您根本无法使用这些参数。

我尝试将接口实现为[in,out,ref]以强制使用C#(ref对象a,ref对象b),但这也不起作用。

更新

如果我们将它声明为[out,ref],那么我们本应该使用NULL ptr调用该函数是完全正确的。

erurainon也是正确的,我们可以使用IntPtr来获取Variant *。

所以这是如何解决的:

int foo ([MarshalAs(UnmanagedType.Struct)]out object a, [MarshalAs(UnmanagedType.Struct)]out object b);

成了

int foo ([MarshalAs(UnmanagedType.Struct)]out object a, IntPtr b );

现在我们可以使用:

测试NULL情况
if ( b == IntPtr.Zero )

但是,由于我们正在处理Variant,因此您无法将值复制到IntPtr,如:

Marshal.StructureToPtr( myValue, b, false );

因此,在this post之后,您需要创建一个结构类:

[StructLayout(LayoutKind.Explicit, Size = 16)]
public struct PropVariant
{
    [FieldOffset(0)]
    public VarEnum variantType;
    [FieldOffset(8)]
    public IntPtr pointerValue;
    [FieldOffset(8)]
    public byte byteValue;
    [FieldOffset(8)]
    public long longValue;
    [FieldOffset(8)]
    public double dateValue;
    [FieldOffset(8)]
    public short boolValue;
}

最终的功能如下:

int foo( out object a, IntPtr b )
{
    a = 100;

    if ( b != IntPtr.Zero )
    {
        var time = new PropVariant();
        time.dateTime = DateTime.Now.ToOADate();
        time.variantType = VarEnum.VT_DATE;

        Marshal.StructureToPtr( time, b, false );
    }

    return 0; // S_OK
}

希望这有助于将来的其他人

2 个答案:

答案 0 :(得分:3)

来自MIDL docs

The [ref] attribute identifies a reference pointer. It is used simply to represent a level of indirection
....
A reference pointer has the following characteristics:
 - Always points to valid storage; never has the value NULL. A reference pointer can always be dereferenced.

代码无效,传递NULL。直接违反[ref]合同。这是雄鹿停止的地方,你 来修复MIDL或本机代码。

答案 1 :(得分:1)

汉斯是对的。要么禁止使用NULL参数调用API,要么使用IntPtr参数实现C#函数并检查IntPtr.Zero