将 NULL 传递给 COM 接口方法的引用/输出参数

本文关键字:引用 输出 参数 方法 接口 NULL COM | 更新日期: 2023-09-27 18:32:43

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

例如,请考虑以下接口:

[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,非 null 值可能会产生性能成本等,因此我想避免它。

将 NULL 传递给 COM 接口方法的引用/输出参数

您可以像这样重新定义接口,例如:

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);

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

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