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

Вниз

правильная реализация MethodToProcedure   Найти похожие ветки 

 
MetalFan ©   (2006-10-26 13:28) [0]

решил вынести в отдельную тему.
проблема: приведение метода класса к процедурному типу (простите, если термины неверны) для передачи в кач. callback функции WinApi или в классы. (типа TList.Sort()).

найдена следующая реализация в madCollection (http://www.madshi.net/)
описание из help"a:
Sometimes you need to give a procedure address in to a Windows API, but you would rather give in a method instead. In such a situation the function "MethodToProcedure" can come in handy. You give in a method address and your current "Self" value and you get a procedure address as the result, which you then can give in to a Windows API.

Please note that this works only for *stdcall* methods! Don"t use it for any other calling convention! (But since almost all Windows APIs are stdcall, this should not be a big problem.)

After you don"t need the procedure pointer anymore, please free it with "VirtualFree".

function MethodToProcedure (self       : TObject;
                           methodAddr : pointer) : pointer; overload;

function MethodToProcedure (method     : TMethod) : pointer; overload;


Here comes a little example which demonstrates a correct and useful usage of "MethodToProcedure":
unit EnumWindows;

// this unit implements a little class named TEnumWindows, which does nothing
// but enumerate all windows

interface

implementation

uses Windows, SysUtils, madTools;

type
 TEnumWindows = class
 private
   function EnumCallbackMethod(window: dword; lParam: integer) : bool; stdcall;
 public
   constructor Create;
 end;

constructor TEnumWindows.Create;
var EnumCallbackProc : pointer;
begin
 inherited;

 // you must give in a procedure address into EnumWindows
 // if you would give in "@TWindowList.EnumCallbackMethod" your code would crash
 // because methods have an additional hidden "Self" parameter
 // so we need to convert our method to a procedure first
 EnumCallbackProc := MethodToProcedure(Self, @TEnumWindows.EnumCallbackMethod);

 // "EnumCallbackProc" now contains a pointer to a newly allocated procedure
 // which does nothing but jump to our "EnumCallbackMethod" with the correct parameters
 EnumWindows(EnumCallbackProc, 0);

 // don"t forget to free the allocated procedure
 VirtualFree(EnumCallbackProc, 0, MEM_RELEASE);
end;

function TEnumWindows.EnumCallbackMethod(window: dword; lParam: integer) : bool; stdcall;
begin
 result := true;

 // do anything with the "window"s you get here...
 [...]
end;

end.


function MethodToProcedure(self: TObject; methodAddr: pointer) : pointer;
type
 TMethodToProc = packed record
   popEax   : byte;                  // $58      pop EAX
   pushSelf : record                 //          push self
                opcode  : byte;      // $B8
                self    : pointer;   // self
              end;
   pushEax  : byte;                  // $50      push EAX
   jump     : record                 //          jmp [target]
                opcode  : byte;      // $FF
                modRm   : byte;      // $25
                pTarget : ^pointer;  // @target
                target  : pointer;   //          @MethodAddr
              end;
 end;
var mtp : ^TMethodToProc absolute result;
begin
 mtp := VirtualAlloc(nil, sizeOf(mtp^), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 with mtp^ do begin
   popEax          := $58;
   pushSelf.opcode := $68;
   pushSelf.self   := self;
   pushEax         := $50;
   jump.opcode     := $FF;
   jump.modRm      := $25;
   jump.pTarget    := @jump.target;
   jump.target     := methodAddr;
 end;
end;


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


 
Юрий Зотов ©   (2006-10-26 13:42) [1]

> объясните ошибочность такого подхода

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

> покажите пример кода

Пишется обычный callback, а в вызывающую его функцию передается ссылка на объект. При вызове callback"а эта ссылка передается ему - а уж он знает, что с ней делать. Например, можно просто вызвать метод этого объекта - и получится как раз то, что хотелось. Но... правой рукой, а не левой ногой.


 
Сергей М. ©   (2006-10-26 13:55) [2]


> MetalFan ©   (26.10.06 13:28)


Сравни с Make/FreeObjectInstance() (classes.pas), удивись ..)


 
Ketmar ©   (2006-10-26 14:11) [3]

>[1] Юрий Зотов(c) 26-Oct-2006, 13:42
>Его главная ошибочность в том, что он на фиг не нужен.
madshi не зря назвал это "madCollection". %-)


 
MetalFan ©   (2006-10-26 14:37) [4]

Юрий Зотов ©   (26.10.06 13:42) [1]
можно и так) но всетаки хочется поизвращенней)

Сергей М. ©   (26.10.06 13:55) [2]
сравнил... похоже...
а можете помочь приведенный код до ума довести? мне опыта не хватает(


 
Ketmar ©   (2006-10-26 14:49) [5]

>[4] MetalFan(c) 26-Oct-2006, 14:37
>а можете помочь приведенный код до ума довести?
какой? который от madshi? так он отлично работает.


 
MetalFan ©   (2006-10-26 14:55) [6]

а можно его не для WinApi использовать?


 
Ketmar ©   (2006-10-26 15:02) [7]

>[6] MetalFan(c) 26-Oct-2006, 14:55
>а можно его не для WinApi использовать?
не надо.


 
Rule ©   (2006-10-26 15:16) [8]

MetalFan ©   (26.10.06 14:55) [6]
зачем ????


 
MetalFan ©   (2006-10-26 15:42) [9]

хорошо, а как его(код) модифицировать, чтобы можно было использовать и для WinApi и для callback в классах делфи?


 
Ketmar ©   (2006-10-26 15:43) [10]

>[9] MetalFan(c) 26-Oct-2006, 15:42
>хорошо, а как его(код) модифицировать, чтобы можно было
>использовать и для WinApi и для callback в классах делфи?
ЗАЧЕМ???


 
MetalFan ©   (2006-10-26 15:47) [11]

Ketmar ©   (26.10.06 15:43) [10]
а почему нет?
чтобы например у наследников TList вызывать Sort  с методом тогоже класса...


 
Ketmar ©   (2006-10-26 15:54) [12]

>[11] MetalFan(c) 26-Oct-2006, 15:47
у "наследников TList" никто не мешает сделать дополнительный метод.


 
MetalFan ©   (2006-10-26 15:59) [13]

>Ketmar ©   (26.10.06 15:54) [12]
т.е. скопировать тот же код, немного его изменив?
а зачем, если можно поизвращаться...
вон, Rule говорит, что заработало у него %)


 
Ketmar ©   (2006-10-26 16:01) [14]

>[13] MetalFan(c) 26-Oct-2006, 15:59
>а зачем, если можно поизвращаться...
ну как тебе сказать, чтобы без мата? %-)


 
MetalFan ©   (2006-11-13 08:43) [15]


> Ketmar ©   (26.10.06 16:01) [14]
>
> >[13] MetalFan(c) 26-Oct-2006, 15:59
> >а зачем, если можно поизвращаться...
> ну как тебе сказать, чтобы без мата? %-)
>

ну уж как нибудь нельзя чтоль?!
только за метлой не посылай ;)



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

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

Наверх




Память: 0.51 MB
Время: 0.043 c
2-1165997990
Клара
2006-12-13 11:19
2006.12.31
Отчеты


2-1165697465
arturich
2006-12-09 23:51
2006.12.31
Таймер


1-1161854933
MetalFan
2006-10-26 13:28
2006.12.31
правильная реализация MethodToProcedure


2-1165852682
Makhanev Alexander
2006-12-11 18:58
2006.12.31
смена состояния always on top на лету...


4-1156274077
Dot
2006-08-22 23:14
2006.12.31
поиск hwnd одного из двух окон