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

Вниз

Callback для метода класса. Реально?   Найти похожие ветки 

 
dmk ©   (2004-02-01 17:04) [0]

Поискал информацию по конференциям на эту тему.
Кто-то говорит можно, кто-то говорит нельзя.
Встречал "хакерские" способы, но они исключительно
для Си. Для Delphi все говорят - невозможно!
Это действительно так?


 
Юрий Федоров ©   (2004-02-01 17:07) [1]

глупости
все реально


 
Saracin ©   (2004-02-01 17:15) [2]

Как ты думаешь что такое Event ??? :)
и кто его вызывает :)
Дело в том что работа любой колбек функции это просто вызов функции по указателю, ранее передоному обекту.
например obj1 и obj2. Семантика такая: Когда obj1 закончить заниматься фитгней пни obj2 вызвав его функцию pni_menia;
Реализация:
type
TCallBackFunction = function (I: Integer): Integer;

TObj1 = class
public
FCallBack: TCallBackFunction;

procedure do_fignu;
end

TObj2 = class
function pni_menia(I: Integer):Integer;
end;

procedure TObj1.do_fignu;
begin
...
FCallBack(10);
end;

begin
...
obj1.FcallBack := obj2.pni_menia;
obj1.do_fignu;
end.

Примерно так, Делфи не стоит 100% правельность проверить не могу, но суть такая :)

С Уважением Saracin.


 
Vuk ©   (2004-02-01 17:33) [3]

to dmk:
Все зависит от того, что Вы имеете в виду под callback. Если просто event, то это, я думаю особых проблем не вызывает. Если же имеется в виду передача метода в качестве функции обратного вызова для WinAPI, то здесь не так все просто - для методов объектов важен не только адрес кода, но и адрес экземпляра. К тому же первым параметром метода всегда передается указатель на экземпляр (для методов класса - сслка на класс). То есть если функуия обратного вызова не поддерживает передачу дополнительных параметров, предоставляемых приложением, напрямую передавать адрес метода для этих целей не стоит.
Но путь решения проблемы есть и этот путь используется в VCL. Если внимательно присмотреться к модулю Classes, то можно обнаружить там методы MakeObjectInstance и FreeObjectInstance. Они используются как раз для того, чтобы позволить методу WndProc работать в качестве оконной процедуры (типичный callback). Работа функции MakeObjectInstance заключается в том, что она выделяет небольшой блок памяти и пишет туда код, который при выполнении обеспечивает вызов метода WndProc конкретного экземпляра. При этом адрес экземпляра пишется непосредственно в этот блок памяти. Результатом работы функции является адрес этого блока памяти. Он же и служит адресом, который теперь может использоваться в качестве адреса функции обратного вызова.

to Saracin:
>TCallBackFunction = function (I: Integer): Integer;
Надо бы of object дописать...


 
dmk ©   (2004-02-01 17:38) [4]

2 Saracin © (01.02.04 17:15) [2]
Как раз такая конструкция и не работает на Delphi.
Объявляю
Type TEnumProc = Function(Wnd:HWND; Data:Pointer): bool of object;

в классе EnumProc: TEnumProc;

В итоге результат я присвоить не могу.
Вот сама функция

Function TImageForm.FEnumProc:TEnumProc;
var
WinStyle,
ExStyle : Cardinal;
PStruct: TRepaintStruct;

Function AcceptStyle(WindowStyle, ExWindowStyle:Cardinal): boolean;
var
r1, r2, r3: boolean;

begin
r1 := ((ExWindowStyle and WS_EX_TOPMOST) <> 0) and
((ExWindowStyle and WS_EX_TOOLWINDOW) <> 0) and
((WindowStyle and WS_VISIBLE) <> 0);

r2 := ((ExWindowStyle and WS_EX_TOPMOST) <> 0) and
((WindowStyle and WS_VISIBLE) <> 0);

r3 := ((ExWindowStyle and WS_EX_TOOLWINDOW) <> 0) and
((WindowStyle and WS_VISIBLE) <> 0);

Result := r1 or r2 or r3;
end;

begin
Result := True;

PStruct := TRepaintStruct(Data^);

WinStyle := GetWindowLong(WindowHandle, GWL_STYLE);
ExStyle := GetWindowLong(WindowHandle, GWL_EXSTYLE);

If AcceptStyle(WinStyle, ExStyle) then
begin
With PStruct do
Self.RepaintTopFormIntersect(iX, iY, iPrevX, iPrevY, dX, dY, WindowHandle);
end;
end;


 
vuk ©   (2004-02-01 17:42) [5]

to dmk:
Где Вы пытаетесь использовать эту процедуру как callback?


 
dmk ©   (2004-02-01 17:44) [6]

2 Vuk
Под callback я понимаю stdcall.
Мне надо просто перечислить окна.
EnumWindows(@EnumProc, Integer(@FRepaintStruct));
Я конечно передавал данные через второй параметр,
но в связи с некоторыми особенностями класса
это неправильно, данные передаются устаревшие.
В случае с методом класса все будет Ок.


 
vuk ©   (2004-02-01 17:52) [7]

to dmk:
В этом случае можно поступить проще. Этот callback позволяет передавать дополнительные параметры, и поэтому нужно только вручную написать функцию-переходник примерно такого вида:

