经常使用windows系统的同学可能都会遇到这样一种情况,刚按照完的应用程序,可能会在桌面产生一个提示信息,指示当前快捷方式可以使用了,并给出相应的文字说明,指示该快捷方式的功能。那么大家有没有考虑过这供功能是怎么实现的呢,使用一般的窗口spy工具应该都能抓取windows系统桌面使用的窗口类,我使用彗星小助手抓取了下,效果如图1所示。原来windows桌面窗口是一个listview,那么问题就变得简单了,我们只需要拿到窗口句柄,并向其发送消息LVM_GETITEMCOUNT消息,获取到窗口item数量后,在发送LVM_GETITEMTEXTA消息,并读取每一项的文本名称,在和我们自己想要的桌面文件名称对比,如果是目标文件在发送LVM_GETITEMRECT消息,就可以拿到具体的桌面文件位置。下面看具体的实现过程。

图1

看到这篇文章的同学,我推荐一下这个彗星小助手工具,功能挺丰富的,看图1的标题栏就知道了,在没有发现彗星小助手工具之前我采集屏幕颜色一致使用的是picpick,也挺好用,推荐大家使用。除此之外还推荐大家:everything硬盘搜索工具、小屁孩桌面便签

一、首先是获取桌面窗口句柄

获取桌面窗口句柄需要区分xp系统和win7系统,首先我们按win7方式获取,如果获取失败,那么我们再按win xp方式获取,代码如下,拿到桌面窗口句柄后,我们就可以进一步的给桌面窗口发送消息,并获取桌面图标相关信息,不过在此之前我们还需要做一件事,就是区分当前系统的位数,因为32位系统和64位系统的结构有所不一样,需要我们分开做处理。

 CRect cRect;
HWND hDeskWnd = nullptr;//桌面上SysListView32的窗口句柄
HWND hWnd = ::FindWindow(L"WorkerW", nullptr);//先当WIN7系统查找
while (hWnd)
{
HWND hShellView = ::FindWindowEx(hWnd, nullptr, L"SHELLDLL_DefView", nullptr);
if (hShellView)
{
hDeskWnd = ::FindWindowEx(hShellView, nullptr, L"SysListView32", nullptr);
break;
}
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
} if (hDeskWnd == nullptr)
{
qDebug() << QStringLiteral("WIN7系统查找方式失败");
//如果没找到,再按XP方式查找
hWnd = ::FindWindow(L"Progman", L"Program Manager");
if (hWnd)
{
hWnd = ::FindWindowEx(hWnd, nullptr, L"SHELLDLL_DefView", nullptr);
hDeskWnd = ::FindWindowEx(hWnd, nullptr, L"SysListView32", nullptr);
}
} if (hDeskWnd == nullptr)
{
QMessageBox::warning(nullptr, QStringLiteral("警告"), QStringLiteral("查找桌面窗口句柄失败"));
return false;
}

判断系统位数的方法不难,代码如下:

 BOOL Is64Bit_OS()//判断操作系统位数
{
BOOL bRetVal = false;
SYSTEM_INFO si = { };
LPFN_PGNSI pGNSI = (LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
if (pGNSI == nullptr)
{
return false;
}
pGNSI(&si);
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64
|| si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
{
bRetVal = true;
}
else
{
// 32 位操作系统
//_tprintf(L"is 32 bit OS\r\n");
}
return bRetVal;
}

在桌桌面引导的时候你可能还需要显示桌面,我使用的代码如下:

 void ShowDesktop(void)//显示桌面
{
CoInitialize();
IShellDispatch4 * pdisp = nullptr;
CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_ALL, __uuidof(IShellDispatch4), (void **)&pdisp);
if (pdisp)
{
pdisp->ToggleDesktop();//这句是用来切换桌面的
pdisp->Release();
}
}

二、获取桌面图标位置

从第一步我们可以成功拿到桌面窗口句柄,接下来我们就只需要给桌面窗口发送一些列的消息,然后拿到我们自己需要的信息。下面我一步一步讲解,贴上关键代码。

注意:32位系统和64位系统发送消息的流程一模一样,只是定义的结构体不一样,因此我只讲解32位的代码,64位的自己一看便明白,文章最后我会附上相关的示例demo。

1、首先是打开一个已存在的进程对象,并返回进程的句柄

GetWindowThreadProcessId(hDeskWnd, &PID); HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, PID);

2、在一些机器上,可能会存在打开进程失败的情况,比如我在xp系统上就出现这个问题,那么这个时候就需要提升进程的访问权限,提升进程访问权限代码如下:

 BOOL EnableDebugPrivilege()
{
HANDLE hToken;
BOOL fOk = FALSE;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = ;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[].Luid); tp.Privileges[].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return fOk;
}

