|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Передача массива из DLL в основную программу
В DLL у меня происходят вычисления и в основную программу передается массив записей.
Но, почему то после успешной отработки DLL я не могу работать с возвращенными данными Собственно код... Код:
Общий класс основной программы и DLL ... type TKoef = Record name: PChar; abbr: PChar; val_bgn: real; val_end: real; delta: real; criterion: boolean; cr_min: real; cr_max: real; dev_bgn: boolean; dev_end: boolean; dev_bgn_val: real; dev_end_val: real; info: PChar; valid: boolean; end; Основная программа ... type TArr = array of TKoef; TPArr = ^TArr; ... procedure TfMain.mModuleCalcClick(Sender: TObject); var Arr: TArr; PArr: TPArr; begin try try hDLL := LoadLibrary(PAnsiChar(FN)); @GetModuleData := nil; if hDLL >= 32 then begin @GetModuleData := GetProcAddress(hDLL,'GetModuleData'); if (@GetModuleData<>nil) then begin SetLength(Arr,5); PArr := Addr(Arr); if GetModuleData(ORG, PArr) then begin ---> вот здесь я пытаюсь работать с Arr, но вылетают ошибки end; end; end; finally @GetModuleData := nil; FreeLibrary(hDLL); end; except end; end; ... DLL ... const KOEF_CLOUNT = 5; type TArr = array[1..KOEF_CLOUNT] of TKoef; TPArr = ^TArr; ... function GetModuleData(dllORG: TOrganization; aPArr:TPArr): Boolean; stdcall; begin with aPArr^[1] do begin ... end; ... with aPArr^[5] do begin ... end; end; ... |
#2
|
|||
|
|||
Ну так в основной программе
Код:
array of TKoeff Код:
array [1..of KOEF_CLOUNT] TKoeff В основной программе надо Код:
type TArr = array of TKoef; TPArr = ^TKoef; // <<==-- Вот TGetModuleData = function (dllORG: TOrganization; aPArr:TPArr): Boolean; stdcall; ... PArr := @(Arr[0]); //<<==-- Вот if GetModuleData(ORG, PArr) ... |
#3
|
||||
|
||||
И еще в процедурах, которые возвращают данные в параметрах, обьявляй эти параметры после var.
Код:
function GetModuleData(dllORG: TOrganization;var aPArr:TPArr): Boolean; stdcall; |
#4
|
|||
|
|||
Всем спасибо.
Сделал так: передача массива не через указатель на массив, а собственно передача динамического массива. И в программе и в ДЛЛ стал использовать единый тип (динамический массив). Все работает. |
#5
|
|||
|
|||
Цитата:
А вот это вредный совет. |
#6
|
|||
|
|||
Цитата:
А для такого способа не забывать внимательно читать комментарий, который Delphi пишет в заготовке проекта DLL. |
#7
|
|||
|
|||
Не совсем понял о чем речь...
|
#8
|
||||
|
||||
Цитата:
Насчет поста о комментарии в DLL - я тоже ничего не понял. Там, кажись, написано о строках, а не динамических массивах. ИМХО все из-за совместимости dll для разных языков программирования. И ТС использует PChar, String нигде нет. |
#9
|
|||
|
|||
В алгоритме, который привёл автор топика, в DLL передаётся указатель на уже выделенную память, в DLL она только заполняется. Поэтому лишний var тут не нужен. Var может понадобится в случае, когда передаётся структура и в DLL она будет изменена. Посмотрите модуль windows.pas. Во многих случаях, когда в API функции требуется указатель на переменную или структуру, в паскале используется синтаксис в var. А когда нужен массив - используются указатели.
По поводу комментария - механизм работы со строками и динамическими массивами один и тот же. |
#10
|
|||
|
|||
Спасибо за информацию.
Сейчас вычисления в DLL проходят нормально и результаты я использую в основной программе, но при закрытии программы вылетает ошибка чтения памяти. Может надо какой ресурс очистить? Код ниже Это общий класс DLL и основной программы Код:
unit uExchange; interface uses SysUtils; const F1_COUNT = 67; F2_COUNT = 21; F5_COUNT = 10; type TKoef = Record name: String; abbr: String; val_bgn: Currency; val_end: Currency; delta: Currency; criterion: boolean; cr_type: integer; cr_min: Currency; cr_max: Currency; dev_bgn: boolean; dev_end: boolean; dev_bgn_val: Currency; dev_end_val: Currency; info: String; valid: boolean; end; TMKoef = array of TKoef; TModule = Record id: integer; koef_count: integer; mKoef: TMKoef; isCalc: Boolean; end; TOrganization = record FileName: String; Name: String; Address: String; Ruk: String; RukPhone: String; Buh: String; BuhPhone: String; INN: String; KPP: String; EMail: String; BankName: String; BankBIK: String; BankKS: String; OKPO: String; OKVED: String; Information: String; f1: array[1..4,1..F1_COUNT] of String; f2: array[1..4,1..F2_COUNT] of String; f5: array[1..4,1..F5_COUNT] of String; modules: array of TModule; end; implementation ... end. Это DLL Код:
library module1; uses uExchange, SysUtils; function GetModuleData(var O: TOrganization; module_number:integer): Boolean; stdcall; begin with O.modules[module_number].mKoef[0] do begin ... end; with O.modules[module_number].mKoef[1] do begin ... end; Result := True; end; exports GetModuleData; begin end. И код программы Код:
public ORG: TOrganization; ... GetModuleData: function(var O: TOrganization; module_number: integer): Boolean; stdcall; ... procedure TfMain.mModuleCalcClick(Sender: TObject); begin try try hDLL := LoadLibrary(PAnsiChar(FN)); @GetModuleData := nil; if hDLL >= 32 then begin @GetModuleData := GetProcAddress(hDLL,'GetModuleData'); if (@GetModuleData<>nil) then begin GetModuleData(ORG, 0) then begin end; end; finally @GetModuleData := nil; FreeLibrary(hDLL); end; except end; end; ... |
Этот пользователь сказал Спасибо Сергей77 за это полезное сообщение: | ||
OTVET (22.01.2013)
|
#11
|
||||
|
||||
to icWasya
Цитата:
Ну, если так, то сделай следующее: Обьяви динамический массив размером 5 и строку длиной 5 символов, затем попробуй обратится к массив[5] элементу и строка[5] элементу, а также массив[0] элементу и строка[0] элементу - скажи что получилось. И как dll должна реагировать на 0 элемент строки. Как я уже писал, в разных языках программирования (отчасти Delphi и C) строки отличаются друг от друга, и в С строка оканчивается на NULL(для признака последнего символа), в Delphi же в 0 индексе содержится информация о длне строки. Так что эта заметка к динамическим массивам отношения не имеет. to Сергей77 А если запускать не из среды программирования, вылеты тоже наблюдаются? |
#12
|
|||
|
|||
Да. При завершении работы выскакивает, что программа некорректные действия и та же ошибка памяти.
|
#13
|
|||
|
|||
>но при закрытии программы вылетает ошибка чтения памяти.
Ну вот как раз на такой случай и нужно прочитать комментарий в заготовке DLL. На этот раз у Вас в передаваемой структуре находятся строки, при работе с которыми возможно перевыделение памяти. |
Этот пользователь сказал Спасибо icWasya за это полезное сообщение: | ||
Сергей77 (03.10.2012)
|
#14
|
||||
|
||||
Ну да, как уже раньше писалось - у тебя в классах используются String, а их для отправки в DLL использовать не рекомендуется. Поменяй String на PChar или ShortString, или, как пишет в комментарии при создании DLL из визарда, пропиши ShareMem первим в разделе Uses, но тогда твоя прога будет зависимая от BORLANDMM.DLL. Выбирай меньшее из двух зол
|
#15
|
|||
|
|||
Спасибы.
Ваши ответы мне помогли. |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|
|