设置活动窗口 AttachThreadInput SetForegroundWindow

最近一直在使用RainMeter制作桌面,需要屏蔽Win按键,并使Win按键触发自己的菜单。
在网上没有找到直接适合我用的,后来根据前人的步伐,尝试出来适用于这个情况的方法。
现在我觉得这个方法挺实用的,所以在这里分享一下。

    • 说明
    • 方法
    • AttachThreadInput
    • SetForegroundWindow
    • 解决方案


说明

RainMeter,可能有些人听过,一个制作自定义桌面很强大的工具,到底多强大,我这里就不说了,总之就强大。
我用这个工具制作自己的桌面,在RainMeter插件中,使用全局钩子,去屏蔽Win按键,理所当然的简单的几个Win组合快捷键就被屏蔽了,但是Win+L没有屏蔽,这里就不做讨论。在屏蔽了Win按键时,做了处理,使得按Win键弹出自己定义的菜单,并设置菜单为活动窗口,来响应↑↓←→、回车按键。

方法

网上一搜,各种方法,总结一下,无奈就这几个SetFocusShowWindowSetForegroundWindowSetActiveWindow
SwitchToThisWindow,也挺多的。后面连SendMessage都用上了,搞到我头都大了,就差没有直接发送鼠标事件去激活窗口了。

后来发现了用人使用AttachThreadInputSetForegroundWindow的组合来设置活动窗口。
我引用一个别人的——如何将当前窗口带到带到最顶层,并设置为活动窗口

因为我弹出来的菜单完成后,再按一下win键要把菜单隐藏,并把焦点还给弹出菜单前的窗口。用他的方法中,代码窗口就是当前活动窗口,可以设置。
但是在我的情况,代码运行的线程就没有窗口,结果只能完成我的前半步,后半步有问题,有时连前半步都不行。
根据他的方法,去各种尝试,根本触摸不到它系统的怎么跑的,都快吐血了。但是皇天不负有心人啊,最终还是解决了。用的就是这两个函数AttachThreadInputSetForegroundWindow

AttachThreadInput

AttachThreadInput 的使用方法我就直接百度百科

SetForegroundWindow

——百度百科

解决方案

先上我自己的代码,这个是在钩子钩Win按键处理的:

/* 弹出dalong菜单 */
static HWND previousFocusWnd = NULL;
static HWND rmWnd = NULL;
if ( previousFocusWnd && rmWnd == GetForegroundWindow() )
{
    SendMessage( rmWnd, WM_KILLFOCUS, 0, 0 );

    AttachThreadInput( GetWindowThreadProcessId( rmWnd, NULL ), GetCurrentThreadId(), TRUE );
    AttachThreadInput( GetWindowThreadProcessId( previousFocusWnd, NULL ), GetWindowThreadProcessId( rmWnd, NULL ), TRUE );
    SetForegroundWindow( previousFocusWnd );
    AttachThreadInput( GetWindowThreadProcessId( previousFocusWnd, NULL ), GetWindowThreadProcessId( rmWnd, NULL ), FALSE );
    AttachThreadInput( GetWindowThreadProcessId( rmWnd, NULL ), GetCurrentThreadId(), FALSE );

    previousFocusWnd = NULL;
    rmWnd = NULL;
    return(TRUE);
}else  {
    previousFocusWnd = GetForegroundWindow();
    //菜单窗口句柄
    rmWnd = FindWindowA( "", "" );

    AttachThreadInput( GetWindowThreadProcessId( previousFocusWnd, NULL ), GetCurrentThreadId(), TRUE );
    AttachThreadInput( GetWindowThreadProcessId( previousFocusWnd, NULL ), GetWindowThreadProcessId( rmWnd, NULL ), TRUE );
    SendMessage( rmWnd, WM_SETFOCUS, 0, 0 );
    SetForegroundWindow( rmWnd );
    AttachThreadInput( GetWindowThreadProcessId( previousFocusWnd, NULL ), GetWindowThreadProcessId( rmWnd, NULL ), FALSE );
    AttachThreadInput( GetWindowThreadProcessId( previousFocusWnd, NULL ), GetCurrentThreadId(), FALSE );
}

我的代码中,当前线程不是活动窗口,所以我用了两次AttachThreadInput

  1. 先把当前线程和活动窗口线程的输入队列连接起来
  2. 再把活动窗口线程的输入队列和待设置为活动窗口的线程连在一起
  3. 调用SetForegroundWindow,把指定窗口设置为前端窗口,并成为活动状态。

焦点的话,有没有在这个上面不太清楚,不过这个设置应该不难,这里不多说。
经过这样,终于把设置活动窗口这一步做好了,告一段落。

不知道你们有没有发现,其实,如果我的菜单是一个Win32窗口,只需要打开一下,设置一个位置,后面关闭菜单,活动窗口就会自动回到上一个窗口,也就不需要那么多设置活动窗口了。
问题就是RainMeter的窗口很奇葩,不能用Win32窗口去衡量,到底是怎么我也不懂,因为我是个菜鸟,对windows的东西还不是太懂。

现在能满足自己的需求就算了,搞了那么多天,终于搞通了,记录一下自己的成果!O(∩_∩)O

后续:2016年1月5日17:31:29
SwitchToThisWindow 这个函数我今天试了一下,可以用的。不知道当时为什么不能用,不知道是不是使用情况不一样,大家在用的时候,可以先考虑这个函数

你可能感兴趣的:(Windows,C\C++)