![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как получить адрес процедур собственной программы (по названию п) [D4, D5, Win95/98, WinXP]
AllDontFire © (2005-10-29 15:24:00)Пробовал
GetProcAddress, но, насколько я понял, так нельзя, это только для Dll?
Polevi (2005-10-31 10:47:00) [1]можно сделать через FindClass
Digitman (2005-10-31 10:17:00) [2]
> raiks (30.10.05 13:39) [11]
> связано с атрибутами доступа к памяти?
нет, это связано с совершенно иным - с обработкой загрузчиком таблицы релокации и инициализацией pe-модуля
raiks (2005-10-30 13:39:00) [3]Джо
Ради интереса опробовал 1-й ваш пример. Работает :) Потом решил проделать то же самое с другим *.exe, в раздел exports которого добавлена соответствующая строка. Файл нормально загрузился с помощью LoadLibrary, адрес процедуры DoSomething тоже нашелся, но при попытке вызвать ее вылезло неизбывное сообщение об Access Violation. Я так понимаю, это связано с атрибутами доступа к памяти? Можно ли это исправить?
-----------Project1.exe------------
program Project1;
uses Windows;
procedure DoSomething;
begin
MessageBox(0, 'Hello from DoSomething()', nil, MB_ICONWARNING);
end;
exports
DoSomething;
begin
end.
-----------Project2.exe------------
var
hLib: THandle;
DoSmth: procedure;
begin
hLib:=LoadLibrary('f:\project1.exe');
if hLib<>0 then
begin
MessageBox(0, 'Module Project1 was loaded!', nil, MB_ICONWARNING);
@DoSmth:=GetProcAddress(hLib, 'DoSomething');
if @DoSmth<>nil then
begin
MessageBox(0, 'Procedure DoSomething() was found!', nil, MB_ICONWARNING);
DoSmth;
end;
FreeLibrary(hLib);
end;
end;
AllDontFire (2005-10-30 11:23:00) [4]Спасибо, всё понятно.
Ну это нужно, например, когда, в зависимости от какого-либо входного параметра, необходимо запустить опр. процедуру. Можно конечно выйти из положения черезIF, но, а если много вариантов входных параметров, то и "Ифов" будет много, а это не удобно я думаю.
Джо (2005-10-30 02:37:00) [5]
> [4] AllDontFire (29.10.05 22:15)
Разумумный ответ см. [1] begin...end © (29.10.05 15:48)
Другой подход - сделать процуры published-методами какого-нибудь класса, скомпилированным с директовой {$M+}. Тогда можно искать методы по имени.
Непонятно только, зачем это нужно? Может, если объяснить конкретную задачу, найдется более оптимальное решение.
Джо (2005-10-30 02:34:00) [6]Мда... спешка к добру не приводит. Исправления во второй пример, позорные:
var
...
Proc: procedure of object;
...
TMethod(Proc).Code := Commander.MethodAddress (ProcName);
TMethod(Proc).Data := Commander;
raiks (2005-10-30 02:29:00) [7]Объясните конкретнее, для чего вам это нужно. Почему нельзя использовать приведенный пример?
Джо (2005-10-30 02:01:00) [8]Делать мне, наверное, нечего.
В общем, вот иллюстрация обоих подходов, два консольных приложения, в качестве параметра коммандной строки принимающих имя процедуры, которую необходимо выполнить.
---
Подход с получением адреса экспортируемой функции.
program Project2;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils;
// эта процедура экспортируется
procedure DoSomething;
begin
WriteLn ('DoSomething called.');
end;
// эта процедура экспортируется
procedure DoSomethingElse;
begin
WriteLn ('DoSomethingElse called.');
end;
// а эта процедура НЕ экспортируется
procedure YouCannotCallMe;
begin
WriteLn ('You should not see this message.');
end;
// экспортируем нужные функции
exports
DoSomething,
DoSomethingElse;
var
ProcName: string;
Proc: procedure;
begin
ProcName := ParamStr(1);
if ProcName = '' then
begin
WriteLn ('Specify a procedure name');
Exit;
end;
proc := GetProcAddress(0,PChar(ProcName));
if Assigned(Proc) then
Proc()
else
WriteLn ('Procedure ',ProcName,' not found in executable.');
ReadLn;
end.
---
Подход с получением адреса published-метода класса.
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils,
TypInfo;
type
TCommander = class
public
procedure YouCannotCallMe;
published
procedure DoSomething;
procedure DoSomethingElse;
end;
{ TCommander }
procedure TCommander.DoSomethingElse;
begin
WriteLn ('DoSomethingElse called.');
end;
procedure TCommander.DoSomething;
begin
WriteLn ('DoSomething called.');
end;
procedure TCommander.YouCannotCallMe;
begin
WriteLn ('You should not see this message.');
end;
var
ProcName: string;
Proc: procedure;
Commander: TCommander;
begin
ProcName := ParamStr(1);
if ProcName = '' then
begin
WriteLn ('Specify a procedure name');
Exit;
end;
Commander := TCommander.Create;
try
Proc := Commander.MethodAddress (ProcName);
if Assigned (Proc) then
Proc ()
else
WriteLn ('Unknown command requested.');
finally
Commander.Free;
end;
ReadLn;
end.
П.С. Надеюсь, пригодится.
И -- я наврал насчет директивы {$M+}, сейчас вожусь с RTTI и немного заработался, видимо :(
wp2 (2005-10-30 01:39:00) [9]Удалено модератором
AllDontFire (2005-10-29 22:15:00) [10]raiks,
p:=@DoSomething - -это понятно.
Но мне нужно найти адрес, передавая символьное название процедуры как в
GetProcAddress.
raiks (2005-10-29 19:05:00) [11]procedure DoSomething;
begin
end;
var p: Pointer;
begin
p:=@DoSomething;
ShowMessage('Адрес DoSomething: ' + IntToStr(Cardinal(p)));
end;
wp2 (2005-10-29 15:52:00) [12]А если попробовать @
begin...end (2005-10-29 15:48:00) [13]> AllDontFire (29.10.05 15:24)
Это возможно и для EXE, но нужные подпрограммы нужно включить в список exports.