Windows获取进程完整路径
#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呢(非本例)
在 VC2005 中 std::fstream 的打开文件的函数实现里,传入的 char const* 文件名作为多字节首先被mbstowcs 转换成宽字节后,再转发给 Unicode 版本的 API 进行实际的打开文件操作
_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 下转换错误
在本机上vs2017运行本例时出现了无法打印中文字符串的现象
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix