окно поверх других приложений когда и почему
От: Шебеко Евгений  
Дата: 19.09.11 08:19
Оценка:
Заказчику нужно было окно, которое появляется поверх других приложений.
Мотивация такая: "Когда диспетчер смотрит фильм, необходимо чтобы тревога выскакивала у него поверх всего".
К счастью код на скрипте так и заработал.



Скрипт использует VCL от Builder6 для создания окон.
Код окна такой:
  fm.pConstructor(mainForm);
  fm.Caption="Тревога";
  fm.Width=248;
  fm.Height=159;
  fm.BorderStyle=bsSizeToolWin;
  fm.AutoScroll=false;
  fm.FormStyle=fsStayOnTop;
  fm.Visible=false;
  fm.Left=200;
  fm.Top=200;
  fm.Visible=false;
  fm.setEventHandler("OnClose","fmAlertClose");
  fm.ShowHint=true;
  fm.Color=clRed;

За стили отвечают выделенные фрагменты.
Не скажу точно, как оно ложится на WIN API.
Если надо, могу посмотреть Spy++.


Вопрос в том, почему это работает?
Бывает пытаешься создать такое окно, а оно не выходит.
Помигает твоё приложение в taskbar и всё. Мол пользователь сам княпнуть должен, чтобы сделать приложение
(главное окно приложения) активным.
Читал, что по дизайну это некошерно, когда выскакивают окна неактивных приложений.
Поэтому, код, который это делает, теперь только мигает в taskbar'e.
А тут само появилось. При определённых условиях вообще от него фиг избавишься.
Окно выскакивает и в XP, и в Win7.
Или некошерно только для модальных окон?

В общем кто может авторитетно просветить по этому вопросу?

ЗЫ. Такое страшное окно захотел заказчик
Re: окно поверх других приложений когда и почему
От: 5er Россия  
Дата: 19.09.11 10:17
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:


ШЕ>В общем кто может авторитетно просветить по этому вопросу?


ШЕ>ЗЫ. Такое страшное окно захотел заказчик


Посмотрите описание SetForegroundWindow.
Скрипт, думаю, использует нулевой таймаут.
Что-то типа:


        ::SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &dwTimeOut, 0 );
        ::SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE );

        ::SetForegroundWindow( hWnd );

        ::SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)dwTimeOut, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE );
Re: окно поверх других приложений когда и почему
От: CoolCmd Россия  
Дата: 19.09.11 10:44
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>За стили отвечают выделенные фрагменты.

ШЕ>Не скажу точно, как оно ложится на WIN API.
ШЕ>Вопрос в том, почему это работает?
В твоем коде судя по названиям окну добавляются стили WS_EX_TOPMOST и WS_EX_TOOLWINDOW. Окно показывает стиль WS_EX_TOPMOST. Но обычно он не делает окно активным как SetForegroundWindow(), только показывает поверх других.
простите, я убил небо
Re: окно поверх других приложений когда и почему
От: icWasya  
Дата: 19.09.11 11:13
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>...К счастью код на скрипте так и заработал.


ШЕ>...

ШЕ>Вопрос в том, почему это работает?
ШЕ>...

А если после выскакивания окна тревоги переключиться на другое приложение,
то где оно будет выскакивать второй раз?
Re[2]: окно поверх других приложений когда и почему
От: Шебеко Евгений  
Дата: 19.09.11 11:35
Оценка:
Здравствуйте, CoolCmd, Вы писали:

CC>Здравствуйте, Шебеко Евгений, Вы писали:


ШЕ>>За стили отвечают выделенные фрагменты.

ШЕ>>Не скажу точно, как оно ложится на WIN API.
ШЕ>>Вопрос в том, почему это работает?
CC>В твоем коде судя по названиям окну добавляются стили WS_EX_TOPMOST и WS_EX_TOOLWINDOW. Окно показывает стиль WS_EX_TOPMOST. Но обычно он не делает окно активным как SetForegroundWindow(), только показывает поверх других.

