[英]unable to invoke function of dll written in c++ from c#
我需要從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#中制作的struct
[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結構。 不幸的是,它沒有幫助我
乍一看,我想說的問題是,您嘗試映射到C#字符串的C ++結構中的固定大小char數組。
當使用固定大小的數組時,它會嵌入到結構本身中,這與使用指針相反,后者只會將指針添加到結構中,而不會添加指向它的數據。
您可以修改C#結構,以便.NET知道如何使用MarshalAs
-attribute將其映射到本機世界:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
string OtherCardInformation;
這適用於.NET字符串到C ++ char數組的所有映射。
您可能還需要使用設置結構的字符編碼
[StructLayout(CharSet = CharSet.Ansi)]
public struct TCardInfoEx
例如,如果您的C ++程序使用ANSI字符。
您已經指定了打包值( #pragma pack(1)
)。 這也必須使用
[StructLayout(CharSet = CharSet.Ansi, Pack = 1)]
public struct TCardInfoEx
最后,您的簽名並不完全匹配:
int GetCardInfoEx(
INT64 Card, // long
DWORD Restaurant, // uint
DWORD UnitNo, // uint
TCardInfoEx* Info, // must be ref TCarfInfoEx
char* InpBuf, // could be string, could also be byte[]
DWORD InpLen, // uint
WORD InpKind, // ushort
char* OutBuf, // could be StringBuilder, or IntPtr
DWORD OutLen, // uint
WORD OutKind) // ushort
在.NET中,結構是按值傳遞的,因此您必須通過ref傳遞它,以使簽名匹配。
將C ++ char *
映射到.NET類型始終是上下文相關的。 有時,這樣的指針用作輸入字符串,有時用於任意輸入數據,當然,它也可以只是單個字符輸出參數。
並且(希望最后)您的呼叫約定不匹配。 DllImport
的默認調用約定為StdCall
而函數使用__cdecl
。 因此,您也必須將其添加到DllImport
屬性中
[DllImport(..., CallingConvetion = CallingConvention.Cdecl, ...)]
感謝@DavidHeffernan,這篇文章從原始版本擴展了很多,在該版本中,我只討論了固定數組大小的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.