c# - 如何从 C# 调用 DLL 中的 C 函数?
问题描述
我需要通过在 C# 中导入 DLL 来调用 C 的以下函数,但它给出了以下错误。
我已导入 DLL 并成功执行了其他函数,而此函数抛出错误。
C方法:
long __stdcall VBVMR_Input_GetDeviceDescA(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
C#代码:
[DllImport("VoicemeeterRemote.dll", EntryPoint = "VBVMR_Input_GetDeviceDescA", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private static extern int VBVMR_Input_GetDeviceDescA(long zindex, ref long nType, [Out] byte[] szDeviceName, [Out] byte[] szHardwareId);
long nType = 0;
byte[] c = new byte[100];
byte[] b = new byte[100];
long i=0;
int rep = VBVMR_Input_GetDeviceDescA(i,ref nType, c, b);
它在执行时抛出异常VBVMR_Input_GetDeviceDescA
:
调用 PInvoke 函数
'Voicemeter!Voicemeter.Program::VBVMR_Input_GetDeviceDescA'
使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。
解决方案
如果导出的函数__stdcall
在导出它的 DLL 中使用调用约定声明,则需要在 C# 代码中使用CallingConvention.StdCall
而不是Cdecl
.
这种调用约定不匹配出现“不平衡堆栈”错误的原因是cdecl
,在调用函数后,调用代码预计会在函数调用后调整堆栈指针寄存器,以删除传递给函数的参数。堆。但是,由于您的函数实际上是一个stdcall
函数,它本身在ret imm16
它使用的指令中执行此操作,因此当调用代码“清理堆栈”时,您的堆栈也会下溢。
下一个问题是long
C# 和long
MSVC 中的大小不同,因此即使使用stdcall
调用约定,被调用函数也会弹出与其认为参数列表正确大小相对应的字节数,但由于 C# 的大小不一long
样大小与 MSVC 一样,在 DLL 函数结束long
的指令之后,堆栈仍然不平衡。ret imm16
但是, C# 的int
类型对应于 a long
。
推荐阅读
- python - `lightgbm.Dataset()` 中的 `free_raw_data` 有什么作用?
- c# - 无法将 XML 读取到对象
- solr - Solr 停用词没有被删除
- php - 如何使用带有重定向 URL 的 FPDI SetSourceFile?
- python - ModuleNotFound 错误:未找到 Mysql 模块?
- java - 如何在序列化程序类中调用默认方法
- linux - 在运行级别 3 中无法登录
- r - 将趋势线添加到条形图
- ios - 从左到右滑动动画背景颜色 UIView 或 UIButton
- sql-server - Delphi 注册一个 dbexpress dll (dbexpsda40.dll) & Windows 服务无法启动和卸载