Активным его делает (и вообще показывает) fm.Show();
Вот исходники VCL. Там вообще много кода, особенно связанными со свойствами.
Я выдрал только часть.

procedure TCustomForm.Show;
begin
  Visible := True;
  BringToFront;
end;

procedure TCustomForm.SetVisible(Value: Boolean);
begin
  if fsCreating in FFormState then
    if Value then
      Include(FFormState, fsVisible) else
      Exclude(FFormState, fsVisible)
  else
  begin
    if Value and (Visible <> Value) then SetWindowToMonitor;
    inherited Visible := Value;
  end;
end;

procedure TControl.BringToFront;
begin
  SetZOrder(True);
end;

procedure TWinControl.SetZOrder(TopMost: Boolean);
const
  WindowPos: array[Boolean] of Word = (HWND_BOTTOM, HWND_TOP);
var
  N, M: Integer;
begin
  if FParent <> nil then
  begin
    if TopMost then N := FParent.FWinControls.Count - 1 else N := 0;
    M := 0;
    if FParent.FControls <> nil then M := FParent.FControls.Count;
    SetZOrderPosition(M + N);
  end
  else if FHandle <> 0 then
    SetWindowPos(FHandle, WindowPos[TopMost], 0, 0, 0, 0,
      SWP_NOMOVE + SWP_NOSIZE);
end;
Re: окно поверх других приложений когда и почему
От: Pavel Dvorkin Россия  
Дата: 19.09.11 13:14
Оценка: 2 (1)
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>fm.FormStyle=fsStayOnTop;[/b]


Подозреваю, что это CreateWindowEx/WS_EX_TOPMOST.

Создаем в VC++ Win32 проект и в нем меняем

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

на

