0

SetWindowPos 関数に奇妙な問題があります。この関数は、次のコードでアプリを最上位にするために使用されます。

                if (!SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, NO_FOCUS_FLAGS))
                    Log.LogError("SetWindowPos HWND_TOPMOST returned false");

                if (!SetWindowPos(this.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, NO_FOCUS_FLAGS))
                    Log.LogError("SetWindowPos HWND_NOTOPMOST returned false");

ほとんどの場合、Windows からの通常のイベント スタックを確認できます。

WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0
WndProc(): m - msg=0x14 (WM_ERASEBKGND) hwnd=0x21016 wparam=0xffffffffc60128f1 lparam=0x0 result=0x0
WndProc(): m - msg=0x135 (WM_CTLCOLORBTN) hwnd=0x21016 wparam=0xffffffff950128ae lparam=0x40f2e result=0x0
WndProc(): m - msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0
WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0
WndProc(): m - msg=0x135 (WM_CTLCOLORBTN) hwnd=0x21016 wparam=0xffffffffc60128f1 lparam=0x40f2e result=0x0
WndProc(): m - msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x21016 wparam=0x0 lparam=0x20d688 result=0x0

しかし、時々私は次のようになりました:

WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x104f4 wparam=0x0 lparam=0x3ad6cc result=0x0
WndProc(): m - msg=0x14 (WM_ERASEBKGND) hwnd=0x104f4 wparam=0x26012ce9 lparam=0x0 result=0x0
WndProc(): m - msg=0x135 (WM_CTLCOLORBTN) hwnd=0x104f4 wparam=0x90127a1 lparam=0x105de result=0x0
WndProc(): m - msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x104f4 wparam=0x0 lparam=0x3ad6cc result=0x0

この場合、SetWindowPos() は成功を返しましたが、アプリケーションは最上位に表示されませんでした。

この問題は再現が難しすぎて、簡単にテストできません。

WM_WINDOWPOSCHANGED が欠落していることを誰かが知っていますか? この問題に対処するにはどうすればよいですか?

前もって感謝します!

4

1 に答える 1

0

プログラムを前面に出す最も効果的な方法は、次の組み合わせです。

  1. P/Invoke - AttachThreadInput
  2. P/Invoke - BringWindowToTop
  3. P/Invoke - パラメータ SW_SHOW を持つ ShowWindow

それは私にとって毎回機能し、私が試したどのアプリケーションからもフォーカスを奪います。Citrix やリモート デスクトップを全画面表示にするように、プログラムが前面に表示されます。

秘訣は、(AttachThreadInput API を使用して) スレッドをアタッチし、別の API である BringWindowToTop を使用して、プロセスとターゲット ウィンドウ (hwnd) が関連しているとウィンドウに「思わせる」ことです。

public static void AttachedThreadInputAction(Action action)
{
    var foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
    var appThread = GetCurrentThreadId();
    bool threadsAttached = false;
    try
    {
        threadsAttached =
            foreThread == appThread ||
            AttachThreadInput(foreThread, appThread, true);
        if (threadsAttached) action();
        else throw new ThreadStateException("AttachThreadInput failed.");
    }
    finally
    {
        if (threadsAttached)
            AttachThreadInput(foreThread, appThread, false);
    }
}

使用法:

public const uint SW_SHOW = 5;

///<summary>
/// Forces the window to foreground.
///</summary>
///<hwnd>The HWND.</param>
public static void ForceWindowToForeground(IntPtr hwnd)
{
    AttachedThreadInputAction(
        () =>
        {
            BringWindowToTop(hwnd);
            ShowWindow(hwnd, SW_SHOW);
        });
}
于 2015-09-24T13:04:46.250 に答える