保存和恢复桌面上的图标位置

本文介绍如何在 Windows 桌面上保存和还原图标的位置。

介绍

最近,我的公司为我的笔记本电脑提供了一个扩展坞。这是一个不错的玩具,但很快我就遇到了一个小问题。重新启动后,我的笔记本电脑不时(实际上相当频繁)会忘记屏幕分辨率。它不会太困扰我,因为恢复屏幕分辨率既快速又简单。但问题是,使用分辨率时,它会忘记桌面上所有图标的位置。再次放置它们很容易,但速度不快,因为我有很多图标。

当然,有像IconRestorerDesktopOK 9.73 Save and restore the desktop icon positions.icon-default.png?t=M276https://www.softwareok.com/?seite=Freeware/DesktopOK这样的程序可以帮助我。但毕竟,我们是程序员,这是一个有趣的任务。所以,让旅程开始吧!

注册表

我谷歌了Windows存储有关桌面上图标位置的信息的位置。并且有一个很好的和简单的答案,这些信息存储在注册表项"CurrentUser\Software\Microsoft\Windows\Shell\Bags\1\Desktop"中。我知道如何使用注册表,这是一项简单的任务。但很快我就意识到这不是一个正确的答案。看起来 Windows 在登录时读取此信息并存储在注销时。我想在不重新启动计算机的情况下恢复图标的位置。所以我需要另一个解决方案。

PInvoke

我再次谷歌搜索,发现实际上桌面是某些进程中的控件。任何人都可以使用 Windows 的标准 API 向此控件发送消息。并得到一些结果。但这意味着我应该使用PInvoke技术来使用传统的Windows API。就个人而言,我对PInvoke感到不安。首先,您应该知道每个必需函数所在的 DLL。然后有不同的封送处理问题。我对此感到害怕。但幸运的是,我找到了一个很棒的网站:PInvoke.net。它非常易于使用,并且包含许多本机Windows函数和结构的.NET包装器,包括一些有用的重载。我肯定会在以后使用这个网站,并希望它也能帮助你。ListViewSendMessage

桌面流程

为了能够向控件发送消息,应获取其句柄 - Windows 中控件的唯一 ID。为了做到这一点,应该首先识别包含此控件的进程。在这里,我遇到了第一个问题。你看,Windows可以在不同的进程中托管对桌面的控制。如果桌面上有一个静态映像,则只有一个进程。如果您有多个图像,并且Windows不时更改背景图像,那么您还有另一个过程。我花了一些时间才找到一个通用算法,它应该在这里处理桌面控制。

设置图标的位置

如前所述,图标只是显示在控件中的项目。很容易获得这些项目的总数:ListView

C#
var numberOfIcons = 
  (int)Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);

将图标的位置设置到某个点也很容易:(x,y)

C#
public static IntPtr MakeLParam(int wLow, int wHigh)
{
    return (IntPtr)(((short)wHigh << 16) | (wLow & 0xffff));
}
 
...
 
Win32.SendMessage(_desktopHandle, Win32.LVM_SETITEMPOSITION, iconIndex, MakeLParam(x, y));

其中 是 和 之间的图标的索引。iconIndex 0numberOfIcons - 1

所以接下来要做的就是获得图标位置。这是另一个等待我的问题。

获取图标的位置

看起来很容易获得图标的位置。你只需这样称呼:

C#
Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMPOSITION, iconIndex, pointerToResult);

和变量包含指向一个简单结构的指针,该结构描述了带有索引的图标的位置。但它不起作用。问题是,我们向其发送消息的控制处于另一个进程中。因此,该变量指向另一个进程中的内存。由于内存保护,我们无法访问它。因此,算法变得更加复杂。我从这里拿走了它。很快,您必须首先分配共享内存,然后发送命令将一些信息写入此共享内存,然后从那里读取所需的信息。pointerToResult iconIndexpointerToResult

现在,我有能力获取和设置图标的位置。我写了一个简单的程序来保存和恢复这些位置。但似乎这不是结束。

获取图标文本

很快,在我开始使用我的程序后,我意识到它可能会交换图标。我的Microsoft Word图标已在回收站等位置恢复。这意味着在重新启动Microsoft Word图标的索引被更改后,我不能只依赖索引。我开始思考我可以使用什么作为常量值来区分图标。显而易见的答案是:"他们的文本"。但这个简单的任务变成了一场噩梦。互联网上有很多示例,您可以使用相同的机制在桌面上获取图标文本。没有人在我的笔记本电脑上工作。最后,我遇到了这段使用汇编来解决此任务的代码。它允许我获取图标的文本,并将它们与图标索引连接起来。我存储了带有位置的文本,并使用图标的索引在当前计算机负载上具有相同的文本来恢复位置。SendMessageUIAutomationClient

最后一件

现在我能够享受我的程序。它成功保存并恢复了图标的位置。但很快,我注意到了另一个问题。加载笔记本电脑后,我恢复了图标的位置。他们被安置得很好。但是当我启动几个应用程序时,所有图标突然又搞砸了。我开始调查这个问题,发现我需要刷新桌面以保留图标位置。幸运的是,这很容易做到:

C#
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

...

SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);

但很快,很明显,这段代码有一个副作用。它还经常排列图标。这并不完全是"刷新"命令对桌面的作用。我开始寻找如何进行真正的刷新。而且我没有在我的笔记本电脑上找到任何工作。一段时间后,我突然意识到Windows中有一个快捷方式"F5"可以刷新桌面,我只需要将此密钥发送到桌面即可。代码相当简单:

C#
PostMessage(_desktopHandle, WM_KEYDOWN, VK_F5, 0);

其中 类似于 。现在一切似乎都很好。PostMessage SendMessage

兴趣点

如果有一种方法可以使用以下方法获取图标文本,对我来说仍然很有趣:SendMessage

C#
Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMTEXT, iconIndex, ...);

一定有办法...

附言

我知道文章中没有太多代码。但毕竟,我没有创建很多代码。其中大部分取自不同的来源。我只是想展示解决保存和恢复图标位置的陷阱。如果您需要代码,只需下载我的完整项目(请参阅文章顶部的链接)。或者按照文本中的链接转到我的信息来源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值