2010-09-22 9 views
12

Tengo una serie bastante compleja de aplicaciones que dependen de la capacidad de cambiar aplicaciones en primer plano.Win32 SetForegroundWindow no fiable

Mi problema es que cada 5 o 6 veces de cambiar las aplicaciones en primer plano, simplemente no logra llevar la aplicación hacia adelante. GetLastError no informa ningún problema. Muchas veces veo la aplicación correcta destellar en primer plano por un momento, luego la aplicación anterior es visible.

Tengo una aplicación de administrador que tengo como fuente, genera y controla aproximadamente 4 aplicaciones para las que no tengo fuente. una de las aplicaciones que genera/controla también es un administrador que engendra/controla alrededor de 5 aplicaciones.

Este es un tipo de diseño de quiosco por lo que el usuario ni siquiera tendrá un teclado o mouse, solo una pantalla táctil.

He intentado cada combinación de las llamadas de Win32 para controlarlas. Me acabo de ir de las ideas.

Mi primer intento fue:

SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); 
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); 

Mi segundo intento fue:

SetForegroundWindow(hApp); 
SetActiveWindow(hApp); 
SetFocus(hApp); 

mi tercer intento: DWORD dwThreadId = GetWindowThreadProcessId (Happ, NULL); AttachThreadInput (dwThreadID, GetCurrentThreadId(), verdadero);

SetForegroundWindow(hApp); 
SetActiveWindow(hApp); 
SetFocus(hApp); 

AttachThreadInput(dwThreadID, GetCurrentThreadId(), false); 

mi vuelta intento:

DWORD dwThreadID = GetWindowThreadProcessId(hApp, NULL); 
AttachThreadInput(dwThreadID, GetCurrentThreadId(), true); 

SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); 
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); 

SetForegroundWindow(hApp); 
SetActiveWindow(hApp); 
SetFocus(hApp); 

AttachThreadInput(dwThreadID, GetCurrentThreadId(), false); 

siento que me falta un Gotcha importante cuando se trata de la ventana de cambio. Sé que solo el proceso en primer plano puede cambiar las ventanas, pero como mi programa principal de Gerente está generando y comenzando todos los otros procesos que necesito controlar, siento que debería ser capaz de mover estas ventanas. Cualquier sugerencia o consejo es apreciado.

+2

Primera paso, lea y comprenda esto: http://blogs.msdn.com/b/oldnewthing/archive/2009/02/20/9435239.aspx –

+0

También: http://blogs.msdn.com/b/oldnewthing/archive /2008/08/01/8795860.aspx –

+0

Intenta minimizar seguido de restauración. –

Respuesta

4

Su AttachThreadInput() hack es (creo) una forma conocida de vencer las medidas de robo de foco en Windows. Sin embargo, está utilizando el controlador incorrecto, desea conectarlo al hilo que actualmente tiene el foco. Lo cual no será hApp, de lo contrario no necesitarías este código.

Utilice GetForegroundWindow() para obtener el identificador de la ventana con el foco.

AttachThreadInput(
    GetWindowThreadProcessId(GetForegroundWindow(), NULL), 
    GetCurrentThreadId(), TRUE 
); 

aunque creo que el segundo argumento debe ser ID del hilo de Happ. Porque no quieres meter tu propia ventana si entendí correctamente. No estoy seguro de si eso puede funcionar.

+0

Esto es definitivamente un truco que estoy utilizando como último recurso, no estoy seguro de por qué tendría que adjuntarme al proceso de primer plano ya que todo en el primer plano es un elemento secundario de mi aplicación Manager. Quizás algo que estoy haciendo está haciendo perder el foco. Gracias por identificar el error, realmente espero que este sea el problema. –

+0

Creo que esta resuelto mayormente mi problema, todavía tengo un problema ocasional, pero lo que terminó haciendo era algo así como: para i 0 a 3 y hecho atribuyen a enhebrar conjunto como tapa la mayoría conjunto como superior detach if getforegroundwindow = aplicación done = true –

+2

