versiones - embarcadero delphi full
¿Cómo llevar mi aplicación al frente? (8)
Sé todas las razones por las cuales es una mala idea. No me gusta si una aplicación roba el foco de entrada, pero esto es para uso puramente personal y quiero que suceda; no molestará a nada.
(Para los curiosos: estoy ejecutando pruebas unitarias en NetBeans, que generan un archivo de registro. Cuando mi aplicación en segundo plano ve la marca de tiempo del archivo de registro cambiar, quiero que analice el archivo de registro y llegue al frente para mostrar los resultados).
Esta pregunta no ayudó, ni buscó en Google. Parece que BringToFront()
no funcionó durante mucho tiempo y no puedo encontrar ninguna alternativa que lo haga.
¿Algunas ideas?
Aquí hay algo simple que parece funcionar, probado con múltiples cajas que consisten en XP, Server2003, Vista, Server2008, W7. La aplicación de prueba se ejecutó con una cuenta estándar (o de administrador), robó el foco de entrada desde el bloc de notas mientras escribía en primer plano.
var
Input: TInput;
begin
ZeroMemory(@Input, SizeOf(Input));
SendInput(1, Input, SizeOf(Input)); // don''t send anyting actually to another app..
SetForegroundWindow(Handle);
Puede ajustarlo más para una aplicación minimizada o, si es necesario.
Estoy haciendo algo similar en una de mis aplicaciones y esta función funciona para mí en 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;
Otra solución es no robar el foco y simplemente poner la ventana TOPMOST en el búfer 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;
No puedes hacer esto de manera confiable. Windows XP tenía una solución que lo permitía, pero las versiones desde entonces lo prohíben en su mayor parte (ver nota a continuación). Esto se establece expresamente en la sección de comentarios de la documentación de MSDN en SetForegroundWindow
:
El sistema restringe qué procesos pueden establecer la ventana de primer plano. Un proceso puede establecer la ventana de primer plano solo si una de las siguientes condiciones es verdadera:
- El proceso es el proceso en primer plano.
- El proceso fue iniciado por el proceso en primer plano.
- El proceso recibió el último evento de entrada.
- No hay un proceso en primer plano.
- El proceso en primer plano se está depurando.
- El primer plano no está bloqueado (ver LockSetForegroundWindow).
- El tiempo de espera de bloqueo de primer plano ha caducado (consulte SPI_GETFOREGROUNDLOCKTIMEOUT en SystemParametersInfo).
- No hay menús activos.
Una aplicación no puede forzar una ventana al primer plano mientras el usuario está trabajando con otra ventana. En cambio, Windows muestra el botón de la barra de tareas de la ventana para notificar al usuario.
Tenga en cuenta el último párrafo de la documentación citada, especialmente la primera oración.
El problema con
esto es para uso puramente personal y quiero que suceda; no molestará a nada.
es que cualquier aplicación podría intentar hacer lo mismo. ¿De qué manera el "uso puramente personal" dice que es usted personalmente y no solo una aplicación? :-)
Nota: He intentado todo lo que puedo pensar para mostrar la documentación del IDE en primer plano cuando hago clic en el botón de la herramienta de ayuda, pero todo lo que puedo obtener es el botón de la barra de tareas (y yo, como el usuario lo quiero hacer) .
Podría escribir un archivo ejecutable para solucionar esa limitación. Tomemos, por ejemplo, una aplicación simple (no visual) (básicamente una aplicación de consola pero sin {$ APPTYPE CONSOLE}) con el único propósito de mostrar su ventana deseada al frente.
Su aplicación de monitoreo de fondo llama a la aplicación auxiliar a través de una llamada de línea de comando (por ejemplo, ShellExecute) cada vez que se necesita una acción bring-front. Dado que esta aplicación se está convirtiendo en el proceso en primer plano, es capaz de traer otras ventanas al frente (SetForeGroundWindow). Puede usar FindWindow para obtener un control sobre su ventana de destino o pasar los parámetros apropiados al iniciar su aplicación de ayuda.
Form.bringtfront; ?
Deberia trabajar. Si lo pones en un temporizador, permanecerá al frente.
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'');
Asumiendo que no hay otras aplicaciones StayOnTop ejecutándose, puede establecer temporalmente sus formularios FormStyle para que sean fsStayOnTop y luego lo hagan y Application Restore y BringToFront y luego cambie el estilo de formulario a lo que sea.
tmpFormStyle := Application.MainForm.FormStyle;
Application.MainForm.FormStyle := fsStayOnTop;
Application.Restore; // optional
Application.BringToFront;
Application.MainForm.FormStyle := tmpFormStyle;
De nuevo, esto solo funciona si no hay otras aplicaciones stayontop.
Esto debería funcionar incluso en el sistema operativo Windows 7 + 8. El único requisito es que una aplicación en sí misma pueda llamar a funciones. Es más complicado usar una aplicación externa para configurar el frente de la ventana de otro proceso.
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);
Editar Ok Encontré un problema con esto. La aplicación se lleva al frente pero el enfoque se guarda en una aplicación original. Usa esta respuesta para solucionar el problema, es un método bastante complejo, pero copiar pega el truco. Antes de llamar a ForceForegroundWindow (wnd) es posible que deba llamar a Application.Restore para realizar una minimización de una ventana. https://.com/a/5885318/185565