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 ...
随机推荐
- mybatis常用类起别名
在mybatis的配置文件中添加如下配置 <settings> <setting name="cacheEnabled" value="true&quo ...
- numpy库补充 mean函数应用
mean()函数功能:求取均值经常操作的参数为axis,以m * n矩阵举例: axis 不设置值,对 m*n 个数求均值,返回一个实数 axis = 0:压缩行,对各列求均值,返回 1* n 矩阵 ...
- Linux-day1-上课笔记
命令的组成 命令关键字 [选项] [参数] 注意: 1. 通常情况下 选项- --连接 ls -l /etc 2. - 选项和选项之间是可以合并的 ls -ld /etc ls 罗列文件 常见的选 ...
- Java类是如何默认继承Object的
前言 学过Java的人都知道,Object是所有类的父类.但是你有没有这样的疑问,我并没有写extends Object,它是怎么默认继承Object的呢? 那么今天我们就来看看像Java这种依赖于虚 ...
- 图解CSS3核心技术与案例实战(1)
前言: 我买了一本<图解CSS3核心技术与案例实战>大漠写的,为了提高自己的自觉性呢,抓紧看书,把读书笔记放在这上面,跟大家一起分享,也为督促自己完成读书计划. 文末有微信公众号,感谢你的 ...
- 学习之路-->大小文件读取并分页展示
1.读取小文件,并进行分页 商品|价格 飞机|1000 大炮|2000 迫击炮|1000 手枪|123 ..... lis = [] n = 10 #每页显示10条信息 with open('小文件' ...
- D. Frets On Fire 前缀和+二分
这个题真的难了我一天了,这种方法一开始没想出来,后来看了题解后明白了大致思路开始自己做但是!!!但是自己实现的时候老是一些细节出错!!!,调bug调了得有一个小时,蠢死了,这道题我一定要好好总结,总结 ...
- 口袋appnabcd
N(need)需求:依据我们学习经历的情况而言,对于初次接触的专业的学生来说,对学习的方向上会感到迷茫,不知道如何学习以及不知道学什么.比如对于计算机专业来说,对于一些软件的选择和下载,应用环境配置等 ...
- Android Studio 设置不同分辨率的图标Icon
右键你的项目 -->"NEW"-->"Image Asset" 'Asset Type' 勾选”Image“才可以选择”Path“,其他选项可以自己 ...
- Objective-C 优秀文章分享
1. Objective-C Runtime 2.KVO + Block 3.Method Swizzling 和 AOP 实践