windows之桌面程序引导功能
经常使用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
如果需要定制好看的界面可以参考:
很重要--转载声明
- 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
- 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。
windows之桌面程序引导功能的更多相关文章
- 卸载Windows控制面板的程序和功能中找不到的一些软件的方法
卸载Windows控制面板的程序和功能中找不到的一些软件的方法 找到卸载程序进行卸载即可
- 迁移桌面程序到MS Store(3)——开机自启动
迁移桌面程序的时候,有可能你会遇到这么个需求——开机自启动.Windows传统桌面程序的传统陋习.不论什么奇葩软件都想要开机自启动,默认就给你打开,一开机哐哐哐什么雷,什么企鹅都蹦出来,也不管你用不用 ...
- 空闲时间研究一个小功能:winform桌面程序如何实现动态更换桌面图标
今天休息在家,由于天气热再加上疫情原因,就在家里呆着,空闲时想着,在很早以前(约3年前),产品人员跟我提了一个需求,那就是winform桌面程序的图标能否根据节日动态更换,这种需求在移动APP上还是比 ...
- 在桌面程序上和Metro/Modern/Windows store app的交互(相互打开,配置读取)
这个标题真是取得我都觉得蛋疼..微软改名狂魔搞得我都不知道要叫哪个好.. 这边记录一下自己的桌面程序跟windows store app交互的过程. 由于某些原因,微软的商店应用的安全沙箱导致很多事情 ...
- Shepherd – 在应用程序中轻松实现引导功能
Shepherd 是一个指导用户使用应用程序的 JavaScript 库.它使用 Tether——另一个开源库,实现所有的步骤.Tether 确保你的步骤不会溢出屏幕或被剪裁.你可以很容易地指导用户使 ...
- c#实现windows远程桌面连接程序
c#实现windows远程桌面连接程序 使用winform制作windows远程桌面连接程序,windows自带了远程桌面连接,我们需要将远程桌面连接集成 到自己的winform程序,并实现管理远程主 ...
- c#实现windows远程桌面连接程序代码
使用winform制作windows远程桌面连接程序,windows自带了远程桌面连接,我们需要将远程桌面连接集成 到自己的winform程序,并实现管理远程主机的配置. 远程桌面核心类库 windo ...
- 在WINDOWS任务计划程序下执行PHP文件 PHP定时功能的实现
最近需要做一个定时任务功能,从网站找了很多相关的代码,windows实现方法综合起来大概就两种, 一.使用PHP ignore_user_abort 函数 即使关掉浏览器也能正常运行:(个人感觉PHP ...
- C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案
本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...
随机推荐
- ImCash:币圈英文术语大全
近年来随着数字货币的火热,在全世界范围内涌现出了一群数字货币的“发烧友”和忠实投资者,他们形成了自己的圈子“币圈”,并且有了自己的文化和语言,今天就让我们一起来了解一下外国币圈有哪些有意思的英文“专用 ...
- Python + Anaconda + vscode环境重装(2019.4.20)
目录 卸载程序 安装Ananconda 检查系统环境变量 更换国内镜像源 设置VS CODE 用户配置及工作环境配置 @(Python + Anaconda + vscode环境重装) 工程目录的使用 ...
- 【C语言编程练习】5.10寻找水仙数
1. 题目要求 如果一个3位数等于各位数字的立方和,则称这个数为水仙数,例如407=4^3+0^3+7^3.编写一个程序,找出全部的水仙数 2. 题目分析 感觉又和之前的题目大同小异了,先找出解空间, ...
- 1095 A+B for Input-Output Practice (VII)
一直presentation不对 ,看了别人的解释,还是不知道为什么最后还要\n http://acm.hdu.edu.cn/showproblem.php?pid=1095 #include< ...
- [CF1140C]Playlist
Description: 给你n首歌,每首歌有一个长度\(a_i\)和美丽度\(b_i\) 现在可以选出最多k首,动听值为\(\sum a_i*min_{\sum b_i}\) Hint: \(n \ ...
- centos7 安装python3.7.11 笔记
安装python依赖包yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-deve ...
- freebsd 时间校准
修改 /etc/rc.conf ntpdate_enable='YES'ntpd_enable='YES' 如果这里不指定ntpdate_hosts=参数的话,ntpdate会读取/etc/ntp.c ...
- 三色GDOI
前面说点什么.. 翻了翻别人的游记.. 发现自己从来没写过gdoi的游记.. 那就.. 一起写完它吧.. GDOI2015 肇庆 没啥印象,只有复联2的首映.. 那时候真的是什么都不懂.. 就是外出打 ...
- 用JDBC把Excel中的数据导入到Mysql数据库中
步骤:0.在Mysql数据库中先建好table 1.从Excel表格读数据 2.用JDBC连接Mysql数据库 3.把读出的数据导入到Mysql数据库的相应表中 其中,步骤0的table我是先在Mys ...
- Spark内部执行机制
Spark内部执行机制 1.1 内部执行流程 如下图1为分布式集群上spark应用程序的一般执行框架.主要由sparkcontext(spark上下文).cluster manager(资源管理器)和 ...