Как перенести мое приложение на фронт?
Я знаю все причины, почему это плохая идея. Мне не нравится, если приложение крадет фокус ввода, но это для личного использования, и я хочу, чтобы это произошло; это ничего не потревожит.
(для любопытных: я запускаю модульные тесты в NetBeans, которые генерируют файл журнала. Когда мое фоновое приложение видит изменение метки времени файла журнала, я хочу, чтобы он анализировал файл журнала и выходил на передний план, чтобы показать результаты).
Этот вопрос не помог, и не сделал googling. Похоже, что BringToFront()
не работал долгое время, и я не могу найти альтернативы, которая делает.
Любые идеи?
Ответы
Ответ 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;
Должен работать.
Если вы поместите его в таймер, он останется впереди.