// Copyright 2021 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #ifndef MUMBLE_POSITIONAL_AUDIO_WIN32_H_ #define MUMBLE_POSITIONAL_AUDIO_WIN32_H_ #ifndef MUMBLE_POSITIONAL_AUDIO_MAIN_H_ # error "Include mumble_positional_audio_main.h instead of mumble_positional_audio_win32.h" #endif #include #include // Define "NOMINMAX" only if it isn't already. // MinGW defines it by default, which results in a redefinition warning. #ifndef NOMINMAX # define NOMINMAX #endif #include #include #include #include #include #include static HANDLE hProcess; static inline procid_t getProcess(const wchar_t *exename) { PROCESSENTRY32 pe; procid_t pid = 0; pe.dwSize = sizeof(pe); HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap != INVALID_HANDLE_VALUE) { BOOL ok = Process32First(hSnap, &pe); while (ok) { if (wcscmp(pe.szExeFile, exename) == 0) { pid = pe.th32ProcessID; break; } ok = Process32Next(hSnap, &pe); } CloseHandle(hSnap); } return pid; } static inline procptr_t getModuleAddr(const procid_t &pid, const wchar_t *modname) { MODULEENTRY32 me; procptr_t ret = 0; me.dwSize = sizeof(me); HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid); if (hSnap != INVALID_HANDLE_VALUE) { BOOL ok = Module32First(hSnap, &me); while (ok) { if (wcscmp(me.szModule, modname) == 0) { uintptr_t addr = reinterpret_cast< uintptr_t >(me.modBaseAddr); ret = static_cast< procptr_t >(addr); break; } ok = Module32Next(hSnap, &me); } CloseHandle(hSnap); } return ret; } static inline bool peekProc(const procptr_t &addr, void *dest, const size_t &len) { SIZE_T r; const BOOL ok = ReadProcessMemory(hProcess, reinterpret_cast< void * >(addr), dest, len, &r); return (ok && (r == len)); } static void generic_unlock() { if (hProcess) { CloseHandle(hProcess); hProcess = nullptr; } pPid = 0; pModule = 0; } static bool initialize(const std::multimap< std::wstring, unsigned long long int > &pids, const wchar_t *procname, const wchar_t *modname = nullptr) { hProcess = nullptr; pModule = 0; if (!pids.empty()) { auto iter = pids.find(std::wstring(procname)); if (iter != pids.end()) { pPid = static_cast< procid_t >(iter->second); } else { pPid = 0; } } else { pPid = getProcess(procname); } if (!pPid) { return false; } hProcess = OpenProcess(PROCESS_VM_READ, false, pPid); if (!hProcess) { pPid = 0; return false; } pModule = getModuleAddr(procname); if (!pModule) { generic_unlock(); return false; } const int8_t result = isProcess64Bit(pModule); if (result == -1) { generic_unlock(); return false; } if (modname) { pModule = getModuleAddr(modname); if (!pModule) { generic_unlock(); return false; } } // We compare to 1 to prevent the following warning: // C4800: 'BOOL': forcing value to bool 'true' or 'false' (performance warning) is64Bit = (result == 1); return true; } #endif