Подтвердить что ты не робот

Как перенести мое приложение на фронт?

Я знаю все причины, почему это плохая идея. Мне не нравится, если приложение крадет фокус ввода, но это для личного использования, и я хочу, чтобы это произошло; это ничего не потревожит.

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

Этот вопрос не помог, и не сделал googling. Похоже, что BringToFront() не работал долгое время, и я не могу найти альтернативы, которая делает.

Любые идеи?

4b9b3361

Ответ 1

Вы не можете сделать это надежно. В Windows XP было обходное решение, которое позволяло бы это делать, но версии с тех пор запрещают его по большей части (см. Примечание ниже). Это прямо указано в разделе примечаний документации MSDN по SetForegroundWindow:

Система ограничивает, какие процессы могут устанавливать окно переднего плана. Процесс может установить окно переднего плана, только если выполнено одно из следующих условий:

  • Процесс является процессом переднего плана.
  • Процесс был запущен процессом переднего плана.
  • Процесс получил последнее событие ввода.
  • Не существует процесса переднего плана.
  • Отлаживается процесс переднего плана.
  • Передний план не заблокирован (см. LockSetForegroundWindow).
  • Время ожидания блокировки переднего плана истекло (см. SPI_GETFOREGROUNDLOCKTIMEOUT в SystemParametersInfo).
  • Нет меню.

Приложение не может форсировать окно на переднем плане, пока пользователь работает с другим окном. Вместо этого Windows мигает кнопкой панели задач окна, чтобы уведомить пользователя.

Обратите внимание на заключительный абзац цитируемой документации, особенно на первое предложение.

Проблема с

это для чисто личного использования, и я хочу, чтобы это произошло; это ничего не потревожит.

заключается в том, что любое приложение может попытаться сделать то же самое. Как "чисто личное использование" говорит это вам лично, а не только какое-либо приложение?:-)

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

Ответ 2

Здесь что-то простое, что кажется, работает, протестировано с несколькими ящиками, состоящими из XP, Server2003, Vista, Server2008, W7. Приложение для тестирования запускалось со стандартной (или административной) учетной записью, украл фокус ввода из блокнота во время записи на переднем плане.

var
  Input: TInput;
begin
  ZeroMemory(@Input, SizeOf(Input));
  SendInput(1, Input, SizeOf(Input)); // don't send anyting actually to another app..
  SetForegroundWindow(Handle);

Вы можете настроить его далее f.i. для минимизированного приложения или, если требуется,.

Ответ 3

Я делаю что-то подобное в одном из моих приложений, и эта функция работает для меня в xp/vista/w7:

function ForceForegroundWindow(hwnd: THandle): Boolean;
const
  SPI_GETFOREGROUNDLOCKTIMEOUT = $2000;
  SPI_SETFOREGROUNDLOCKTIMEOUT = $2001;
var
  ForegroundThreadID: DWORD;
  ThisThreadID: DWORD;
  timeout: DWORD;
begin
  if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE);

  if GetForegroundWindow = hwnd then Result := True
  else
  begin
    // Windows 98/2000 doesn't want to foreground a window when some other
    // window has keyboard focus

    if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4)) or
      ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and
      ((Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and
      (Win32MinorVersion > 0)))) then
    begin
      Result := False;
      ForegroundThreadID := GetWindowThreadProcessID(GetForegroundWindow, nil);
      ThisThreadID := GetWindowThreadPRocessId(hwnd, nil);
      if AttachThreadInput(ThisThreadID, ForegroundThreadID, True) then
      begin
        BringWindowToTop(hwnd); // IE 5.5 related hack
        SetForegroundWindow(hwnd);
        AttachThreadInput(ThisThreadID, ForegroundThreadID, False);
        Result := (GetForegroundWindow = hwnd);
      end;
      if not Result then
      begin
        // Code by Daniel P. Stasinski
        SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @timeout, 0);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0),
          SPIF_SENDCHANGE);
        BringWindowToTop(hwnd); // IE 5.5 related hack
        SetForegroundWindow(hWnd);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(timeout), SPIF_SENDCHANGE);
      end;
    end
    else
    begin
      BringWindowToTop(hwnd); // IE 5.5 related hack
      SetForegroundWindow(hwnd);
    end;

    Result := (GetForegroundWindow = hwnd);
  end;
end;

Другим решением является не крать фокус и просто поместить окно TOPMOST в буфер z:

procedure ForceForegroundNoActivate(hWnd : THandle);

begin
 if IsIconic(Application.Handle) then
  ShowWindow(Application.Handle, SW_SHOWNOACTIVATE);
 SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE);
 SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE);
end;

Ответ 4

Вы можете написать исполняемый файл для обхода этого ограничения. Возьмем, к примеру, простое (не визуальное) приложение (в основном консольное приложение, но без {$ APPTYPE CONSOLE}) с единственной целью - довести ваше нужное окно до фронта.

Ваше фоновое фоновое фоновое приложение вызывает вспомогательное приложение через вызов командной строки (например, ShellExecute), когда требуется ваше действие. Поскольку это приложение становится процессом переднего плана, оно позволяет переносить другие окна на передний план (SetForeGroundWindow). Вы можете использовать FindWindow, чтобы получить дескриптор целевого окна или передать соответствующие параметры при запуске своего вспомогательного приложения.

Ответ 5

Это должно работать даже в ОС Windows7 + 8. Только требование - само приложение может вызывать функции. Сложно использовать внешнее приложение, чтобы установить другое окно процесса.

Application.Restore; // unminimize window, makes no harm always call it
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE);
SetWindowPos(self.Handle, HWND_TOPMOST,0,0,0,0, SWP_NOMOVE or SWP_NOSIZE);
SetWindowPos(self.Handle, HWND_NOTOPMOST,0,0,0,0, SWP_SHOWWINDOW or SWP_NOMOVE or SWP_NOSIZE);

Изменить Хорошо, я обнаружил одну проблему с этим. Приложение выводится на передний план, но фокус сохраняется в оригинальном приложении. Используйте этот ответ, чтобы исправить проблему, ее довольно сложный метод, но copypaste делает трюк. Перед вызовом ForceForegroundWindow (wnd) вам может потребоваться вызвать Application.Restore, чтобы исключить окно. fooobar.com/questions/289328/...

Ответ 6

function WinActivate(const AWinTitle: string): boolean;
var
  _WindowHandle: HWND;
begin
  Result := false;
  _WindowHandle := FindWindow(nil, PWideChar(AWinTitle));
  if _WindowHandle <> 0 then
  begin
    if IsIconic(_WindowHandle) then
      Result := ShowWindow(_WindowHandle, SW_RESTORE)
    else
      Result := SetForegroundWindow(_WindowHandle);
  end;
end;

if WinActivate(self.Caption) then
  ShowMessage('This works for me in Windows 10');

Ответ 7

Предполагая, что нет других приложений StayOnTop, вы можете временно установить свои формы FormStyle как fsStayOnTop, а затем выполнить и восстановление приложений и BringToFront, а затем изменить форму стиля на все, что было.

tmpFormStyle := Application.MainForm.FormStyle;
Application.MainForm.FormStyle := fsStayOnTop;
Application.Restore; // optional
Application.BringToFront;
Application.MainForm.FormStyle := tmpFormStyle;

Опять же, это работает только в том случае, если нет других приложений stayontop.

Ответ 8

Form.bringtofront;

Должен работать. Если вы поместите его в таймер, он останется впереди.