Какой лучший способ разрешить путь к файлу? - PullRequest
2 голосов
/ 22 марта 2010

У меня есть ряд файловых путей, которые выглядят примерно так:

  • C: \ Windows \ System32 \ svchost.exe -k LocalSystemNetworkRestricted
  • C: \ Windows \ System32 \ Svchost
  • C: \ Program Files (x86) \ Общие файлы \ 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 ]

3 голосов
/ 22 марта 2010

Номер 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) \ Common
  4. C: \ Program Files (x86) \ Общие файлы \ Stream \ StreamService.exe
  5. C: \ Program Files (x86) \ Общие файлы \ Steam \ SteamService.exe / RunAsService

Каждый шаг проверяет, существует ли файл с таким именем. Если так, то это тот, который он выбирает. Он также пытается добавить «.exe» к имени. Таким образом, на первом этапе он проверяет, существует ли файл с именем «C: \ Program.exe», и если это так, то это первый. Если нет, он переходит ко второму шагу и пытается «C: \ Program Files.exe». Если этого не существует, оно переходит к следующему и т. Д.

В прошлом были проблемы с тем, как работает этот алгоритм, например, см. Здесь .

0 голосов
/ 22 марта 2010

См. Функции обработки пути оболочки в shlwapi.h. Ваши примеры должны сделать это с ::PathRemoveArgs(sPath), за которым следует ::PathMatchSpec(sPath, _T("*.exe")).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...