Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 788

/ вопрос решён /

Здравствуйте. У меня возник вопрос по загрузке функции из динамической библиотеки (плагина). Подробнее в приложении.
Заранее спасибо за помощь.

Приложение:
  1.  
  2. function PluginExec(text:string):string;
  3. begin
  4.  
  5. end;
  6. ....
  7. exports
  8. PluginExec;
  9.  
  10.  
  11. procedure TForm1.Button1Click(Sender: TObject);
  12. var
  13. PluginExec: function(text:string):string;
  14. LibHandle: THandle;
  15. begin
  16. LibHandle := LoadLibrary('LIB.DLL');
  17. if LibHandle <> 0 then begin
  18. PluginExec := GetProcAddress(LibHandle,'PluginExec');
  19. if PluginExec <> nil then
  20.  
  21. edit1.Text:=PluginExec(edit2.Text);
  22. end;
  23. FreeLibrary(LibHandle);
  24. end;


Phoenix Вопрос решён, но можно продолжить его обсуждение в мини-форуме

Вопрос задал: Phoenix (статус: Посетитель)
Вопрос отправлен: 24 июля 2007, 21:34
Состояние вопроса: решён, ответов: 4.

Ответ #1. Отвечает эксперт: Dron

Здравствуйте, Phoenix!
Вообще, когда используется динамическое связывание с DLL, функцию описывают типом данных, а не указывают явным образом как тип переменной. Т.е.

var
  PluginExec: function(text:string):string;
желательно заменить на:
type
   TMyFunc = function(text:string):string;
var
   PluginExec: TMyFunc;
Теперь по поводу ошибки. Если написано exports PluginExec;, то это ещё не означает, что функция будет видна для приложений. Чтобы функция действительно экспортировалась, нужно после её заголовка указать ключевое слово export (сделать это нужно в коде DLL):
function PluginExec(text:string):string; export;

Ответ отправил: Dron (статус: Студент)
Время отправки: 24 июля 2007, 22:13
Оценка за ответ: 5

Комментарий к оценке: спасибо за уточнение, буду знать наперед, но все-таки проблема в другом, буду разбираться

Ответ #2. Отвечает эксперт: Матвеев Игорь Владимирович

Здравствуйте, Phoenix!
Проблема в том, что передавать строки в параметрах Dll функций нельзя (ну вернее очень нежелательно), что собственно и написанно в пустом .dpr файле при создании нового проекта dll.

Замените тип string на PChar.

Ответ отправил: Матвеев Игорь Владимирович (статус: Студент)
Время отправки: 25 июля 2007, 03:24

Ответ #3. Отвечает эксперт: min@y™

Когда создаёшь DLL-проект, то IDE вставляет в файл здоровенный комментарий, вот такой вот:

{ Important note about DLL memory management: ShareMem must be the
first unit in your library\'s USES clause AND your project\'s (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

Переводить всё на русский язык неохота, скажу вкратце: если передаёшь строки из EXE в DLL и/или обратно, то надо вписать в раздел uses EXE и DLL проекта на первое место модуль ShareMem. А если строки короткие (<= 255 символов), то можно юзать ShortString. Если > 255 символов, то лучше юзать PChar (я так делаю). BORLNDMM.DLL - это борландовский хитрый менеджер памяти.

Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 25 июля 2007, 08:45

Ответ #4. Отвечает эксперт: Feniks

Здравствуйте, Phoenix!
С удовольствием отвечу тёске !!! :))

Все, что тебе выше изложили, чистая правда. ;-)
Только немного суховато и без ньюансов.
Я несколько лет назад на старой работе писал проект с использование своих DLL-ок.
И наступил на кучу граблей.
Попробую тебе изложить. Могу прислать и куски кодов.

Во-первых, что бы можно было юзать ф-цию или процедуру из ДЛЛ в других проектах, их надо экспортировать в ДЛЛке, при этом им надо указать имя под которым они будут видны в проекте или идексы.
Имя и/или идексы придумываешь сам. Или же, можно не давать имя или индекс, а оставить родное имя ф-ции.
Например, у тебя есть в ДЛЛки ф-ция ShowMessageForm. При экспорте, в разделе Export, даешь ей имя экспортируемое имя DisplayMessage (при этом это имя необязательно должно совпадать с реальным именем ф-ции ShowMessageForm) или индекс 101 (нумерация произвольная).
Export
ShowMessageForm name DisplayMessage;
или
Export
ShowMessageForm index 101;
или
Export
ShowMessageForm;

