2010-09-22 15 views
12

Ho una serie piuttosto complessa di applicazioni che dipendono dalla possibilità di passare le applicazioni in primo piano.Win32 SetForegroundWindow non affidabile

Il mio problema è, ogni 5 o 6 volte di passare le applicazioni in primo piano, semplicemente non riesce a portare avanti l'applicazione. GetLastError non segnala alcun problema. Spesso vedo l'applicazione corretta lampeggiare in primo piano per un momento, quindi l'applicazione precedente è visibile.

Possiedo un'applicazione Manager di cui dispongo, genera e controlla circa 4 applicazioni per le quali non dispongo di origine. una delle applicazioni che genera/controlla è anche un manager che genera/controlla circa 5 applicazioni.

Questa è una sorta di struttura del chiosco in modo che l'utente non abbia nemmeno una tastiera o un mouse, solo un touch screen.

Ho provato tutte le combinazioni delle chiamate Win32 per controllarle. Sono appena uscito dalle idee.

Il mio primo tentativo è stato:

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

Il mio secondo tentativo è stato:

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

mio terzo tentativo: DWORD dwThreadID = GetWindowThreadProcessId (Happ, NULL); AttachThreadInput (dwThreadID, GetCurrentThreadId(), true);

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

AttachThreadInput(dwThreadID, GetCurrentThreadId(), false); 

mio tentativo indietro:

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); 

Mi sento come se mi manca un Gotcha importante quando si tratta di commutazione finestra. So che solo il processo in primo piano può cambiare finestra, ma mentre il mio programma Manager principale si avvia e tutti gli altri processi che devo controllare, ho la sensazione che dovrebbe essere in grado di spostare queste finestre. Qualsiasi suggerimento o consiglio è apprezzato.

+2

First passo, leggi e capisci questo: http://blogs.msdn.com/b/oldnewthing/archive/2009/02/20/9435239.aspx –

+0

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

+0

Prova a ridurre a icona seguito da ripristino. –

risposta

4

L'hacking AttachThreadInput() è (penso) un modo noto per sconfiggere le contromisure di Windows. Si sta usando la maniglia sbagliata, tuttavia, si desidera allegare alla discussione che attualmente ha lo stato attivo. Quale non sarà hApp, non avresti bisogno di questo codice altrimenti.

Utilizzare GetForegroundWindow() per ottenere l'handle della finestra con lo stato attivo.

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

Anche se penso che il secondo argomento deve essere l'ID thread di hApp. Perché non vuoi spingere la tua finestra se ho capito bene. Non sono sicuro che possa funzionare.

+0

Questo è sicuramente un trucco che sto usando come ultima risorsa, non sono sicuro del motivo per cui avrei bisogno di collegarmi al processo Foreground poiché tutto in Primo piano è figlio della mia applicazione Manager. Forse qualcosa che sto facendo sta facendo perdere la concentrazione. Grazie per aver identificato l'errore, spero davvero che questo sia stato il problema! –

+0

Penso che questo in gran parte risolto il mio problema, ho ancora un problema occasionale, ma quello che ha finito per fare era qualcosa di simile: per i da 0 a 3 e fatto allegare ad infilare set in riferimento al più set in riferimento al distacco if getforegroundwindow = app done = true –

+2

Questo hack [può causare il blocco del programma] (http://blogs.msdn.com/b/oldnewthing/archive/2008/08/01/8795860.aspx) – MarkJ

0

Provare prima a spingere le altre finestre dell'applicazione sullo sfondo.

Inoltre è un po 'strano che si usi SetWindowPos (SWP) per spingere una finestra in primo piano e poi spingerla fuori dal perdreound prima di usare SetForegroundWindow per riportarlo indietro. Personalmente ho sempre usato il metodo SWP senza problemi ... ma ho sempre spinto anche le altre finestre verso il basso.

+0

Sei facendo riferimento a NOTOPMOST seguito da TOPMOST? –

1

Abbiamo avuto un problema simile un paio di anni fa.Potremmo risolverlo con la seguente chiamata di funzione:

SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE); 

Fare un tentativo. Vedere la documentazione here.

+0

Sto impostando ForegroundLocktimeout nel registro, è la stessa cosa? –

+0

Ho appena chiamato 'SystemParametersInfo (SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE)' e ha impostato 'HKEY_CURRENT_USER \ Control Panel \ Desktop \ ForegroundLockTimeout' su zero. – Bill

+0

È inoltre possibile fare riferimento a questo collegamento per ulteriori informazioni: http://www.codeproject.com/Tips/76427/Come-per-bracciare-finestra-con-opzione-SetForegroundWindo – Ankur

2

Alcune finestre sono bloccate con setforeground (...), è necessario sbloccarle. Questa sequenza è utile con qualsiasi finestra:

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

il nome della classe e la finestra nome è possibile recuperare con ranorexspy da esempio 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

ho avuto lo stesso problema e non volevo rovinare con fili. Durante gli esperimenti ho osservato un semplice trucco per far funzionare SetForegroundWindow() nel modo previsto. Ecco quello che ho fatto:

  1. ridurre la finestra se non è già ridotto al minimo
  2. ripristinare la finestra ridotta a icona
  3. chiamata SetForegroundWindow(), e la finestra sarà in cima
0

È inoltre è necessario considerare le possibilità di ridurre al minimo la finestra. Se la finestra o varie applicazioni sono ridotte a icona, SetForegroundWindow (hApp) non funzionerà. Per sicurezza usa ShowWindow (hApp, 9); Preferisco il valore 9. Dai un'occhiata alla sua documentazione e scegli quello che trovi adatto a te.

+0

Preferisco le costanti simboliche. Seriamente, questo è il 2015, e tu sei ** ancora ** usando numeri magici? Cosa c'è di sbagliato in 'SW_RESTORE'? – IInspectable

1

La soluzione più semplice in C# per portare una finestra in primo piano:

volta che hai la maniglia per la finestra, si può semplicemente chiamare:

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); 
    } 

dove

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