N
N
Nashev2012-09-11 17:50:15
Delphi
Nashev, 2012-09-11 17:50:15

Independently attach multiple WindowProc handlers to an arbitrary TWinControl descendant?

There are at least three components that, having received a link to TWinControl, want to start adjusting their position when the position of that control changes, and somehow react to events that come to it.
All three, independently of each other, can be added and removed in any order. Both in runtime and design time.
All three, in principle, are in my source code - but a setup: they belong to different component packages and, accordingly, I cannot fix them so that they use some kind of auxiliary class that I have in common for them - the WindowProc replacement queue manager. In addition, perhaps someone else also uses the same method, but I have not yet discovered it.
Now all three of them use the same very popular approach to parasitize, thinking that each of them is unique:

procedure T***.PatchControl;
begin
  FOldWndProc := FLinkedControl.WindowProc;
  FLinkedControl.WindowProc := MyWndProc;
end;

procedure T***.UnpatchControl;
begin
  FLinkedControl.WindowProc := FOldWndProc;
end;

Naturally, each has its own analogue of the first code is called when binding, the second - when unbinding. It is also natural that when several such parasites are bound, and they begin to unbind not in the reverse order, but in any other order, then those who unbind later bind back those handlers from already unbinded ones, the links to which they remembered when they were attached after them.
To verify this, I stuck a check like this:
procedure T***.UnpatchControl;
var
  m: TWndMethod;
begin
  m := MyWndProc;
  Assert((TMethod(FLinkedControl.WindowProc).Code = TMethod(m).Code), 'unlink only own handler to prevent errors');

  FLinkedControl.WindowProc := FOldWndProc;
end;

Naturally, assertions began to pour in, naturally even in the IDE with its form designer. And before that, from time to time, it was not assertions that poured, but the IDE itself.
The question is what to do with it? I've already broken my head ...
PS Perhaps, somehow rehashing only WM_WindowPosChanged would suit me too ...

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
debose, 2012-09-16
@Nashev

I would do this:
1) First of all, I checked if it is possible to implement the same without overriding WndProc, for example, using TAppEvents.OnMessage.
2) If not, then:
Created a separate package. I would make a separate component in it that allows you to organize a chain of calls to WinProc. Well, actually, you already have such a class in your code. T***(.UnpatchControl_. If there are many such classes, then it makes sense to make them a common successor. Or change the T*** class so that PatchControl delegates the call to an instance of TMyWndProcQueeHandler (proxy).
The class would look something like this:

type
  TMyWndProcQueeHandler = class(TComponent)
  private
    FWndProcsList: array of TWndMethod; // или TList<TWndMethod>
  public
     // здесь присваиваем контролу MyWndProc в качестве WndProc
     // а оригинальный добавлем в FWndProcsList
     procedure PatchControl;

     // здесь соответственно восстанавливаем оригинальный WndProc
     procedure UnpatchControl;

     // здесь вызываем WndProc-ы в нужном порядке. (начиная с последнего (кастомного) до 0-го (оригинального))
     procedure MyWndProc(var Message: TMessage);

     // тут просто добавляем aWndProc в список
     procedure AddWndProc(const aWndProc: TWndProc);
     
     // ну и конечно надо ещё сделать конструктор/деструктор. Опционально переопределить Notification, чтобы получать уведомления от освобожденных связанных компонентов.
    // И добавить property LinkedControl с setter-ом.
end;

For each WinControl in which something needs to be redefined, create an instance of TMyWndProcQueeHandler.

C
ComodoHacker, 2012-09-11
@ComodoHacker

And if you make a proxy WinControl and slip it on them? And destroy everything in it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question