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

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.01 c
1-29442
Grinder
2004-01-30 22:31
2004.02.10
как определить находится ли курсор над формой или нет?


1-29309
rexelf
2004-01-30 10:57
2004.02.10
создание rar архива ???...


6-29515
ruffest
2003-12-02 22:09
2004.02.10
Wake On Lan


4-29670
mRodion
2003-12-03 12:00
2004.02.10
Как определить, что окно стало активным по щелчку мыши?


4-29653
frost
2003-12-06 15:21
2004.02.10
Буфер Windows





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский