设置活动窗口 AttachThreadInput SetForegroundWindow

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


说明

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 这个函数我今天试了一下,可以用的。不知道当时为什么不能用,不知道是不是使用情况不一样,大家在用的时候,可以先考虑这个函数

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
是的,您可以使用 SetForegroundWindow API 函数来设置多个窗口。但是,这个函数只能将一个窗口设置为前台窗口。如果您想要将多个窗口设置为前台窗口,您需要按照以下步骤执行: 1. 枚举所有需要设置为前台窗口窗口句柄。 2. 对于每个窗口句柄,使用 SetForegroundWindow 函数将其设置为前台窗口。 下面是一个示例代码: ```csharp using System.Runtime.InteropServices; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32.dll")] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount); [DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd); delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); static void SetForegroundWindows(string windowTitle) { List<IntPtr> handles = new List<IntPtr>(); EnumWindows(delegate (IntPtr hWnd, IntPtr lParam) { if (IsWindowVisible(hWnd)) { StringBuilder sb = new StringBuilder(1024); GetWindowText(hWnd, sb, sb.Capacity); if (sb.ToString().Contains(windowTitle)) { handles.Add(hWnd); } } return true; }, IntPtr.Zero); foreach (IntPtr handle in handles) { SetForegroundWindow(handle); } } ``` 在这个示例代码中,EnumWindows 函数用于枚举所有可见窗口,GetWindowText 函数用于获取窗口标题,SetForegroundWindow 函数用于将窗口设置为前台窗口SetForegroundWindows 函数用于设置多个窗口为前台窗口,其参数为窗口标题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值