Как сделать так, чтобы окно приложения не сворачивалось при нажатии "Свернуть все" (Toggle desktop, Win+D)? (или сворачивалось, но быстро восстанавливалось обратно). Если нажать "Свернуть все", то сворачиваются все окна и выполнение Application.Restore ничего не делает, окно остается скрытым пока снова не нажать "Свернуть все" или кнопку приложения на таск баре.
Это реализуемо: Например QIP icq-клиент не сворачивается при нажатии "Свернуть все"
Зачем это нужно: отображать записки, приколотые к рабочему столу - свернули все - видим записки. Рисовать на рабочем столе - не выход.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
17-09-2008 05:49 | Комментарий к предыдущим ответам
>>> Но при этом окно получило WM_SHOWWINDOW (Show = False) с причиной SW_PARENTCLOSING (при этом у Form1 Parent = 0)
Кстати, об этом даже VCL в курсе:
procedure TCustomForm.WMShowWindow(var Message: TWMShowWindow);
const
ShowCommands: array[saRestore..saMaximize] of Integer =
(SW_SHOWNOACTIVATE, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED);
begin
with Message do
case Status of
SW_PARENTCLOSING:
begin
if IsIconic(Handle) then FShowAction := saMinimize else
if IsZoomed(Handle) then FShowAction := saMaximize else
FShowAction := saRestore;
inherited;
end;
SW_PARENTOPENING:
if FShowAction <> saIgnore then
begin
ShowWindow(Handle, ShowCommands[FShowAction]);
FShowAction := saIgnore;
// This occurs when MainFormOnTaskbar is False
// and the ShowDesktop button is clicked.
if Self = Application.MainForm then
AppIconic := False;
end;
else
inherited;
end;
end;
procedure TForm1.CreateParams(var Params: TCreateParams);
var wd:HWnd;
begin
repeat
wd:=FindWindow('Progman','Program Manager');
until wd<>0;
inherited CreateParams(Params);
Params.WndParent:=wd;
Params.Style:=WS_CHILD;
end;
Работает, форма висит только на рабочем столе и не сворачивается. Все идеально но есть огромный минус - перестает работать прозрачность компонентов на форме и самой формы. То есть у того же Label при включенном transparent фон виден clBtnFace. У формы AlphaBlend не работает... И т.д...
Подозреваю это потому что винда считает что под рабочим столом фона нет и быть не может...
Если убрать строчку:
Params.Style:=WS_CHILD;
то прозрачность работает, форма не сворачивается, но Win+D блокируется. Свернуть все окна кроме формы можно, а вот развернуть обратно - нельзя. Форма словно перехватывает это сообщение и блокирует его... Поэтому способ не годится.
Проблему с прозрачностью не решил до сих пор. Спрашивал автора одной дельфийской программулины которая вела себя корректно, но тот зажлобился. Типа "секрет"...
Намекнул только про назначение рабочего стола родителем, но это я и без него знал.
Подскажите кто знает. Ведь делают же, значит точно можно!
Для размышлений:
1. Что касается QIP, то он ловит некое "AppBarNotify" (я так понял, зарегистрированное через RegisterWindowMessage). Смотрел это в Spy++. Наверное, это каким-то образом связано с SHAppBarMessage
Во время сворачивания всех окон, приходит это сообщение с wParam = 2 (м.б. ABN_FULLSCREENAPP?), lParam = 1.
2. Ещё заметил: у меня Total Commander при сворачивании убирается в трей. Так вот, когда жмёшь на "свернуть все окна", то он сворачивается в трей. Т.е. сам Total Commander в курсе, что его сворачивают.
3. Создал обычное пустое приложение, заблокировал CS_MINIMIZE у формы и Application. Приложение сворачивается при Свернуть все окна (никаких WM_SYSCOMMAND не рассылается).
Но при этом окно получило WM_SHOWWINDOW (Show = False) с причиной SW_PARENTCLOSING (при этом у Form1 Parent = 0), а Application - WM_SIZE с SIZE_MINIMIZED и пачку WM_WINDOWPOSCHANGING.
Эх... Кто-нибудь решил данную проблематику ? Все вышеупомянутые варианты у меня на машине НЕ сработали ... :( Свертывается все... И честно говоря - я еще НЕ видел программы, которая по этому клику НЕ сворачивалась ...
А про Квип - судя по всему - все зависит от пропатченности винды ... и ее настройки (хотя где такие есть (именно по объекту - свернуть все)?)
03-05-2006 14:04 | Комментарий к предыдущим ответам
А HRESULT какой?
А вот теперь уже не скажу, но вроде OleCheck выдавало сообщение "Класс не зарегистрирован". На доступном мне сейчас компе всё работает нормально в плане CoCreateInstance, хотя данный код никак не влияет на появление окна, кнопка моргает лишняя (если Sleep поставить, иначе не заметить), но больше ничего не происходит.
Ну в общем я нашёл комп на котором мой код не работает и вот что получилось:
type
TDummyObject=class
class function AppWndProc(var Msg:TMessage):Boolean;
end;
class function TDummyObject.AppWndProc(var Msg:TMessage):Boolean;
var
Input:TInput;
begin
Result:=True;
case Msg.Msg of
WM_SIZE:
if Msg.wParam=SIZE_MINIMIZED then
SetTimer(Application.Handle,1,200,nil);
WM_TIMER:begin
KillTimer(Application.Handle,1);
FillChar(Input,SizeOf(Input),0);
SendInput(1,Input,SizeOf(TInput));
SetForegroundWindow(Application.Handle);
Application.Restore;
end;
else
Result:=False;
end;
end;
Это всё конечно очень грязно (особенно трюк с SendInput) и основано на таймере (то есть будет мигать и нет гарантии срабатывания во всех ситуациях), но у меня вроде заработало.
Прошу всех оттестировать и написать о своих результатах!
Ну во первых условие "s = 'WorkerW'" не выполняется (или не всегда выполняется) при сворачивании по Win+D, но всегда срабатывет при сворачивании через меню, во вторых у меня CoCreateInstance всегда возвращает в hs nil, так что ваш код просто не срабатывает.
Опытным путем найдено, хоть и кривое, но решение! Прошу всех оттестировать и написать о своих результатах! Данное решение позволяет восстанавливать окно сразу после сворачивания по Win+D используя ITaskBarList:
type
ITaskBarList = interface(IUnknown)
['{56FDF342-FD6D-11d0-958A-006097C9A090}']
function HrInit(): HResult; stdcall;
function AddTab(WND: HWND): HResult; stdcall;
function DeleteTab(WND: HWND): HResult; stdcall;
function ActivateTab(WND: HWND): HResult; stdcall;
function SetActiveAlt(WND: HWND): HResult; stdcall;
end;
implementation
...
procedure TForm1.Timer1Timer(Sender: TObject); // Таймер каждую миллисекунду
var
hs: ITaskbarList;
s: array[0..255] of char;
begin
GetClassName(GetForegroundWindow,s,255);
if s = 'WorkerW' then //Такой класс у окна которое активно после Win+D (может не только тогда, поэтому и прошу протестить на баги)
begin
CoCreateInstance(CLSID_TaskBarList,nil,CLSCTX_ALL,IID_ITaskBarList,hs);
hs.HrInit; //Инициализируем ITaskBarList
hs.AddTab(Handle); //Создаем на TaskBar'е кнопку нашего окна
hs.ActivateTab(Handle); //Активируем его
hs.DeleteTab(Handle); //Удаляем кнопку
SetForegroundWindow(Handle); //Активируем наше окно
end;
end;
Кривенько, но лучше чем ничего! Жду отчетов по тестированию! Спасибо всем!
2DRON
Да, скорее всего какие-то настройки и дополнительные программы влияют. У меня предложенные методы не работают (Тоже на XP SP2 и все патчи). Работает только метод Ins'а
Ставлю на форму таймер и выполняю "Application.Restore", в XP гарантированно не работает.
Делал то же самое всё работает, похоже это зависит не только от версии виндов (у меня XP SP2 со всеми апдейтами), но и от каких-то настроек.
Любой отказ от WS_EX_TOPMOST заставляет окно сворачиваться.
А у меня нет. Мистика какая-то.
SetWindowLong(Application.Handle,GWL_STYLE,GetWindowLong(Application.Handle,GWL_STYLE)and not WS_GROUP);
Это всё, никаких StayOnTop и прочего не нужно, просто добавьте этот код в DPR-файл. Почему это вообще работает и какие тут могут быть побочные эффекты я не в курсе.
PS: вот вылез один эффект: форма не реагирует на нажатие кнопки приложения на тулбаре.
Способ действительно рабочий, но для моего случая к сожалению не подходит - нужно чтоб записки были приколоты к рабочему столу, а не поверх всего. Любой отказ от WS_EX_TOPMOST заставляет окно сворачиваться. Даже выполнения кода после его создания с флагом WS_EX_TOPMOST:
SetWindowPos(Handle,HWND_BOTTOM,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE);
делает окно уязвимым для ToggleDesktop;
2DRON: Ставлю на форму таймер и выполняю "Application.Restore", в XP гарантированно не работает.
Привет! qip 2005A. Alpha, Build 7840 - Действительно не сворачивается, если включить опцию "поверх всех окон". Странно однако, разработчики qip знают как это делается, а мы...?
У кого есть под рукой
Оно у меня всегда под рукой, но блокирование почти всех сообщений из полученного списка к нужному результату не приводит.
Зависшее окно у меня не сворачивается, а вот QIP (вчерашняя версия) у меня всё равно сворачивается. Может в вашем случае стоит сделать листочки Child-ами рабочего стола?
QIP последней версии не сворачивается, еще раз проверил.
Наблюдение:
Если в свернутом состоянии выполнить
MessageBox(Handle,'a','a',0);
то диалог не заставит приложение развернуться, а если
MessageBox(0,'a','a',0);
то оно развернется и отобразит диалог.
02-05-2006 10:53 | Комментарий к предыдущим ответам
К сожалению это не работает. Я тут уже и WM_SYSCOMMAND и WM_SIZE и даже WM_WINDOWPOSCHANGING попробовал, причём и у формы и у Application. Под XP ничего не помогает и упомянутый автором QIP тоже прекрасно сворачивается. Не сворачиваются, по моему, только зависшие окна.
Такой метод работать не будет. При нажатии "Свернуть все" сворачивается все (даже диалоги и прочие несворачивающиеся окна) причем SC_MINIMIZE им не отправляется! Все программы продолжают думать что они сейчас в развернутом состоянии.
Думал что вообще это фича Windows такая, запретить программам не сворачиваться, чтоб пользователь мог беспрепятственно получить доступ к рабочему столу, однако QIP же остается несвернутым, хотя и мигает 1 раз - очевидно восстанавливает каким-то образом свое окно. Но ни Restore, ни ShowWindow, ни изменение любых параметров через SetWindowLong ни приводят к нужному эффекту!
Можно сделать так, но в этом случае Form1 вообще не будет сворачиваться (даже по нажатию на кнопке "свернуть" самой формы). Ничего другого че-то в голову не лезет.
TForm1 = class(TForm)
private
{ Private declarations }
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.WMSysCommand(var Message: TWMSysCommand);
begin
if (Message.CmdType and $FFF0 = SC_MINIMIZE) then exit;
inherited;
end;
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.