当参数之一是指针数组时,如何从 C# 调用 C++ DLL
Posted
技术标签:
【中文标题】当参数之一是指针数组时,如何从 C# 调用 C++ DLL【英文标题】:How to call C++ DLL from C# when one of the parameters is an array of pointers 【发布时间】:2017-11-27 23:32:24 【问题描述】:我有一个 DLL pin C++,它接受两个参数,类似于 C 中的 main() 函数:参数数量,后跟指向各个参数的指针数组:
__declspec(dllexport) void Calculate(int argc, void** argv)
if (argc >= 7)
auto sourceX = *((int*)(argv[0]));
auto sourceY = *((int*)(argv[1]));
auto iterations = *((int*)(argv[2]));
auto resize = *((bool*)(argv[3]));
auto input = (double*)(argv[4]);
auto targetX = *((int*)(argv[5]));
auto targetY = *((int*)(argv[6]));
// Do computations
我能够以这种方式从另一个 C 代码调用导出的函数(在通过 LoadLibrary 和 GetProcAddress 调用加载 DLL 库之后):
int X, Y, iterations;
bool Resize;
double* Input;
// Initialize variables, allocate data for Input
// ...
void* Params[] = &X, &Y, &iterations, &Resize, Input, &X, &Y ;
_Calculate(7, Params);
但是,当我尝试从 C# 调用 DLL 时,它崩溃了。这是我正在使用的 C# sn-p:
[DllImport("computedll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern void Calculate(int argc, void** argv);
public void Compute()
int X, Y, iterations;
bool Resize;
double* Input;
// Initialize variables, allocate data for Input
// ...
var Parameters = stackalloc void*[7];
Parameters[0] = &X;
Parameters[1] = &Y;
Parameters[2] = &iterations;
Parameters[3] = &Resize;
Parameters[4] = Input;
Parameters[5] = &X;
Parameters[6] = &Y;
Calculate(7, Parameters);
我在这里做错了什么?有没有办法使这种使用指针数组(void**)的模式起作用?提前致谢。
【问题讨论】:
见:***.com/tags/pinvoke/info 猜测您已经验证了您的 C++ 代码并且您的 C# 代码使用相同的指针大小? 【参考方案1】:构建为 x64,以下工作。这几乎是您的代码。我讨厌在 C/C++ 之外使用 cdecl,所以如果这对你很重要……对不起。重点是...如果您遇到问题,这不是您的实际代码或概念的基础。
Interopy.h:
extern "C"
__declspec(dllexport) void __stdcall Calculate(int argc, void** argv);
来源:
#include "Interopy.h"
void __stdcall Calculate(int argc, void** argv)
if (argc >= 7)
auto sourceX = *((int*)(argv[0]));
auto sourceY = *((int*)(argv[1]));
auto iterations = *((int*)(argv[2]));
auto resize = *((bool*)(argv[3]));
auto input = (double*)(argv[4]);
auto targetX = *((int*)(argv[5]));
auto targetY = *((int*)(argv[6]));
*(int*)argv[5] = 42; //to test
// Do computations
c#(平台目标 x64):
public static class iop
[DllImport("InteropyDll1.dll", CallingConvention = CallingConvention.StdCall)]
unsafe public static extern void Calculate(int argc, void** argv);
unsafe static public void Compute()
int X, Y, iterations;
bool Resize;
double* Input = (double*)IntPtr.Zero;
// Initialize variables, allocate data for Input
// ...
void **Parameters = stackalloc void*[7];
Parameters[0] = &X;
Parameters[1] = &Y;
Parameters[2] = &iterations;
Parameters[3] = &Resize;
Parameters[4] = Input;
Parameters[5] = &X;
Parameters[6] = &Y;
Calculate(7, Parameters);
请注意,此程序集现在依赖于平台。我过去通过多种构建配置解决了这个问题,但我相信还有更好的方法可以解决。无论如何,出于这个原因和其他原因,您都希望将这个不安全的代码放在它自己的程序集中。
【讨论】:
谢谢你!我实施了你的建议,效果很好!我尝试对您的答案进行投票,不幸的是,我的声誉 (6) 还不够。 @StephenDaedalusSepara 不过,您始终可以接受它作为提问者。我相信它旁边有一个复选标记? @StephenDaedalusSepara - 顺便说一句,我不知道这段代码的用途,但如果你要维护它,我会留意 C# 中的Span<T>
和 Memory<T>
7.2.它们专为此类不需要不安全的场景而设计。不过,目前还不错。
(旧版)c++ 代码用于执行在 c# 中不可用或速度较慢的计算。是的,我会维护这些代码一段时间,直到我们得到更好的计算实现。看起来 Span<T>
和 Memory<T>
将成为 c# 的有趣和有用的开发,再次感谢。以上是关于当参数之一是指针数组时,如何从 C# 调用 C++ DLL的主要内容,如果未能解决你的问题,请参考以下文章
C# 调用C++ DLL,而c++函数的有一个参数需要是null,该怎么传递?
当引入参数时,从指针调用成员函数的 C++ 调用内存访问冲突