gpt4 book ai didi

c++ - 如何从 C++ 显示 C# 中结构的值

转载 作者:可可西里 更新时间:2023-11-01 17:38:50 26 4
gpt4 key购买 nike

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);

abc.cpp(动态链接库文件)

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;
}

结构:-

[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;

函数调用:-

[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";
}

当我尝试在 C# 中调用它们时,我在 C# 中得到垃圾值。当我调试它们时,我发现正确地存储了这些值。关于必须如何传递值的任何帮助都将非常有用。 提前致谢。

最佳答案

C# 声明是正确的,只是细节上有细微的错误。一个好的起点是 this post ,向您展示了如何编写一些测试代码来验证结构声明是否匹配良好。在这个特定的上这样做:

C++: auto len = sizeof(SP_CIMNOTETYPELIST);                    // 196 bytes
C# : var len = Marshal.SizeOf(typeof(sp_BankNoteTypeList)); // 296 bytes

不接近,您必须获得完全匹配才能正确编码。内部结构的 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);

sp_BankNoteTypeList 声明没问题。重新运行测试,您现在也应该在 C# 中获得 196 个字节。注释更改:

  • CharSet = CharSet.Ansi
    那是让 CHAR 成员正确编码所必需的。它是 char 的 Windows typedef,一种 8 位类型。如果 native 结构使用 WCHAR,CharSet.Auto 将是正确的选择。
  • public uint cim_ulValues;
    Windows 使用 LLP64 data model ,它在 32 位和 64 位程序中都将 ULONG 保持在 32 位。这使得 uint 成为正确的 C# 等价物,而不是 ulong。
  • 私有(private)字节_cim_bConfigured;
    bool 是一个非常棘手的类型,标准化程度很低。在 C++ 中为 1 个字节,在 C 中为 4 个字节,在 COM 互操作中为 2 个字节,在托管代码中为 1 个字节。默认编码(marshal)处理假定 BOOL 作为匹配的 native 类型,这是在 winapi 中完成的方式。使用公共(public)属性 getter 将其声明为私有(private)字节是一种方法,我在这里更喜欢这种方法,将 [MarshalAs(UnmanagedType.U1)] 属性应用于该字段是另一种方法。
  • CallingConvention = CallingConvention.Stdcall
    明确这一点非常重要,这里的另一个常见选择是 CallingConvention.Cdecl。我无法从 native 代码片段中判断哪个是正确的,BNA_API 是一个宏,但您没有提到提示它的 PInvokeStackImbalance MDA,因此 Stdcall 有点可能是正确的。请确保您没有将其关闭。
  • [Out]out sp_BankNoteTypeList 列表
    [Out] 属性在这里是必需的,以说服 pinvoke 编码器需要将结构复制回来。这是非常不直观的,大多数程序员认为 out 就足够了。但这是编码程序不知道的 C# 语言细节。必须明确要求复制回来,该结构不是“blittable”的。或者换句话说, native 布局与内部托管布局不同。 ByValArray 使这成为必然。

相当多的洗衣 list ,我希望我能全部找到。让结构尺寸相同是成功的 95%。

关于c++ - 如何从 C++ 显示 C# 中结构的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45035424/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com