Simon Fell > Its just code > COM / .NET Interop

Thursday, September 9, 2004

So I'm sure this is possible, I just can't work out the right set of incantations. I have a COM interface which represents a simple readable stream

[
	object,
	uuid(114BD3E3-983B-4509-8DD7-42DC36F4D262),
	local,
	helpstring("IStreamReader Interface"),
	pointer_default(unique)
]
interface IStreamReader : IUnknown
{
	HRESULT Read( void *pv,           // Pointer to buffer into which the stream is read
                      ULONG cb,           // Specifies the number of bytes to read
                      ULONG *pcbRead );   // Pointer to location that contains actual
                                          // number of bytes read

	HRESULT Reset() ;                 // resets the current position in the stream back to the begining.
} ;

No rocket science here, pass a buffer into the Read call and it'll populate some or all of it. Now, I'm trying to provide an implementation of this COM interface in C#, what I've got so far is

[ComImport, Guid("114BD3E3-983B-4509-8DD7-42DC36F4D262")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStreamReader
{
	[PreserveSig]
	void Read ( [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte [] buffer, 
			uint cb, 
			out uint pcbRead ) ;
	[PreserveSig]
	void Reset ();
}

Now I can see my call into the c# code, it gets a right sized buffer, it drops data into the buffer and updates pcbRead, everything looks fine on the .NET side, step through back to the C++ code, and pcbRead is fine, but there's no data in the buffer, it didn't get marshalled back. This seems to be because the buffer is only marshalled as an [in], I tried adding a ref to the byte [] buffer, but now when my c++ code tries to call it i get a HRESULT of 0x80131535 which is MarshalDirectiveException.

Anyone know the trick for this one ?

Update : As this things always go, I worked it out 5 minutes later, ditching the ref and adding an [In,Out] to the byte [] parameter did the trick.