将NULL传递给COM接口方法的ref / out参数

时间:2013-09-24 07:11:54

标签: c# com null interop com-interop

如果定义为[In, Out] ref int pchEaten,如何将NULL传递给COM接口方法的参数?

例如,请考虑以下界面:

[ComImport, Guid ("000214E6-0000-0000-C000-000000000046")]
[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellFolder
{
    void ParseDisplayName (
        [In] IntPtr hwnd,
        [In] IBindCtx pbc,
        [In, MarshalAs (UnmanagedType.LPWStr)] string pszDisplayName,
        [In, Out] ref uint pchEaten,
        [Out] out PIDLIST ppidl,
        [In, Out] ref SFGAO pdwAttributes);
    // ...
}

MSDN对pchEaten参数说明如下:指向ULONG值的指针,该值接收已解析的显示名称的字符数。如果您的应用程序不需要此信息,请将pchEaten设置为NULL,并且不返回任何值。 pdwAttributes参数也可以设置为NULL。

但是,当我从C#调用ParseDisplayName方法时,我认为无法将null传递给ref参数。

如果我从DLL调用函数,我可以多次导入一个函数:一个带有IntPtr参数,一个带有正确的签名,并根据我需要传递和接收值来选择过载。但是,如果我尝试在COM中多次导入相同的方法,它将不起作用,因为方法的顺序是至关重要的,函数指针将会移位。

问题:如何使用值和输入/输出参数的NULL调用COM方法?

注意:这只是一个例子。我知道我可以创建一个虚拟变量,将其传递给ref参数并忽略返回的值。但是,方法的行为可能取决于值是否为NULL,非空值可能会产生性能成本等,所以我想避免它。

2 个答案:

答案 0 :(得分:4)

您可以像这样重新定义界面:

internal interface IShellFolder
{
    void ParseDisplayName (
        [In] IntPtr hwnd,
        [In] IBindCtx pbc,
        [In, MarshalAs (UnmanagedType.LPWStr)] string pszDisplayName,
        IntPtr pchEaten,
        [Out] out PIDLIST ppidl,
        [In, Out] ref SFGAO pdwAttributes);
    // ...
}

如果要传递null,请调用它:

ParseDisplayName(...., IntPtr.Zero, ...);

如果你想传递一个uint值,或者像这样:

IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)));
uint i = 1234;
Marshal.StructureToPtr(i, p, false);
ParseDisplayName(...., p, ...);
i = (uint)Marshal.PtrToStructure(p, typeof(uint)); // read the value back
Marshal.FreeHGlobal(p);

答案 1 :(得分:3)

令我感到震惊的是,你可能在努力避免使用指针。 C#语言支持它们很好,您可以将参数声明为[In] uint* pchEaten。现在,您拥有以母语提供的所有可用选项,您可以传递&local以及null。其中local应该是调用方法的局部变量,以便指针稳定,您不必担心固定。

但是,您必须声明该方法不安全。当然,当你正确编程时,它不是这样的:)