Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Вызов dll из разных мест


Автор: Mailman 16.6.2006, 01:17
Итак, пусть у нас есть некий проект, состоящий из exe и энного набора динамич библиотек. Многие из библиотек, а также exe вызывают функцию(и) одной dll. Сейчас это происходит статически. Проблема состоит в том, что к процессу приложения подгружается столько экземпляров dll, из скольки модулей она загружалась. Также, соответственно, процедура инициализации dll (между begin и end.) происходит такое же количество раз и каждая часть проекта работает со своим экземпляром.

Вопрос мой состоит в том, как сделать так, чтобы библиотека подгружалась 1 раз или хотя бы инициализировалась один раз (методы обхода этого не предлагать - сам умею). Я видел справку по DllProc, но сам попробовать пока не успел. Можно ли решить вопрос с помощью определения обработчика с помощью DllProc? Если да/нет, то как это сделать?

Заранее спасибо.  

Автор: bems 16.6.2006, 01:23
Код

procedure LibraryProc(reason:integer);
begin
case reason of
 DLL_PROCESS_ATTACH:begin
   
                   end;
 DLL_PROCESS_DETACH:begin

                   end;
end;
end;

begin
DLLProc:=@LibraryProc;
LibraryProc(DLL_PROCESS_ATTACH);
end. 
  

Автор: Mailman 16.6.2006, 11:23
Хм, мысь конечно интересная, но что это меняет? Всё равно DLL_PROCESS_ATTACH вызывается прикаждой подгрузке библ из каждого модуля (... LibraryProc(DLL_PROCESS_ATTACH); ...) Ты же сам так написал. Таким образом количество экземпляров и количество раз инициализации нисколько не изменилось.

ЗЫ Мож я что не так понял? 

Автор: Guedda 16.6.2006, 12:19
Цитата(Mailman @  16.6.2006,  12:23 Найти цитируемый пост)
ЗЫ Мож я что не так понял?

Как раз таки "да"...
Ты видишь, что он проинициализировал в процедуре заново константы DLL_PROCESS_ATTACH & etc...
И сделал, как ты можешь видить, их пустыми. 

Автор: DragonFire 16.6.2006, 12:31
Guedda
Чет я не понял ниче, можешь коментарии расставить че это за строки, поподробнее... И куда это писать? в библиотеку? 

Автор: Mailman 16.6.2006, 12:33
Хм. Как я уже сказал у меня это не сработало.

Guedda, покажи мне плз то место в коде, где он их проинициализировал, может я просто этого не заметил?

Добавлено @ 12:37 
Да, это писать в библиотеку. Строки след-го содержания - присвоить указателю на обработчик системных вызовов в длл линк на процедуру LibraryProc, вызвать её при инициализации библиотеки. Внутри процедуры - case по случаю того, что же собственно произошло. 

Автор: drkot 16.6.2006, 13:20
Может так:
  загрузить библиотеку в главном модуле (loadlibrary)
  во вспомогательные передавать указатель и там находить нужную процедуру (GetProcAddress)


возможно получится напрямую адресс передавать (хотя сомнительно)
 

Автор: DragonFire 16.6.2006, 14:35
Хм. А вот это мне нравится. Спасибо, я попробую.

Напрямую... Хм. Не буду спрашивать, как. Просто за этой фразой была идея, или просто мысль такая?
Mailman. 

Автор: drkot 16.6.2006, 14:53
Идея, не идея так предположение.
Если адресс кода процедуры для всей системы, а не для процесса то может сработать.
А для передачи можно много способов придумать. Начиная от банального - в виде параметра функции, до отображаемых файлов и реестра.

Добавлено @ 14:54 
Цитата(DragonFire @  16.6.2006,  14:35 Найти цитируемый пост)
 я попробую.

сообщи о результате, а то самому проверять щас времени нет  smile  

Автор: bems 16.6.2006, 17:16
Цитата(Mailman @  16.6.2006,  01:17 Найти цитируемый пост)
Проблема состоит в том, что к процессу приложения подгружается столько экземпляров dll, из скольки модулей она загружалась
Нет. Происто увеличивается щетцик ссылок на библиотеку.
Цитата(Mailman @  16.6.2006,  01:17 Найти цитируемый пост)
Также, соответственно, процедура инициализации dll (между begin и end.)происходит такое же количество раз и каждая часть проекта работает со своим экземпляром.
Это правда только если один модуль загрузил длл, потом выгрузил, потом другой загрузил. Если подключаешь статически, то вообще иниц. она только один раз.
Цитата

DLL_PROCESS_ATTACH    
Indicates that the DLL is attaching to the address space of the current process as a result of the process starting up or as a result of a call to LoadLibrary. DLLs can use this opportunity to initialize any instance data or to use the TlsAlloc function to allocate a thread local storage (TLS) index.
During initial process startup or after a call to LoadLibrary, the operating system scans the list of loaded DLLs for the process. For each DLL that has not already been called with the DLL_PROCESS_ATTACH value, the system calls the DLL's entry-point function. This call is made in the context of the thread that caused the process address space to change, such as the primary thread of the process or the thread that called LoadLibrary.

 А код который я выше привел это как наглядно и похоже на стиль МС. Нв самом деоле из этого же кода видно, что DLL_PROCESS_ATTACH это и есть то что между begin-end. И виноват в єтом стартовый код длл от дельфей.

 

Автор: Mailman 16.6.2006, 17:26
Цитата(bems @  16.6.2006,  17:16 Найти цитируемый пост)
Это правда только если один модуль загрузил длл, потом выгрузил, потом другой загрузил. Если подключаешь статически, то вообще иниц. она только один раз.

Ты не прав. При старте приложения все модули загрузили библиотеку. Она проинициализировалась много раз.


