Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-61156
Werewolfru
2002-09-07 12:18
2002.09.19
Происходит ошибка при обращении к блоку памяти! (FULL)


1-61155
micolka
2002-09-07 08:26
2002.09.19
прошу помощи...


1-61154
DDi
2002-09-07 05:12
2002.09.19
Работа с Датой и Временем


14-61268
RV
2002-08-23 12:20
2002.09.19
вот, например, что можно сделать, если


1-61153
Вован
2002-09-06 19:08
2002.09.19
Отображение информации на StatusBar е





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