Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.08.21;
Скачать: CL | DM;

Вниз

Динамический импорт функции из DLL   Найти похожие ветки 

 
Igit   (2005-06-23 11:43) [0]

Здравтсвйте мастера! Есть у меня одлин модуль, в нем описываются функции вызываемые из NTDLL.DLL...  они видны в таблице импорта... и из-за них под вин9x программа не запускается вовсе... (у меня в программе идет проверка какая винда и в зависимости от этого исп. тот или иной метод). Так вот, как можно переписать например вот это

Function DbgUiConnectToDbg(): NTStatus;stdcall;external "ntdll.dll";

на такое чтоб не жестко привязывалось к ntdll а динамически?


 
PVOzerski ©   (2005-06-23 11:45) [1]

В общем виде, используют сочетание функций LoadLibrary и GetProcAddress применительно к процедурной переменной.


 
-=XP=- ©   (2005-06-23 11:53) [2]

type
 TDbgUiConnectToDbg = function({параметры}): NTStatus; // Обявление процедурного типа

var
 Lib: THandle;
 DbgUiConnectToDbg: TDbgUiConnectToDbg; // "Будущая" процедура/функция
 Status: NTStatus;
begin
 Lib := LoadLibrary("ntdll.dll"); // Загрузка библиотеки
 if Lib <> 0 then // Если удачно, то
 try
   DbgUiConnectToDbg := GetProcAddress(Lib, "DbgUiConnectToDbg"); // Получение адреса процедуры/функции
   if Assigned(DbgUiConnectToDbg) then // Если процедура/функция найдена (адрес задан)
     Status := DbgUiConnectToDbg({параметры}); // Вызов процедуры/функции с передачей параметров и получением результата
 finally
   FreeLibrary(Lib); // Выгрузка библиотеки
 end;
end;


 
Igit   (2005-06-23 12:02) [3]

Все, понял, буду разбираться, спасибо!


 
begin...end ©   (2005-06-23 12:04) [4]

> -=XP=- ©   (23.06.05 11:53) [2]

Э-э-э... А stdcall не помешает?


 
-=XP=- ©   (2005-06-23 12:12) [5]

Э-э-э... А stdcall не помешает?

Э-э-э-э... естественно. :)
Для пущей надежности - safecall.

В контексте, автору:

TDbgUiConnectToDbg = function({параметры}): NTStatus; stdcall; {safecall;}


 
Igit   (2005-06-23 12:16) [6]

Я запутался... =(

Вот есть примерный модуль.

unit SuUnit;

interface
  uses windows;

////////////////////////// Ntdll.dll Functions ///////////////////////

Function ZwCreateThread(ThreadHandle: pdword;
                       DesiredAccess: ACCESS_MASK;
                       ObjectAttributes: pointer;
                       ProcessHandle: THandle;
                       ClientId: PClientID;
                       ThreadContext: pointer;
                       UserStack: pointer;
                       CreateSuspended: boolean):NTStatus;
                       stdcall;external "ntdll.dll";

implementation

end.

Как мне изменить его так, чтобы в самой программе и в других модулях использующих этот прошло все прозрачно, т.е. менять ничего не нужно было бы.


 
-=XP=- ©   (2005-06-23 12:34) [7]

unit SuUnit;

interface

uses
Windows;

type
TZwCreateThread = function(ThreadHandle: pdword;
                      DesiredAccess: ACCESS_MASK;
                      ObjectAttributes: pointer;
                      ProcessHandle: THandle;
                      ClientId: PClientID;
                      ThreadContext: pointer;
                      UserStack: pointer;
                      CreateSuspended: boolean):NTStatus;
                      stdcall;

var
 ZwCreateThread: TZwCreateThread;

implementation

end.


Только вот библиотеку загрузить надо. И указатель на функцию получить. В противном случае, при использовании неинициализированной процедурной переменной будет вызван Access Violation. Когда это (загрузку) сделать - Ваше дело. Главное, чтобы это было сделано до первого использования функции. Ну, или в любом месте, где используется эта функция - делать проверку:

if Assigned(ZwCreateThread) then ZwCreateThread({параметры});

Но, судя по вопросу - такая проверка невозможна.

Поэтому, можете пойти по другому пути - написать "подставную" функцию, возвращающую "подставной" результат. В разделе инициализации модуля написать:

implementation

function ZwCreateThread_Int({параметры}): NTStatus;
begin
 // Не забудьте определить возвращаемые значения
end;

initialization
 ZwCreateThread := @ZwCreateThread_Int;

end;


А если потом удастся загрузить внешнюю библиотеку - будете пользоваться ею.


 
-=XP=- ©   (2005-06-23 12:37) [8]

stdcall; - естественно, тоже указать. :)


 
Igit   (2005-06-23 12:44) [9]

Я не доконца понял, но навязался такой вопрос, может он глупый, но возник :) Т.к. функции в этом модуле вызываются только если запущена WinNT, то может неоязательно загружать библиотеку ntdd, она ведь в NT всегда загружена?


 
Digitman ©   (2005-06-23 12:52) [10]


> может неоязательно загружать библиотеку ntdd, она ведь в
> NT всегда загружена?


