无法从c#调用用c++编写的dll函数
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#中制作的结构
[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
-属性将其映射到本地世界:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
string OtherCardInformation;
这适用于.NET字符串到C++字符数组的所有映射。
您可能还需要使用设置结构的字符编码
[StructLayout(CharSet = CharSet.Ansi)]
public struct TCardInfoEx
例如,如果您的C++程序使用ANSI字符。
您已经指定了一个包值(#pragma pack(1)
)。还必须使用将其翻译成.NET世界
[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,这篇文章从最初的版本扩展了很多,在最初的版本中,我只讨论了固定数组大小的问题。
- Visual c ++,使用字符串引用/指针调用 dll 函数
- 在 Microsoft Access SQL 中调用自定义 DLL 函数时传递的内存地址无效
- 调用 "project" 函数和调用 DLL 函数之间的区别
- 代码在 msvcrt .dll函数上设置断点失败
- VB.NET DLL中的C++DLL函数复制
- 在python-ctypes中声明变量并传递给dll函数
- 从 Python 调用 Windows DLL 函数时出错
- 调用 dll 函数时"Run-Time Check Failure #0 - The value of ESP"
- 列出 C# 中的 non-.NET DLL 函数
- 基本 DLL 函数
- 如何在不可修改的源代码中使用 DLL 函数?
- 对需要双精度数组和结构作为输入C++ DLL 函数的 C# 调用
- WScript.CreateObject 在调用 C++ COM dll 函数时返回空
- 如何在 lua cpp 模块中调用托管 c++ dll 函数
- 测试C++ DLL 函数
- 从 C# GUI 将 char * 参数传递给C++ dll 函数
- 使用指针调用C++ DLL 函数
- 在C++中导入 DLL 函数
- #VALUE!在 64 位 Excel 中调用 DLL 函数 (C++) 时
- 如何从 UWP 应用调用"libheif.dll"函数