如何从C#中调用DLL中的C函数?

问题描述 投票:0回答:1

我需要通过在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签名的调用约定和参数是否与目标非托管签名匹配。

c# c dll pinvoke
1个回答
1
投票

如果导出的函数是使用导出它的DLL中的调用约定__stdcall声明的,则需要使用CallingConvention.StdCall而不是Cdecl在C#代码中导入它。

这种调用约定不匹配表现出“不平衡堆栈”的错误的原因是因为在调用cdecl函数之后,调用代码应该在函数调用之后调整堆栈指针寄存器以删除传递给函数的参数。堆栈。但是,由于你的函数实际上是一个stdcall函数,它在它使用的ret imm16指令中执行它,所以当调用代码“清理堆栈”时你的堆栈会下溢。

接下来的问题是C#中的long和MSVC中的long是不同的大小,所以即使使用stdcall调用约定,被调用函数也会弹出与其认为参数列表的正确大小相对应的字节数,但是因为C#的long与MSVC的long大小不同,在DLL函数结束时ret imm16指令后堆栈仍然不平衡。然而,C#的int类型对应于long

© www.soinside.com 2019 - 2024. All rights reserved.