Tec*_*Tru 8 c++ pointers structure cen-xfs xfs
abc.h文件
typedef struct sp_BankNoteTypeList
{
int cim_usNumOfNoteTypes;
struct sp_notetype
{
USHORT cim_usNoteID;
CHAR cim_cCurrencyID[3];
ULONG cim_ulValues;
bool cim_bConfigured;
}SP_CIMNOTETYPE[12];
}SP_CIMNOTETYPELIST,*SP_LPCIMNOTETYPELIST;
BNA_API int BanknoteType(SP_CIMNOTETYPELIST *sp_BankNoteType);
Run Code Online (Sandbox Code Playgroud)
abc.cpp(DLL文件)
int BanknoteType(SP_CIMNOTETYPELIST *sp_BankNoteType)
{
LPWFSCIMNOTETYPE fw_notetypedata;
LPWFSCIMNOTETYPELIST lpNoteTypeList; //output param
hResult = WFSGetInfo(hService, WFS_INF_CIM_BANKNOTE_TYPES, (LPVOID)NULL, 400000, &res);
lpNoteTypeList=(LPWFSCIMNOTETYPELIST)res->lpBuffer;
if(hResult!=0)
{
return (int)hResult;
}
sp_BankNoteType->cim_usNumOfNoteTypes = lpNoteTypeList->usNumOfNoteTypes;
for(int i=0;i<lpNoteTypeList->usNumOfNoteTypes;i++)
{
sp_BankNoteType->SP_CIMNOTETYPE[i].cim_usNoteID = lpNoteTypeList->lppNoteTypes[i]->usNoteID;
sp_BankNoteType->SP_CIMNOTETYPE[i].cim_ulValues = lpNoteTypeList->lppNoteTypes[i]->ulValues;
sp_BankNoteType->SP_CIMNOTETYPE[i].cim_bConfigured = lpNoteTypeList->lppNoteTypes[i]->bConfigured;
sp_BankNoteType->SP_CIMNOTETYPE[i].cim_cCurrencyID[0] = lpNoteTypeList->lppNoteTypes[i]->cCurrencyID[0];
sp_BankNoteType->SP_CIMNOTETYPE[i].cim_cCurrencyID[1] = lpNoteTypeList->lppNoteTypes[i]->cCurrencyID[1];
sp_BankNoteType->SP_CIMNOTETYPE[i].cim_cCurrencyID[2] = lpNoteTypeList->lppNoteTypes[i]->cCurrencyID[2];
}
return (int)hResult;
}
Run Code Online (Sandbox Code Playgroud)
结构体 :-
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct sp_notetype
{
public ushort cim_usNoteID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public char[] cim_cCurrencyID;
public ulong cim_ulValues;
public bool cim_bConfigured;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct sp_BankNoteTypeList
{
public int cim_usNumOfNoteTypes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
public sp_notetype[] SP_CIMNOTETYPE;
};
public sp_notetype[] SP_CIMNOTETYPE;
public sp_BankNoteTypeList SP_CIMNOTETYPELIST;
Run Code Online (Sandbox Code Playgroud)
功能调用: -
[DllImport(@"abc.dll")]
public static extern int BanknoteType(out sp_BankNoteTypeList SP_CIMNOTETYPELIST);
public string BNA_BankNoteType(out int[] NoteID,out string[]CurrencyID,out string[] Values,out bool[] Configured)
{
NoteID = new int[12];
CurrencyID = new string[12];
Values = new string[12];
Configured = new bool[12];
try
{
trace.WriteToTrace(" Entered in BNA_BankNoteType ", 1);
hResult = BanknoteType(out SP_CIMNOTETYPELIST);
for (int i = 0; i < 12; i++)
{
NoteID[i] = (SP_CIMNOTETYPELIST.SP_CIMNOTETYPE[i].cim_usNoteID);
CurrencyID[i] = (SP_CIMNOTETYPELIST.SP_CIMNOTETYPE[i].cim_cCurrencyID[0]).ToString() + (SP_CIMNOTETYPELIST.SP_CIMNOTETYPE[i].cim_cCurrencyID[1]).ToString() + (SP_CIMNOTETYPELIST.SP_CIMNOTETYPE[i].cim_cCurrencyID[2]).ToString();
Values[i] = (SP_CIMNOTETYPELIST.SP_CIMNOTETYPE[i].cim_ulValues).ToString();
Configured[i] = (SP_CIMNOTETYPELIST.SP_CIMNOTETYPE[i].cim_bConfigured);
}
return DicErrorCode(hResult.ToString());
}
catch (Exception ex)
{
return "FATAL_ERROR";
}
Run Code Online (Sandbox Code Playgroud)
当我尝试在C#中调用它时,我在C#中获得了垃圾值.当我调试它们时,我发现正确存储值.关于如何传递值的任何帮助都将非常有用..提前感谢.
C#声明是在正确的轨道上,只是细节是巧妙的错误.一个很好的起点是这篇文章,向您展示如何编写一些测试代码来验证结构声明是否匹配良好.在这个特定的一个这样做:
C++: auto len = sizeof(SP_CIMNOTETYPELIST); // 196 bytes
C# : var len = Marshal.SizeOf(typeof(sp_BankNoteTypeList)); // 296 bytes
Run Code Online (Sandbox Code Playgroud)
不接近,你必须得到完全匹配,以便有正确编组的希望.内部结构的C#声明应如下所示:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct sp_notetype {
public ushort cim_usNoteID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public char[] cim_cCurrencyID;
public uint cim_ulValues;
private byte _cim_bConfigured;
public bool cim_bConfigured {
get { return _cim_bConfigured != 0; }
}
};
[DllImport(@"abc.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern int BanknoteType([Out]out sp_BankNoteTypeList list);
Run Code Online (Sandbox Code Playgroud)
sp_BankNoteTypeList声明没问题.重新运行测试,你现在应该在C#中获得196个字节.注释更改:
CharSet = CharSet.Ansichar8位类型的Windows typedef .如果原生结构使用WCHAR,CharSet.Auto将是正确的选择.public uint cim_ulValues;ULONG在32位和64位程序中保持32位.这使得uint正确的C#等价而不是ulong.private byte _cim_bConfigured;bool是一个非常棘手的类型,标准化很差.它是C++中的1个字节,C中的4个字节,COM互操作中的2个字节,托管代码中的1个字节.默认编组假定BOOL为匹配的本机类型,即在winapi中完成的方式.将它声明为具有公共属性getter的字节是一种方法,这是我喜欢的方法,将[MarshalAs(UnmanagedType.U1)]属性应用于该字段将是另一种方法.CallingConvention = CallingConvention.Stdcall[Out]out sp_BankNoteTypeList listout已经足够了.但这是编组人员不知道的C#语言细节.必须明确要求复制,结构不是"blittable".或者换句话说,本机布局与内部托管布局不同.ByValArray使这不可避免.相当一个洗衣清单,我希望我得到它们.获得相同的结构大小是战斗的95%.
我重新创建了C++部分,因为我遇到了与其相关的结构相关的错误WFSGetInfo,所以我用一些随机数据填充字段(关于字段的注释char[3]:我用 3 个随机大写字母填充它)。受到MSDN的启发和SO的许多其他问题,我确定了代码中的问题列表;解决这些问题后,我能够从C#中获取正确的数据。请注意,我使用的是VStudio2015。
一些基本注意事项:
BNA_API对我来说是__declspec(dllexport) 函数声明位于
#if defined(__cplusplus)
extern "C" {
#endif
// Function declaration comes here
#if defined(__cplusplus)
}
#endif
Run Code Online (Sandbox Code Playgroud)
块,以避免C++ 名称损坏。有关更多详细信息,请查看[MSDN]:修饰名称
问题:
__cdecl,而C#封送拆收器使用__stdcall. 这效果不太好,当压入/弹出ping 参数时它会破坏堆栈。为了解决这个问题,您必须更改默认值仅在一处更改默认值:
BNA_API int __stdcall BanknoteType(SP_CIMNOTETYPELIST *sp_BankNoteType); - 这是我选择的方法DllImport(@"abc.dll", CallingConvention = CallingConvention.Cdecl)]- 这也有效struct sp_notetype的C#定义中,您应该具有:。检查[MSDN]:封送参数public uint cim_ulValues;以获取完整列表Charset您的结构 - 在C中,char使用(8位宽) - 将其从 更改Charset.Auto为Charset.Ansi。检查[SO]:C# 调用 C DLL,传递 char * 作为参数不正确| 归档时间: |
|
| 查看次数: |
494 次 |
| 最近记录: |