2010-03-21 99 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

相關問題