我应该如何声明这个C结构用于互操作?

Ric*_*lde 6 .net c c# pinvoke interop

我必须在我正在开发的应用程序中使用遗留的C例程.这里的代码可行,但我必须将几乎所有字段转换为char数组才能使用它.还有更好的方法吗?我试过一些使用字符串的版本,但都无济于事.

这是在原始头文件中找到的代码...

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;
Run Code Online (Sandbox Code Playgroud)

...这是我在C#应用程序中使用的声明......

[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;
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法呢?

编辑:

根据Justin Rudd的回答,我测试了这个版本的结构:

[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 ... */
}
Run Code Online (Sandbox Code Playgroud)

我已经在一些领域尝试了成功,但我改变了所有这些,返回值的问题出现了.例如,我发送这个......

pxucamrv3.xumrpgmservidorc08 = "PHAPREXW";
pxucamrv3.xumrversaopgmsrvc02 = "01";
pxucamrv3.xumrpgmclientec08 = "PHAOCLXN";
pxucamrv3.xumrversaopgmclientec02 = "02";
pxucamrv3.xumridservidorc30 = "N006";
pxucamrv3.xumrcodfalhac05 = "00000";
pxucamrv3.xumrretcomc02 = "00";
pxucamrv3.xumrretusuc02 = "00";
Run Code Online (Sandbox Code Playgroud)

......得到这个......

pxucamrv3.xumrpgmservidorc08 == "PHAPREX"
pxucamrv3.xumrversaopgmsrvc02 == "0"
pxucamrv3.xumrpgmclientec08 == "PHAOCLX"
pxucamrv3.xumrversaopgmclientec02 == "0"
pxucamrv3.xumridservidorc30 == "N006"
pxucamrv3.xumrcodfalhac05 == "01 "
pxucamrv3.xumrretcomc02 == "W"
pxucamrv3.xumrretusuc02 == "0"
Run Code Online (Sandbox Code Playgroud)

......正如我们所看到的,字符串的编组/解组存在问题.char字段看起来还不错.这不是映射问题,因为字符串字段的开始是可以的.但它似乎正在截断字符串的结尾.并且我的测试调用不应该返回错误(使用前面的结构,它可以工作),所以C例程没有收到数据,因为它也应该(在xumrretcomc02中只返回零;返回的"W"表示有一个错误,但我有很多以"W"开头的错误代码.

我会继续深入研究它.

再次,抱歉我的英语不好.:)

Ric*_*lde 5

我最终使用字节数组作为结构的表示,并使用构建器来设置值.性能提升并不大,但它确实存在.并且还有内存优势,因为我可以将其固定在内存中并将其直接发送到非托管例程.它实际上帮助我解决另一个问题:这个结构有两个版本,不同的xumrdadosc10000大小...原始的一个是10000字节,但新的是200000字节,但出于兼容性的目的,名称是相同的.所以,我可以在构造函数中创建正确的大小,然后关闭.

/// <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 ... */   
}
Run Code Online (Sandbox Code Playgroud)

使用Marshal.OffsetOf方法可以轻松找到偏移量.

当我使用这个时,我会将这个答案标记为正确答案.但如果有更好的答案,我可以改变它.我仍然愿意尝试新的想法!