Как переместить окно на передний план?
От: Александр Шаргин Россия RSDN.ru
Дата: 15.06.02 22:25
Оценка: 389 (15) +1
Статья:
Как переместить окно на передний план?
Автор(ы): Александр Шаргин


Авторы:
Александр Шаргин

Аннотация:
Многие знают, что для перемещения окна на передний план существует функция SetForegroundWindow из Win32 API (в MFC ей соответствует обёртка CWnd::SetForegroundWindow). Она отлично работала под Windows 95 и Window NT. Но потом парни из Майкрософт провозгласили новый принцип: "Никто кроме пользователя не имеет право выдвигать окно на передний план". И хотя их собственные продукты продолжают делать это при необходимости, функция SetForegroundWindow перестала работать, как раньше. Теперь только активный процесс (foreground process) может переместить окно на передний план с использовании этой функции, а окно фонового процесса начнёт "мерцать" на панели задач, чтобы привлечь внимание пользователя.

В общем случае не рекомендуется нарушать правила работы пользовательского интерфейса, предписанные Микрософт. Как правило, окно, выпрыгивающее из ниоткуда, только раздражает пользователя. Тем не менее, в некоторых приложениях бывает необходимо добиться именно такого поведения. Рассмотрим несколько способов достижения требуемого.
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Помещение окна на передний план...
От: Филимонов Илья Вячеславович Россия  
Дата: 16.06.02 22:25
Оценка: 3 (1)
BOOL SetWindowPos(HWND,HWND,int,int,int,int,UINT)
Первый параметр дискриптор окна которое надо переместить на передний план
Второй параметр необходимо установить в HWND_TOP или HWND_TOPMOST
а седьмой в SWP_NOSIZE|SWP_NOMOVE
остальные параметры не имеют значения :)))
Главное — это рабочая концепция и ослиная доля упрямства.
Re: Помещение окна на передний план...
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 16.06.02 23:06
Оценка:
только не "или", а сначала HWND_TOPMOST а потом HWND_TOP. И на передний план оно вылазит, но фокус ввода не получает :(
Re: Помещение окна на передний план...
От: Alexander Shargin Россия RSDN.ru
Дата: 16.06.02 23:59
Оценка:
Можно попробовать после этого сделать окну клик в виде mouse_event или SendInput. Если прокатит, будет ещё один способ в нашей копилке. :)
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Re: Небольшое дополнение
От: SVV Беларусь  
Дата: 11.03.04 15:00
Оценка:
Приведенный код работал у меня не всегда, поэтому я дополнил его и оформил свою функцию:
BOOL    mySetActiveWindow (HWND hWin)
{
  BOOL    rv = FALSE;
  HWND hActiveWin = ::GetForegroundWindow();
  if (hActiveWin==NULL)
    rv = SetForegroundWindow (hWin);
  else
  {
    DR    idMyThread = GetCurrentThreadId();
    DR    idxThread = GetWindowThreadProcessId (hActiveWin, 0);
    if (::AttachThreadInput (idMyThread, idxThread, TRUE))
    {
      if (::ShowWindow(hWin, SW_HIDE))
        if (::ShowWindow(hWin, SW_RESTORE))
          if (SetForegroundWindow (hWin))
          {
            rv = TRUE;
          }
      AttachThreadInput (idMyThread, idxThread, FALSE);
    }
  }
return    rv;
}


главное выделено жирным, без этого подопытное приложение (Calc.Exe, Win2k Sp4 Eng) иногда не хотело выскакивать на верх...
Re[2]: Небольшое дополнение
От: DmitryT  
Дата: 25.01.05 08:34
Оценка:
Здравствуйте, SVV, Вы писали:

SVV>Приведенный код работал у меня не всегда, поэтому я дополнил его и оформил свою функцию:


В каких ситуациях он у тебя не работал?

Есть очень большая программа.
В определенной ситуации она ''выкидывает'' модальный диалог.
Проблема в том, что иногда если юзер не прореагировал на него, через определенное время ''смежники'' выбрасывают
из другого потока еще один модальный диалог.
Так вот после истечения таймаута надо вернуть фокус первому модальному диалогу и закрыть его с возвращением на строку
if (pDlg->DoModal() == IDOK) в коде родителя.

Я применил для этого базовый код Александра Шаргина :
в OnClose() модального диалога при срабатывании таймера:
    if (GetForegroundWindow() != this)
    {
        HWND hCurrWnd;
        int iMyThreadID, iCurrThreadID;

        hCurrWnd = ::GetForegroundWindow();
        iMyThreadID   = GetCurrentThreadId();
        iCurrThreadID = GetWindowThreadProcessId(hCurrWnd, 0);

        AttachThreadInput(iMyThreadID, iCurrThreadID, TRUE);

        SetForegroundWindow();

        AttachThreadInput(iMyThreadID, iCurrThreadID, FALSE);
    }


