我有一个供应商的API调用,我想在我的C#
Windows Forms应用程序中使用它.问题是无论我尝试什么
P/Invoke,我都会在线路上发生崩溃,说明呼叫已经使堆栈失衡.我尝试与供应商合作,但他们没有Visual Studio 2012,也没有任何C#或
.NET的经验,经过几次来回的电子邮件,他们基本上都洗了问题.
这是他们的官方C/C++声明
const char *<dll name here>(int Param1,
const char *Param2,
const char *Param3,
unsigned long Param4,
unsigned short Param5,
unsigned short Param6,
unsigned short Param7,
unsigned short Param8,
unsigned short Param9);
这是我尝试过的最近的P / Invoke DLLImport行.
[System.Runtime.InteropServices.DllImport(
"<dll name here>", EntryPoint = "<AnsiFunctionName>", ExactSpelling = true,
CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
public static extern String <AnsiFunctionName>(int Param1,
String Param2,
String Param3,
ulong Param4,
Int16 Param5,
Int16 Param6,
Int16 Param7,
Int16 Param8,
Int16 Param9);
这是实际的错误消息:
Subject Line: PInvokeStackImbalance was detected
A call to P/Invoke function ” has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the P/Invoke signature match the target unmanaged signature.
我尝试了各种各样的东西,甚至设置了一个void返回类型我尝试不使用返回类型.我试过而不是Strings,StringBuilders和IntPtrs.无论我尝试什么,都没有用.
我在阅读Stack Overflow上的一篇文章之后向供应商提到,返回字符串是危险的,不应该这样做.他们的回应是:
“The string return problems mentioned on that page don’t apply to
our functions. They return a pointer to a statically-allocated string, so you don’t need to free it (and must not try to do so). It looks like the “UnmanagedType.LPStr” should work (though the IntPtr thing should work too, with the proper conversions or casting).
更新#1:正如评论中所提到的,我在使用uint,而不是ulong,直到这篇文章.我只是觉得我让比较看起来更好. uint和ulong都不起作用.
更新#2:也许给出实际的功能名称会有所帮助.它是Armadillo CreateCodeShort3A.展望未来,我使用纯.NET,但我仍然需要与之接口,目前还不是真的可行.更重要的是,这个问题让我很好奇为什么我无法解决像P / Invoke那样简单的事情.毕竟,有多少变化? (不是一个严肃的问题).
最佳答案 以下是我可以看到的可能性:
>返回值不应该是String.使用IntPtr并转换为Marshal.PtrToStringAnsi的字符串.
> C类型unsigned long应该与uint匹配.您在C#中使用了ulong,它是64位类型.在Windows上的C中,unsigned long是无符号的32位类型.
> C类型的unsigned short应与ushort匹配.
> C DLL使用的调用约定可能是cdecl.将CallingConvention = CallingConvention.Cdecl添加到您的P/Invoke.
>不要将SetLastError用于此类函数.这与Win32 API函数一起使用,它通过GetLastError返回错误条件.这个DLL文件几乎肯定不会.
所以P / Invoke应该是这样的:
[DllImport(@"mydll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern IntPtr FunctionName(
int Param1,
string Param2,
string Param3,
uint Param4,
ushort Param5,
ushort Param6,
ushort Param7,
ushort Param8,
ushort Param9
);