操作桌面图标的位置

今天的小程序演示了如何操作桌面图标的位置。

整个程序只是搭建脚手架,让我们可以调用和. IFolder­View::Get­Item­Position IFolder­View::Select­And­Position­Items

首先,我们调整我们之前看到IFolder­View的从窗口中提取的代码。

提醒:这些“小程序”不进行错误检查,因为它们旨在作为演示,而不是生产就绪的应用程序。

void FindDesktopFolderView(REFIID riid, void **ppv)
{
 CComPtr<IShellWindows> spShellWindows;
 spShellWindows.CoCreateInstance(CLSID_ShellWindows);

 CComVariant vtLoc(CSIDL_DESKTOP);
 CComVariant vtEmpty;
 long lhwnd;
 CComPtr<IDispatch> spdisp;
 spShellWindows->FindWindowSW(
     &vtLoc, &vtEmpty,
     SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp);

 CComPtr<IShellBrowser> spBrowser;
 CComQIPtr<IServiceProvider>(spdisp)->
     QueryService(SID_STopLevelBrowser,
                  IID_PPV_ARGS(&spBrowser));

 CComPtr<IShellView> spView;
 spBrowser->QueryActiveShellView(&spView);

 spView->QueryInterface(riid, ppv);
}

Find­Desktop­Folder­View函数从之前的文章中获取代码,并使用它来提取桌面的 shell 视图。除了对 的调用之外,这里的所有内容都应该看起来很熟悉(只是穿着不同的服装),Find­Window­SW因为我们正在按位置寻找特定的窗口,而不是仅仅枚举所有窗口。

的第一个参数Find­Window­SW。是我们要查找的文件夹。在我们的例子中,我们正在寻找桌面。

第二个参数是保留的,必须是VT_EMPTY.

第三个参数描述了我们正在寻找的窗口类型。我们使用特殊标志(从 Windows Vista 开始提供)说,“嘿,我知道桌面不是人们在寻找资源管理器窗口时想到的那种东西,但我知道我在说什么,所以给我吧。”SWC_DESKTOP

第四个参数接收窗口句柄,这对我们没有兴趣,但参数是强制性的,所以我们必须给它一些东西。

第五个参数指定搜索选项。我们常说,“请在第六个参数中返回”。第六个参数是我们希望返回的位置。SWFO_NEED­DISPATCHIDispatchIDispatch

好的,我们已经有足够的能力枚举所有桌面图标并打印它们的名称和位置。

#define UNICODE
#define _UNICODE
#include <windows.h>
#include <shlobj.h>
#include <exdisp.h>
#include <shlwapi.h>
#include <atlbase.h>
#include <atlalloc.h>
#include <stdio.h>

// CCoInitialize incorporated by reference

int __cdecl wmain(int argc, wchar_t **argv)
{
 CCoInitialize init;
 CComPtr<IFolderView> spView;
 FindDesktopFolderView(IID_PPV_ARGS(&spView));
 CComPtr<IShellFolder> spFolder;
 spView->GetFolder(IID_PPV_ARGS(&spFolder));

 CComPtr<IEnumIDList> spEnum;
 spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum));
 for (CComHeapPtr<ITEMID_CHILD> spidl;
      spEnum->Next(1, &spidl, nullptr) == S_OK;
      spidl.Free()) {
  STRRET str;
  spFolder->GetDisplayNameOf(spidl, SHGDN_NORMAL, &str);
  CComHeapPtr<wchar_t> spszName;
  StrRetToStr(&str, spidl, &spszName);

  POINT pt;
  spView->GetItemPosition(spidl, &pt);
  
  wprintf(L"At %4d,%4d is %ls\n", pt.x, pt.y, spszName);
 }
 return 0;
}

拿到后IFolder­View,我们也索要相应的IShell­Folder。这实际上不是枚举图标所必需的,但它可以让我们打印它们的名称。

我们询问视图的Items枚举,然后继续枚举每个项目。对于每个项目,我们询问IShell­Folder其名称,并询问IFolder­View其位置。然后我们打印结果。

好的,这很简洁,但您可以做的不仅仅是查询职位。您也可以修改它们。

