我应该如何声明这个C结构进行互操作?声明、结构、操作

2023-09-03 07:16:36 作者:- 宣你痞痞的笑i

我必须使用我开发的应用程序中的传统的C程序。在code在这里工作,但我不得不转换几乎所有的领域,以字符数组才能使用它。有一种更好的方式来做到这一点?我已经使用字符串,一切都是徒劳尝试了一些版本。

这是原来的头文件中找到的code ...

  typedef结构PXUCAMR
{
   烧焦xumrversaocomc01;
   炭xumrretcomc02 [2];
   炭xumrretusuc02 [2];
   炭xumrcodfalhac05 [5];
   烧焦xumrfiller1c01;
   烧焦xumrtipoambclic01;
   烧焦xumrambientec01;
   烧焦xumrconvertec01;
   烧焦xumroperacaoc01;
   烧焦xumropcaoexec01;
   xumrcom_t * xumrhandleconnb31;
   炭xumrreshconnc04 [4];
   长xumrtamdadosb31;
   炭xumrtransacaosrvc08 [8];
   炭xumrtransrvdb2c04 [4];
   炭xumrpgmservidorc08 [8];
   炭xumrversaopgmsrvc02 [2];
   烧焦xumrconectardbc01;
   炭xumrusuariosrvc08 [8];
   炭xumrsenhasrvc08 [8];
   炭xumridcriptc08 [8];
   炭xumrpgmclientec08 [8];
   炭xumrversaopgmclientec02 [2];
   焦炭xumridclientec20 [20];
   烧焦xumrtipoidclientec01;
   炭xumrusuarioclientec08 [8];
   炭xumrprodutophac16 [16];
   焦炭xumridservidorc30 [30];
   焦炭xumrdadosc10000 [10000]
}
pxucamr_t;
 

...这是我用我的C#应用​​程序的声明...

  [StructLayout(LayoutKind.Sequential)
内部结构PXUCAMR
{
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumrversaocomc01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 2)]
    公众的char [] xumrretcomc02;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 2)]
    公众的char [] xumrretusuc02;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 5)]
    公众的char [] xumrcodfalhac05;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumrfiller1c01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumrtipoambclic01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumrambientec01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumrconvertec01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumroperacaoc01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)] // 16
    公众的char [] xumropcaoexec01;
    [的MarshalAs(UnmanagedType.I4)
    公众诠释xumrhandleconnb31;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 4)]
    公众的char [] xumrreshconnc04;
    [的MarshalAs(UnmanagedType.I4)
    公众诠释xumrtamdadosb31;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)] // 36
    公众的char [] xumrtransacaosrvc08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 4)]
    公众的char [] xumrtransrvdb2c04;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)]
    公众的char [] xumrpgmservidorc08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 2)]
    公众的char [] xumrversaopgmsrvc02;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)]
    公众的char [] xumrconectardbc01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)] // 67
    公众的char [] xumrusuariosrvc08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)]
    公众的char [] xumrsenhasrvc08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)]
    公众的char [] xumridcriptc08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)]
    公众的char [] xumrpgmclientec08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 2)] // 93
    公众的char [] xumrversaopgmclientec02;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 20)]
    公众的char [] xumridclientec20;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 1)] // 114
    公众的char [] xumrtipoidclientec01;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 8)]
    公众的char [] xumrusuarioclientec08;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 16)] // 138
    公众的char [] xumrprodutophac16;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 30)] // 168
    公众的char [] xumridservidorc30;
    [的MarshalAs(UnmanagedType.ByValArray,SizeConst = 10000)
    公众的char [] xumrdadosc10000;
}
 
C 11 C 14学习 2

有没有这样做的更好的办法?

编辑:

