[.NET Desktop] 类似于360或者腾讯电脑管家的托盘嵌入程序(目前不稳定)

前言

使用过360或者腾讯电脑管家的人(较新版本的对应软件)应该都见过他的一个新功能,那就是托盘嵌入悬浮球,这东西怎么说呢,真是把悬浮球玩出花样了,又搞出了新的交互模式。不得不佩服这些老Windows开发(不知道他们当初去腾讯或者360的时候是不是windows开发还是热门啊),毕竟和杀毒软件这种对系统核心需要很深层次了解的东西对比起来,这种对 windows Shell 很深层次的了解对他们而言应该算是小菜一碟。
在这里插入图片描述
这个就是电脑管家的嵌入托盘,不了解windows的开发者可能还好,觉得这个就和托盘图标一个样,但是对于有一些windows开发经验的人而言,这东西可头疼了,他不是 NotificationIcon 不是 Deskband ,你甚至无法知道这种模式的学名叫什么,因为他肯定不是windows推荐的交互模式,或者说他可能有像 Deskabnd 一样的COM扩展方式,但是你无法查到(毕竟windows的系统图标很多都是这种的,使用spy++在”Tray_ShellWnd“下可以看到他们)。不过好在天无绝人之路,我思考这个问题思考了两年了,上大学就在想,但因为一开始接触的不是WinAPI或者MFC的那种比较低级的Windows开发,使我对一些WindowsAPI比较陌生,始终没办法做出来这个东西。最近在GitHub上找到一个T-Clock的项目,他的功能是定制系统时钟
在这里插入图片描述
这个功能已经和我想要的很接近了,毕竟它里面肯定有如何改变任务栏嵌入窗体宽度的代码。于是在经过一番研究后,我弄出了一个简陋的可以将WPF窗体嵌入通知区域的程序。
下面我就不说什么废话了

预览

在这里插入图片描述
这个是使用 WPF 按钮做的一个小控件没有关联其他任何事件。效果已经非常接近360或者管家的样子了。

说明

下面先说明一下:

  • 这个控件应该还有很多BUG,但是我不一定有时间试和改,如果不放心我搬的代码的话可以去找T-Clock自己改,毕竟我看面向过程代码真的能力有限,有漏掉什么也说不定。
  • 这个东西在和管家或者360同时打开时位置计算会出问题,这个就要你自己改了,我想应该可以在原先调整位置的WM_NOTIFY事件里去找下有没有360或者管家的窗体然后重新计算下需不需要在我们的subclassproc里去加那个空间(我没试过360能不能和管家共存,但我觉得不会有人同时装这两个吧。)
  • 在改变任务栏布局时(水平或者竖直)会出问题,问题很严重。目前我觉得唯一可行的办法就是再钩个任务栏的窗体过程,去里面挂钩鼠标左键按下事件,在事件触发后不刷新我们的图标,而在鼠标左键抬起后PostMessage给我们的图标进行刷新。
  • 由于我不太会使用VS的C++我里面使用spdlog而且也添加头文件了,但是VS一会能识别一会识别不了,我也很无奈。
  • 最好在一个窗体中去试这个窗体,退出时一定不要用Stop Debug退出,这要会导致dll没法脱钩,你得重启explorer。因为脱钩得调我的dispose,但Stop Debug没法触发那个事件,一旦退出。dll的引用计数就有偏差了。

这个说明只是想告诉读者,如果你的精力有限,或者windows开发方面的知识比较浅薄,又或者怕麻烦不愿意一次次调试,还是不要碰这个东西为好,要不然弄得你电脑反复重启explorer你还要来骂我。

在这里插入图片描述
关于windows任务栏的扩展,算上我前面的文章应该是全了。(除了taskbar的鼠标悬停预览小窗体)DeskBand即上图1区域,NotifyIcon即上图2区域(没啥好说的,Winform封装好的),今天这个就是上图3区域的扩展。
(嘿嘿,那个雷达是我改的SSR的可视化)

实现原理简要说明

代码我放在Github上了(如果这个东西确实帮到你的话,可以给个星,在这多谢了,毕竟这个资料真的很少,找的我好辛苦,都是翻Google6-7页才找到的,不像DeskBand还有那么点线索 ) 在里面搜TrayEmbeddedWindow具体怎么操作看注释,然后搜hsystrayembed整个项目msvc编译,这是用来注入的DLL(生成时注意位数和主窗口一致也不要改名字,或者你得在代码里也改,不然loadlibrary会失败),因为这个东西搞不好会让你的explorer崩溃,所以还是有一定开发经验的同道们使用起来比较好,不推荐新手接触。
原理主要就是用一个 Native 的 DLL 去做注入(SetWindowHookEx WH_CALLWNDPROC)(因为不允许托管dll做注入,托管DLL只能做全局钩子)

  • 先注入任务栏中随便一个窗口,然后通过注入的窗体过程去找一个你要放你嵌入窗体的位置旁边的窗体,比如我选的是输入法(用spy++去找)。
  • 然后SubClass任务栏通知区域(TrayNotifyWnd),处理其:
    WM_USER + 100 :这是任务栏布局时询问其子窗体大小变化的消息,可以在此消息中修改其返回值让任务栏留出你所要的空间大小
    WM_NOTIFY 在这个事件中重新布局窗体,将你的窗体放置在该放的地方
  • 主窗体启动时调用DLL中的export方法进行上述操作,并在其SubClass完后取消挂钩,然后将自身大小以自定义消息发送过去,使其重新布局。
  • 主窗体退出时调用DLL中的export方法,取消subclass,清空dll中指针变量,主窗体释放非托管资源,主窗体空置托管指针变量。

其中最主要的还是那两个消息,这是我以前一直能挂钩到窗体过程却实现不了这个效果的主要原因,还有就是如果你有能力一定要仔细改改,现在我代码肯定有许多问题只是我还没有试出来而已。

猜你喜欢

转载自blog.csdn.net/q886yes/article/details/109337741
今日推荐