может и необязательно.

GetModulehandle() в дан.случае даст тот же результат, что и LoadLibrary()

разница в дан.случае практически неощутима - Load/FreeLibrary() инкрементирует/декрементирует некий (детали неважны) внутрисистемный сч-к использования библ-ки, кроме собссно ее штатной загрузки/иниц-ии/деиниц-ции/выгрузки, в то время как GetModuleHandle() просто ищет модуль в АП процесса, возвращает его хэндл (в случае с НТ - гарантированно), и этот хэндл в любой момент можно передать на вход GetProcAddress(), без опасений ан тему неактуальности в некий момент времени полученного адреса.


 
-=XP=- ©   (2005-06-23 12:54) [11]

она ведь в NT всегда загружена

Библиотека загружается или динамически (LoadLibrary) или статически (с указанием external).
Если модуль имеет объявления extrnal процедур/функций - то библиотека будет загружена автоматически при запуске приложения; если библиотека не обнаружится на компьютере - приложение не запустится никогда. Если нет явного указания (статического) использования внешних процедур/функций из этой библиотеки - она (библиотека) не будет загружена автоматически никогда. Для динамической загрузки используйте LoadLibrary.

Резюмируя: хотите кроссплатформенности - используйте динамическую загрузку библиотек; использование статического подключения библиотек, при отсутствии оных на компьютрере пользователя, вызовет аварийное завершение работы программы.


 
-=XP=- ©   (2005-06-23 12:56) [12]

GetModuleHandle() просто ищет модуль в АП процесса, возвращает его хэндл (в случае с НТ - гарантированно)

Почему?


 
Igit   (2005-06-23 13:04) [13]

-=XP=- Если модуль имеет объявления extrnal процедур/функций - то библиотека будет загружена автоматически при запуске приложения; если библиотека не обнаружится на компьютере

NativeAPI в NT берутся из ntdll... все АПИ используют NativeAPI, значит в NT она по идее загружена всегда.


 
-=XP=- ©   (2005-06-23 13:08) [14]

Так ntdd или ntdll? :)

Я описал ситуацию в общем, применительно к любой библиотеке.
Что делать в конкретном случае - Ваше дело. ;)


 
Digitman ©   (2005-06-23 13:14) [15]


> -=XP=- ©   (23.06.05 12:56) [12]
> Почему?


речь, очевидно, шла о ntdll.dll

импорт ее - статический

гоняй туда-сюда ее счетчик - выгрузить штатными ср-вами тебе ее не удастся

потому и сабж


 
-=XP=- ©   (2005-06-23 13:21) [16]

NativeAPI в NT берутся из ntdll... все АПИ используют NativeAPI, значит в NT она по идее загружена всегда.

program Test;
var
 f: TextFile;
begin
 AssignFile(f, "c:\test.txt");
 Rewrite(f);
 Writeln(f, "Я подозреваю, что в адресное пространство этого "приложения" не загружено ни одной библиотеки");
 CloseFile(f);
end.


Но это так, к примеру.

Еще раз: если в приложении есть статическая линковка какой-то библиотеки, то эта библиотека будет загружена в АП. Если статической линковки нет - библиотека загружена не будет. Исключение - когда одна библиотека линкует другую библиотеку. Но опираться на этот факт не стоит, ибо это недокументированное поведение.
Хотите в приложении знать, загружена ли библиотека, или нет - используйте как приведено в [10], но, все же, проверяйте Handle на валидность.


 
-=XP=- ©   (2005-06-23 13:26) [17]

речь, очевидно, шла о ntdll.dll

Если так - то да, в приложениях Delphi (с использованием VCL), работающих под NT, эта библиотека загружена всегда. Хотя, это поведение, насколько мне известно - не документированно Microsoft?


 
Igit   (2005-06-23 13:58) [18]

Так, проверить решил..

Заморозил выполнение на CloseFile(f); и посмотрел в LordPE. Вместе  сней загружены такие dll

rptc4.dll
advapi32.dll
gdi32.dll
user32.dll
kernel32.dll
ntdll.dll


И еще вопрос, я не понял, в коде
-=XP=- ©   (23.06.05 12:34) [7] куда передавать хэнд загруженной dll?


 
-=XP=- ©   (2005-06-23 14:20) [19]

Так, проверить решил..

О как! Век живи - век учись! :о)

куда передавать хэнд загруженной dll

В GetProcAddress(<Handle>, "<ProcName>");


 
Igit   (2005-06-23 14:28) [20]

Нет, неправильно выразился, в этом модуле

unit SuUnit;

interface

uses
Windows;

type
TZwCreateThread = function(ThreadHandle: pdword;
                     DesiredAccess: ACCESS_MASK;
                     ObjectAttributes: pointer;
                     ProcessHandle: THandle;
                     ClientId: PClientID;
                     ThreadContext: pointer;
                     UserStack: pointer;
                     CreateSuspended: boolean):NTStatus;
                     stdcall;

var
ZwCreateThread: TZwCreateThread;

implementation

end.