根据在贾斯汀陆克文的回答,我已经测试这个版本的结构的:

  [StructLayout(LayoutKind.Sequential,字符集= CharSet.Ansi)
内部结构PXUCAMRV3
{
    公共字符xumrversaocomc01;

    [的MarshalAs(UnmanagedType.ByValTStr,SizeConst = 2)]
    公共字符串xumrretcomc02;
    [的MarshalAs(UnmanagedType.ByValTStr,SizeConst = 2)]
    公共字符串xumrretusuc02;
    [的MarshalAs(UnmanagedType.ByValTStr,SizeConst = 5)]
    公共字符串xumrcodfalhac05;

    公共字符xumrfiller1c01;
    公共字符xumrtipoambclic01;
    公共字符xumrambientec01;
    公共字符xumrconvertec01;
    公共字符xumroperacaoc01;
    公共字符xumropcaoexec01; // 16

    [的MarshalAs(UnmanagedType.I4)
    公众诠释xumrhandleconnb31;
    [的MarshalAs(UnmanagedType.ByValTStr,SizeConst = 4)]
    公共字符串xumrreshconnc04;
    [的MarshalAs(UnmanagedType.I4)
    公众诠释xumrtamdadosb31;
    [的MarshalAs(UnmanagedType.ByValTStr,SizeConst = 8)] // 36
    公共字符串xumrtransacaosrvc08;
    [的MarshalAs(UnmanagedType.ByValTStr,SizeConst = 4)]
    公共字符串xumrtransrvdb2c04;

    / * ...相同的模式,以剩余的领域... * /
}
 

我已经尝试过在短短与成功的一些领域,但我改变了这一切,问题的返回值出现。例如,我把这个...

  pxucamrv3.xumrpgmservidorc08 =PHA preXW;
pxucamrv3.xumrversaopgmsrvc02 =01;
pxucamrv3.xumrpgmclientec08 =PHAOCLXN;
pxucamrv3.xumrversaopgmclientec02 =02;
pxucamrv3.xumridservidorc30 =N006;
pxucamrv3.xumrcodfalhac05 =00000;
pxucamrv3.xumrretcomc02 =00;
pxucamrv3.xumrretusuc02 =00;
 

...得到这个...

  pxucamrv3.xumrpgmservidorc08 ==PHA $ P $的pX
pxucamrv3.xumrversaopgmsrvc02 ==0
pxucamrv3.xumrpgmclientec08 ==PHAOCLX
pxucamrv3.xumrversaopgmclientec02 ==0
pxucamrv3.xumridservidorc30 ==N006
pxucamrv3.xumrcodfalhac05 ==01
pxucamrv3.xumrretcomc02 ==W
pxucamrv3.xumrretusuc02 ==0
 

...我们可以看到,有一个与弦的编组/解组的一个问题。在焦炭领域正在寻找好的。这不是一个映射的问题,作为字符串字段的一开始就都ok。但它似乎是截断字符串的末尾。而我的测试呼叫不应返回一个错误(使用previous结构,它的工作原理),故C例程没有接收数据,因为它应该太(应该仅返回零的 xumrretcomc02 的;返回的W是指有一个错误,但是我有很多错误codeS开始的W)

我会继续挖进去。

再次对不起我的英文不好。 :)

解决方案

最后我用一个字节数组作为结构的重新presentation,并使用生成器设置的值。在性能提升并不大,但它的存在。还有就是内存的优势也一样,我可以固定在内存中,并直接发送到非托管程序。它实际上帮助我一个问题:这个结构有两个版本,有diferent的 xumrdadosc10000 的大小...原来是10000个字节,但新的一个是200000个字节,但名称是相同的兼容的目的。所以,我可以创建在构造大小合适,而且离我去了。

  ///<总结>构建PXUCAMR / PXUCAMRV3作为一个字节数组< /总结>
内部类PxucamrBuilder
{
    内部字节[] Pxucamr;

    ///<总结>获取/设置现场xumrversaocomc01,偏移量为0,大小为1字节< /总结>
    内部字符串StructureVersion
    {
        {返回Encoding.ASCII.GetString(this.Pxucamr,0,1); }
        集合{Encoding.ASCII.GetBytes(值,0,1,this.Pxucamr,0); }
    }

    ///<总结>获取/设置现场xumrambientec01,偏移12,大小为1字节< /总结>
    内部字符串上下文
    {
        {返回Encoding.ASCII.GetString(this.Pxucamr,12,1); }
        集合{Encoding.ASCII.GetBytes(值,0,1,this.Pxucamr,12); }
    }

    ///<总结>获取/设置现场xumrcodfalhac05,偏移5,大小5个字节< /总结>
    内部字符串错误code
    {
        {返回Encoding.ASCII.GetString(this.Pxucamr,5,5); }
        集合{Encoding.ASCII.GetBytes(值,0,5,this.Pxucamr,5); }
    }

    ///<总结>获取/设置现场xumridservidorc30,偏移130,大小30个字节< /总结>
    内部字符串服务器ID
    {
        {返回Encoding.ASCII.GetString(this.Pxucamr,130,30); }
        集合{Encoding.ASCII.GetBytes(值0,value.Length,this.Pxucamr,130); }
    }

    ///<总结>获取/设置现场xumrtamdadosb31,偏移24,大小为4个字节< /总结>
    内部INT数据大小
    {
        得到
        {
            字节[]字节=新字节[4];
            Array.Copy(this.Pxucamr,24,字节,0,4);
            返回this.ByteArrayToInt32(字节);
        }
        组
        {
            字节[]字节= this.Int32ToByteArray(值);
            Array.Copy(字节,0,this.Pxucamr,24,4);
        }
    }

    / * ...相同的模式,以剩余的领域... * /
}
 

偏移量,可以方便地与的 Marshal.OffsetOf 的方法发现。

由于我使用的这一个,我将标志着这个答案是正确的。但是,如果一个更好的答案来了我可以改变它。我还是愿意尝试新的想法!

I have to use a legacy C routine in the application I am developing. The code in here works, but I have to convert almost all the fields to char arrays in order to use it. There is a better way to do it? I have tried some version using strings, all to no avail.

This is the code found in the original header file...

typedef struct PXUCAMR
{
   char xumrversaocomc01;
   char xumrretcomc02[2];
   char xumrretusuc02[2]; 
   char xumrcodfalhac05[5];
   char xumrfiller1c01; 
   char xumrtipoambclic01; 
   char xumrambientec01; 
   char xumrconvertec01; 
   char xumroperacaoc01; 
   char xumropcaoexec01; 
   xumrcom_t *xumrhandleconnb31;
   char xumrreshconnc04[4];
   long xumrtamdadosb31; 
   char xumrtransacaosrvc08[8];
   char xumrtransrvdb2c04[4];
   char xumrpgmservidorc08[8]; 
   char xumrversaopgmsrvc02[2];
   char xumrconectardbc01;
   char xumrusuariosrvc08[8];
   char xumrsenhasrvc08[8]; 
   char xumridcriptc08[8];
   char xumrpgmclientec08[8];
   char xumrversaopgmclientec02[2]; 
   char xumridclientec20[20];  
   char xumrtipoidclientec01;
   char xumrusuarioclientec08[8];
   char xumrprodutophac16[16]; 
   char xumridservidorc30[30]; 
   char xumrdadosc10000[10000];
}
pxucamr_t;

... and this is the declaration I am using in my C# app...

[StructLayout(LayoutKind.Sequential)]
internal struct PXUCAMR
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumrversaocomc01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public char[] xumrretcomc02;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public char[] xumrretusuc02;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
    public char[] xumrcodfalhac05;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumrfiller1c01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumrtipoambclic01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumrambientec01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumrconvertec01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumroperacaoc01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // 16
    public char[] xumropcaoexec01;
    [MarshalAs(UnmanagedType.I4)]
    public int xumrhandleconnb31;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public char[] xumrreshconnc04;
    [MarshalAs(UnmanagedType.I4)]
    public int xumrtamdadosb31;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 36
    public char[] xumrtransacaosrvc08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public char[] xumrtransrvdb2c04;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public char[] xumrpgmservidorc08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    public char[] xumrversaopgmsrvc02;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
    public char[] xumrconectardbc01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] // 67
    public char[] xumrusuariosrvc08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public char[] xumrsenhasrvc08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public char[] xumridcriptc08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public char[] xumrpgmclientec08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] // 93
    public char[] xumrversaopgmclientec02;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public char[] xumridclientec20;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // 114
    public char[] xumrtipoidclientec01;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public char[] xumrusuarioclientec08;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] // 138
    public char[] xumrprodutophac16;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)] // 168
    public char[] xumridservidorc30;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10000)]
    public char[] xumrdadosc10000;
}

