写一个Windows上的守护进程(8)获取进程路径
写一个Windows上的守护进程(8)获取进程路径
要想守护某个进程,就先得知道这个进程在不在。我们假设要守护的进程只会存在一个实例(这也是绝大部分情形)。
我是遍历系统上的所有进程,然后判断他们的路径和要守护的进程是否一致,以此来确定进程是否存在。
遍历进程大家都知道用CreateToolhelp32Snapshot系列API,但是他们最后取得的是进程exe名称,不是全路径,如果仅依靠名称就可以达到目的也就罢了,但是有的时候还是得取到全路径,这样会更靠谱一些。
那么问题来了,如何取到进程全路径?
首先登场的是GetModuleFileNameEx。大多数时候,我们都可以用这个函数来取得进程的全路径,而且这个函数是全平台都有,但是你有没有注意到这样一段话:

(来自VS2008的MSDN文档)
这个函数有缺陷。除了这个问题之外,还有一个问题:如果你是32进程要获取某个64位进程的全路径,有可能也会出错,具体请看我很早前写过的一片帖子http://blog.csdn.net/mkdym/article/details/8688597。
当然微软也说了,你还可以用GetProcessImageFileName和QueryFullProcessImageName两个函数呀。
那么接下来说GetProcessImageFileName。这函数确实不存在GetModuleFileNameEx的两个问题,但是它不支持Windows2000,当然如果你不需要支持Windows2000这种老古董,你完全不用理会这个缺憾。然而,它还有别的问题:
1. 这家伙返回的是个内核名称,形如\Device\Harddisk0\Partition1\WINNT\System32\Ctype.nls。内核名称咱不怕,咱用QueryDosDevice反向获取:先用QueryDosDevice获取到所有磁盘的驱动器名称和内核名称的对应关系,然后把刚获取到的内核名称的前面部分换掉就可以了。你到网上一搜,也全是这种办法。
以为这就结束了吗?请看https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217(v=vs.85).aspx 下面关于动态磁盘的问题,这个问题是我提的:在动态磁盘的情况下,驱动器的链接会有两层,这个你可以从Winobj中看到,而QueryDosDevice只能获取到第一层,GetProcessImageFileName返回的是第二层的!我勒个去!网上一番搜索之后,许多人给出的答案都是在结果上反复调用QueryDosDevice,我只能对这些人呵呵,也许他们的电脑比较特殊,QueryDosDevice可以那样使用。
关于动态磁盘的问题,你还可以看我在上面给出的那个csdn的帖子,那是我发现这个问题的过程。
怎么办?后来忘了在那个论坛里边看到的,用内核函数NtQuerySymbolicLinkObject可以做到QueryDosDevice一样的事情,经过试验,这个函数是可以在结果上重复调用的,能够获取到最底层的内核名称。嗯,这个问题就这样解决了。
当然,一般的机子不会有动态磁盘。
2. 当你看MSDN页面上我说的“动态磁盘”的问题的时候,应该会注意到,下面有个哥们说,这个函数会返回短路径名,所以咱也得注意了。把每个返回的路径都转换成长路径名,不管它是不是短路径名(我也不知道它是不是短路径名啊)。虽然我测试的时候它返回的都是长路径名。
这里还有一点,咱给进程们做了快照了,快照的那一刻驱动器们是确定的,所以完全不需要获取每个进程路径的时候都去获取所有驱动器的名称对应关系,只需要在遍历开始的时候,准备一下这些名称,然后遍历的时候直接拿来用。
嗯,用这个API就是这么麻烦。
最后咱们说QueryFullProcessImageName。这个函数啥都好,就是平台要求太高,得是Vista及以上啊,所以只能是能用则用。
最终我获取进程路径的方案是这样的:如果有QueryFullProcessImageName函数,就用这个函数,没有的话先上GetModuleFileNameEx,如果GetModuleFileNameEx出错了再上GetProcessImageFileName。把最麻烦的放到最后。
类名CProcessPathQuery。
大家看代码的时候可能会注意到,我在处理的时候用了个for循环,这是因为我也不知道进程路径有多长,如果返回错误码说缓冲区不够,就加长重试,但是也不能无限重试,有个限度。
进程路径获取出来之后,因为有可能是GetProcessImageFileName获取出来的,那就是一个内核名称,需要转换,转换类是CDosPathConverter。
进程遍历类是CProcessScanner,可以看到我在里面放了一个CDosPathConverter的实例,随着遍历类的初始化一起初始化。
遍历进程的时候需要注意,有几类特殊的进程我们是获取不到路径的,或者获取他们的路径是没有意义的,可以看CProcessPathQuery的注释。
有一点需要注意,一定要提权,否则就会有好多进程因为我们自己权限不够而query失败。
源码:https://git.oschina.net/mkdym/DaemonSvc.git (主)&& https://github.com/mkdym/DaemonSvc.git (提升逼格用的)。
2015年11月19日星期四
写一个Windows上的守护进程(8)获取进程路径的更多相关文章
- 写一个Windows上的守护进程(7)捕获异常并生成dump
写一个Windows上的守护进程(7)捕获异常并生成dump 谁都不能保证自己的代码不出bug.一旦出了bug,最好是崩溃掉,这样很快就能被发现,若是不崩溃,只是业务处理错了,就麻烦了,可能很长时间之 ...
- 写一个Windows上的守护进程(6)Windows服务
写一个Windows上的守护进程(6)Windows服务 守护进程因为要开机启动,还要高权限,所以我就把它做成Windows服务了. 关于Windows服务的官方文档,大家可以看https://msd ...
- 写一个Windows上的守护进程(5)文件系统重定向
写一个Windows上的守护进程(5)文件系统重定向 在Windows上经常操作文件或注册表的同学可能知道,有"文件系统/注册表重定向"这么一回事.大致来说就是32位程序在64位的 ...
- 写一个Windows上的守护进程(4)日志其余
写一个Windows上的守护进程(4)日志其余 这次把和日志相关的其他东西一并说了. 一.vaformat C++日志接口通常有两种形式:流输入形式,printf形式. 我采用printf形式,因为流 ...
- 写一个Windows上的守护进程(3)句柄的管理
写一个Windows上的守护进程(3)句柄的管理 在Windows中编程,跟HANDLE打交道是家常便饭.为了防止忘记CloseHandle,我都是使用do-while-false手法: void f ...
- 写一个Windows上的守护进程(2)单例
写一个Windows上的守护进程(2)单例 上一篇的日志类的实现里有个这: class Singleton<CLoggerImpl> 看名字便知其意--单例.这是一个单例模板类. 一个进程 ...
- 写一个Windows上的守护进程(1)开篇
写一个Windows上的守护进程(1)开篇 最近由于工作需要,要写一个守护进程,主要就是要在被守护进程挂了的时候再把它启起来.说起来这个功能是比较简单的,但是我前一阵子写了好多现在回头看起来比较糟糕的 ...
- C#依据进程名称获取进程的句柄?
C#依据进程名称获取进程的句柄或C#怎样获取其它进程的句柄? 有时候标题名是动态变化的,所以不使用FindWindow方法! [StructLayout(LayoutKind.Sequential)] ...
- C#根据进程名称获取进程的句柄?
C#根据进程名称获取进程的句柄或C#如何获取其他进程的句柄? 有时候标题名是动态变化的,所以不使用FindWindow方法! [StructLayout(LayoutKind.Sequential)] ...
随机推荐
- java 中解析xml的技术
最初,XML 语言仅仅是意图用来作为 HTML 语言的替代品而出现的,但是随着该语言的不断发展和完善,人们越来越发现它所具有的优点:例如标记语言可扩展,严格的语法规定,可使用有意义的标记,内容存储和表 ...
- 三个重要的游标sp_cursoropen
請問這三個存諸過程的作用是什么﹖ sp_cursoropen, sp_cursorfetch, sp_cursorclose API 服务器游标实现 SQL Server OLE DB 提供程序. ...
- CSS3 基础知识
CSS3 基础知识1.边框 1.1 圆角 border-radius:5px 0 0 5px; 1.2 阴影 box-shadow:2px 3px 4px 5px rgba(0,0,0 ...
- 使用MSSM管理工具登录LOCALDB
调试程序没有安装 sql server时,可以使用localdb.这是一个简易的sql server数据库,用于本地测试是很方便,省去安装SQL SERVER的工作 电脑上安装了VS2013 VS20 ...
- JDBC框架
一.元数据介绍 元数据指的是"数据库"."表"."列"的定义信息. 1.1.DataBaseMetaData元数据 Connection.g ...
- Symfony2 Doctrine从现有Database生成Entity(转载自http://blog.it985.com/6809.html)
在我的以前一章Symfony之十分钟入门说了怎样生成数据库,然后设计实体Entity,再同步数据库的表结构,一般我们的顺序都是这样:生成数据库->设计实体Entity->同步数据库表结构. ...
- tableView点击后取消选中效果
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES]; @impo ...
- 在Wince模拟器接入网络的方法
我第一次使用wince调用WCF服务的时候总是报错,找了半原因发现程序部署在模拟器中,而模拟器没有连接到网络,所以无法连接到WCF服务器. 以下是wince接入网络的方法: 1.点击模拟 ...
- HTML5 的段落首行缩进
text-indent:0em;表示当前行不需要缩进,文本顶头开始.这个属性可以用在 div p等元素下面 文本首行的缩进(在首行文字之前插入指定的长度) p { line-height: 2em ...
- sgu Kalevich Strikes Back
这道题就是求一个大矩形被n个矩形划分成n+1个部分的面积,这些矩形之间不会相交,可能包含.. #include <cstdio> #include <cstring> #inc ...