hWnd = CreateWindowEx(WS_EX_TOPMOST,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

Сидит наверху как влитое, как ни переключайся на другие окна.


Можно также менять по ходу работы

SetWindowPos c HWND_TOPMOST / HWND_NOTOPMOST
With best regards
Pavel Dvorkin
Re[2]: окно поверх других приложений когда и почему
От: 5er Россия  
Дата: 19.09.11 13:25
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, Шебеко Евгений, Вы писали:


ШЕ>>fm.FormStyle=fsStayOnTop;[/b]


PD>Подозреваю, что это CreateWindowEx/WS_EX_TOPMOST.


PD>Создаем в VC++ Win32 проект и в нем меняем


PD> hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

PD> CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

PD>на


PD> hWnd = CreateWindowEx(WS_EX_TOPMOST,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

PD> CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

PD>Сидит наверху как влитое, как ни переключайся на другие окна.



PD>Можно также менять по ходу работы


PD>SetWindowPos c HWND_TOPMOST / HWND_NOTOPMOST



У вас на win7 этот способ работает?
Дело в том, что я недавно как раз с этим возился. На XP да, работает как часы.
Но на Win7 сработал только способ со сбросом таймаута в ноль (SystemParametersInfo SPI_SETFOREGROUNDLOCKTIMEOUT).

Ни SetWindowPos, ни какие-либо манипуляции с z-order не помогли.
Re[3]: окно поверх других приложений когда и почему
От: Шебеко Евгений  
Дата: 19.09.11 13:48
Оценка:
5er>У вас на win7 этот способ работает?
5er>Дело в том, что я недавно как раз с этим возился. На XP да, работает как часы.
5er>Но на Win7 сработал только способ со сбросом таймаута в ноль (SystemParametersInfo SPI_SETFOREGROUNDLOCKTIMEOUT).
5er>Ни SetWindowPos, ни какие-либо манипуляции с z-order не помогли.

Работает. Я только что проверил.
Только это ведь единственное окно приложения.

Скажем будет ли такое же работать, если:
1. основное окно не WS_EX_TOPMOST
2. Запустили приложение и переключились в другое.
3. А потом возникает ещё одно окно нашего приложения уже с WS_EX_TOPMOST

Вопрос в том, вылезет ли оно поверх чужого приложения или нет?
Re[3]: окно поверх других приложений когда и почему
От: Pavel Dvorkin Россия  
Дата: 19.09.11 13:58
Оценка:
Здравствуйте, 5er, Вы писали:

5er>У вас на win7 этот способ работает?


Да. Как вариант с CreateWindowEx, так и

case ID_FILE_TOPMOST: // изначально создано topmost
{
static bool bTopMost = false;
SetWindowPos(hWnd,bTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
bTopMost = !bTopMost;
break;
}



W7/x64. Ничего не делал кроме того, что описал.
With best regards
Pavel Dvorkin
Re[4]: окно поверх других приложений когда и почему
От: Pavel Dvorkin Россия  
Дата: 19.09.11 14:04
Оценка: 6 (1)
Здравствуйте, Шебеко Евгений, Вы писали:

5er>>У вас на win7 этот способ работает?

5er>>Дело в том, что я недавно как раз с этим возился. На XP да, работает как часы.
5er>>Но на Win7 сработал только способ со сбросом таймаута в ноль (SystemParametersInfo SPI_SETFOREGROUNDLOCKTIMEOUT).
5er>>Ни SetWindowPos, ни какие-либо манипуляции с z-order не помогли.

ШЕ>Работает. Я только что проверил.

ШЕ>Только это ведь единственное окно приложения.

Делаем заново Win32 проект, без моих изменений. Там есть диалог About. В его функции

    case WM_INITDIALOG:
        SetWindowPos(hDlg, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
        return (INT_PTR)TRUE;



Основное окно теперь не topmost, а диалог, если его показать сидит как влитой, хоть что делай.
With best regards
Pavel Dvorkin
Re[5]: окно поверх других приложений когда и почему
От: Шебеко Евгений  
Дата: 19.09.11 14:18
Оценка:
PD>Основное окно теперь не topmost, а диалог, если его показать сидит как влитой, хоть что делай.
Да,да я проверил.
У меня здесь основное окно обычное, а по таймеру через 10 секунд создаётся About с WS_EX_TOPMOST.
Я допёр. Окно чудно появляется поверх всех окон даже в Win7.
Но оно неактивное. В том плане, что фокус остаётся у другого приложения.
Так что всё честно




...
HWND hMainWnd;
UINT_PTR timer_id;
...
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
...
    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow)) 
    {
        return FALSE;
    }

    timer_id=SetTimer(hMainWnd,1,10000,0);
...
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   hMainWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hMainWnd)
   {
      return FALSE;
   }

   ShowWindow(hMainWnd, nCmdShow);
   UpdateWindow(hMainWnd);

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
....
    case WM_TIMER:
    {
        KillTimer(hMainWnd,timer_id);
        DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
        break;
    }
...
}

LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_INITDIALOG:
        SetWindowPos(hDlg, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
        return TRUE;
...
    }
    return FALSE;
}
Re: один важный момент про топ-окна
От: CEMb  
Дата: 20.09.11 02:39
Оценка: 1 (1) +1
Обычно все джигиты, которые делают топ(мост)-окна, забывают о юзерах, которые, например, набирают текст в блокноте. Юзер смотрит в клаву и набирает текст, тут джигит поднимает своё гордое окно поверх всех окон, юзер в наборе текста жмёт пробел — тынц, окно закрылось! Юзер смотрит на экран и думает, а чё это часть текста не пропечаталась?...
Re[2]: один важный момент про топ-окна
От: CEMb  
Дата: 20.09.11 15:11
Оценка:
Здравствуйте, CEMb, Вы писали:

CEM>Обычно все джигиты, которые делают топ(мост)-окна, забывают о юзерах, которые, например, набирают текст в блокноте. Юзер смотрит в клаву и набирает текст, тут джигит поднимает своё гордое окно поверх всех окон, юзер в наборе текста жмёт пробел — тынц, окно закрылось! Юзер смотрит на экран и думает, а чё это часть текста не пропечаталась?...


Тьфублин, я чё сказать-то хотел! Вот у outpost сделано нормально — там окно появляется поверх всех окон, но оно — неактивное! Так делать надо
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.