Is there a better way of doing it?

EDIT:

Based in Justin Rudd's answer, I have tested this version of the struct:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
internal struct PXUCAMRV3
{
    public char xumrversaocomc01;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
    public string xumrretcomc02;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
    public string xumrretusuc02;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
    public string xumrcodfalhac05;

    public char xumrfiller1c01;
    public char xumrtipoambclic01;
    public char xumrambientec01;
    public char xumrconvertec01;
    public char xumroperacaoc01;
    public char xumropcaoexec01; // 16

    [MarshalAs(UnmanagedType.I4)]
    public int xumrhandleconnb31;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string xumrreshconnc04;
    [MarshalAs(UnmanagedType.I4)]
    public int xumrtamdadosb31;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] // 36
    public string xumrtransacaosrvc08;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    public string xumrtransrvdb2c04;

    /* ... same pattern to remaining fields ... */
}

I have tried it in just some fields with success, but I changed all of it, problems with the returning values appear. For example, I send this...

pxucamrv3.xumrpgmservidorc08 = "PHAPREXW";
pxucamrv3.xumrversaopgmsrvc02 = "01";
pxucamrv3.xumrpgmclientec08 = "PHAOCLXN";
pxucamrv3.xumrversaopgmclientec02 = "02";
pxucamrv3.xumridservidorc30 = "N006";
pxucamrv3.xumrcodfalhac05 = "00000";
pxucamrv3.xumrretcomc02 = "00";
pxucamrv3.xumrretusuc02 = "00";

