2013-11-12 2 views
3

В C++ заголовок библиотеки есть следующий кодAccessViolationException выброшен, когда я называю метод импортируется из DLL

#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. Что я делаю не так?

+2

COleDateTime - ваш заклятый враг, DateTime - это * не * замена. Разницы в размерах достаточно, чтобы объяснить AVE. Написание C++/CLI-обертки * рекомендуется * желательно. –

+0

В этом примере многое происходит. Я бы сводил его к простейшему примеру, который решает ошибку и затем работает. Вопросы/предложения: какая конвенция вызова _ADODLL? Попробуйте LayoutKind.Explicit и фиксированные смещения поля. Это также может быть ссылка C++ const. Не уверен точно, как эти маршаллы. – dkackman

+0

Явный макет - ужасный совет. Если вы не любите себя причиненную боль. И ссылка const не является проблемой. Это соответствует 'ref' просто отлично. –

ответ

0

Из документов для UnmanagedType.ByValTStr:

Используется для рядного, фиксированной длиной символьных массивов, которые появляются в пределах структуры. Тип символа, используемый с ByValTStr, определяется параметром System.Runtime.InteropServices.CharSet атрибута System.Runtime.InteropServices.StructLayoutAttribute, примененного к содержащейся структуре. Всегда используйте поле MarshalAsAttribute.SizeConst, чтобы указать размер массива. Типы .NET Framework ByValTStr ведут себя как строки C-style, фиксированные строки внутри структуры (например, char s [5]).

Какая у вас кодировка? Моя догадка - это что-то вроде юникода.

+0

Я пробовал использовать все доступные. Результат все тот же. – gisek

+0

По умолчанию charset - ANSI. Это не проблема. –

0

Если я должен был догадаться, я бы сказал, что вам нужно указать кодировку символов как ANSI в макете структуры в объявлении strcuture C#. ByValTStr будет нести кодировку содержащейся структуры и на основе вашей структуры C++ с использованием char, я думаю, что вам нужно, чтобы они были закодированы как Ansi.

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

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

UnmanagedType.ByValTStr

фиксированной длины массива символов; тип массива определяется набором символов содержащейся структуры.

+0

Это не помогло. Все те же исключения. – gisek

+0

По умолчанию используется Ansi. Это ничего не меняет. –

0

Вам также может понадобиться добавить Pack=1 to your StructLayout attribute.
Большинство ваших строк/массивов нечетное число байтов в длину и по умолчанию .NET подушечка каждый из тех, к границе четных байтов.

+0

Все то же самое :( – gisek

+1

* Никогда не делайте этого, компиляторы C или C++. –

+0

Никогда не кажется немного окончательным, конечно, иногда это необходимо @HansPassant? Конечно, мне приходилось иногда использовать его, хотя это было очевидно здесь есть что-то, что мы ожидаем увидеть в определении заголовка, которое указывает, когда это или не подходит? – Nanhydrin

2

Проблемы, которые я могу видеть:

  1. Ваш сортировочных из COleDateTime полей неправильно. Это потому, что COleDateTime является классом C++, и они просто недействительны для двоичного взаимодействия. И .net DateTime, конечно, не соответствует. Это, безусловно, является источником нарушения вашего доступа.
  2. Функция возвращает C++ long, которая имеет ширину 32 бит в Windows. Таким образом, ваше объявление функции C# неверно, потому что C# long имеет ширину 64 бит. Измените возвращаемое значение в C# на int.
  3. Ваш телефонный звонок C# - stdcall.Что такое вызывающая конвенция функции C++? Это предположительно содержится в _ADODLL. Вам нужно будет проверить, что это stdcall. Если соглашение о вызове не указано, оно равно cdecl.

Вопрос с COleDateTime здесь большой. Остальные легко фиксируются. Не так для COleDateTime. Вы можете изменить код C++, чтобы принять дружеское представление даты. Если вы не можете изменить код на C++ для решения проблемы элемента 1, ваше решение будет включать в себя создание смешанной оболочки C++/CLI.

0

Вы должны просмотреть структуру, тип COleDateTime - это класс C++, и не нужно создавать атрибут для взаимодействия напрямую. Просмотрите элементы, которые вам нужны для доступа, и повторите настройку.

Смежные вопросы