Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.12.31;
Скачать: [xml.tar.bz2];

Вниз

правильная реализация 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.49 MB
Время: 0.042 c
15-1165809858
Slider007
2006-12-11 07:04
2006.12.31
С днем рождения ! 10 декабря


15-1165562990
KrylovVN
2006-12-08 10:29
2006.12.31
TCP/IP - UDP


15-1165594151
Kerk
2006-12-08 19:09
2006.12.31
Какнить вообще можно бороться с такими уродами?


3-1161084645
safo
2006-10-17 15:30
2006.12.31
Как трассировать sql-запросы к ODBC?


15-1165840218
Чапаев
2006-12-11 15:30
2006.12.31
"Достаться на орехи"





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский