Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как получить адрес процедур собственной программы (по названию п) [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.


Наверх

Титульная страница Поиск, карта сайта Написать письмо