Форум: "WinAPI";
Текущий архив: 2004.10.10;
Скачать: [xml.tar.bz2];
ВнизОкно поверх всех окон - проблема(+) Найти похожие ветки
← →
UNIVERSAL (2004-09-09 10:25) [0]Для модераторов: В FAQ и поиске ничего не нашёл, точнее нашёл, но не то.
Здравствуйте уважаемые Мастера. Вроде всё легко, но глюк замучал. Сделал CBT хук на HCBT_ACTIVATE, HCBT_MINMAX, HCBT_MOVESIZE, хотя наверное хватило бы только HCBT_ACTIVATE, но это я уже просто от безысходности добавил. Так вот окно действительно выводится поверх всех, но иногда, а именно, когда я щёлкаю мышью на окно, которое должно быть поверх всех, или на главное окно приложения, а потом на чужое окно оно уходит вниз, т.е. перестаёт быть поверх всех. Пробовал создать новое приложение только с одним главным окном и сделать его TOPMOST с помощью того же хука - работает, и даже, когда я на него щёлкаю мышью. Но дело в том,что мне нужно именно чтобы не главное окно приложения было поверх всех. Может кто сталкивался подскажите.
Вот код модуля хука
library H_CBT;
uses
SysUtils,
Windows, Messages, shellapi;
{$R *.RES}
type
PHookRec = ^THookRec;
THookRec = record
WndHandle: HWND;
HookHandle: HHOOK;
end;
const rHookRec: PHookRec=nil;
WM_SETWNDMSGTOP=WM_USER+106;
var HookSet:boolean;
//
procedure EntryPointProc(Reason: Integer);forward;
//
function CBTProc(nCode : Integer; wParam, lParam: integer): LResult; stdcall;
begin
if nCode >= 0 then
begin
if ((nCode=HCBT_ACTIVATE) or (nCode=HCBT_MINMAX)or (nCode=HCBT_MOVESIZE)){ and (wParam<>rhookrec^.HookHandle) }then
SendMessage(rHookRec^.WndHandle ,WM_SETWNDMSGTOP,wParam,1);
end;
Result := CallNextHookEx(rhookrec^.HookHandle, nCode, wParam, lParam);
end;
// поставить хук
procedure SetCBTHook;
begin
rHookRec^.HookHandle:= SetWindowsHookEx(WH_CBT,@CBTProc,HInstance,0);
// SendMessage(rHookRec^.WndHandle ,WM_SETWNDMSGTOP,0,1);
HookSet:=rHookRec^.HookHandle>0;
end;
// убрать хук
procedure RemoveCBTHook;
begin
SendMessage(rHookRec^.WndHandle ,WM_SETWNDMSGTOP,0,0);
HookSet:=UnhookWindowsHookEx(rHookRec^.HookHandle);
end;
procedure EntryPointProc(Reason: Integer);
const
hMapObject: THandle = 0; // this project was declared with Assignable Typed Constants
begin
case reason of
DLL_PROCESS_ATTACH:
begin
hMapObject := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(THookRec), "_CBT");
rHookRec := MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, 0);
end;
DLL_PROCESS_DETACH:
begin
try
UnMapViewOfFile(rHookRec);
CloseHandle(hMapObject);
except
end;
end;
end;
end;
// we have to tell the DLL where our entry point proc is and call it as an attach
procedure SetMainHandle(Handle: HWND);stdcall;
begin
rHookRec^.WndHandle:= Handle;
end;
function HookIsSet:Boolean;stdcall;
begin
Result:=HookSet;
end;
exports
HookIsSet,
SetCBTHook,
RemoveCBTHook,
SetMainHandle;
begin
HookSet:=false;
DllProc := @EntryPointProc;
EntryPointProc(DLL_PROCESS_ATTACH);
end.
← →
UNIVERSAL (2004-09-09 11:44) [1]Ау люди вы где? Неужеди никто не сталкивался с этим?
Один способ, но не совсем то что надо я нашёл: это в обработке сообщения, которое отсылает хук моему окну поставить вместоSetWindowPos(frmMessages.handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE)
этот кодSetWindowPos(Application.handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE)
, но тогда HWND_TOPMOST получается всё приложение. в общем терпимо конечно, но это уже дело принципа.
← →
DVM © (2004-09-09 11:57) [2]Зачем тут ловушка вообще? Единственный способ быть почти всегда поверх всех - это в таймере двигать свое окно наверх с пом. SetWindowPos, причем чем таймер чаще, тем это будет надежнее.
НО ВСЕГДА ПОВЕРХ ВСЕХ ОКОН НЕЛЬЗЯ!
← →
UNIVERSAL (2004-09-09 12:06) [3]А почему не ловушка? И это не "единственный способ". В таймере, я думаю будут "провалы", с окном или тормоза, если сильно маленкий интервал задать. А с ловушкой у меня проблем нет, проблема мне кажется с глюком у делфей(ну или у меня из-за незнания :-) ), которые главную форму приложения делают поверх окон, а неглавную не всегда. И ещё дело в том, что у меня уже есть два таймера из-за сабжа приложения, не хочется мне ещё один лепить. Неужели в Аське и Download Master-е используется таймер? что-то я сомневаюсь.
← →
сруигкфещк (2004-09-09 12:18) [4]Не понял, а в чём проблема то ?
{ and (wParam<>rhookrec^.HookHandle) } - зачем коментарил ?
хотя должно быть wParam <> rHookRec^.WndHandle
Result := CallNextHookEx(rhookrec^.HookHandle, nCode, wParam, lParam); - лестная строка для других форм :о), но как ты хочешь сделать ТОР-окно, если передаёшь код об активации окна дальше по цепочке получателей сообщений ?
Может так ?
function CBTProc(nCode : Integer; wParam, lParam: integer): LResult; stdcall;
begin
if (nCode = HCBT_ACTIVATE) and (wParam <> rHookRec^.WndHandle)
then
begin
SendMessage(rHookRec^.WndHandle ,WM_SETWNDMSGTOP,wParam,1);
CBTProc := 0;
end
else
Result := CallNextHookEx(rhookrec^.HookHandle, nCode, wParam, lParam);
end;
Где rHookRec^.WndHandle - HWND нужного тебе окна для показа на верху ? Попробуй...
← →
DVM © (2004-09-09 12:18) [5]
> UNIVERSAL (09.09.04 12:06) [3]
Большинство игр с легкостью перекроют твое окно.
> Неужели в Аське и Download Master-е используется таймер?
> что-то я сомневаюсь.
А это легко узнать, воспользовавшись SPY++. А если они используют ловушки, то скорее всего есть dll с характерными экспортируемыми функциями.
Но я бы лично обошелся без ловушек. При первом запуске двинуть окно наверх. Потом обрабатывая WM_WINDOWPOSCHANGING, не давать ему "спуститься ниже".
А еще есть fsStayOnTop.
← →
UNIVERSAL (2004-09-09 12:43) [6]2сруигкфещк блин, правда ошибся :)
2DVM © fsStayOnTop -по-моему это работает только внутри данного приложения.
Неужели дело в хуке? ведь в приложении, где хук шлёт сообщение для MainForm всё работает...
← →
UNIVERSAL (2004-09-09 14:28) [7]2сруигкфещк rHookRec^.WndHandle - да это хендл HWND нужного мне окна для показа на верху. К сожалению суть не поменялась :(.
← →
evvcom © (2004-09-10 03:49) [8]..сруигкфещк = cheburator..
> fsStayOnTop -по-моему это работает только внутри данного
> приложения.
Не только, но если есть другое окно с fsStayOnTop, то оно с легкостью может перекрыть первое.
← →
UNIVERSAL (2004-09-10 09:20) [9]2evvcom Спасибо за расшифровку :)
← →
UNIVERSAL (2004-09-10 09:33) [10]Кстати объясните попутно, пожалста, ещё одну вещь:
вот код, который мне посоветовал cheburator.
function CBTProc(nCode : Integer; wParam, lParam: integer): LResult; stdcall;
begin
if (nCode = HCBT_ACTIVATE) and (wParam <> rHookRec^.WndHandle)
then
begin
SendMessage(rHookRec^.WndHandle ,WM_SETWNDMSGTOP,wParam,1);
CBTProc := 0;
end
else
Result := CallNextHookEx(rhookrec^.HookHandle, nCode, wParam, lParam);
end;
Ну так вот у меня он не хочет корректно работать почему-то (окна в приложении не двигаются.), хотя в примерах я видел именно такой код и это считается правильным. Отличе от моего в том что я не присваиваю процедуре хука результат 0, когда его обрабатываю, а вызываю обработку следующего хука, причём, всегда (см модуль в первом сообщении). Хотелось бы узнать как именно правиль и что происходит, если не присваивать процедуре хука 0?. Заранее благодарен.
← →
tmp_name (2004-09-10 13:59) [11]Почему используется: "SendMessage(rHookRec^.WndHandle ,WM_SETWNDMSGTOP,wParam,1);",
а не как в MSDN написано: "SetWindowPos(rHookRec^.WndHandle, HWND_TOPMOST, x, y, w, h, 0);"?
Я поставил кнопку на Form1, на клик написал: SetWindowPos(Form2.Handle, HWND_TOPMOST, Form2.Left, Form2.Top, Form2.Width, Form2.Height, 0);. Все работает.
← →
UNIVERSAL (2004-09-10 14:32) [12]Не понял связи между хуком и кликом на кнопку. При авктивации других окон это окно "упадёт" под него. можно конечно сразу попробовать поставить окно на верх, не отсылая сообщения для него....
← →
tmp_name (2004-09-10 16:22) [13]Если тебе нужен был хук только для topmost, то это изврат какой-то получается.
Попробуй новый пример:
2 видимые формы.
На первую кидаешь TApplicationEvents и на события Activate и DeActivate этого компонента пишешь:SetWindowPos(Form2.Handle, HWND_TOPMOST, Form2.Left, Form2.Top, Form2.Width, Form2.Height, 0);
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.10.10;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.039 c