Question

How to pass NULL to a parameter of a COM interface method if it is defined like [In, Out] ref int pchEaten?

For example, consider the following interface:

[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 says the following about the pchEaten parameter: A pointer to a ULONG value that receives the number of characters of the display name that was parsed. If your application does not need this information, set pchEaten to NULL, and no value will be returned. The pdwAttributes parameter can also be set to NULL.    

However, when I call the ParseDisplayName method from C#, I see no way to pass null to a ref parameter.

If I were calling functions from a DLL, I could import a function multiple times: one with IntPtr parameter, one with proper signature, and choose the overload depending on wether I need to pass and receive the values. However, if I try importing the same method multiple times in COM, it won't work as the order of methods is crucial and function pointers will shift.

Question: How to make calling a COM method both with a value and NULL of an in/out parameter possible?

Note: This is just an example. I know I can create a dummy variable, pass it to a ref parameter and ignore the returned value. However, behavior of a method may depend on wether the value is NULL, non-null value may incur performance costs etc., so I'd like to avoid it.

Was it helpful?

Solution 2

It strikes me that you are probably trying too hard to avoid pointers. The C# language supports them just fine, you can declare the argument as [In] uint* pchEaten. Now you have all of the options available that you have in a native language, you can pass &local as well as null. Where local should be a local variable of the calling method so that the pointer is stable and you won't have to fret about pinning.

But yes, you do have to declare the method unsafe. Of course it is not when you program it correctly :)

OTHER TIPS

You can redefine the interface like this for example:

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);
    // ...
}

And call it like this if you want to pass null:

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

Or like this if you want to pass a uint value:

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top