int __cdecl wmain(int argc, wchar_t **argv)
{
 CCoInitialize init;
 CComPtr<IFolderView> spView;
 FindDesktopFolderView(IID_PPV_ARGS(&spView));

 CComPtr<IEnumIDList> spEnum;
 spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum));
 for (CComHeapPtr<ITEMID_CHILD> spidl;
      spEnum->Next(1, &spidl, nullptr) == S_OK;
      spidl.Free()) {
  POINT pt;
  spView->GetItemPosition(spidl, &pt);
  pt.x += (rand() % 5) - 2;
  pt.y += (rand() % 5) - 2;

 PCITEMID_CHILD apidl[1] = { spidl };
 spView->SelectAndPositionItems(
     1, apidl, &pt, SVSI_POSITIONITEM);
 }
 return 0;
}

这一次,我们不再打印项目的名称和位置,而是将图标位置随机抖动几个像素,然后将抖动的坐标设置为新位置。

关闭桌面上的自动排列图标对齐图标到网格,然后运行该程序。嘿,看,你的图标随机移动了几个像素。

对于额外的 hijinx,在进入循环之前调用 (以编程方式关闭自动排列和对齐网格),然后将此程序放入循环中,并将其滑入朋友(或敌人)的计算机上。spView->Set­Current­Folder­Flags(FWF_AUTO­ARRANGE | FWF_SNAP­TO­GRID, 0)

更严重的是,我们可以将这两部分放在一起,制作一个保存和恢复桌面图标位置的程序。

第二个提醒:这些“小程序”不进行错误检查,因为它们旨在用作演示,而不是生产就绪的应用程序。

void SavePositions(IFolderView *pView, PCWSTR pszFile)
{
 CComPtr<IStream> spStream;
 SHCreateStreamOnFileEx(pszFile, STGM_CREATE | STGM_WRITE,
     FILE_ATTRIBUTE_NORMAL, TRUE, nullptr, &spStream);
 CComPtr<IEnumIDList> spEnum;
 pView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum));
 for (CComHeapPtr<ITEMID_CHILD> spidl;
      spEnum->Next(1, &spidl, nullptr) == S_OK;
      spidl.Free()) {
  IStream_WritePidl(spStream, spidl);
  POINT pt;
  pView->GetItemPosition(spidl, &pt);
  IStream_Write(spStream, &pt, sizeof(pt));
 }
}

Save­Positions函数枚举视图中的所有图标并将它们的标识和位置写入文件。

void RestorePositions(IFolderView *pView, PCWSTR pszFile)
{
 CComPtr<IStream> spStream;
 SHCreateStreamOnFileEx(pszFile, STGM_READ,
     FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &spStream);
 POINT pt;
 for (CComHeapPtr<ITEMID_CHILD> spidl;
      SUCCEEDED(IStream_ReadPidl(spStream, &spidl)) &&
      SUCCEEDED(IStream_Read(spStream, &pt, sizeof(pt)));
      spidl.Free()) {
  PCITEMID_CHILD apidl[1] = { spidl };
  pView->SelectAndPositionItems(1, apidl, &pt, SVSI_POSITIONITEM);
 }
}

Restore­Positions函数执行相反的操作。它从文件中读取身份和位置,并调用将项目移动到其先前保存的位置。IFolder­View::Select­And­Position­Items

int __cdecl wmain(int argc, wchar_t **argv)
{
 if (argc != 3) {
  wprintf(L"Usage: %ls save filename\n"
          L"       %ls restore filename\n", argv[0], argv[0]);
  return 0;
 }
 CCoInitialize init;

 CComPtr<IFolderView> spView;
 FindDesktopFolderView(IID_PPV_ARGS(&spView));

 if (wcscmp(argv[1], L"save") == 0) {
  SavePositions(spView, argv[2]);
 } else if (wcscmp(argv[1], L"restore") == 0) {
  RestorePositions(spView, argv[2]);
 }
 return 0;
}

剩下的就是编写基于命令行参数调用Save­Positionsor函数的主程序。Restore­Positions

练习:讨论如果重命名桌面上的项目,然后尝试恢复其位置会发生什么。可以做些什么来解决这个问题?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值