24

私はそれが悪い考えであるすべての理由を知っています。アプリケーションが入力フォーカスを盗むのは嫌いですが、これは純粋に個人的な使用のためであり、発生させたいと思っています。それは何も邪魔しません。

(興味深いことに、ログ ファイルを生成する NetBeans で単体テストを実行しています。バックグラウンド アプリケーションがログ ファイルのタイムスタンプの変更を確認したら、ログ ファイルを解析し、前面に出て結果を表示したいと考えています)。

この質問は役に立ちませんでしたし、グーグルも役に立ちませんでした。長い間機能していないようでBringToFront()、代替手段が見つかりません。

何か案は?

4

8 に答える 8

37

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

必要に応じて、最小化されたアプリなどに合わせてさらに微調整できます。

于 2012-10-18T08:40:07.913 に答える
20

これを確実に行うことはできません。Windows XP にはそれを可能にする回避策がありましたが、それ以降のバージョンではほとんどの場合禁止されています (以下の注を参照)。これは、次の MSDN ドキュメントの備考セクションに明示的に記載されていますSetForegroundWindow

システムは、フォアグラウンド ウィンドウを設定できるプロセスを制限します。プロセスは、次の条件のいずれかに該当する場合にのみ、フォアグラウンド ウィンドウを設定できます。

  • プロセスはフォアグラウンド プロセスです。
  • プロセスはフォアグラウンド プロセスによって開始されました。
  • プロセスは最後の入力イベントを受け取りました。
  • フォアグラウンド プロセスはありません。
  • フォアグラウンド プロセスはデバッグ中です。
  • 前景はロックされていません (LockSetForegroundWindow を参照)。
  • フォアグラウンド ロックのタイムアウトが期限切れになりました (SystemParametersInfo の SPI_GETFOREGROUNDLOCKTIMEOUT を参照)。
  • アクティブなメニューはありません。

ユーザーが別のウィンドウで作業している間、アプリケーションはウィンドウを強制的に前面に出すことはできません。代わりに、Windows はウィンドウのタスクバー ボタンを点滅させてユーザーに通知します。

引用されたドキュメントの最後の段落、特に最初の文に注意してください。

問題は

これは純粋に個人的な使用のためのものであり、私はそれが実現することを望んでいます。それは何も邪魔しません。

どのアプリケーションでも同じことを試みる可能性があるということです。「純粋に個人的な使用」とは、それが単なるアプリケーションではなく、あなた個人であることをどのように伝えますか? :-)

注: ヘルプ ツールボタンをクリックしたときに IDE のドキュメントが最前面に表示されるように、考えられるすべてのことを試しましたが、タスクバー ボタンが点滅するだけです (ユーザーとしてはそうしてほしいと思っています)。 .

于 2012-10-18T02:42:21.610 に答える
15

私は自分のアプリケーションの 1 つで同様のことを行っていますが、この関数は 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;

もう 1 つの解決策は、フォーカスを奪わず、単にウィンドウ 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;
于 2012-10-18T07:56:51.050 に答える
5

これは Windows7+8 OS でも動作するはずです。唯一の要件は、アプリケーション自体が関数を呼び出すことができることです。外部アプリを使用して別のプロセスのウィンドウ フロントを設定するのは、よりトリッキーです。

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

編集OKこれで1つの問題が見つかりました。アプリケーションは前面に出されますが、焦点は元のアプリケーションに保たれます。この回答を使用して問題を解決します。非常に複雑な方法ですが、コピーペーストはうまくいきます。ForceForegroundWindow(wnd) を呼び出す前に、ウィンドウの最小化を解除する Application.Restore を呼び出す必要がある場合があります。 https://stackoverflow.com/a/5885318/185565

于 2013-12-20T16:11:12.517 に答える
3

その制限を回避するために実行可能ファイルを作成できます。たとえば、目的のウィンドウを前面に表示することのみを目的としたシンプルな (非ビジュアル) アプリケーション (基本的にはコンソール アプリですが、{$APPTYPE CONSOLE} はありません) を考えてみましょう。

監視バックグラウンド アプリケーションは、bringtofront アクションが必要になるたびに、コマンド ライン呼び出し (ShellExecute など) を介してヘルパー アプリを呼び出します。このアプリはフォアグラウンド プロセスになるため、他のウィンドウを前面に出すことができます (SetForeGroundWindow)。FindWindow を使用して、ターゲット ウィンドウのハンドルを取得したり、ヘルパー アプリの起動時に適切なパラメーターを渡したりできます。

于 2012-10-18T07:43:28.477 に答える
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');
于 2015-10-07T04:34:08.877 に答える
-2

Form.bringtofront; ?

動作するはずです。タイマーに入れると手前に留まります。

于 2012-10-25T17:51:40.263 に答える