解决文件路径的最佳方法是什么?

时间:2010-03-21 23:17:58

标签: c++ windows path

我有一系列看起来像这样的文件路径:

  • C:\ Windows \ System32 \ svchost.exe -k LocalSystemNetworkRestricted
  • C:\ Windows \ System32下\ svchost的
  • C:\ Program Files(x86)\ Common Files \ Steam \ SteamService.exe / RunAsService
  • “C:\ Program Files(x86)\ Common Files \ Steam \ SteamService.exe”/ RunAsService

我需要找到这些路径的实际位置。所以,上面分别是:

  • C:\ Windows \ System32下\ svchost.exe的
  • C:\ Windows \ System32下\ svchost.exe的
  • C:\ Program Files(x86)\ Common Files \ Steam \ SteamService.exe
  • C:\ Program Files(x86)\ Common Files \ Steam \ 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;
}

}

2 个答案:

答案 0 :(得分:3)

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

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

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

  1. C:\程序
  2. C:\ Program Files
  3. C:\ Program Files(x86)\ Common
  4. C:\ Program Files(x86)\ Common Files \ Stream \ StreamService.exe
  5. C:\ Program Files(x86)\ Common Files \ Steam \ SteamService.exe / RunAsService
  6. 每一步,它都会检查是否存在具有该名称的文件。如果是这样,那就是它选择的那个。它还尝试在名称后附加“.exe”。因此,在第一步中,它会检查是否有一个名为“C:\ Program.exe”的文件,如果有,那就是第一步。如果没有,它将移至第二步并尝试“C:\ Program Files.exe”。如果不存在,则移动到下一个,依此类推。

    过去在此算法的工作原理方面存在问题,例如see here

答案 1 :(得分:-1)

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