2010-03-21 84 views
2

我有一系列的文件路径是这个样子的:解决文件路径的最佳方法是什么?

  • C:\ WINDOWS \ SYSTEM32 \ svchost.exe的-k LocalSystemNetworkRestricted
  • C:\ WINDOWS \ SYSTEM32 \ svchost的
  • Ç :\ Program Files文件(x86)的\ Common Files文件\蒸汽\ SteamService.exe/RunAsService
  • “C:\ Program Files文件(x86)的\ Common Files文件\蒸汽\ SteamService.exe”/ RunAsService

和我需要找到这些路径'ac地理位置。因此,分别,上面是:

  • C:\ WINDOWS \ SYSTEM32 \ svchost.exe的
  • C:\ WINDOWS \ SYSTEM32 \ svchost.exe的
  • C:\ Program Files文件(x86)的\共同文件\蒸汽\ SteamService.exe
  • C:\ Program Files文件(x86)的\ Common Files文件\蒸汽\ SteamService.exe

什么是去这样做的最佳方式? Windows有一个API函数来完成它吗?我基本上正在试图找出如果我将它传递给那个路径,CreateProcess将调用哪个可执行文件。

谢谢!

Billy3

编辑:这是我定居在现在的代码:

#include <algorithm> 
#include <vector> 
#include <string> 
#include <boost/algorithm/string.hpp> 
#include <Windows.h> 

namespace Path { 

bool Exists(const std::wstring& path) 
{ 
    DWORD result = GetFileAttributesW(path.c_str()); 
    return result != INVALID_FILE_ATTRIBUTES; 
} 

#define PATH_PREFIX_RESOLVE(path, prefix, environment) \ 
if (boost::algorithm::istarts_with(path, prefix)) { \ 
    ExpandEnvironmentStringsW(environment, buffer, MAX_PATH); \ 
    path.replace(0, (sizeof(prefix)/sizeof(wchar_t)) - 1, buffer); \ 
    if (Exists(path)) return path; \ 
} 

std::wstring Resolve(std::wstring path) 
{ 
    using namespace boost::algorithm; 
    wchar_t buffer[MAX_PATH]; 
    trim(path); 
    if (path.empty() || Exists(path)) return path; 

    //Start by trying to see if we have a quoted path 
    if (path[0] == L'"') { 
     return std::wstring(path.begin() + 1, std::find(path.begin() + 1, path.end(), L'"')); 
    } 

    //Check for those nasty cases where the beginning of the path has no root 
    PATH_PREFIX_RESOLVE(path, L"\\", L""); 
    PATH_PREFIX_RESOLVE(path, L"?\?\\", L""); 
    PATH_PREFIX_RESOLVE(path, L"\\?\\", L""); 
    PATH_PREFIX_RESOLVE(path, L"globalroot\\", L""); 
    PATH_PREFIX_RESOLVE(path, L"system32\\", L"%systemroot%\\System32\\"); 
    PATH_PREFIX_RESOLVE(path, L"systemroot\\", L"%systemroot%\\"); 

    static std::vector<std::wstring> pathExts; 
    if (pathExts.empty()) { 
     #define MAX_ENVVAR 32767 
     wchar_t pathext[MAX_ENVVAR]; 
     DWORD length = GetEnvironmentVariableW(L"PATHEXT", pathext, MAX_ENVVAR); 
     if (!length) WindowsApiException::ThrowFromLastError(); 
     split(pathExts, pathext, std::bind2nd(std::equal_to<wchar_t>(), L';')); 
     pathExts.insert(pathExts.begin(), std::wstring()); 
    } 
    std::wstring::iterator currentSpace = path.begin(); 
    do { 
     currentSpace = std::find(currentSpace, path.end(), L' '); 
     std::wstring currentPath(path.begin(), currentSpace); 
     std::wstring::size_type currentPathLength = currentPath.size(); 
     typedef std::vector<std::wstring>::const_iterator ExtIteratorType; 
     for(ExtIteratorType it = pathExts.begin(); it != pathExts.end(); it++) { 
      currentPath.replace(currentPathLength, currentPath.size() - currentPathLength, *it); 
      if (Exists(currentPath)) return currentPath; 
     } 
     if (currentSpace != path.end()) 
      currentSpace++; 
    } while (currentSpace != path.end()); 

    return path; 
} 

} 
+0

那些不是路径,而是那些恰好以路径开头的命令行。 – bmargulies 2010-03-21 23:19:59

+0

@bmargulies:我想这是真的 - 我想我需要上述命令行的路径部分。 – 2010-03-21 23:21:18

+0

#3是个大问题。你如何确定你完成了路径(并且不要忘记一半的时间路径是用正斜杠指定的)并且用斜杠分隔的参数?至少用引号是可行的...... – MPelletier 2010-03-21 23:26:03

回答

3

4号应该是比较容易的。如果路径以“字符开始,只读直到下一个”,那就是路径。与其他人相比,它稍微有点棘手,但Windows的做法是简单地将命令行分成几部分,然后一次尝试一个,所以看着#3,它将它分解为如下这样的数组:

["C:\Program", "Files", "(x86)\Common", "Files\Steam\SteamService.exe", "/RunAsService"] 

然后,它只是从最左边的元素开始和查找文件:

  1. C:\ PROGRAM
  2. C:\ Program Files文件
  3. C:\ Program Files文件(x86)的\通用
  4. C:\ Program File S(86)\共同文件\流\ StreamService.exe
  5. C:\程序文件(x86)\共同文件\蒸汽\ SteamService.exe/RunAsService

每个步骤中,它会检查是否与文件该名称存在。如果是这样,那就是它选择的那个。它还会尝试将“.exe”附加到名称上。因此,在第一步中,它会检查是否存在名为“C:\ Program.exe”的文件,如果是,则是第一个。如果不是,则转到第二步并尝试“C:\ Program Files.exe”。如果不存在,则移至下一个,依此类推。

过去一直存在这个算法如何工作的问题,例如,see here

+1

这不可能是完全正确的 - 我相信CreateProcess解析PATHEXT环境变量。如果我创建一个运行键('HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Run \\ Runme =“C:\ Program”')并将可执行文件放在C:\ program.com中,它将在启动时执行。 – 2010-03-21 23:55:46

+0

是的,我相信你是对的。它会尝试C:\ Program.exe,C:\ Programme,C:\ Program.bat等等 - 将尝试所有PATHEXT的扩展名。 – 2010-03-22 00:11:54

+0

看起来像我自己写的grr ...希望我不要它***! :P – 2010-03-22 00:52:35

-1

请参阅shlwapi.h中的Shell Path Handling Functions。 您的示例应使用::PathRemoveArgs(sPath)后跟::PathMatchSpec(sPath, _T("*.exe"))

+1

这不适用于问题中的案例3。 – 2010-03-22 00:38:35

+0

对,他也应该打电话:: PathUnquoteSpaces():-) – 2010-03-22 01:13:29

+1

'PathUnquoteSpaces'也不会帮助案例3 ... – 2010-03-22 01:19:04

相关问题