Цитата(bems @  16.6.2006,  17:16 Найти цитируемый пост)
 Нв самом деоле из этого же кода видно, что DLL_PROCESS_ATTACH это и есть то что между begin-end. И виноват в єтом стартовый код длл от дельфей.

С этим согласен. Таким образом это подтверждает нерабочесть данного метода.


drkot, спасибо, я просто сразу не понял, что ты имел ввиду адрес процедуры полученный (GetProcAddress). Я попробую, тебе в ПМ напишу. 

Всё, мои вопросы кончились, спасибо всем. 

Автор: Демо 16.6.2006, 17:27
Цитата(Mailman @  16.6.2006,  01:17 Найти цитируемый пост)
и каждая часть проекта работает со своим экземпляром.


Ты уверен в этом?

LoadLibrary в адресное пространство загружает только одну копию DLL. 

Автор: drkot 16.6.2006, 17:58
скорее всего проблема не в количестве загруженных копий библиотеки (она должна быть одна, есди винда не глючит  smile ), а то что видно как множество длл это наверное данные (переменные инициализированные в ней). И задача похоже зактючается в том, чтобы всем процессам были дотупны одни и теже данные.

Цитата(Mailman @  16.6.2006,  17:26 Найти цитируемый пост)
Всё, мои вопросы кончились, спасибо всем

думаю они только начались. 

Автор: bems 16.6.2006, 18:06
Цитата(Mailman @  16.6.2006,  17:26 Найти цитируемый пост)
При старте приложения все модули загрузили библиотеку. Она проинициализировалась много раз.
Быть того не может. А с чего ты решил что инициализация была много раз? Как считал?

Цитата(drkot @  16.6.2006,  17:58 Найти цитируемый пост)
скорее всего проблема не в количестве загруженных копий библиотеки (она должна быть одна, есди винда не глючит   ), а то что видно как множество длл это наверное данные (переменные инициализированные в ней). 
А где они повторно инициализируются? Что вызывает LoadLibrary при повторном обращении к той же длл? Мне такие точки входа неизвестны.

Цитата(drkot @  16.6.2006,  17:58 Найти цитируемый пост)
думаю они только начались.  
и мне так кажется

 

Автор: Mailman 17.6.2006, 22:41
Нет нет нет. 

Во первых,  
Цитата(bems @  16.6.2006,  18:06 Найти цитируемый пост)
 Что вызывает LoadLibrary при повторном обращении к той же длл?
 
То, что к ней первый раз обращаются из некоего исполняемого файла (dll или exe)

Во вторых,
Цитата(bems @  16.6.2006,  18:06 Найти цитируемый пост)
Быть того не может. А с чего ты решил что инициализация была много раз? Как считал?

Ну, у примеру посмотрел в своём таск менеджере. Во вторых при инициализации я пишу на консоль строку, я читать умею, как она пишется 3 раза. =)

В третьих,
Цитата(Демо @  16.6.2006,  17:27 Найти цитируемый пост)
LoadLibrary в адресное пространство загружает только одну копию DLL. 

Да. Только вот статически или динамически, но LoadLibrary вызывается из каждого модуля по разу.


Цитата(Демо @  16.6.2006,  17:27 Найти цитируемый пост)
и каждая часть проекта работает со своим экземпляром.
    
Ты уверен в этом?

Нет, но по-моему это так. Теперь это и не важно. Хотя по теории я прав.

И наконец, я воспользовался методом drkotа. Спасибо огромное за помощь. Да, указатель на функцию или процедуру по ходу глобален, так он удачно передаётся из 1й длл в exe, а exe спокойно выполняет функцию. Ещё раз спасибо большое. Я закончил.

Для тех, кому интересно - просто пример кода:

Библиотека:
Код

function GetAddr: pointer;
var
 h: Thandle;
begin
 h:= LoadLibrary('..\..\Logger\code\modLogger.dll');
 result:= GetProcAddress(h, 'DoLog');
end;


EXE:
Код

var
 DoLog: function (MsgText: ShortString): TexResult;

begin
 @DoLog:= GetAddr;
 DoLog('fghfgh');
 readln;
end.


Вот собственно и решение проблемы. Дальше - архетиктурный момент моей системы, но с этим я уже всё придумал и успешно реализую. Удачи. 

Автор: bems 18.6.2006, 09:17
Если не трудно, приведи пожалуйста кусочек кода, который загружает ДЛЛ в одно адресно пространство дважды 

Автор: Mailman 18.6.2006, 22:09
Procedure DoLog; external <path>;

Dll1:
DoLog

Dll2:
DoLog

smile

Добавлено @ 22:09 
А кто говорил про одно адресное пространство? 

Автор: bems 18.6.2006, 23:48
Цитата(Mailman @  18.6.2006,  22:09 Найти цитируемый пост)
А кто говорил про одно адресное пространство?  


Цитата(Mailman @  16.6.2006,  01:17 Найти цитируемый пост)
Проблема состоит в том, что к процессу приложения подгружается столько экземпляров dll, из скольки модулей она загружалась

Один процесс - одно адресное пространство
 

Автор: Mailman 19.6.2006, 01:38
Итак, да будет это итогом. 

DelphiHelp:
Код

Module handles are not global or inheritable. A call to LoadLibrary by one process does not produce a handle 
that another process can use ¾ for example, in calling GetProcAddress. The other process must make its own 
call to LoadLibrary for the module before calling GetProcAddress. 


Мой код работает. Но до поры до времени.
Соответственно вопросов больше нет.

Добавлено @ 01:49 
В дополнение хочется извиниться и сказать, что на самом деле вся эта мура была не нужна. В случае объявления функций не статически, а динамически всё подгружается всего один раз и работает как часики. 
Вот так в 2:49 начался мой денёк.
Всем удачи. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)