... and get this ...

pxucamrv3.xumrpgmservidorc08 == "PHAPREX"
pxucamrv3.xumrversaopgmsrvc02 == "0"
pxucamrv3.xumrpgmclientec08 == "PHAOCLX"
pxucamrv3.xumrversaopgmclientec02 == "0"
pxucamrv3.xumridservidorc30 == "N006"
pxucamrv3.xumrcodfalhac05 == "01 "
pxucamrv3.xumrretcomc02 == "W"
pxucamrv3.xumrretusuc02 == "0"

... as we can see, there is a problem with the marshalling/unmarshalling of strings. The char fields are looking alright. It's not a mapping problem, as the beggining of the string fields are ok. But it seems to be truncating the end of the strings. And my test call should not return an error (using the previous struct, it works), so the C routine didn't receive the data as it should too (should return only zeros in xumrretcomc02; the returned "W" means there is an error, but I there are lots of error codes starting in "W").

I will keep digging into it.

Again, sorry for my poor english. :)

解决方案

I ended up using a byte array as the representation of the struct, and using a builder to set the values. The performance gain is not big, but it is there. And there is memory advantages too, as I can pin it in memory and send it directly to the unmanaged routine. It actually helps me with another problem: this struct has two versions, with diferent xumrdadosc10000 sizes... the original one is 10000 bytes, but the new one is 200000 bytes, but the name is the same for compatibility purposes. So, I can create the right size in the constructor, and off I go.

/// <summary>Builds PXUCAMR/PXUCAMRV3 as a byte array.</summary>
internal class PxucamrBuilder
{
    internal byte[] Pxucamr;

    /// <summary>Get/set field xumrversaocomc01, offset 0, size 1 byte.</summary>
    internal string StructureVersion
    {
        get { return Encoding.ASCII.GetString(this.Pxucamr, 0, 1); }
        set { Encoding.ASCII.GetBytes(value, 0, 1, this.Pxucamr, 0); }
    }

    /// <summary>Get/set field xumrambientec01, offset 12, size 1 byte.</summary>
    internal string Context
    {
        get { return Encoding.ASCII.GetString(this.Pxucamr, 12, 1); }
        set { Encoding.ASCII.GetBytes(value, 0, 1, this.Pxucamr, 12); }
    }

    /// <summary>Get/set field xumrcodfalhac05, offset 5, size 5 byte.</summary>
    internal string ErrorCode
    {
        get { return Encoding.ASCII.GetString(this.Pxucamr, 5, 5); }
        set { Encoding.ASCII.GetBytes(value, 0, 5, this.Pxucamr, 5); }
    }

    /// <summary>Get/set field xumridservidorc30, offset 130, size 30 bytes.</summary>
    internal string ServerId
    {
        get { return Encoding.ASCII.GetString(this.Pxucamr, 130, 30); }
        set { Encoding.ASCII.GetBytes(value, 0, value.Length, this.Pxucamr, 130); }
    }

    /// <summary>Get/set field xumrtamdadosb31, offset 24, size 4 byte.</summary>
    internal int DataSize
    {
        get
        {
            byte[] bytes = new byte[4];
            Array.Copy(this.Pxucamr, 24, bytes, 0, 4);
            return this.ByteArrayToInt32(bytes);
        }
        set
        {
            byte[] bytes = this.Int32ToByteArray(value);
            Array.Copy(bytes, 0, this.Pxucamr, 24, 4);
        }
    }

    /* ... same pattern to remaining fields ... */   
}

The offsets can be easily found with the Marshal.OffsetOf method.

As I am using this one, I will mark this answer as the correct one. But I can change it if a better answer comes up. I am still willing to try new ideas!