#include <stdio.h> #include <locale.h> #include <windows.h> #include <tlhelp32.h> #include <tchar.h> #include <Psapi.h> #pragma comment (lib,"Psapi.lib") BOOL DosPathToNtPath(LPTSTR pszDosPath, LPTSTR pszNtPath) { TCHAR szDriveStr[500]; TCHAR szDrive[3]; TCHAR szDevName[100]; INT iDevName; INT i; //檢查參數 if (!pszDosPath || !pszNtPath) return FALSE; //獲取本地磁盤全部盤符,以'\0'分隔,因此下面+4 if (GetLogicalDriveStrings(sizeof(szDriveStr), szDriveStr)) { for (i = 0; szDriveStr[i]; i += 4) { if (!lstrcmpi(&(szDriveStr[i]), _T("A:\\")) || !lstrcmpi(&(szDriveStr[i]), _T("B:\\"))) continue; //從C盤開始 //盤符 szDrive[0] = szDriveStr[i]; szDrive[1] = szDriveStr[i + 1]; szDrive[2] = '\0'; if (!QueryDosDevice(szDrive, szDevName, 100))//查詢 Dos 設備名(盤符由NT查詢DOS) return FALSE; iDevName = lstrlen(szDevName); if (_tcsnicmp(pszDosPath, szDevName, iDevName) == 0)//是否爲此盤 { lstrcpy(pszNtPath, szDrive);//複製驅動器 lstrcat(pszNtPath, pszDosPath + iDevName);//複製路徑 return TRUE; } } } lstrcpy(pszNtPath, pszDosPath); return FALSE; } //獲取進程完整路徑 BOOL GetProcessFullPath(DWORD dwPID) { TCHAR szImagePath[MAX_PATH]; TCHAR pszFullPath[MAX_PATH]; HANDLE hProcess; if (!pszFullPath) return FALSE; pszFullPath[0] = '\0'; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, dwPID); //由線程ID得到線程信息 if (!hProcess) return FALSE; if (!GetProcessImageFileName(hProcess, szImagePath, MAX_PATH)) //獲得線程完整DOS路徑 { CloseHandle(hProcess); return FALSE; } if (!DosPathToNtPath(szImagePath, pszFullPath)) //DOS路徑轉NT路徑 { CloseHandle(hProcess); return FALSE; } CloseHandle(hProcess); _tprintf(_T("%5d %s \r\n"), dwPID, pszFullPath); return TRUE; } int main(int argc, char* argv[]) { setlocale(LC_ALL, "chs"); //不設置解析中文字符時可能會出問題 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); //獲得系統全部線程快照 if (INVALID_HANDLE_VALUE == hSnapshot) { return NULL; } PROCESSENTRY32 pe = { 0 }; pe.dwSize = sizeof(PROCESSENTRY32); BOOL fOk; for (fOk = Process32First(hSnapshot, &pe); fOk; fOk = Process32Next(hSnapshot, &pe)) //遍歷 { GetProcessFullPath(pe.th32ProcessID); } return 0; }
爲何要使用setlocal呢(非本例)ios
在 VC2005 中 std::fstream 的打開文件的函數實現裏,傳入的 char const* 文件名做爲多字節首先被mbstowcs 轉換成寬字節後,再轉發給 Unicode 版本的 API 進行實際的打開文件操做windows
_MRTIMP2_NCEEPURE FILE *__CLRCALL_PURE_OR_CDECL _Fiopen(const char *filename, ios_base::openmode mode, int prot) { // open wide-named file with byte name wchar_twc_name[FILENAME_MAX]; if (mbstowcs_s(NULL, wc_name, FILENAME_MAX, filename,FILENAME_MAX - 1) != 0) return (0); return _Fiopen(wc_name, mode, prot);
}
問題的關鍵在於,對於 mbstowcs 函數來講,它須要知道多字節的編碼類型才能正確的將其轉換成寬字節的 unicode,很惋惜這個編碼類型並無體如今函數的參數列表裏,而是隱含依賴全局的 locale 。更加不幸的是,全局 locale 默認沒有使用系統當前語言,而是設置爲沒什麼用處的 "C" locale 。因而 GBK 編碼的文件名在 "C" locale 下轉換錯誤api
在本機上vs2017運行本例時出現了沒法打印中文字符串的現象ide