Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Код хука тривиален
function myRegisterWindowMessageA(name: PAnsiChar): UINT; stdcall;
...
...
len := lstrlen(name);
if copy(name, 1, 10) = 'ControlOfs' then
Result := OriginalRegisterWindowMessageA(PChar('abcd'));
else
Result := OriginalRegisterWindowMessageA(Name);
RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString));RM_GetObjectInstance := RegisterWindowMessage(PChar('ControlAtomString'));'RM_GetObjectInstance' — просто потому, что так описано на Embarcadero Quality Center. Чтобы поменьше разброда было.RM_GetObjectInstance := RegisterWindowMessage(PChar('DelphiRM_GetObjectInstance'));function ObjectFromHWnd(Handle: HWnd): TWinControl;
var
OwningProcess: DWORD;
ProcessId: DWORD;
begin
ProcessId := GetCurrentProcessId;
if (GetWindowThreadProcessId(Handle, OwningProcess) <> 0) and
(OwningProcess = ProcessId) then
Result := Pointer(SendMessage(Handle, RM_GetObjectInstance, ProcessId, 0))
else
Result := nil;
end;function FindControl(Handle: HWnd): TWinControl;
var
OwningProcess: DWORD;
begin
Result := nil;
if (Handle <> 0) and (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and
(OwningProcess = GetCurrentProcessId) then
begin
if GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom then
Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))
else
Result := ObjectFromHWnd(Handle);
end;
end;function IsDelphiHandle(Handle: HWND): Boolean;
var
OwningProcess: DWORD;
begin
Result := False;
if (Handle <> 0) and (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and
(OwningProcess = GetCurrentProcessId) then
begin
{$IF DEFINED(CLR)}
Result := FindControl(Handle) <> nil;
{$ELSE}
if GlobalFindAtom(PChar(WindowAtomString)) = WindowAtom then
Result := GetProp(Handle, MakeIntAtom(WindowAtom)) <> 0
else
Result := ObjectFromHWnd(Handle) <> nil;
{$ENDIF}
end;
end;Кстати в MSDN не сказано что винда не чистит атомы от RegisterWindowMessage
The message remains registered until the session ends.
Я проверил на WIN7 со всеми обновлениями. Сожрал атомы и прибил процесс. Через некоторое время винда очистила хендлы, но очистила их далеко не сразу после регистрации
Какого-то лешего разработчики Windows решили, что в принципе достаточно использовать один скоуп для RegisterClipboardFormat и RegisterWindowMessage
Да и потом, неудача с RM_GetObjectInstance VCL не огорчит
Ситуацию спасает лишь то, что винда периодически (и неизвестно при каких обстоятельствах) чистит эти атомы.
В MSDN сказано, как я цитировал в посте:Упс, не заметил конца фразы.
Атомы вообще или именно RWMовские?Именно RWM-овские. Чистилось не сразу, а через некоторое время, после того как заканчивались. Т.е. я в цикле гоняю пачку RegisterWindowMessage с рандомными именами. Когда начинает возвращать 0 — прекращаю цикл и завершаю приложение. Таким образом у меня все атомы съедены. После этого поперезапускаю процессы (там IDE перезапущу, или еще какие тяжелые процессы), и атомы вновь появляются. По крайней мере RegisterWindowMessage начинает возвращать не ноль.
На WS2008 нет очистки, мы именно на 2008м увидели это впервые. И атомы накапливались там не один день.Это очень печально, потому что RegisterWindowMessage сделан костылем через клипборд.
Ну, как вам сказать — сообщение-то это VCL не нужно, но вот приложение не запустится. Вообще.А у меня все запускается. Там возвращается 0, ну и дальше все типтоп.
А у меня все запускается. Там возвращается 0, ну и дальше все типтоп.
Еще раз об утечке атомов и баге VCL