Este truco [puede hacer que su programa se cuelgue] (http://blogs.msdn.com/b/oldnewthing/archive/2008/08/01/8795860.aspx) – MarkJ

0

Primero intente presionar las otras ventanas de la aplicación al fondo.

También es un poco extraño que use SetWindowPos (SWP) para empujar una ventana al primer plano y luego sacarla del forgreound antes de usar SetForegroundWindow para volverla a poner en marcha. Personalmente, siempre he usado el método SWP sin ningún problema ... pero siempre he empujado las otras ventanas al fondo también.

+0

¿Está usted refiriéndose al NOTOPMOST seguido de TOPMOST? –

1

Tuvimos un problema similar hace un par de años.Podríamos resolverlo mediante la siguiente llamada de función:

SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE); 

darle una oportunidad. Consulte la documentación here.

+0

Estoy estableciendo ForegroundLocktimeout en el registro, ¿es lo mismo? –

+0

Acabo de llamar a 'SystemParametersInfo (SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE)' y ha establecido 'HKEY_CURRENT_USER \ Control Panel \ Desktop \ ForegroundLockTimeout' en cero. – Bill

+0

También puede consultar este enlace para obtener más ayuda: http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with- SetForegroundWindo – Ankur

2

Algunas ventanas están bloqueadas con setforeground (...), necesita desbloquearlas. Esta secuencia es útil con cualquier ventana:

HWND needTopWindow=FindWindow(TEXT("classname"), TEXT("window name")); 

el nombre de clase y el nombre de la ventana se puede recuperar con ranorexspy de ejemplo nanoware.cz

if(!::IsWindow(needTopWindow)) return; 

BYTE keyState[256] = {0}; 
//to unlock SetForegroundWindow we need to imitate Alt pressing 
if(::GetKeyboardState((LPBYTE)&keyState)) 
    { 
    if(!(keyState[VK_MENU] & 0x80)) 
     { 
     ::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0); 
     } 
    } 

    ::SetForegroundWindow(needTopWindow); 

if(::GetKeyboardState((LPBYTE)&keyState)) 
    { 
     if(!(keyState[VK_MENU] & 0x80)) 
     { 
      ::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); 
     } 
    } 


     DWORD dwThreadID = GetWindowThreadProcessId(needTopWindow, NULL); 
     AttachThreadInput(dwThreadID, GetCurrentThreadId(), true); 

     SetWindowPos(needTopWindow, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); 
     SetWindowPos(needTopWindow, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE); 

     SetForegroundWindow(needTopWindow); 
     SetActiveWindow(needTopWindow); 
     SetFocus(needTopWindow); 

     AttachThreadInput(dwThreadID, GetCurrentThreadId(), false); 
9

que estaba teniendo el mismo problema y que no quería echar a perder con hilos. Al experimentar, observé un truco simple para hacer que SetForegroundWindow() funcione de la manera esperada. Esto es lo que hice:

  1. minimizar la ventana si no está ya minimizado
  2. restaurar la ventana minimizada
  3. SetForegroundWindow de llamadas(), y la ventana estará en la parte superior
0

También necesidad de considerar las posibilidades de que se minimice la ventana. Si la ventana o varias aplicaciones se minimizan, SetForegroundWindow (hApp) no funcionará. Para ser seguro, use ShowWindow (hApp, 9); Prefiero el valor 9. Eche un vistazo a su documentación y elija la que más le convenga.

+0

Prefiero las constantes simbólicas. En serio, esto es 2015, y todavía estás ** usando números mágicos? ¿Qué hay de malo con 'SW_RESTORE'? – IInspectable

1

La solución más fácil en C# para acceder a una ventana en primer plano:

Una vez que tenga el mango de la ventana, sólo tiene que llamar:

SetWindowPos(handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 
    ShowWindow(handle, 5); 
    SetForegroundWindow(handle); 

    // If it is minimized, show the window 
    if (IsIconic(handle)) 
    { 
     ShowWindow(handle, 3); 
    } 

donde

const int SWP_NOMOVE = 0x0002; 
const int SWP_NOSIZE = 0x0001; 
const int SWP_SHOWWINDOW = 0x0040; 
Cuestiones relacionadas