Есть как минимум три компонента, которые, получив ссылку на TWinControl, хотят начать корректировать своё положение при изменении положения того контрола, и ещё как-то реагировать на приходящие ему события.
Все три, независимо друг от друга, могут добавляться и удаляться в произвольном порядке. И в рантайме, и в дизайн-тайме.
Все три, в принципе, у меня в исходниках — но подстава: относятся к разным пакетам компонентов и соответственно я не могу их исправить так, чтобы они пользовались каким-то моим общим для них вспомогательным классом — менеджером очереди подменных WindowProc. Кроме того, возможно ещё кто-то тоже пользуется таким-же методом, но я его ещё не обнаружил.
Сейчас они все трое для паразитирования пользуются одним и тем же очень популярным подходом, думая что каждый из них уникален:
procedure T***.PatchControl;
begin
FOldWndProc := FLinkedControl.WindowProc;
FLinkedControl.WindowProc := MyWndProc;
end;
procedure T***.UnpatchControl;
begin
FLinkedControl.WindowProc := FOldWndProc;
end;
Естественно, у каждого свой аналог первого кода вызывается при привязке, второго — при отвязке. Столь же естественно, что когда привязываются несколько таких паразитов а отвязываться они начинают не в обратном порядке, а в любом другом, то отвязывающиеся позднее привязывают обратно те обработчики от уже отвязавшихся, ссылки на которые которые они запомнили когда привязывались после них.
Чтобы убедиться в этом, я повтыкал проверку такого вот вида:
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;
Естественно, ассерты стали сыпаться, естественно даже в IDE с его дизайнером форм. А до того — время от времени сыпались не ассерты, а сама IDE.
Вопрос — чё с этим делать-то?? Голову уже сломал…
P.S. Возможно, как-то иначе перехатывать только WM_WindowPosChanged меня тоже бы устроило…