【发布时间】:2014-09-02 07:03:30
【问题描述】:
我需要从 C# 控制台应用程序调用一个具有用 c++ 编写的 dll 的函数。我在 C# 中进行了编组并编写了相同的数据类型。但无论如何我都会出错。问题出在哪里?
这是dll函数的代码
extern "C" {
SAMPLENATIVEDLL_API int GetCardInfoEx(INT64 Card, DWORD Restaurant, DWORD UnitNo, TCardInfoEx* Info, char* InpBuf, DWORD InpLen, WORD InpKind, char* OutBuf, DWORD OutLen, WORD OutKind) {
int res = getCardInfoEx(Card, Info, UnitNo);
return res;
}
}
这里是TCardInfoEx结构代码
#pragma pack(1)
typedef struct TCardInfoEx {
WORD Size;
BYTE Deleted;
BYTE Seize;
BYTE StopDate;
BYTE Holy;
BYTE Manager;
BYTE Blocked;
CHAR WhyLock[256];
CHAR Holder[40];
INT64 UserID;
DWORD CardAccountNumber;
DWORD TypeOfDefaulter;
WORD Bonus;
WORD Discount;
INT64 Summa;
INT64 AvailableSumma;
INT64 SummaOnCardAccount2;
INT64 SummaOnCardAccount3;
INT64 SummaOnCardAccount4;
INT64 SummaOnCardAccount5;
INT64 SummaOnCardAccount6;
INT64 SummaOnCardAccount7;
INT64 SummaOnCardAccount8;
CHAR OtherCardInformation[256];
CHAR OtherCardInformation1[256];
CHAR OtherCardInformation2[256];
};
这是我用c#制作的结构
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TCardInfoEx
{
ushort Size;
byte Deleted;
byte Seize;
byte StopDate;
byte Holy;
byte Manager;
byte Blocked;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
String WhyLock;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
String Holder;
Int64 UserID;
uint CardAccountNumber;
uint TypeOfDefaulter;
ushort Bonus;
ushort Discount;
Int64 Summa;
Int64 AvailableSumma;
Int64 SummaOnCardAccount2;
Int64 SummaOnCardAccount3;
Int64 SummaOnCardAccount4;
Int64 SummaOnCardAccount5;
Int64 SummaOnCardAccount6;
Int64 SummaOnCardAccount7;
Int64 SummaOnCardAccount8;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
String OtherCardInformation;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
String OtherCardInformation1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
String OtherCardInformation2;
};
这是我调用方法(函数)的代码
class Program
{
[DllImport("SampleNativeDLL.dll", CharSet = CharSet.Unicode)]
public static extern int GetCardInfoEx(Int64 Card, uint Restaurant, uint UnitNo, TCardInfoEx Info, String InpBuf, uint InpLen, ushort InpKind, String OutBuf, uint OutLen, ushort OutKind);
static void Main(string[] args)
{
TCardInfoEx tc = new TCardInfoEx();
GetCardInfoEx(1248000259045, 1, 1, tc, "", 0, 1, "", 1, 1);
}
}
我收到以下错误: 托管调试助手“PInvokeStackImbalance”在“\bin\Debug\FCFake.vshost.exe”中检测到问题。
附加信息:对 PInvoke 函数“Program::GetCardInfoEx”的调用导致堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。
如何解决这个问题?
UPD:我根据 Dirk 的回答编辑了 TCardInfoEx 结构。不幸的是,它没有帮助我
【问题讨论】:
-
尝试为您的字符串成员使用
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = ????)]属性,或者不将它们编组为字符串,而是编组为字节数组。 -
我不确定,但
String WhyLock和String Holder不匹配char WhyLock[256]和char Holder[40]。您认为 String 是如何知道 256 字节长的?! -
包装也错了。并且 p/invoke 需要通过 ref 传递结构。
-
哦,调用约定还不匹配。
-
FWIW 打包导致布局效率低下。你为什么这样做?
标签: c# c++ dll pinvoke marshalling