Куда нужно всавить GetModuleHandle и GetProcAddress чтобы в других модулях использующих эту функцию не нужно было ничего изменять?


 
-=XP=- ©   (2005-06-23 14:45) [21]

<...>
implementation
<...>
var
 Lib: THandle;
<...>
initialization
 if (<Под NT>) then
 begin
   Lib := LoadLibrary(<...>);
   ZwCreateThread := GetProcAddress(Lib, <...>);
   <...>
 end
 else
   <...>

finalization
 if (Lib <> 0) then FreeLibrary(Lib);

end.


 
Igit   (2005-06-23 16:11) [22]

Все зделал как положено, но

type
Function TZwCreateThread(<параметры>):NTStatus;stdcall;


выдает ошибку "Identifier expected but FUNCTION found"

Что я не так сделал?


 
Digitman ©   (2005-06-23 16:21) [23]


> Что я не так сделал?


ты нарушил языковые соглашения Паскаля, который ожидает в дан.случае следующее :

type
TZwCreateThread = Function(<параметры>):NTStatus;stdcall;

где TZwCreateThread - это тот самый cимвольный идентификатор типа, который expected, но вместо которого компилятор встретил зарезервированное ключ.слово function

строки в секции type должны соответствовать правилу

Символьный_Идентификатор_Типа = Выражение_описывающее_тип;


 
-=XP=- ©   (2005-06-23 16:34) [24]

Все зделал как положено, но

А это кому написано было:

type
 TZwCreateThread = function(ThreadHandle: pdword;
                      DesiredAccess: ACCESS_MASK;
                      ObjectAttributes: pointer;
                      ProcessHandle: THandle;
                      ClientId: PClientID;
                      ThreadContext: pointer;
                      UserStack: pointer;
                      CreateSuspended: boolean):NTStatus;
                      stdcall;


 
Igit   (2005-06-23 16:44) [25]

Спасибо большое всем вам за помощь! У меня все получилось... зделал для себя вывод: забыл я все, нужно прочитать про синтаксис паскаля, и организацию модулей.


 
Игорь Шевченко ©   (2005-06-23 19:13) [26]

http://www.schevchenko.net.ru/SRC/Common_60.zip

Там пример (ntdll.pas) который меня ни разу не подводил. Изучай.


 
GrayFace ©   (2005-06-23 20:16) [27]

А если надо, чтобы библиотека загружалась динамически, но навсегда, нормально ли вызывать много раз LoadLibrary, не вызывая Free?


 
Digitman ©   (2005-06-24 08:20) [28]


> нормально ли вызывать много раз LoadLibrary, не вызывая
> Free?


достаточно один раз вызвать LoadLibrary


 
GrayFace ©   (2005-06-27 10:49) [29]

Digitman ©   (24.06.05 8:20) [28]
достаточно один раз вызвать LoadLibrary

Это требует определенных усилий - сохранять, какие библиотеки загружены, какие - нет. А если проверять GetModuleHandle, то ее могут выгрузить. Просто маленькая функция для динамической загрузки - часть моего пакета.


 
-=XP=- ©   (2005-06-27 11:17) [30]

достаточно один раз вызвать LoadLibrary

Мне тут "под руку" попался какой-то китайский менеджер памяти (вместо ShareMem) - называется, кажется, ShareMemRep.pas (но это к слову). Единственное, чем интересен - не требует borlandmm.dll в комплекте с программой поставлять.
Так вот, этот менеджер, при завершении приложения, проверяет динамически загруженные библиотеки, и очень настойчиво ругается (возможна утечка памяти, говорит), если хоть одна библиотека осталась в памяти. Приходится четко отслеживать процесс выгрузки.


 
evvcom ©   (2005-06-27 11:31) [31]


> Это требует определенных усилий - сохранять, какие библиотеки
> загружены, какие - нет. А если проверять GetModuleHandle,
> то ее могут выгрузить.

А ты возьми себе за правило, что если ты в классе вызвал LoadLibrary, то в нем же вызываешь и FreeLibrary, когда более она не нужна. И так в каждом классе. И никаких глобальных счетчиков и проч. Этот счетчик уже есть в системе и работает он лучше, чем напишешь ты.


 
GrayFace ©   (2005-06-28 20:59) [32]

evvcom ©   (27.06.05 11:31) [31]
У меня не класс, а маленькая функция для динамической загрузки. (См. [29])


 
GrayFace ©   (2005-06-28 21:00) [33]

-=XP=- ©   (27.06.05 11:17) [30]
Единственное, чем интересен - не требует borlandmm.dll в комплекте с программой поставлять.

Неужто, обычный требует?



Страницы: 1 вся ветка

Текущий архив: 2005.08.21;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.052 c
4-1119697602
Darkwing
2005-06-25 15:06
2005.08.21
Асинхронный I/O


4-1120122127
Никита
2005-06-30 13:02
2005.08.21
Как получить список всех дисков?


14-1122890968
msguns
2005-08-01 14:09
2005.08.21
Горе-то какое..


14-1122628257
DillerXX
2005-07-29 13:10
2005.08.21
Почему появляются синяки под глазами?


1-1122705542
Igit
2005-07-30 10:39
2005.08.21
Неправильно читается файл