如何从C ++显示C#中结构的值 [英] How to display the values from structures in C# from C++

查看:115
本文介绍了如何从C ++显示C#中结构的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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(DLL文件)


abc.cpp (DLL File)

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#中得到了垃圾值. 在调试它们时,我发现可以正确存储这些值. 关于必须如何传递值的任何帮助将非常有用. 预先感谢.

when I try calling them in C# I get garbage value in C#. While I debug them I find proper storing the values. Any help as to how the values must be passed would be very useful.. Thanks in advance.

推荐答案

C#声明处在正确的轨道上,只是细节有些错误.一个很好的起点是这篇文章,向您展示如何编写一些测试代码来验证结构声明是否匹配良好.为此,请执行以下操作:

The C# declarations are on the right track, it is just that the details are subtly wrong. A good starting point is this post, shows you how to write some test code to verify that the structure declarations are a good match. Doing so on this particular one:

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

尚未结束,您必须获得完全匹配才能对它正确编组产生任何希望.内部结构的C#声明应如下所示:

Not close, you must get an exact match to have any hope of it marshalling correctly. The C# declaration for the inner struct should look like this:

    [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字节.注释更改:

The sp_BankNoteTypeList declaration is okay. Rerun the test and you should now get 196 bytes in C# as well. Annotating the changes:

  • CharSet = CharSet.Ansi
    要使CHAR成员正确地集结,这一点是必要的.它是Windows char的typedef,为8位类型.如果本机结构使用WCHAR,则CharSet.Auto将是正确的选择.
  • public uint cim_ulValues;
    Windows使用 LLP64数据模型,它将ULONG保持在32 32位和64位程序中的位.这使得uint等同于正确的C#,而不是ulong.
  • private byte _cim_bConfigured;
    bool是非常棘手的类型,标准化程度很差.在C ++中为1字节,在C中为4字节,在COM interop中为2字节,在托管代码中为1字节.默认封送处理将BOOL假定为匹配的本机类型,这是在winapi中完成的方式.将其声明为具有公共属性获取器的字节是私有的,这是一种方法,而我在此更喜欢将[MarshalAs(UnmanagedType.U1)]属性应用于该字段将是另一种方法.
  • CallingConvention = CallingConvention.Stdcall
    要明确显示这一点非常重要,这里的另一个常见选择是CallingConvention.Cdecl.从本机代码段中我看不出哪个是正确的,BNA_API是一个宏,但是您没有提到PInvokeStackImbalance MDA对此有所抱怨,因此Stdcall可能是正确的.确保没有关闭它.
  • [Out]out sp_BankNoteTypeList list
    这里必须使用[Out]属性,才能说服pinvoke编组认为需要将结构复制回去.这是很不直观的,大多数程序员认为out就足够了.但这是封送官不知道的C#语言细节.必须明确要求复制,该结构不是可复制的".换句话说,本机布局与内部托管布局不同. ByValArray使这种情况不可避免.
  • CharSet = CharSet.Ansi
    That one was necessary to get the CHAR member to marshal correctly. It is a Windows typedef for char, an 8 bit type. CharSet.Auto would have been the right choice if the native structure used WCHAR.
  • public uint cim_ulValues;
    Windows uses the LLP64 data model, that keeps a ULONG at 32 bits in both 32-bit and 64-bit programs. That makes uint the correct C# equivalent instead of ulong.
  • private byte _cim_bConfigured;
    bool is a very tricky type with poor standardization. It is 1 byte in C++, 4 bytes in C, 2 bytes in COM interop, 1 byte in managed code. The default marshaling assumes BOOL as the matching native type, the way it is done in the winapi. Declaring it private as a byte with a public property getter is one way to do it and the one I favored here, applying the [MarshalAs(UnmanagedType.U1)] attribute to the field would be another.
  • CallingConvention = CallingConvention.Stdcall
    Pretty important to be explicit about this, the other common selection here is CallingConvention.Cdecl. I can't tell from the native snippet which one is correct, BNA_API is a macro, but you did not mention the PInvokeStackImbalance MDA complaining about it so Stdcall is somewhat likely to be correct. Do make sure you did not turn it off.
  • [Out]out sp_BankNoteTypeList list
    The [Out] attribute is necessary here to convince the pinvoke marshaller that copying the structure back is required. This is pretty unintuitive, most programmer think that out is enough. But that is a C# language detail that the marshaller does not know about. Copying back has to be explicitly requested, the structure is not "blittable". Or in other words, the native layout is not the same as the internal managed layout. The ByValArray makes that inevitable.

挺洗衣单的,我希望我能把所有的都弄干净.保持相同的结构尺寸是95%的努力.

Quite a laundry-list, I hope I got them all. Getting the structure sizes the same is 95% of the battle.

这篇关于如何从C ++显示C#中结构的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