2010-03-21 3 views
2

У меня есть ряд путей файлов, которые выглядят примерно так:Каков наилучший способ разрешить путь к файлу?

  • 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

Какой самый лучший способ пойти об этом? У окон есть функция API для ее выполнения? Я, по сути, пытаюсь выяснить, что вызовет исполняемый CreateProcess, если я передам ему этот путь.

Спасибо!

Billy3

EDIT: Это код, который я остановился на сейчас:

#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

+0

@bmargulies: Я полагаю, это правда - я думаю, мне нужна часть пути из указанных команд. –

+0

# 3 - большая проблема. как вы определяете, что вы закончили с путями (и не забывайте, что половина пути времени указана с помощью косой черты) и в параметры с разделителями слэш? По крайней мере, с кавычками это можно сделать ... – MPelletier

ответ

3

Номер 4 должен быть относительно легко. Если путь начинается с символа «a, просто читайте до следующего», и это путь. С другими, это немного более сложно, но способ 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 (x86) \ Common Files \ Поток \ StreamService.exe
  5. C: \ Program Files (x86) \ Common Files \ Steam \ 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, он запускается при запуске. –

+0

Да, я считаю, что вы правы. Он попробует C: \ Program.exe, C: \ Program.com, C: \ Program.bat и т. Д. - будут предприняты все расширения из PATHEXT. –

+0

Похоже, я должен написать это сам grr ... надеюсь, что я этого не сделаю! : P –

-1

См. Shell Path Handling Functions в shlwapi.h. Ваши примеры должны быть сделаны с ::PathRemoveArgs(sPath), а затем ::PathMatchSpec(sPath, _T("*.exe")).

+1

Это не будет работать с вопросом 3 в вопросе. –

+0

Правильно он должен также вызвать :: PathUnquoteSpaces() :-) –

+1

'PathUnquoteSpaces' также не поможет в случае 3 ... –

Смежные вопросы