Interop: marshaling double pointers that can be null
I recently had to implement IMediaBuffer in managed code. The GetBufferAndLength method takes a BYTE** ppBuffer argument, so I initially went with the following straightforward C# declaration:
public void GetBufferAndLength(out IntPtr ppBuffer, out uint cbLength)
{
ppBuffer = myBuffer;…}
This seemed to work fine, until I noticed a lot of first time NullReferenceExceptions were scrolling by in the debugger output window. Puzzled, I turned on breaking on all exceptions in VS and found that the native code calling my IMediaBuffer implementation would sometimes call with a NULL first argument in cases where it was only interested in obtaining the buffer length (cbLength). Apparently the interop layer was silently handling such cases. This was less than ideal, so I spent some time searching for a better way to do the managed declaration, looking at the various MarshalAs and such attributes but with no luck. Finally it dawned on me that a double pointer is also just a pointer and that I could do the dereferencing myself:
public void GetBufferAndLength(IntPtr ppBuffer, out uint cbLength)
{
if (ppBuffer != IntPtr.Zero)
{
Marshal.WriteIntPtr(ppBuffer, myBuffer);
}
...
Voila! This can handle the double pointer being NULL and no more NullReferenceExceptions :)