Вопрос, с которым столкнулся разработчик, заключается в использовании функций из динамически подключаемой библиотеки (DLL), написанной на Delphi, в приложении на C#. Согласно инструкции, сначала необходимо установить путь к XML-файлу с помощью функции SET_XML, а затем можно использовать любую другую функцию из библиотеки. Однако при попытке выполнения кода в C# возникает исключение AccessViolationException, указывающее на попытку чтения или записи защищенной памяти.
Описание проблемы
Пример кода на Visual Basic, который корректно использует функции из DLL:
Public Declare Function SET_XML_PATH Lib "fan.dll" (ByRef path As String) As Long
Public Declare Function GET_CALCULATION_FAN_ALONE Lib "fan.dll" (ByRef path As String) As Long
Sub Main()
Dim a As Long, b As Long, Str_Result As String, Str_Input As String
Str_Input = "C:\path\to\directory"
a = SET_XML_PATH(Str_Input)
Str_Result = "65464;;;1,2;;23;424,8;0,3766;;"
b = GET_CALCULATION_FAN_ALONE(Str_Result)
End Sub
Переписанный код на C# вызывает исключение AccessViolationException:
const string _dllLocation = "EbmPapstFan.dll";
[DllImport(_dllLocation)]
public static extern long SET_XML_PATH(ref String path);
[DllImport(_dllLocation)]
public static extern long GET_CALCULATION_FAN_ALONE(ref String fanDescription);
public Main()
{
String path = @"C:\path\to\directory";
long a = SET_XML_PATH(ref path);
String fanDescription = "65464;;;1,2;;23;424,8;0,3766;;";
long c = GET_CALCULATION_FAN_ALONE(ref fanDescription);
// Здесь может возникнуть AccessViolationException
}
Подтвержденный ответ
Проблема может быть связана с различиями в соглашениях вызова функций между C# и Delphi. Delphi часто использует "fastcall" соглашение, которое отличается от "stdcall" по умолчанию в C#. Попытка изменить соглашение вызова на StdCall не привела к решению проблемы.
Одно из возможных решений - создать оболочку (wrapper) DLL на C++, которая будет вызывать функции Delphi и затем уже вызывать эту оболочку из C#. Это позволит устранить несоответствия в соглашениях вызова.
Пример кода оболочки на C++:
extern "C" __declspec(dllexport) long __stdcall SetXmlPath(char* path) {
// Вызов функции SET_XML из Delphi DLL
}
extern "C" __declspec(dllexport) long __stdcall GetCalculationFanAlone(char* fanDescription) {
// Вызов функции GET_CALCULATION_FAN_ALONE из Delphi DLL
}
Использование оболочки в C#:
[DllImport("Wrapper.dll")]
public static extern long SetXmlPath(ref String path);
[DllImport("Wrapper.dll")]
public static extern long GetCalculationFanAlone(ref String fanDescription);
public Main()
{
String path = @"C:\path\to\directory";
long a = SetXmlPath(ref path);
String fanDescription = "65464;;;1,2;;23;424,8;0,3766;;";
long c = GetCalculationFanAlone(ref fanDescription);
}
Создание оболочки позволяет стандартизировать соглашения вызова и устранить возможные проблемы с несоответствием типов данных и порядком их передачи.
Альтернативный ответ
Если создание оболочки не представляется возможным, стоит обратить внимание на настройки проекта Delphi, в частности, на параметры компиляции, которые могут влиять на соглашения вызова и экспорт функций.
Заключение
При работе с Interop между Delphi и C# важно учитывать различия в соглашениях вызова и типов данных. Создание оболочки DLL может быть эффективным решением для устранения возникающих проблем.
Разработчик столкнулся с ошибкой `AccessViolationException` при попытке вызвать функции из DLL, написанной на Delphi, в приложении на C#, из-за различий в соглашениях вызова между этими двумя языками программирования.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS