3

在库的 C++ 标头中有以下代码

#define STR_DATE        24+1    
#define STR_SIZE        32+1
#define STR_SSIZE       64+1
#define STR_MSIZE       128+1
#define STR_LSIZE       1024+1
#define STR_IPSIZE      15+1
#define STR_MOD_SIZE    20+1
#define STR_AGESIZE     4+1
#define STR_GENDERSIZE  1+1

typedef struct ADO_PINFO{   
    char    P_ID[STR_SSIZE];        
    char    F_Name[STR_SSIZE];          
    char    M_Name[STR_SSIZE];          
    char    L_Name[STR_SSIZE];          

    char    Reg_Num[STR_SSIZE];         
    UINT    nGender;                    
    UINT    nAge;                       

    COleDateTime BirthDay;              
    char    csBirthDay[STR_SIZE];       

    COleDateTime V_Date;                
    char    csV_Date[STR_SIZE];         

    char    Address[_MAX_PATH];         
    char    SubAddress[_MAX_PATH];      

    char    Telephone[STR_SIZE];        
    char    H_Phone[STR_SIZE];          

    char    csMail[STR_SSIZE];
    char    csPicName[_MAX_PATH];       
    COleDateTime InDate;
    char    csInDate[STR_SIZE];
}*PADO_PINFO;

_ADODLL long ADO_AddPatientData(const ADO_PINFO &pPatientInfo);

我正在尝试将 dll 导入我的 C# 应用程序:

[StructLayout(LayoutKind.Sequential)]
public struct ADO_PINFO
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string P_ID;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string F_Name;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string M_Name;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string L_Name;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string Reg_Num;

    public uint nGender;

    public uint nAge;

    public DateTime BirthDay;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string csBirthDay;

    public DateTime V_Date;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string csV_Date;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string Address;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string SubAddress;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string Telephone;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string H_Phone;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string csMail;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string csPicName;

    public DateTime InDate;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string csInDate;
}

public class VatechLibrary
{
    [DllImport("AdodllE.dll")]
    public static extern long ADO_AddPatientData(ref ADO_PINFO patientInfo);
}

但是当我尝试共同调用它时:

var pInfo = new ADO_PINFO();
pInfo.P_ID = "77";
pInfo.F_Name = "name";

var res = VatechLibrary.ADO_AddPatientData(ref pInfo);

我得到 AccessViolationException。我究竟做错了什么?

4

5 回答 5

2

我可以看到的问题:

  1. COleDateTime您对字段的编组是错误的。那是因为COleDateTime它是一个 C++ 类,它们根本不是二进制互操作的有效类型。和.netDateTime肯定不匹配。这肯定是您访问违规的根源。
  2. 该函数返回一个long在 Windows 上为 32 位宽的 C++。所以你的 C# 函数声明是错误的,因为 C#long是 64 位宽的。将 C# 中的返回值更改为int.
  3. 您的 C# 调用约定是stdcall. C++ 函数的调用约定是什么?这大概包含在_ADODLL. 您需要检查它是否是stdcall. 如果未指定调用约定,则为cdecl.

问题COleDateTime是这里的大问题。其他的很容易解决。不是这样COleDateTime。您可以更改 C++ 代码以接受日期的互操作友好表示。如果您无法更改 C++ 代码来处理第 1 项的问题,那么您的解决方案将涉及编写混合模式 C++/CLI 包装器。

于 2013-11-12T16:41:10.443 回答
0

如果我猜的话,我会说您需要在 C# 结构声明中的结构布局上将字符编码指定为 ANSI。ByValTStr 将携带包含结构的编码,并基于您使用 char 的 C++ 结构,我认为您需要将它们编码为 Ansi。

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

来自 MSDN http://msdn.microsoft.com/en-us/library/s9ts558h(v=vs.110).aspx

UnmanagedType.ByValTStr

一个固定长度的字符数组;数组的类型由包含结构的字符集决定。

于 2013-11-12T16:20:11.347 回答
0

您应该查看结构,类型 COleDateTime 是一个 C++ 类,不必创建属性来直接进行互操作。查看您需要访问的项目并重做布局。

于 2013-11-12T17:02:01.877 回答
0

从文档中UnmanagedType.ByValTStr

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

你的字符集是什么?我的猜测是unicode。

于 2013-11-12T15:16:13.437 回答
0

您可能还需要将Pack=1 添加到您的 StructLayout 属性。
大多数字符串/数组的字节数都是奇数,默认情况下,.NET 会将每个字符串/数组填充到偶数字节边界。

于 2013-11-12T16:26:58.177 回答