Форум: "Основная";
Текущий архив: 2002.09.19;
Скачать: [xml.tar.bz2];
ВнизПерехват компонентом сообщений адресованных окну Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.47 MB
Время: 0.006 c