【问题标题】:Handeling NULL pointer out argument in C# COM在 C# COM 中处理 NULL 指针输出参数
【发布时间】:2011-10-01 16:56:19
【问题描述】:

我正在使用具有以下函数定义的 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 object a, ref object b),但这也不起作用。

更新

Hans 是绝对正确的,如果我们将函数声明为 [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
}

希望这对将来的其他人有所帮助

【问题讨论】:

    标签: c# com null idl typelib


    【解决方案1】:

    来自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 或本机代码。

    【讨论】:

    • 是的,我就是这么想的。不幸的是,使用 NULL 调用的版本已经发布。谢天谢地,它只是应用程序的一小部分,但仍然只是想知道。
    【解决方案2】:

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

    【讨论】:

    • 我得试一试。我仍然希望我可以稍微更改 IDL 文件以允许应用程序仍然可以正常使用插件。
    • 这实际上工作得很好,最大的问题是当它不是 NULL/IntPtr.Zero 时将对象复制到地址,谢谢
    猜你喜欢
    • 2014-08-22
    • 1970-01-01
    • 2013-12-16
    • 2020-06-05
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多