当我调用从dll导入的方法时抛出AccessViolationException

时间:2013-11-12 15:00:14

标签: c# c++ pinvoke dllimport

在库的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);
}

但是当我尝试co调用它时:

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

var res = VatechLibrary.ADO_AddPatientData(ref pInfo);

我收到AccessViolationException。我做错了什么?

5 个答案:

答案 0 :(得分:2)

我可以看到的问题:

  1. 您对COleDateTime字段的编组错误。那是因为COleDateTime是一个C ++类,它们根本不是二进制互操作的有效类型。并且.net DateTime肯定不匹配。这肯定是您违反访问权限的来源。
  2. 该函数返回一个C ++ long,在Windows上为32位宽。所以你的C#函数声明是错误的,因为C#long是64位宽。将C#中的返回值更改为int
  3. 您的C#调用约定为stdcall。 C ++函数的调用约定是什么?这大概包含在_ADODLL中。您需要检查它是stdcall。如果未指定调用约定,则为cdecl
  4. COleDateTime的问题在这里很重要。其他很容易修复。 COleDateTime不是这样。您可以更改C ++代码以接受日期的互操作友好表示。如果您无法更改C ++代码来处理第1项的问题,那么您的解决方案将涉及编写混合模式C ++ / CLI包装器。

答案 1 :(得分:0)

来自UnmanagedType.ByValTStr的文档:

  

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

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

答案 2 :(得分:0)

如果我猜测我会说你需要在C#strcuture声明中的struct layout上指定字符编码为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

     

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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