Представление Callback функции как метода класса
Модератор: Модераторы
-
immortal1977
- новенький
- Сообщения: 16
- Зарегистрирован: 14.07.2008 15:52:23
- Откуда: Новоуральск
Представление Callback функции как метода класса
Уважаемые форумчане. Уже много дней мучаюсь, даже спать не могу. Интересует простой вопрос, но ответа пока не у кого не получил - как мне представить метод класса как callback функцию с модификатором stdcall, что бы винда смогла вызывать ее, но при этом рождение нескольких экземпляров класса гарантировало бы рождение нескольких, независимых по памяти callback ф-ций.
P.S. отсюда возникает очень не хорошее следствие, неужели если программа пишется на чистом api, и необходимо породить скажем 10 однотипных тридов, то необходимо сваять 10 одинаковых callback TreadProc. Возможен ли массив одинаковых callback proc?
P.S. отсюда возникает очень не хорошее следствие, неужели если программа пишется на чистом api, и необходимо породить скажем 10 однотипных тридов, то необходимо сваять 10 одинаковых callback TreadProc. Возможен ли массив одинаковых callback proc?
Если в callback приходит чтото уникальное - типа HWND для окон, можно по нему находить свой класс и вызывать соответствующий метод
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
callback функция - это "обычная" процедура, ее невозможно представить как метод класса. Нужно писать по крайней мере переходник, который уже будет вызывать нужный метод.
В WinAPI в большинстве случаев callback-функции имеют пользовательский параметр (lparam), в котором очень удобно передавать указатель на нужный объект.
В случае с оконной процедурой (WndProc) такого параметра нет, приходится изобретать нечто альтернативное. Можно либо использовать хеш-таблицу соответствия HWND<->объект (TBucketList подходит), либо цеплять указатель на объект к окну с помощью SetProp().
В WinAPI в большинстве случаев callback-функции имеют пользовательский параметр (lparam), в котором очень удобно передавать указатель на нужный объект.
В случае с оконной процедурой (WndProc) такого параметра нет, приходится изобретать нечто альтернативное. Можно либо использовать хеш-таблицу соответствия HWND<->объект (TBucketList подходит), либо цеплять указатель на объект к окну с помощью SetProp().
Как уже было сказано,
ибо как пишет дельфёвый хелп:
Как я понимаю, последнее утверждение актуально не только для дельфи, но и для FPC.
callback функция - это "обычная" процедура, ее невозможно представить как метод класса. Нужно писать по крайней мере переходник, который уже будет вызывать нужный метод.
ибо как пишет дельфёвый хелп:
A method pointer is really a pair of pointers; the first stores the address of a method, and the second stores a reference to the object the method belongs to.
Как я понимаю, последнее утверждение актуально не только для дельфи, но и для FPC.
-
immortal1977
- новенький
- Сообщения: 16
- Зарегистрирован: 14.07.2008 15:52:23
- Откуда: Новоуральск
Спасибо за ответы. От себя добавлю, что после долгого гугления, нашел таки исходник переходника class method <-> procedure.
Все таки оно существует...
Все таки оно существует...
Вопрос к знатоками: а как подобное реализовано в VCL (FCL, KOM)?
как было сказано выше, для API функций, которые используют callback, обычно разрешается передать UserData (данные которые будут переданы программисту при вызове этой callback функции.
например есть такая API "условная" функция
эта в эту функции, передаются входные параметры (param1, param2 - не важно что они значат - чисто условные). При работе этой функции будет вызываться CallBackProc, в который будет передана переменная UserData, та же сама, что и была передана при вызове SuperPupperAPIFunction.
как можно этим воспользоваться.
.хз как яснее написать... яснее будет на живом примере!
это использование типично для различный обёрток
и не только Delphi/FPC но и C++ и других объектно-оринетрованных языков, где в качестве UserData передаётся объект, и уже CallBack-процедура решает какой метод объекта нужно вызвать.
и ещё. Если писать класс обёртку, то следует "скрывать" (инкапсулировать - о как!) такое использование API, с помощью дополнительного метода объекта:
отличие этого когда, от перыдущего в том, что использование SuperPupperAPIFunction скрыто, что позволяет добится больше структурированности кода.
и ещё раз: "хз как яснее написать... яснее будет на живом примере"!
ЗЫ: искать хаки, для того чтобы передавать метод объекта, как процедуру - не стоит:
1-х эти решения не будут кроссплатформенными (увы и ах ВСЕГДА придёться лезть в ассемблер и основываться на convention call)
2-х они покажут, что ты программист-индус (в хучшем смысле этого слова).
3-х ненужное усложнение кода.
например есть такая API "условная" функция
Код: Выделить всё
TCallbackProc = procedure (SomeData: Integer; UserData:Pointer); stdcall;
procedure SuperPupperAPIFunction( param1, param2: Integer; CallBackProc: TCallbackProc; UserData: Pointer); stdcall; external;
эта в эту функции, передаются входные параметры (param1, param2 - не важно что они значат - чисто условные). При работе этой функции будет вызываться CallBackProc, в который будет передана переменная UserData, та же сама, что и была передана при вызове SuperPupperAPIFunction.
как можно этим воспользоваться.
Код: Выделить всё
type
TMyObject = class(Tobject)
procedure Callback(SomeData: Integer);
end;
// это обработчик
procedure TMyObject.CallBack(SomeData: Integer);
begin
writeln('SomeData = ', SomeData);
end;
procedure CallBackProc(SomeData: integer; UserData: Pointer); stdcall;
begin
// UserData это объект TMyObject, но нужно привести тип!
TMyObject(UserData).CallBack(SomeData); // передача из функции Callback методу объекта.
end;
...
var
m : TMyObject;
...
m := TMyObject.Create; // создали объект, иначе будет плохо!
...
SuperPupperAPIFunction( x, y, @CallBackProc, m); // в качестве UserData передали объект
...
end.
.хз как яснее написать... яснее будет на живом примере!
это использование типично для различный обёрток
и ещё. Если писать класс обёртку, то следует "скрывать" (инкапсулировать - о как!) такое использование API, с помощью дополнительного метода объекта:
Код: Выделить всё
interface
...
TMyObject = class(Tobject)
protected
procedure Callback(SomeData: Integer); virtual;
public
// обёртка вокруг API функции
procedure SuperPupper(param1, param2: Integer);
end;
...
implementation
procedure CallBackProc(SomeData: integer; UserData: Pointer); stdcall;
begin
// UserData это объект TMyObject, но нужно привести тип!
TMyObject(UserData).CallBack(SomeData); // передача из функции Callback методу объекта.
end;
// это обработчик
procedure TMyObject.CallBack(SomeData: Integer);
begin
writeln('SomeData = ', SomeData);
end;
// этот метод - обёртка для вызова функции SuperPupperAPIFunction
procedure TMyObject.SuperPupper(param1, param2: Integer);
begin
SuperPupperAPIFunction(param1, param2, @CallBackProc, Self);
end;
отличие этого когда, от перыдущего в том, что использование SuperPupperAPIFunction скрыто, что позволяет добится больше структурированности кода.
и ещё раз: "хз как яснее написать... яснее будет на живом примере"!
ЗЫ: искать хаки, для того чтобы передавать метод объекта, как процедуру - не стоит:
1-х эти решения не будут кроссплатформенными (увы и ах ВСЕГДА придёться лезть в ассемблер и основываться на convention call)
2-х они покажут, что ты программист-индус (в хучшем смысле этого слова).
3-х ненужное усложнение кода.
Спс большое, пошел писать не индусские живые примеры 
