#delphi
#delphi
Вопрос:
У меня есть приложение Delphi 5, в коде приложения вызывается функция в DLL, передающая целочисленные и строковые параметры, это хорошо работает, когда DLL вызывается статическим способом, при попытке динамического изменения не работает. как правильно передавать параметры для динамической работы? код выглядит следующим образом
основное приложение
function Modulo_Pptos_Operacion(No_Orden : Integer; pathBD : string; PathBDConf : String) : Integer ; stdcall;
external 'LIB_Pptos_Oper.dll';
Modulo_Pptos_Operacion(DmDatos.OrdenesNO_Orden.AsInteger,
DmDatos.CiasPATHA.AsString, 'Alguna String');
DLL
Modulo_Pptos_Operacion function (No_Orden: Integer; PathDB: AnsiString; PathDBConfig: AnsiString): Integer; StdCall;
ДИНАМИЧЕСКИЙ СБОЙ
основного приложения
type
TDLLPpto = function(No_Orden : Integer; PathDB : AnsiString; PathDBConfig : AnsiString) : Integer;
var
DLLHandle: THandle;
: TDLLPpto;
PROCEDURE CALL
DLLHandle := LoadLibrary('LIB_Pptos_Oper.dll');
DLLHandle <> 0 then
begin
@DLLPpto := GetProcAddress(DLLHandle, 'Modulo_Pptos_Operacion');
end;
;
какой правильный путь?
Ответ №1:
Проблема, вероятно, в том, что вы смешиваете разные среды выполнения и, вероятно, разные кучи. Строки Delphi не являются допустимыми типами взаимодействия, поскольку их реализации варьируются от версии к версии.
В этом случае вы можете просто переключиться на использование строк с нулевым завершением, PAnsiChar .
Комментарии:
1. Точно. AnsiString НИКОГДА не бывает безопасным, даже если вы не смешиваете версии delphi, если только и основной EXE, и DLL не используют общую память (borlandmm.dll ) диспетчер памяти.
Ответ №2:
В случае динамически загружаемой dll вы пропустили stdcall;
директиву соглашения о вызове в объявлении TDLLPpto
. Тем не менее, рекомендуется использовать PAnsiChar
type для передачи строк через границы исполняемого файла.
Комментарии:
1. Это не только желательно, но и часто бывает нестабильным, если вы этого не сделаете. Приготовьтесь к случайной ошибке.
Ответ №3:
Макет ansistring изменился с Delphi XE: теперь также есть поле кодовой страницы с отрицательным смещением, а в D5 его нет. НАПРИМЕР: строки из D5 и DXE совершенно несовместимы. Таким образом, вы должны использовать PAnsiChar или PWideChar в своем интерфейсе, либо заканчивающийся нулем (строки Delphi всегда заканчиваются нулем), либо ввести дополнительный параметр с длиной, если строка может содержать # $ 00 байт.
Также: разные версии Delphi имеют разные менеджеры памяти. Если строка выделяется основным приложением и освобождается библиотекой DLL (строки подсчитываются по ссылкам), указатель get передается неправильному менеджеру памяти, что обычно приводит к повреждению памяти и, следовательно, к неприятным нарушениям доступа и т.д.
Другим решением является использование WideString ; это как в D5, так и в DXE равно COM BSTR stringtype и управляется ОС, а не менеджером памяти Delphi. Они совместимы. Единственная проблема в том, что они медленные по сравнению со строками Delphi и не учитываются ссылки.
В целом: при использовании интерфейсов DLL старайтесь избегать string, используйте PAnsiChar или PWideChar, или WideString
Комментарии:
1.
WideString
также является отличным выбором, который я опустил в своем ответе. Я сомневаюсь, что производительностьWideString
vsUnicodString/AnsiString
здесь имеет значение.2. @David: Я тоже в этом сомневаюсь, но эти ответы также читаются другими из-за их проблем, и обычно такая информация имеет значение ;-).