function EnumWindowsCallback(Wnd: HWnd; Data: Pointer): boolean;
begin
if Data <> nil then
Result := TSomeClass(Data).SomeMethod(...)
else
Result := ...;
end;

Теперь можно вызывать EnumWindows:
EnumWindows(@EnumWindowsCallback, SomeClassInstance);


 
vuk ©   (2004-02-01 17:53) [8]

>EnumWindows(@EnumWindowsCallback, SomeClassInstance);
естественно
integer(SomeClassInstance)


 
Anatoly Podgoretsky ©   (2004-02-01 17:56) [9]

Type
Вот это ты напрасно придумал
TEnumProc = Function(Wnd:HWND; Data:Pointer): bool of object;


 
Saracin ©   (2004-02-01 17:58) [10]

to vuk
со всем согласен :) заставили меня даже Delphi поставить. :)
to dmk
если добавить of object; то все работает , теперь проверил :)


 
dmk ©   (2004-02-01 17:59) [11]

Да. Я так и делал до этого.
Все работает относительно "нормально", но дело в том, что мой класс использует еще один класс TTread. И в момент перечисления окон, экземпляр класса может сменится и тогда данные от другого экземпляра попадают в только что активизировавшийся.
Поэтому я и хотел, чтобы у каждого экземпляра был свой stdcall.
Придется наверно логику работы менять.


 
dmk ©   (2004-02-01 18:00) [12]

2 Anatoly Podgoretsky © (01.02.04 17:56) [9]
Я и без него пробовал. Компилятору не нравится.


 
Юрий Зотов ©   (2004-02-01 18:08) [13]

> dmk © (01.02.04 17:44) [6]

> Под callback я понимаю stdcall.

Что совершенно неверно. Stdcall - это просто одно из соглашений о вызове и к термину Callback не имеет никакого отношения.

> Мне надо просто перечислить окна.
> EnumWindows(@EnumProc, Integer(@FRepaintStruct));

При вызове метода класса ему, помимо явно перечисленных в его объявлении параметров, передается еще один параметр - тот самый Self. А при вызове обычной процедуры/функции никаких дополнительных параметров, конечно же, не передается - вот чем она отличается от методов класса.

Естественно, EnumWindows ни о каких там классах не имеет ни малейшего понятия и поэтому будет вызывать EnumProc, как обычную функцию. Значит EnumProc и должна быть именно обычной функцией (причем как раз с stdcall) - а вот внутри нее Вы уже можете вызывать что угодно. Например, вместо RepaintStruct передавайте ссылку на экземпляр Вашего класса и по ней (приведя тип к нужному) вызывайте любой его метод.


 
dmk ©   (2004-02-01 18:14) [14]

>Что совершенно неверно. Stdcall - это просто одно из соглашений
>о вызове и к термину Callback не имеет никакого отношения.
Это я в Си конференциях подхватил. Там наверное тоже на понимают этого термина как и я. Кстати, что это за термин?


 
default ©   (2004-02-01 18:27) [15]

ф-ции обратного вызова, те которые вызывает ОС


 
Anatoly Podgoretsky ©   (2004-02-01 18:27) [16]

Callback в терминологии Дельфи, это процедурная переменная, все события класса являются Callback функция, которые вызываются через переменную, естественно ее можно передавать в любую функцию как параметр. Для виндоус Callback функции не могут быть классами, любого языка программирования.


 
Юрий Зотов ©   (2004-02-01 18:33) [17]

> dmk © (01.02.04 18:14) [14]

Соглашения о вызове - это правила, устанавливающие способ передачи параметров (через регистры, через стек, комбинированный), порядок следования параметров в стеке (первый вверху или последний вверху) и то, на чьей стороне (вызывающей или вызываемой) должно восстанавливаться состояние стека после завершения работы вызванной функции. По этому поводу см. Calling conventions в справке Delphi - там все расписано подробно.

Callback - это термин, означающий, что при вызове какой-то функции (в Вашем случае - EnumWindows) ей передается адрес так называемой функции обратного вызова (callback-функции - в Вашем случае ею является EnumProc). "Обратный вызов" (callback) здесь означает всего лишь то, что Вы вызываете БИБЛИОТЕЧНУЮ функцию, а она при своей работе снова вызывает ВАШУ функцию, как бы совершая при этом "возврат" в Ваш код.

Таким образом, термины callback и stdcall не связаны друг с другом совершенно никак. Может быть и callback без stdcall, может быть и stdcall без всяких callback"ов.


 
Daniel   (2004-02-02 00:54) [18]

TCallbackFunction = function: Integer of object
YourFunc: TCallbackFunction;
А нельзя ли просто:
FunctionThatRequireCallBack(TMethod(YourFunc).Code); ??


 
dmk ©   (2004-02-02 01:33) [19]

2 Daniel (02.02.04 00:54) [18]
Не получится.
Invalid type cast.



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

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

Наверх




Память: 0.52 MB
Время: 0.018 c
6-29504
Yobz
2003-12-04 21:13
2004.02.10
TCP/IP


4-29674
Sword-Fish
2003-12-04 01:46
2004.02.10
Консольное приложение


7-29626
Babay
2003-11-25 10:32
2004.02.10
Список служб W2K, XP


6-29511
Alek_1
2003-12-04 15:12
2004.02.10
Служба сообщений виндовс


1-29307
Алексей
2004-01-30 05:52
2004.02.10
Запрос XPath в XMLdocument