2012-10-18 21 views
18

我知道爲什麼它是一個壞主意的所有原因。我不喜歡它,如果一個應用程序竊取輸入焦點,但這是純粹的個人使用,我希望它發生;它不會干擾任何事情。如何將我的應用程序放在前面?

(好奇的是:我正在NetBeans中運行單元測試,它會生成一個日誌文件,當我的後臺應用程序看到日誌文件的時間戳更改時,我希望它解析日誌文件並顯示結果)。

This question沒有幫助,谷歌搜索也沒有幫助。看起來BringToFront()已經很長時間沒有工作,我找不到任何替代方法。

任何想法?

+1

你不能這樣做。 Windows XP有一個解決方法,允許它;從那時起版本禁止它。 –

+0

+1 @ken如果你100%確定,然後發佈一個答案,我會獎勵。我希望有一些晦澀的技巧,像收縮到系統托盤,然後恢復,或隱藏然後再次顯示... – Mawg

+1

完成 - 將工作? :-) –

回答

16

你不能可靠地做到這一點。 Windows XP有一個可以允許的解決方法,但是從那時起版本大部分都禁止它(請參閱下面的註釋)。這在SetForegroundWindow上的MSDN文檔的註釋部分中有明確說明:

系統限制哪些進程可以設置前臺窗口。只有滿足以下條件之一時,進程才能設置前景窗口:

  • 該進程是前臺進程。
  • 該過程由前臺進程啓動。
  • 該進程收到最後一個輸入事件。
  • 沒有前臺進程。
  • 正在調試前臺進程。
  • 前景未鎖定(請參閱LockSetForegroundWindow)。
  • 前臺鎖定超時已過期(請參閱SystemParametersInfo中的SPI_GETFOREGROUNDLOCKTIMEOUT)。
  • 沒有菜單處於活動狀態。

當用戶使用另一個窗口時,應用程序無法強制窗口到前臺。相反,Windows會閃爍窗口的任務欄按鈕以通知用戶。

請注意引用文檔的最後一段,尤其是第一句。

這是純粹的個人使用,我希望它發生的問題;它不會干擾任何事情。

是,任何應用程序可以嘗試做同樣的事情。 「純粹個人使用」是如何告訴你個人而不是任何應用? :-)

注意:我嘗試了所有我能想到的方法來獲取IDE的文檔,以便在單擊幫助工具按鈕時在前臺顯示,但我所能得到的是閃爍的任務欄按鈕(以及作爲用戶希望它這樣做)。

+0

+1(以及您上面的評論;-)顯然,我會活在希望之中,並在頒發前將其打開幾個小時。正如我所說的那樣,我希望有一些晦澀的技巧,比如縮小到系統托盤,然後恢復,或者隱藏然後再次顯示 - 但我沒有嘗試過: - (這是很多工作,只是爲了避免Alt-Tab(嗯,也許如果我有一個「啓動器」應用程序,然後啓動一個「過程」應用程序,那麼新應用程序會在前臺啓動?) – Mawg

+0

您可以使用AlwaysOnTop風格,而不是它對其他應用程序友好,但它會吸引美國人雖然也許一些像Growl/Snarl這樣的特別警報服務會更好一些 –

+0

@Ken,謝謝,現在已經很好了,我刪除了我的評論和+1 –

3

您可以編寫一個可執行文件來解決該限制。以一個簡單的(非視覺)應用程序爲例(基本上是一個控制檯應用程序,但沒有{$ APPTYPE CONSOLE}),唯一的目的是將你想要的窗口放在前面。

無論何時需要使用前置操作,您的監控後臺應用程序都會通過命令行調用(例如ShellExecute)調用幫助器應用程序。由於此應用程序正在成爲前臺進程,因此可以將其他窗口置於前面(SetForeGroundWindow)。您可以使用FindWindow獲取目標窗口的句柄或在啓動助手應用程序時傳遞適當的參數。

+0

+1 @erik是的,我正在承認這一點。是稍微更努力/有點messt,但如果它是唯一的方法... – Mawg

12

我做在我的應用程序一個類似的東西,這個功能對我的作品 在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; 
+0

這是否總是*工作? –

+1

這不適用於作爲非管理員運行的Win7,也不能在運行的機器上正常工作在Win2008域中,所以它沒有總是工作,這就是爲什麼我給出了我所做的答案。 :-)當然,我(以及操作系統本身的製造者)知道什麼? –

+0

這個以及類似的方法在我的應用程序不活躍時從未適用於我。 –

29

這裏的東西簡單,似乎工作,與包括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.對於最小化的應用程序或如果需要的話。

+0

爲什麼會偷竊? –

+1

@DavidHeffernan,因爲「進程收到最後一次輸入事件」。我已經測試過它,並且它工作得很好。 – kobik

+1

謝謝!也適用於Windows 8.1。 –

-1

Form.bringtofront; ?

應該工作。 如果你把它放在計時器中,它會留在前面。

3

即使在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來取消最小化窗口。 https://stackoverflow.com/a/5885318/185565

3
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'); 
2

假設有運行,您可以臨時設置窗體FormStyle是fsStayOnTop然後做和應用程序還原和BringToFront,然後更改formstyle回不管它是沒有其他StayOnTop應用。

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

此外,這隻適用於沒有其他stayontop應用程序。

相關問題