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

Вниз

Перехват компонентом сообщений адресованных окну   Найти похожие ветки 

 
Outman ©   (2002-09-09 19:01) [0]

Хочу написать компонент который при установке на форму - подменял бы обработчик Windows сообщений окна, на свой вроде бы что могло бы быть проще - прописываеш свой метод через
SetWindowLong(TForm(Owner).Handle,GWL_WndProc,LongInt(NewWndProc)) и нет проблем - но начинаются немеренные глюки :(

Он у меня начинает перехватывать сообщения не окна даже а всего IDE - ни одна кнопка не действует - мышь за пределы формы не выпускает ... и остаётся только снимать задачу ...

полазил по инету нашёл схожий вопрос - посмотрел что там было написано в качестве ответа - упростил свой исходник до того уровня - результат тот же ...

Если кто может помочь - подскажите плз... А то я ж ету задачу не брошу и просижу над какой нить фигнёй фиг знает скока.

Исходник компонента:

unit Winhook;
interface
uses
Windows, Messages, SysUtils, Classes, Forms,Controls;
type
TWinHookCompomnent = class(TComponent)
private
procedure HookOwner;
procedure UnhookOwner;
procedure HookWndProc(var Msg:TMessage);Virtual;
protected
public
constructor Create(Owner: TComponent); override;
destructor Destroy; override;
end;
var OldWndProc,NewWndProc:Pointer;
Seted:boolean;
procedure Register;
implementation
constructor TWinHookCompomnent.Create(Owner: TComponent);
begin
inherited Create(Owner);
HookOwner;
end;
destructor TWinHookCompomnent.Destroy;
begin
UnhookOwner;
inherited Destroy;
end;
procedure TWinHookCompomnent.HookWndProc(var Msg:TMessage);
var OldPtr:Pointer;
begin
CallWindowProc(OldWndProc,TForm(Owner).Handle,Msg.Msg ,Msg.WParam,Msg.LParam);
end;

procedure TWinHookCompomnent.HookOwner;
var Test:Cardinal;
begin
if Assigned(Owner) then
begin
OldWndProc := Pointer(GetWindowLong(TForm(Owner).Handle,GWL_WndProc));
NewWndProc := MakeObjectInstance(HookWndProc);
Test := SetWindowLong(TForm(Owner).Handle,GWL_WndProc,LongInt(NewWndProc));
if Test = 0 then MessageBox (TForm(Owner).Handle,"Can not hook owner window procedure","Error",0);
Seted:=true;
end;
end;
procedure TWinHookCompomnent.UnhookOwner;
begin
if Assigned (Owner) And Assigned(OldWndProc) then
begin SetWindowLong(TForm(Owner).Handle,GWL_WndProc,LongInt(OldWndProc));
if Assigned(NewWndProc) then FreeObjectInstance(NewWndProc);
NewWndProc := nil;
OldWndProc := nil;
end;
end;
procedure Register;
begin
RegisterComponents("Additional", [TWinHookCompomnent]);
end;
end.


 
Юрий Зотов ©   (2002-09-09 23:01) [1]

Есть 2 пути.

1. SetWindowLong (но сначала MakeObjectInstance - посмотрите, как это делается в VCL). Сразу могу сказать, что таким образом некоторые сообщения отловить не удастся (например, WM_SETTEXT, сам когда-то с этим мучился).

2. Записать адрес своей процедуры в свойство WindowProc (конечно, запомнив старый адрес), что фактически переопределяет метод WndProc и позволяет отловить все сообщения (этот путь я в итоге и использовал).

В любом случае это нужно делать только в run-time (проверять csDesigning in ComponentState), чтобы не помешать работе IDE (что у Вас, видимо, и получилось).

Второй подводный камень - нужно предусмотреть ситуацию, когда юзер бросит на форму, скажем, три Ваших компонента (и каждый из них перехватит WndProc), а затем удалит их - но не в обратном порядке, а, например, в порядке 2-1-3. Если не предусмотреть специальных мер, восстановить родной обработчик формы окажется невозможно и могут начаться любые чудеса.

Третий подводный камень - юзер может создать Ваш компонент динамически, назначив его владельцем не форму, а что угодно еще (даже nil). Такую ситуацию тоже надо правильно разрулить.

Эти подводные камни я обходил в конструкторе своего компонента. Там проверялось, чтобы владельцем была именно TCustomForm и чтобы такой компонент на форме был единственным (логика его работы именно этого и требовала). Если что-то не так, возбуждалось исключение - а исключение в конструкторе, как известно, приводит к автоматическому уничтожению свежесозданного объекта и, таким образом, предохраняет от утечек памяти.

Вот, собственно, и все фокусы. В итоге компонент вполне успешно заработал.


 
Озверевший кадастрат   (2002-09-09 23:05) [2]

Если перехватывать нужно не все сообщения, а только те, которые не обрабатываются самой VCL (а таких немало, напр., полезное сообщение WM_DROPFILES), то извращений не надо, есть Application.OnMessage.
А если ловить всё, что летит... то вроде вышеприведенный текст (сорри, не всматривался еще) должон работать. А в чем "немерянные глюки"?


 
Юрий Зотов ©   (2002-09-09 23:09) [3]

Назначать обрабочик Application.OnMessage в компоненте ?

Это несерьезно.


 
Озверевший кадастрат   (2002-09-09 23:28) [4]

Почему не серьезно?


 
Озверевший кадастрат   (2002-09-09 23:33) [5]

2 Юрий Зотов
Кстати, спасибо за совет (не мне) переопределять WndProc, способ, что называется, "железный" и безотказный.


 
Юрий Зотов ©   (2002-09-09 23:51) [6]

> Почему не серьезно?

Допустим, я - юзер такого компонента. Кладу его на форму, правильно настраиваю - все ОК.

Потом пишу свой обработчик Application.OnMessage и в FormCreate назначаю его. Ничего нелегального, все точно по справке. И никто мне этого запретить не может, и запрещать не должен.

После чего - большой привет. Компонент не работает.

А почему? Потому что его автор нарушил железное правило, которое обязан знать и строго соблюдать каждый component writer - КОМПОНЕНТ НЕ ИМЕЕТ ПРАВА ИСПОЛЬЗОВАТЬ ДОСТУПНЫЕ ЕГО ЮЗЕРУ СОБЫТИЯ. Это закон.

Между разработкой инструментария (в частности, компонентов) и разработкой приложений есть существенная разница. Это и несколько другая идеология построения кода. Это и несколько другая психология программиста (взгляд как бы "с обратной стороны экрана"). Это и несколько другой стиль программирования. И еще многое что.

Поэтому в каждой софтверной компании существуют люди, которые пишут прикладной код и люди, которые пишут базовый код, ядро. У них не просто разная квалификация - у них разный способ мышления. Это и есть главное.


 
Озверевший кадастрат (уже не очень)   (2002-09-10 01:05) [7]

2 Юрий Зотов © (09.09.02 23:51)
Не ожидал столь хорошо аргументированного ответа.
Действительно, криво выходит с ОнМессаджем.



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

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

Наверх




Память: 0.49 MB
Время: 0.015 c
3-60961
juster
2002-08-28 17:57
2002.09.19
Навигация по набору данных


6-61230
Alibaba
2002-07-16 13:58
2002.09.19
Как подождать результата соединения клиента с сервером?


1-61199
Sour
2002-09-07 19:14
2002.09.19
Как отловить собыитие, когда в CD-ROM привод запихали диск.


3-60949
ev1972
2002-08-28 09:54
2002.09.19
Advantage Dataset: Как открыть DBF не подключая CDX?


14-61315
lak_b
2002-08-24 23:49
2002.09.19
память