3、如果进程打开失败,则提升进程访问权限,并在此打开进程

 if (hProcess == nullptr)
{
unsigned short errorCode = GetLastError();
qDebug() << QStringLiteral("获取进程句柄操作失败32 hWnd=%1,PID=%2,errorCode=%3")
.arg((int)hDeskWnd).arg(PID).arg(errorCode);
if (errorCode == )
{
qDebug() << QStringLiteral("拒绝访问");
if (EnableDebugPrivilege())
{
qDebug() << QStringLiteral("提升进程访问权限成功");
}
else
{
qDebug() << QStringLiteral("提升进程访问权限失败");
} GetWindowThreadProcessId(hDeskWnd, &PID);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, PID);
if (hProcess == nullptr)
{
qDebug() << QStringLiteral("进程依然打开失败");
}
else
{
qDebug() << QStringLiteral("提升权限后开成功");
}
}
}

4、进程打开成功后,想桌面程序发送LVM_GETITEMCOUNT消息,并获取桌面文件个数

5、遍历桌面所有文件,并发送LVM_GETITEMTEXTA消息,拿到文件的名称,如果是目标文件则进行下一步,否则一直遍历,直到遍历完所有文件并结束

6、如果是目标文件,则发送LVM_GETITEMRECT消息,拿到文件在位置,并返回。

