Win32 SetForegroundWindow不可靠

时间:2010-09-22 18:00:16

标签: c++ winapi

我有一系列相当复杂的应用程序,它依赖于在前台切换应用程序的能力。

我的问题是,每隔5到6次在前台切换应用程序,它就无法使应用程序前进。 GetLastError不报告任何问题。通常我会在前台看到正确的应用程序闪存片刻,然后可以看到上一个应用程序。

我有一个管理器应用程序,我有源代码,它产生并控制了大约4个我没有源代码的应用程序。它产生/控制的应用程序之一也是一个产生/控制大约5个应用程序的管理器。

这是一种自助服务终端设计,因此用户甚至没有键盘或鼠标,只需一个触摸屏。

我已经尝试过Win32调用的每个组合来控制它们我只是出于想法。

我的第一次尝试是:

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

我的第三次尝试:     DWORD dwThreadID = GetWindowThreadProcessId(hApp,NULL);     AttachThreadInput(dwThreadID,GetCurrentThreadId(),true);

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

AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);

我的第四次尝试:

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

当谈到窗口切换时,我觉得我错过了一个重要的问题。我知道只有前台进程可以切换窗口,但是当我的主管理器程序正在产生并启动我需要控制的所有其他进程时,我觉得它应该能够移动这些窗口。任何建议或意见都表示赞赏。

7 个答案:

答案 0 :(得分:10)

我遇到了同样的问题,我不想搞乱线程。在实验中,我观察到一个简单的黑客攻击,使SetForegroundWindow()以预期的方式工作。这是我做的:

  1. 如果窗口尚未最小化,请将窗口最小化
  2. 恢复最小化窗口
  3. 调用SetForegroundWindow(),您的窗口将位于顶部

答案 1 :(得分:5)

你的AttachThreadInput()hack是(我认为)一种已知的方法来打败在Windows中窃取反措施的焦点。您正在使用错误的句柄,您想要附加到当前具有焦点的线程。哪个不是hApp,否则你不需要这个代码。

使用GetForegroundWindow()获取焦点窗口的句柄。

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

虽然我认为第二个参数需要是hApp的线程ID。因为如果我理解正确你不想推开自己的窗户。不确定这是否可行。

答案 2 :(得分:2)

有些窗口被setforeground(...)锁定, 你需要解锁他们。此序列适用于任何窗口:

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

您可以使用例如ranorexspy检索的类名和窗口名称。 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);

答案 3 :(得分:1)

几年前我们遇到过类似的问题。我们可以通过以下函数调用来解决它:

SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE);

试一试。请参阅文档here

答案 4 :(得分:1)

C#中最简单的解决方案是将窗口置于前台:

获得窗口的句柄后,您只需致电:

scope

,其中

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

答案 5 :(得分:0)

首先尝试将其他应用程序窗口推送到后台。

使用SetWindowPos(SWP)将窗口推到前台,然后将其推出forgreound,然后使用SetForegroundWindow将其带回前面,这有点奇怪。我个人总是使用SWP方法没有任何问题...但我总是将其他窗口推到底部。

答案 6 :(得分:0)

您还需要考虑窗口最小化的可能性。如果窗口或各种应用程序最小化,则SetForegroundWindow(hApp)将不起作用。为了安全使用ShowWindow(hApp,9);我更喜欢价值9.查看其文档并选择适合您的文档。