包含字符串的Marshal结构 - 在非托管C函数中接收的字符串不正确

时间:2015-08-24 08:39:15

标签: c# visual-c++ pinvoke marshalling unmarshalling

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct sName_d
{
[MarshalAs(UnmanagedType.LPStr)]
public string szCountry;
[MarshalAs(UnmanagedType.LPStr)]
public string szCommonName;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct sCertData_d
{
public Int32 dwVersion;

public sName_d sIssuer;

public sName_d sSubject;
}

public void GenerateCert()
{
sCertData_d cert = new sCertData_d();
sName_d caIssuer = new sName_d();
caIssuer.szCountry = "US";
caIssuer.szCommonName = "John";
sName_d caSubject = new sName_d();
caSubject.szCountry = "UK";
caSubject.szCommonName = "Johann";
cert.sIssuer = caIssuer;
cert.sSubject= caSubject;
NativeMethods.GenerateCert(ref cert);
}

在上面的代码中,NativeMethods.GenerateCert是C的非托管函数。 当Call到达此函数内部时,我没有得到字符串值" John"," UK"," Johann"和"美国"。

[DllImport("AuthLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int GenerateCert(ref sCertData_d cert);

非托管函数原型就是这样 -

typedef struct sName_d
{
char szCountry[0x35];

char szCommonName[0x35];
}sName_d;

typedef struct sCertData_d
{
int version;
sName_d sIssuer;
sName_d sSubject;
}sCertData_d;
int GenerateCert(const sCertData_d *psCert);

1 个答案:

答案 0 :(得分:1)

sName_d的翻译错误。非托管结构是:

typedef struct sName_d
{
    char szCountry[0x35];
    char szCommonName[0x35];
} sName_d;

这些是内联字符数组。您将这些编组为UnmanagedType.LPStr。这是一个指向以null结尾的字符串的指针。您需要使用UnmanagedType.ByValTStr

  

用于出现在结构中的内嵌式固定长度字符数组。与ByValTStr一起使用的字符类型由应用于包含结构的System.Runtime.InteropServices.StructLayoutAttribute属性的System.Runtime.InteropServices.CharSet参数确定。始终使用MarshalAsAttribute.SizeConst字段指示数组的大小。   .NET Framework ByValTStr类型在结构中的行为类似于C风格的固定大小的字符串(例如,char s[5])。

您的翻译应该是:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct sName_d
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x35)]
    public string szCountry;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x35)]
    public string szCommonName;
}