Лучше всего использовать индексы. Так рекомендуют классики и книги. На поиск ф-ции в длл-ки уходит тогда меньше времени.
Лично я всегда индексы юзаю. :))

Во-вторых, использовать/подключать функции из DLL-ки можно _динамически_ и _статически_.
_Статически_ - это когда ты в проекте в разделе Interface описываешь/объявляешь свою функцию из ДЛЛки:
function ShowMessageForm(MsgType : TMessageType; MsgCaption, MsgText : PChar): integer; External \'Util.Dll\' index 101;
И далее можешь смело ее сразу юзать где тебе надо в твоем проекте, но это длл-ка должна лежать там же, где и ЕХЕ-шник твоего проекта или в папке перемонной окружения PATH, что бы Винда смогла сразу найти библиотеку.
В таком слачае, при старте твоей проги Винда сразу ищит ДЛЛ-ку и в ней эту ф-цию и если того или другого там нет, вываливает ошибку и прога сворачивается.
Т.е. при их отсутствии работать не будет. А если все ОК, тада и прога и длл-ка грузятся в память, т.е. длл-ка полностью загружается и сидит там пока твоя прога работает.
Что есть не очень удобным...

В таком случае надо использовать _Динамический_ способ. Это когда сама длл-ка и нужная ф-ция подключаются динамически.
Это как раз тот способ, который ты используешь.
_Отличный пример тебе дал Градов Ю.М._

Ответ отправил: Feniks (статус: Бакалавр)
Время отправки: 25 июля 2007, 14:26
Оценка за ответ: 5

Комментарий к оценке: спасибо, это мне определенно пригодится.

Мини-форум вопроса

Всего сообщений: 6; последнее сообщение — 24 июля 2007, 23:05; участников в обсуждении: 3.
Градов Ю.М.

Градов Ю.М. (статус: 8-ой класс), 24 июля 2007, 22:06 [#1]:

Функция обычно вызывается так:

function PluginExec(text:string); external \'LIB.DLL\';
Градов Ю.М.

Градов Ю.М. (статус: 8-ой класс), 24 июля 2007, 22:13 [#2]:

Уточнение:
function PluginExec(text:string):string; external \'LIB.DLL\';
Phoenix

Phoenix (статус: Посетитель), 24 июля 2007, 22:16 [#3]:

так, конечно будет работать, я бы и не спрашивал, если бы мне нужно было простое прикрепление библиотеки к программе. Нужен именно динамический (!) способ подгрузки!
Градов Ю.М.

Градов Ю.М. (статус: 8-ой класс), 24 июля 2007, 22:31 [#4]:

Посмотрите вот этот пример из DelphiWorld:

unit uMain;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons;

type
TForm1 = class(TForm)
btnClose: TBitBtn;
btnReport: TBitBtn;
procedure btnReportClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.btnReportClick(Sender: TObject);
var
LibHandle: THandle;
fDisplaySampleReport: procedure;
begin
LibHandle := LoadLibrary(\'Report.dll\');
if LibHandle = 0 then
raise Exception.Create(\'Unable to Load DLL...\')
else
begin
try @fDisplaySampleReport := GetProcAddress(LibHandle, \'DisplaySampleReport\');
if @fDisplaySampleReport <> nil then
fDisplaySampleReport; // Invoke the Procedure within the DLL
except
on E: Exception do
ShowMessage(\'Exception error: \' + E.Message);
end;
end;
FreeLibrary(LibHandle); // Free Memory Allocated for the DLL
end;

end.

////////////////////////////////////////////////
// DLL Project

library Report;

uses SysUtils, Classes,
uReport in \'uReport.pas\' {Form1};

procedure DisplaySampleReport;
begin
Form1 := TForm1.Create(nil);
try
Form1.QuickRep1.Preview;
finally
Form1.Free;
end;
end;

exports DisplaySampleReport;

end.
Dron

Dron (статус: Студент), 24 июля 2007, 22:34 [#5]:

Phoenix: прочтите лучше мой ответ... По-моему, проблема должна решиться.
Если нет - укажите, какая именно ошибка возникает и в какой момент.
С уважением.
Phoenix

Phoenix (статус: Посетитель), 24 июля 2007, 23:05 [#6]:

дело в том, что не обрабатывается сама строка: edit1.Text:=PluginExec(edit2.Text);
Функция в библиотеке рабочая, проверено external\'ом.

31 января 2011, 20:02: Статус вопроса изменён на решённый (изменил модератор Ерёмин А.А.): Автоматическая обработка (2 и более ответов с оценкой 5)

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:42
Выполнено за 0.03 сек.