如何在C#/ Win32中获取正在运行的进程的DOS路径名?

时间:2010-09-08 22:24:10

标签: c# .net winapi interop

总结一下,我需要这样做:

  

12345(hWnd) - > “C:\ SETUP.EXE”


现在,我正在使用GetProcessImageFileName来检索进程句柄的内核设备路径。我正在使用OpenProcess检索句柄,并将PID传递给它。我正在使用GetWindowThreadProcessId检索PID(我也需要)。

然而,这让我得到一个像:

这样的字符串
  

\设备\ Harddisk1的\ SETUP.EXE

此时,我使用DriveInfo.GetDrives()枚举系统上的所有驱动器,然后调用QueryDosDevice。最后,我可以做一些字符串操作魔法,并且“繁荣”,我有自己的道路。

<小时/> 好的,我的问题是:

  1. 此过程在网络驱动器上出现故障。
  2. 我真正想要的只是XP上的QueryFullProcessImageName
  3. 有一个更好的方法来做到这一点。请赐教,哦,WIN32API的众神!

2 个答案:

答案 0 :(得分:2)

显而易见的问题是,为什么你不只是使用QueryFullProcessImageName,如果这是你想要的?您是否需要与旧版Windows兼容?

在XP上可用的QueryFullProcessImageName最接近的等价物可能是GetModuleFileNameEx。我可能会检测QueryFullProcessImageName是否可用并尽可能使用它,否则会回到GetModuleFileNameEx

编辑:虽然GetModuleFileNameEx并非100%可靠地检索每个可能进程的可执行文件的名称,但它至少在相当长的一部分时间内起作用。以下是我编写的一小段测试代码:

#include <windows.h>
#include <psapi.h>
#include <iterator>
#include <iostream>
#include <string>
#include <map>

std::string getfilename(DWORD pid) { 
    HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid);
    static int winver;
    char path[256]= {0};
    DWORD size = sizeof(path);

    if (winver==0) 
        winver = GetVersion() & 0xf; 

#if WINVER >= 0x600
    if (winver >= 6)    
        QueryFullProcessImageName(process, 0, path, &size);
    else
#endif
    if (!GetModuleFileNameEx(process, NULL, path, sizeof(path)))
        strcpy(path, "Unknown");
    return std::string(path);
}

typedef std::map<DWORD, std::string> win_map;

namespace std { 
    ostream &operator<<(ostream &os, win_map::value_type const &v) { 
        return os << v.first << ": " << v.second;
    }
}

BOOL CALLBACK show_info(HWND window, LPARAM lParam) {
    win_map &exes = *(win_map *)lParam;

    DWORD pid;
    GetWindowThreadProcessId(window, &pid);
    exes[pid] = getfilename(pid);
    return true;
}

int main() {
    win_map exes;
    EnumWindows(show_info, (LPARAM)&exes);
    std::copy(exes.begin(), exes.end(), std::ostream_iterator<win_map::value_type>(std::cout, "\n"));
    return 0;
}

快速测试的结果有点有趣。编译为32位代码,使用QueryFullProcessImageName的版本找到了33个具有顶级窗口的进程,并找到了其中31个可执行文件的名称。使用GetModuleFileNameEx的版本也找到了33个进程,但只找到了21个可执行文件的名称。但是,如果我将其编译为64位代码,那么 版本会找到33个可执行文件中的31个的文件名(并且相同的两个失败)。考虑到你看XP / x64的频率,这可能没那么重要,但我发现它很有趣。

在任何情况下,即使功能最弱的版本(32位/ GMFNE)也会找到文件的~2 / 3 rds 的名称。虽然那肯定不是你所希望的,但肯定比什么都好。

答案 1 :(得分:1)

必须可以检索正在运行的进程的文件路径,因为Sysinternals的Process Explorer可以执行此操作。当然,Process Explorer使用NtQueryInformationProcess,这不是受支持的功能。 (另一方面,由于您专门针对XP并且将在Vista及更高版本上使用QueryFullProcessImageName,因此担心API在未来版本的Windows中不可用可能不是一个问题。)

CodeProject has an article about how to use NtQueryInformationProcess