下面我提上完整的获取桌面图标位置代码(32系统上)

 if (hProcess)
{
LVITEMA * pLVITEM = (LVITEMA *)VirtualAllocEx(hProcess, nullptr, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
char* pszText = (char *)VirtualAllocEx(hProcess, nullptr, , MEM_COMMIT, PAGE_READWRITE);
RECT* pItemRc = (RECT *)VirtualAllocEx(hProcess, nullptr, sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);
RECT rc; if (!pItemRc || !pLVITEM)
{
qDebug() << QStringLiteral("无法分配内存!");
}
else
{
LVITEMA LVITEM;
LVITEM.mask = LVIF_TEXT;
LVITEM.cchTextMax = ;
LVITEM.pszText = pszText;
char ItemBuf[];
int nCount = ::SendMessage(hDeskWnd, LVM_GETITEMCOUNT, , ); for (int iItem = ; iItem < nCount; ++iItem)
{
LVITEM.iItem = iItem;
LVITEM.iSubItem = ;
//将设置好的结构插入目标进程
WriteProcessMemory(hProcess, pLVITEM, &LVITEM, sizeof(LVITEM), nullptr);
//发送LVM_GETITEM消息
BOOL r = (BOOL)::SendMessage(hDeskWnd, LVM_GETITEMTEXTA, iItem, (LPARAM)pLVITEM);
//获取pszText
ReadProcessMemory(hProcess, pszText, ItemBuf, , nullptr);
QString str = QString::fromLocal8Bit(ItemBuf);
//AfxMessageBox(str);
if (str == strIconName)
{
::SendMessage(hDeskWnd, LVM_GETITEMRECT, iItem, (LPARAM)pItemRc);
ReadProcessMemory(hProcess, pItemRc, &rc, sizeof(RECT), nullptr);
memcpy(lpRect, &rc, sizeof(RECT));
bRet = true;
break;
} }
VirtualFreeEx(hProcess, pLVITEM, , MEM_RELEASE);
VirtualFreeEx(hProcess, pszText, , MEM_RELEASE);
VirtualFreeEx(hProcess, pItemRc, , MEM_RELEASE);//释放内存
}
CloseHandle(hProcess);
}

三、效果展示

下面我展示下我自己在各个平台下测试的结果

1、windows xp 32位,如图2

图2

2、windows 7 32位 如图3

图3

3、windows 10 64位 如图4

图4

demo下载链接:http://download.csdn.net/detail/qq_30392343/9590201

如果需要定制好看的界面可以参考:

QPainterPath 不规则提示框

QPainterPath 不规则提示框(二)

如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! 

 

很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。

windows之桌面程序引导功能的更多相关文章

  1. 卸载Windows控制面板的程序和功能中找不到的一些软件的方法

    卸载Windows控制面板的程序和功能中找不到的一些软件的方法 找到卸载程序进行卸载即可

  2. 迁移桌面程序到MS Store(3)——开机自启动

    迁移桌面程序的时候,有可能你会遇到这么个需求——开机自启动.Windows传统桌面程序的传统陋习.不论什么奇葩软件都想要开机自启动,默认就给你打开,一开机哐哐哐什么雷,什么企鹅都蹦出来,也不管你用不用 ...

  3. 空闲时间研究一个小功能:winform桌面程序如何实现动态更换桌面图标

    今天休息在家,由于天气热再加上疫情原因,就在家里呆着,空闲时想着,在很早以前(约3年前),产品人员跟我提了一个需求,那就是winform桌面程序的图标能否根据节日动态更换,这种需求在移动APP上还是比 ...

  4. 在桌面程序上和Metro/Modern/Windows store app的交互(相互打开,配置读取)

    这个标题真是取得我都觉得蛋疼..微软改名狂魔搞得我都不知道要叫哪个好.. 这边记录一下自己的桌面程序跟windows store app交互的过程. 由于某些原因,微软的商店应用的安全沙箱导致很多事情 ...

  5. Shepherd – 在应用程序中轻松实现引导功能

    Shepherd 是一个指导用户使用应用程序的 JavaScript 库.它使用 Tether——另一个开源库,实现所有的步骤.Tether 确保你的步骤不会溢出屏幕或被剪裁.你可以很容易地指导用户使 ...

  6. c#实现windows远程桌面连接程序

    c#实现windows远程桌面连接程序 使用winform制作windows远程桌面连接程序,windows自带了远程桌面连接,我们需要将远程桌面连接集成 到自己的winform程序,并实现管理远程主 ...

  7. c#实现windows远程桌面连接程序代码

    使用winform制作windows远程桌面连接程序,windows自带了远程桌面连接,我们需要将远程桌面连接集成 到自己的winform程序,并实现管理远程主机的配置. 远程桌面核心类库 windo ...

  8. 在WINDOWS任务计划程序下执行PHP文件 PHP定时功能的实现

    最近需要做一个定时任务功能,从网站找了很多相关的代码,windows实现方法综合起来大概就两种, 一.使用PHP ignore_user_abort 函数 即使关掉浏览器也能正常运行:(个人感觉PHP ...

  9. C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...

随机推荐

  1. mybatis常用类起别名

    在mybatis的配置文件中添加如下配置 <settings> <setting name="cacheEnabled" value="true&quo ...

  2. numpy库补充 mean函数应用

    mean()函数功能:求取均值经常操作的参数为axis,以m * n矩阵举例: axis 不设置值,对 m*n 个数求均值,返回一个实数 axis = 0:压缩行,对各列求均值,返回 1* n 矩阵 ...

  3. Linux-day1-上课笔记

    命令的组成 命令关键字 [选项] [参数] 注意: 1. 通常情况下 选项- --连接 ls -l /etc 2. - 选项和选项之间是可以合并的 ls -ld /etc ls 罗列文件   常见的选 ...

  4. Java类是如何默认继承Object的

    前言 学过Java的人都知道,Object是所有类的父类.但是你有没有这样的疑问,我并没有写extends Object,它是怎么默认继承Object的呢? 那么今天我们就来看看像Java这种依赖于虚 ...

  5. 图解CSS3核心技术与案例实战(1)

    前言: 我买了一本<图解CSS3核心技术与案例实战>大漠写的,为了提高自己的自觉性呢,抓紧看书,把读书笔记放在这上面,跟大家一起分享,也为督促自己完成读书计划. 文末有微信公众号,感谢你的 ...

  6. 学习之路-->大小文件读取并分页展示

    1.读取小文件,并进行分页 商品|价格 飞机|1000 大炮|2000 迫击炮|1000 手枪|123 ..... lis = [] n = 10 #每页显示10条信息 with open('小文件' ...

  7. D. Frets On Fire 前缀和+二分

    这个题真的难了我一天了,这种方法一开始没想出来,后来看了题解后明白了大致思路开始自己做但是!!!但是自己实现的时候老是一些细节出错!!!,调bug调了得有一个小时,蠢死了,这道题我一定要好好总结,总结 ...

  8. 口袋appnabcd

    N(need)需求:依据我们学习经历的情况而言,对于初次接触的专业的学生来说,对学习的方向上会感到迷茫,不知道如何学习以及不知道学什么.比如对于计算机专业来说,对于一些软件的选择和下载,应用环境配置等 ...

  9. Android Studio 设置不同分辨率的图标Icon

    右键你的项目 -->"NEW"-->"Image Asset" 'Asset Type' 勾选”Image“才可以选择”Path“,其他选项可以自己 ...

  10. Objective-C 优秀文章分享

    1.  Objective-C Runtime 2.KVO + Block 3.Method Swizzling 和 AOP 实践