我正在使用一个现有代码库,该代码库由一些用 C++ 编写的带有 C# 前端的 COM 接口(interface)组成。有一些新功能需要添加,所以我不得不修改 COM 部分。在一种特殊情况下,我需要将一个数组(从 C# 分配)传递给要填充的组件。
我想做的是能够将一个 int 数组传递给 C# 中的方法,例如:
// desired C# signature
void GetFoo(int bufferSize, int[] buffer);
// desired usage
int[] blah = ...;
GetFoo(blah.Length, blah);
工作中的几个 Spanner :
- 不能使用 C++/CLI 或托管 C++(在这种情况下可以取消 COM)。
- C# 端不能用/unsafe 编译(允许使用 Marshal)。
COM 接口(interface)仅由 C# 部分使用(并且永远只会使用),因此我不太关心与其他 COM 使用者的互操作性。 32 位和 64 位之间的可移植性也不是问题(一切都在 32 位机器上编译和运行,因此代码生成器将指针转换为整数)。最终,它将仅被 C++/CLI 取代,但这还有很长的路要走。
我的初步尝试
类似于:
HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
并且输出的TLB定义是(貌似合理):
HRESULT _stdcall GetFoo([in] int bufferSize, [in] int* buffer);
这是由 C# 导入的(不太合理):
void GetFoo(int bufferSize, ref int buffer);
我可以使用
int[] b = ...;
fixed(int *bp = &b[0])
{
GetFoo(b.Length, ref *bp);
}
...除了我无法使用/unsafe 进行编译。
此刻
我正在使用:
HRESULT GetFoo([in] int bufferSize, [in] INT_PTR buffer);
导入为:
void GetFoo(int bufferSize, int buffer);
我需要像这样使用它:
int[] b = ...;
GCHandle bPin = GCHandle.Alloc(b, GCHandleType.Pinned);
try
{
GetFoo(b.Length, (int)Marshal.UnsafeAddrOfPinnedArrayElement(b, 0));
}
finally
{
bPin.Free();
}
哪个有效...,但我想找到一种更简洁的方法。
所以,问题是
在这种情况下,是否有对从 TLB 生成器导入 C# 友好的 IDL 定义?如果不是,在 C# 端可以做些什么来让它更安全一些?
最佳答案
因此,您要求 IDL 数据类型在 32 位机器上为 32 位,在 64 位机器上为 64 位。但是您不希望编码(marshal)处理代码将其视为指针,只是作为 int。那么,当您从 64 位进程调用 32 位进程时,您希望额外的 32 位发生什么情况?
对我来说这听起来像是违反物理学的。
如果它只是 inproc,请参阅此讨论的底部:http://www.techtalkz.com/vc-net/125190-how-interop-net-client-com-dll.html .
建议似乎是使用 void * 而不是 intptr 并用 [local] 标记,这样编码器就不会参与。
关于c# - 函数的 IDL 声明(在 C++ 中)将从 C# 获取 C 样式数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/199629/