Reputation: 683
We have a C#/.Net COM server (COM-visible assembly) with the following interface & class declarations:
[ComVisible(true)]
[Guid( "..." )]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITest
{
void TestMethod( [In] int nNumElements,
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] byte [] bArray );
}
[ComVisible(true)]
[Guid( "..." )]
[ClassInterface( ClassInterfaceType.None )]
[ProgId( "CSCOMServer.CSTest" )]
public class CSTest : ITest
{
public void TestMethod( int nNumElements, byte [] bArray )
{
for (int i = 0; i < bArray.Length; i++)
{
bArray [i] = (byte)i;
}
}
}
The resulting IDL/typelib is:
...
interface ITest : IUnknown {
HRESULT _stdcall TestMethod(
[in] long nNumElements,
[in, out] unsigned char* bArray);
};
...
coclass CSTest {
interface _Object;
[default] interface ITest;
};
The goal is to be able to utilize this from a C++ COM client, which works fine using the following:
int iSize = 10;
ITest *test;
byte *buf = (byte*)CoTaskMemAlloc( iSize * sizeof(byte) );
CoCreateInstance( CLSID_CSTest, NULL, CLSCTX_INPROC_SERVER, IID_ITest, (void **) &test );
test->TestMethod( iSize, buf );
The buffer is allocated by C++ and passed to C# for population. All works well and upon the completion of TestMethod() the C++ array (buf) contains correct values set by the C# method.
The question is about efficiency:
Does the Interop wrapper perform array copying during marshaling ("In" phase) and then back ("Out" phase) OR does the C# method operate directly on the passed in memory (which may be pinned)?
Upvotes: 0
Views: 1806
Reputation: 941545
No, a copy is definitely required here since you ask for a structural change. The CLR must create a managed array object to meet the byte[] argument type requirement. And the source array isn't in any way usable as-is since it is nothing but a raw chunk of memory. The other way around (byte[] to unsigned char*) can work but that's not the case here.
The normal COM automation type for arrays is SAFEARRAY btw, no speed advantage but there are a lot more COM clients that could use your server.
Upvotes: 2
Reputation: 9497
In this case a reference will be passed between unmanaged and the managed code. The "pinning optimization" do that for you in certain cases even if the in/out parameter is not specified (but for use as a tlib one always have to specify the in/out modifier).
You can assume that single dimension arrays of primitive types always will be pinned (passed by reference) between unmanaged and managed code running on the same apartment.
You can read more about it here: http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.80).aspx
More about "pinning optimization": http://msdn.microsoft.com/en-us/library/23acw07k.aspx
Upvotes: 1