我们有一个C#/ .Net COM服务器(COM可见组件),带有以下接口&类声明:
[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;
}
}
}
生成的IDL / typelib是:
...
interface ITest : IUnknown {
HRESULT _stdcall TestMethod(
[in] long nNumElements,
[in, out] unsigned char* bArray);
};
...
coclass CSTest {
interface _Object;
[default] interface ITest;
};
目标是能够在C ++ COM客户端中使用它,使用以下方法可以正常工作:
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 );
缓冲区由C ++分配并传递给C#进行填充。 一切正常,在完成TestMethod()后,C ++数组(buf)包含由C#方法设置的正确值。
问题在于效率:
Interop包装器是否在编组期间(“In”阶段)然后返回(“Out”阶段)执行数组复制或者C#方法是否直接在传入的存储器(可能被固定)上运行?
答案 0 :(得分:1)
在这种情况下,将在非托管代码和托管代码之间传递引用。 即使未指定输入/输出参数,“钉扎优化”也会在某些情况下为您执行此操作(但是,如果要用作tlib,则始终必须指定输入/输出修改器。)
您可以假设基本类型的单维数组始终将在同一个公寓上运行的非托管代码和托管代码之间固定(通过引用传递)。
您可以在此处详细了解: http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.80).aspx
有关“固定优化”的更多信息: http://msdn.microsoft.com/en-us/library/23acw07k.aspx
答案 1 :(得分:1)
不,这里肯定需要一份副本,因为你要求进行结构改变。 CLR 必须创建托管数组对象以满足byte []参数类型要求。并且源数组不会以任何方式可用,因为它只是一块原始内存。另一种方式(byte []到unsigned char *)可以工作,但这不是这种情况。
数组的正常COM自动化类型是SAFEARRAY btw,没有速度优势但是有更多的COM客户端可以使用你的服务器。