c# - .NET 互操作是来回复制数组数据,还是固定数组?

标签 c# c++ .net com com-interop

我有这个 COM 方法签名,在 C# 中声明:

void Next(ref int pcch,
          [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
          char[] pchText);

我这样调用它:

int cch = 100;
var buff = new char[cch];
com.Next(ref cch, buff);

.NET 互操作层是否首先将整个数组复制到一个临时的非托管内存缓冲区,然后再复制回来?还是数组会自动固定并通过引用传递?

为了尝试,我在 COM 对象 (C++) 中这样做了:

*pcch = 1;
pchText[0] = L'A';
pchText[1] = L'\x38F'; // 'Ώ'

当我返回时在 C# 中检查 buff[1] 时,我确实得到了 'Λ'。但我不认为这是数组被固定而不是来回复制的有力证据。

最佳答案

这并不总是那么容易分辨,尤其是当您使用无效声明时。 char[] 不能被编码为 LPWStr,它必须是 LPArray。现在 CharSet 属性发挥作用,因为您没有指定它,char[] 将被编码为 8 位 char[],而不是 16 位 wchar_t[]。编码的数组元素大小不同(它不是“blittable”),因此编码器必须复制数组。

非常不受欢迎,特别是考虑到您的 C++ 代码需要 wchar_t。在这种特定情况下,一种非常简单的判断方法是数组中没有返回任何内容。如果数组是通过复制编码的,那么您必须明确告诉编码器该数组需要在调用后复制回来。您必须在参数上应用 [In, Out] 属性。你会得到中文。

判断数组是否通过复制编码的正常方法是使用调试器。在 C# 程序中启用非托管调试。在调用上设置断点,并在 native 函数的第一条语句中设置断点。当遇到第一个断点时,使用 Debug + Windows + Memory + Memory 1。将 buff 放入地址框中并将显示切换为“4 字节整数”。您将看到数组对象的地址、4 字节类型句柄、4 字节数组长度和数组内容本身。所以你知道如果数组没有被复制,那么传递的地址就是显示的地址加 8。

按F5继续, native 函数中的断点命中。查看 pchText 参数,调试器会告诉您它的地址。如果匹配,则编码器简单地传递一个指针。如果不是,那么您将获得数组的拷贝。

关于c# - .NET 互操作是来回复制数组数据,还是固定数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25029593/

相关文章:

c# - Kentico Uniselector 中的自定义表格

c++ - Boost Asio C++ HTTPS 请求未命中服务器。没有错误

c++ - 使用继承类时处理构造函数

c# - 小型 3D 应用程序的最佳框架

.net - TaskFactory.StartNew 与 ThreadPool.QueueUserWorkItem

c# - Linq to SQL 奇怪的 SQL 翻译

c# - 使用 MVVM 从列表拖放到 Windows Phone 上的 Canvas

c++ - c - 如何在资源管理器中打开选定的文件

c# - .Net 无法创建 SSL/TLS 安全通道

c# - 如何将txt文件移动到其他文件夹?