![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
правильная реализация MethodToProcedure [D6, D7, Win2k, WinXP]
MetalFan © (2006-10-26 13:28:00)решил вынести в отдельную тему.
проблема: приведение метода класса к процедурному типу (простите, если термины неверны) для передачи в кач. 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;
Мастера, объясните ошибочность такого подхода, а так же, если не сложно, покажите пример кода, выполняющий эту задачу
MetalFan (2006-11-13 08:43:00) [1]
> Ketmar © (26.10.06 16:01) [14]
>
> >[13] MetalFan(c) 26-Oct-2006, 15:59
> >а зачем, если можно поизвращаться...
> ну как тебе сказать, чтобы без мата? %-)
>
ну уж как нибудь нельзя чтоль?!
только за метлой не посылай ;)
Ketmar (2006-10-26 16:01:00) [2]>[13] MetalFan(c) 26-Oct-2006, 15:59
>а зачем, если можно поизвращаться...
ну как тебе сказать, чтобы без мата? %-)
MetalFan (2006-10-26 15:59:00) [3]>Ketmar © (26.10.06 15:54) [12]
т.е. скопировать тот же код, немного его изменив?
а зачем, если можно поизвращаться...
вон, Rule говорит, что заработало у него %)
Ketmar (2006-10-26 15:54:00) [4]>[11] MetalFan(c) 26-Oct-2006, 15:47
у "наследников TList" никто не мешает сделать дополнительный метод.
MetalFan (2006-10-26 15:47:00) [5]Ketmar © (26.10.06 15:43) [10]
а почему нет?
чтобы например у наследников TList вызывать Sort с методом тогоже класса...
Ketmar (2006-10-26 15:43:00) [6]>[9] MetalFan(c) 26-Oct-2006, 15:42
>хорошо, а как его(код) модифицировать, чтобы можно было
>использовать и для WinApi и для callback в классах делфи?
ЗАЧЕМ???
MetalFan (2006-10-26 15:42:00) [7]хорошо, а как его(код) модифицировать, чтобы можно было использовать и для WinApi и для callback в классах делфи?
Rule (2006-10-26 15:16:00) [8]MetalFan © (26.10.06 14:55) [6]
зачем ????
Ketmar (2006-10-26 15:02:00) [9]>[6] MetalFan(c) 26-Oct-2006, 14:55
>а можно его не для WinApi использовать?
не надо.
MetalFan (2006-10-26 14:55:00) [10]а можно его не для WinApi использовать?
Ketmar (2006-10-26 14:49:00) [11]>[4] MetalFan(c) 26-Oct-2006, 14:37
>а можете помочь приведенный код до ума довести?
какой? который от madshi? так он отлично работает.
MetalFan (2006-10-26 14:37:00) [12]Юрий Зотов © (26.10.06 13:42) [1]
можно и так) но всетаки хочется поизвращенней)
Сергей М. © (26.10.06 13:55) [2]
сравнил... похоже...
а можете помочь приведенный код до ума довести? мне опыта не хватает(
Ketmar (2006-10-26 14:11:00) [13]>[1] Юрий Зотов(c) 26-Oct-2006, 13:42
>Его главная ошибочность в том, что он на фиг не нужен.
madshi не зря назвал это "madCollection". %-)
Сергей М. (2006-10-26 13:55:00) [14]
> MetalFan © (26.10.06 13:28)
Сравни с Make/FreeObjectInstance() (classes.pas), удивись ..)
Юрий Зотов (2006-10-26 13:42:00) [15]> объясните ошибочность такого подхода
Его главная ошибочность в том, что он на фиг не нужен. Можно, конечно, чесать правое ухо и левой ногой, но гораздо проще и гораздо удобнее делать это правой рукой.
> покажите пример кода
Пишется обычный callback, а в вызывающую его функцию передается ссылка на объект. При вызове callback'а эта ссылка передается ему - а уж он знает, что с ней делать. Например, можно просто вызвать метод этого объекта - и получится как раз то, что хотелось. Но... правой рукой, а не левой ногой.