В 95% случаев работает ''на ура''.
Но иногда обваливается Debug Assertion Failed: file: wincore.cpp line: 4486.
А именно в строчке ASSERT(ContinueModal()):

               // phase2: pump messages while available
                do
                {
                        ASSERT(ContinueModal());
..........................................................

Kaкие будут идеи?
Мы знаем: время растяжимо. Оно зависит от того,
Какого рода содержимым Вы заполняете его. (C. Маршак)
Re[3]: Небольшое дополнение
От: SVV Беларусь  
Дата: 25.01.05 09:33
Оценка:
Здравствуйте, DmitryT, Вы писали:

DT>Здравствуйте, SVV, Вы писали:


SVV>>Приведенный код работал у меня не всегда, поэтому я дополнил его и оформил свою функцию:


DT>В каких ситуациях он у тебя не работал?

есть определенные приложения, написанные фирмой Wincorr Nixdorf...
...
DT>Kaкие будут идеи?
по поводу Assert? никаких идей.
Re[4]: Небольшое дополнение
От: DmitryT  
Дата: 25.01.05 14:34
Оценка:
Поправка: Debug Assertion Failed: file: wincore.cpp line: 3486 (а не 4486).
Мы знаем: время растяжимо. Оно зависит от того,
Какого рода содержимым Вы заполняете его. (C. Маршак)
Re: Как переместить окно на передний план?
От: DmitryT  
Дата: 27.01.05 06:43
Оценка:
Александр Шаргин
Хотелось бы услышать Ваш ''разбор полетов''...
Особенно, в части перехвата пользовательского ввода функцией AttachThreadInput (подключая свой поток к обработке пользовательского ввода, ты все-таки вмешиваешься в ''нормальную жизнь'' системы).
Не может ли это привести иногда к проблемам в многопоточной программе?
Мы знаем: время растяжимо. Оно зависит от того,
Какого рода содержимым Вы заполняете его. (C. Маршак)
Re[2]: Как переместить окно на передний план?
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 27.01.05 06:56
Оценка: 8 (3)
Здравствуйте, DmitryT, Вы писали:

DT>Особенно, в части перехвата пользовательского ввода функцией AttachThreadInput (подключая свой поток к обработке пользовательского ввода, ты все-таки вмешиваешься в ''нормальную жизнь'' системы).

DT>Не может ли это привести иногда к проблемам в многопоточной программе?

IMHO, все это потеряло актуальность по причине — http://gzip.rsdn.ru/?Forum/Info.aspx?name=FAQ.winapi.wndsetfg
Re[3]: Как переместить окно на передний план?
От: DmitryT  
Дата: 27.01.05 09:36
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>IMHO, все это потеряло актуальность по причине — http://gzip.rsdn.ru/?Forum/Info.aspx?name=FAQ.winapi.wndsetfg


Можна развить Вашу мысль?
Почему потеряло актуальность?
Почему
::SendMessage(::GetDesktopWindow(), WM_SYSCOMMAND, (WPARAM) SC_HOTKEY, (LPARAM) hWin);

лучше?
Тем более, мы находимся в той же программв, а не управляем из другой программы...
Мы знаем: время растяжимо. Оно зависит от того,
Какого рода содержимым Вы заполняете его. (C. Маршак)
Re[4]: Как переместить окно на передний план?
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 27.01.05 09:57
Оценка:
Здравствуйте, DmitryT, Вы писали:

DT>Почему потеряло актуальность?

DT>Почему лучше?

все остальные способы, включая тот что с AttachThreadInput() и их комбинации, срабатывают не всегда (результат собственных экспериментов), а этот действует железно.

DT>Тем более, мы находимся в той же программв, а не управляем из другой программы...


результат нестабильный, включая "в той же программе".
Re[5]: Как переместить окно на передний план?
От: DmitryT  
Дата: 27.01.05 11:49
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>все остальные способы, включая тот что с AttachThreadInput() и их комбинации, срабатывают не всегда (результат собственных экспериментов), а этот действует железно.


Но как-то немного ''неловко'' "в той же программе", в том же окне (модальный диалог), посылать себе же
что-то типа:
void C...NumberDlg::OnTimer(UINT nIDEvent) 
{
 ::SendMessage(::GetDesktopWindow(), WM_SYSCOMMAND, (WPARAM) SC_HOTKEY, (LPARAM) this->m_hWnd);
 PostMessage(WM_CLOSE);
 CDialog::OnTimer(nIDEvent);
}

чтобы закрыть его с возвращением на строку if (pDlg->DoModal() == IDOK) в коде родителя.

OE>результат нестабильный, включая "в той же программе".

И в Вашем методе результат нестабильный?
Мы знаем: время растяжимо. Оно зависит от того,
Какого рода содержимым Вы заполняете его. (C. Маршак)
Re[6]: Как переместить окно на передний план?
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 27.01.05 11:51
Оценка:
Здравствуйте, DmitryT, Вы писали:

DT>И в Вашем методе результат нестабильный?


во всех приведенных кроме SC_HOTKEY
Re[3]: Как переместить окно на передний план?
От: DmitryT  
Дата: 01.02.05 09:46
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>IMHO, все это потеряло актуальность по причине — http://gzip.rsdn.ru/?Forum/Info.aspx?name=FAQ.winapi.wndsetfg


Moжешь не поверить, но вариант
::SendMessage(::GetDesktopWindow(), WM_SYSCOMMAND, (WPARAM) SC_HOTKEY, (LPARAM) this->m_hWnd);

у меня вообще не работает...
Мы знаем: время растяжимо. Оно зависит от того,
Какого рода содержимым Вы заполняете его. (C. Маршак)
Re[4]: Как переместить окно на передний план?
От: Аноним  
Дата: 02.07.08 09:46
Оценка:
Здравствуйте, DmitryT, Вы писали:

DT>Moжешь не поверить, но вариант

DT>
DT>::SendMessage(::GetDesktopWindow(), WM_SYSCOMMAND, (WPARAM) SC_HOTKEY, (LPARAM) this->m_hWnd);
DT>

DT>у меня вообще не работает...

А у меня не работает тоже
Re[5]: Как переместить окно на передний план?
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 02.07.08 09:58
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>А у меня не работает тоже


да, отпало, после SP1 кажется
... << RSDN@Home 1.2.0 alpha 4 rev. 1090>>
Re[6]: Как переместить окно на передний план?
От: xmen  
Дата: 22.08.08 22:47
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, <Аноним>, Вы писали:


А>>А у меня не работает тоже


OE>да, отпало, после SP1 кажется


SetForegroundWindow можно разрешить через AllowSetForegroundWindow

Что и демонстрирует мой код:
#define _WIN32_WINNT 0x0500 // Minimum system Windows 2000

bool SetForWindow(HWND hWnd)
{
    if (IsIconic(hWnd))
    {
        ShowWindow(hWnd, SW_RESTORE);
    }

    if (!IsWindowVisible(hWnd))
    {
        ShowWindow(hWnd, SW_SHOW);
    }

    SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
                 SWP_NOSIZE | SWP_NOMOVE);
    
    DWORD pId;
    
    if (GetWindowThreadProcessId(hWnd, &pId))
    {
        AllowSetForegroundWindow(pId);
    }
    
    return SetForegroundWindow(hWnd);
}
Re: Как переместить окно на передний план?
От: Eugeny__ Украина  
Дата: 28.01.09 16:53
Оценка:
Здравствуйте, Александр Шаргин, Вы писали:

