如何获取与Windows内置混音器一致的音频会话友好名称
音频会话友好名称获取方案
Windows 内置混音器的显示名称遵循固定的优先级逻辑,按照如下步骤实现即可拿到完全一致的效果:
整体逻辑优先级
- 优先取
IAudioSessionControl::GetDisplayName()返回值,部分进程会主动设置自定义会话名(如播放器正在播放的媒体名、游戏专属会话名),非空时直接使用 - 上述值为空时,读取会话对应进程exe的版本信息中的
ProductName字段,该字段即为你需要的Steam、Chrome Browser这类官方产品名 - 若版本信息读取失败,兜底使用exe文件名即可
具体实现步骤
1. 从音频会话获取进程PID
首先将 IAudioSessionControl 接口QueryInterface转为 IAudioSessionControl2,调用 GetProcessId 方法拿到对应进程的PID,系统音效会话的PID为0,直接显示系统声音即可。
2. 读取进程完整exe路径(解决非ASCII字符乱码问题)
统一使用宽字符版本API,开大缓冲区避免路径截断:
#include <windows.h> #include <string> std::wstring GetProcessExePath(DWORD pid) { std::wstring path; // 用PROCESS_QUERY_LIMITED_INFORMATION权限,兼容性远高于PROCESS_VM_READ HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); if (hProcess == NULL) return path; WCHAR buf[MAX_PATH * 2] = {0}; DWORD bufSize = _countof(buf); if (QueryFullProcessImageNameW(hProcess, 0, buf, &bufSize)) { path = buf; } CloseHandle(hProcess); return path; }
该实现可正常读取包含西里尔文、中文等非ASCII字符的路径,不会出现仅返回C:\Users\的问题。
3. 读取exe文件的ProductName版本信息
std::wstring GetExeProductName(const std::wstring& exePath) { std::wstring productName; DWORD dummyHandle = 0; DWORD versionInfoSize = GetFileVersionInfoSizeW(exePath.c_str(), &dummyHandle); if (versionInfoSize == 0) return productName; std::vector<BYTE> versionInfoBuf(versionInfoSize); if (!GetFileVersionInfoW(exePath.c_str(), dummyHandle, versionInfoSize, versionInfoBuf.data())) { return productName; } // 读取语言与代码页映射 struct LANGANDCODEPAGE { WORD wLanguage; WORD wCodePage; } *langList = nullptr; UINT langListSize = 0; if (!VerQueryValueW(versionInfoBuf.data(), L"\\VarFileInfo\\Translation", (LPVOID*)&langList, &langListSize)) { return productName; } // 优先匹配系统默认语言,找不到则取第一条 WORD defaultLang = GetUserDefaultLangID(); int targetLangIndex = 0; for (UINT i = 0; i < langListSize / sizeof(LANGANDCODEPAGE); i++) { if (langList[i].wLanguage == defaultLang) { targetLangIndex = i; break; } } // 构造查询路径读取ProductName WCHAR queryStr[256]; swprintf_s(queryStr, L"\\StringFileInfo\\%04x%04x\\ProductName", langList[targetLangIndex].wLanguage, langList[targetLangIndex].wCodePage); WCHAR* productNameBuf = nullptr; UINT nameBufSize = 0; if (VerQueryValueW(versionInfoBuf.data(), queryStr, (LPVOID*)&productNameBuf, &nameBufSize) && nameBufSize > 0) { productName = productNameBuf; } return productName; }
补充说明
- 遇到UWP应用进程读取不到exe路径的情况,可额外调用UWP的Package管理接口读取应用显示名称,普通桌面应用上述流程完全覆盖
- 所有API均使用W后缀宽字符版本,禁止使用ANSI版本,避免非英文环境下乱码
内容的提问来源于stack exchange,提问作者Light Steel
相关产品推荐
相关产品推荐

