写一个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)获取进程路径的更多相关文章

  1. 写一个Windows上的守护进程(7)捕获异常并生成dump

    写一个Windows上的守护进程(7)捕获异常并生成dump 谁都不能保证自己的代码不出bug.一旦出了bug,最好是崩溃掉,这样很快就能被发现,若是不崩溃,只是业务处理错了,就麻烦了,可能很长时间之 ...

  2. 写一个Windows上的守护进程(6)Windows服务

    写一个Windows上的守护进程(6)Windows服务 守护进程因为要开机启动,还要高权限,所以我就把它做成Windows服务了. 关于Windows服务的官方文档,大家可以看https://msd ...

  3. 写一个Windows上的守护进程(5)文件系统重定向

    写一个Windows上的守护进程(5)文件系统重定向 在Windows上经常操作文件或注册表的同学可能知道,有"文件系统/注册表重定向"这么一回事.大致来说就是32位程序在64位的 ...

  4. 写一个Windows上的守护进程(4)日志其余

    写一个Windows上的守护进程(4)日志其余 这次把和日志相关的其他东西一并说了. 一.vaformat C++日志接口通常有两种形式:流输入形式,printf形式. 我采用printf形式,因为流 ...

  5. 写一个Windows上的守护进程(3)句柄的管理

    写一个Windows上的守护进程(3)句柄的管理 在Windows中编程,跟HANDLE打交道是家常便饭.为了防止忘记CloseHandle,我都是使用do-while-false手法: void f ...

  6. 写一个Windows上的守护进程(2)单例

    写一个Windows上的守护进程(2)单例 上一篇的日志类的实现里有个这: class Singleton<CLoggerImpl> 看名字便知其意--单例.这是一个单例模板类. 一个进程 ...

  7. 写一个Windows上的守护进程(1)开篇

    写一个Windows上的守护进程(1)开篇 最近由于工作需要,要写一个守护进程,主要就是要在被守护进程挂了的时候再把它启起来.说起来这个功能是比较简单的,但是我前一阵子写了好多现在回头看起来比较糟糕的 ...

  8. C#依据进程名称获取进程的句柄?

    C#依据进程名称获取进程的句柄或C#怎样获取其它进程的句柄? 有时候标题名是动态变化的,所以不使用FindWindow方法! [StructLayout(LayoutKind.Sequential)] ...

  9. C#根据进程名称获取进程的句柄?

    C#根据进程名称获取进程的句柄或C#如何获取其他进程的句柄? 有时候标题名是动态变化的,所以不使用FindWindow方法! [StructLayout(LayoutKind.Sequential)] ...

随机推荐

  1. hdu1087 简单DP

    I - 简单dp 例题扩展 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     ...

  2. python保留指定文件、删除目录其他文件的功能(1)

    由于给客户的发布版本上客户改动了些代码和图片,我们这边给他们更新publish都是增量更新(开发提供更新指定的文件,我们提取出来给客户进行覆盖更新),但有时需要更新的文件较多导致不得不一个一个的进行查 ...

  3. 记事本创建servlet在tomcat中发布基本思路

    在webapps中新建文件夹H,在其中再创建WEB-INF文件夹,在创建classes文件夹和web.xml文件,web.xml需要配置一下,classes文件夹中存放Servlet经编译过的clas ...

  4. find之exec和args

    本来以为以前的差不多够用了.呵呵,看到很多高手用高技巧,心痒痒的觉得我自己还可以提升啊..哈哈哈. 这个实践起来之后,,SED,AWK也得深化一下,,,SHELL和PYTHON,作运维的两样都不能废. ...

  5. AT89C 系列单片机解密原理

    单片机解密简单就是擦除单片机片内的加密锁定位.由于AT89C系列单片机擦除操作时序设计上的不合理.使在擦除片内程序之前首先擦除加密锁定位成为可能.AT89C系列单片机擦除操作的时序为:擦除开始---- ...

  6. Qt实现基于G.729A(G729A)的语音聊天

    一.G.729协议简介G.729协议是由ITU-T的第15研究小组提出的,并在1996年3月通过的8Kbps的语音编码协议.G.729系列主要有以下几种:G.729—最基本的G.729标准协议,原始版 ...

  7. PowerShell为什么强大

    PowerShell为什么强大 本文索引 [隐藏] 5.1举例介绍 1破天荒的方便 2面向对象 3绑上.NET这棵大树 4强大的兼容性 5基于平台的可扩展性 微软是一个很”低调”的公司,取名为微软,感 ...

  8. boost库使用:仿SGI-STL实现的一个树节点allocator

    ////////////////////////////////////////////////////////////////////////// //code by hzs //email: hu ...

  9. java设计模式--行为型模式--策略模式

    策略模式: 策略模式 概述 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 适用性 1.许多相关的类仅仅是行为有异.“策略”提供了一种用多个行 ...

  10. WebDriver使用IE浏览器

    开始使用Selenium2之后就一直在用FireFox,因为文章上都说webdriver对firefox支持的最好,同时也很好上手,试了一下就可用了,也就没再用其他浏览器,不过最近遇到了一个问题,是我 ...