АШ>Статья:

АШ>Как переместить окно на передний план?
Автор(ы): Александр Шаргин


АШ>Авторы:

АШ> Александр Шаргин

АШ>Аннотация:

АШ>Многие знают, что для перемещения окна на передний план существует функция SetForegroundWindow из Win32 API (в MFC ей соответствует обёртка CWnd::SetForegroundWindow). Она отлично работала под Windows 95 и Window NT. Но потом парни из Майкрософт провозгласили новый принцип: "Никто кроме пользователя не имеет право выдвигать окно на передний план". И хотя их собственные продукты продолжают делать это при необходимости, функция SetForegroundWindow перестала работать, как раньше. Теперь только активный процесс (foreground process) может переместить окно на передний план с использовании этой функции, а окно фонового процесса начнёт "мерцать" на панели задач, чтобы привлечь внимание пользователя.

АШ>В общем случае не рекомендуется нарушать правила работы пользовательского интерфейса, предписанные Микрософт. Как правило, окно, выпрыгивающее из ниоткуда, только раздражает пользователя. Тем не менее, в некоторых приложениях бывает необходимо добиться именно такого поведения. Рассмотрим несколько способов достижения требуемого.


Добрый день всем.

Скажите, а есть решение, которое работает на XP SP3? Сейчас попробывал все те, что указаны в статье — не работают. Самое интересное в третьем случае, SetForegroundWindow просто возвращает ложь, при этом GetLastError возвращает 0...
А нужна программка для переключение приложений, причем висящая как демон, без собственного интерфейса(активизируется по хуку, когда что-то подносят к сканеру штрихкодов, вобщем, не вирусы пишу ).
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Re[2]: Как переместить окно на передний план?
От: YuriKobets Россия http://www.truelaunchbar.com — замена панели быстрого запуска
Дата: 28.01.09 19:42
Оценка:
Здравствуйте, Eugeny__, Вы писали:

E__>Скажите, а есть решение, которое работает на XP SP3? Сейчас попробывал все те, что указаны в статье — не работают. Самое интересное в третьем случае, SetForegroundWindow просто возвращает ложь, при этом GetLastError возвращает 0...

E__>А нужна программка для переключение приложений, причем висящая как демон, без собственного интерфейса(активизируется по хуку, когда что-то подносят к сканеру штрихкодов, вобщем, не вирусы пишу ).


Как вариант можно использовать SwitchToThisWindow. У меня оно точно работает вплоть до висты.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.