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

	helpstring("IStreamReader Interface"),
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")]
public interface IStreamReader
	void Read ( [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte [] buffer, 
			uint cb, 
			out uint pcbRead ) ;
	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.