挂钩DLL中播放资源音频导致游戏无法启动的问题排查
挂钩DLL播放内置音频资源导致游戏无法启动的故障排查
问题场景
我需要在挂钩的DLL中播放其内置资源里的音频文件,使用的代码为:
PlaySoundA(MAKEINTRESOURCEA(IDR_WAVE1), hModule, SND_RESOURCE);
我的DLL代码
HINSTANCE m_hinst_dll = nullptr; extern "C" UINT_PTR mProcs[17]{ 0 }; LPCSTR import_names[] = { "GetFileVersionInfoA", "GetFileVersionInfoByHandle", "GetFileVersionInfoExA", "GetFileVersionInfoExW", "GetFileVersionInfoSizeA", "GetFileVersionInfoSizeExA", "GetFileVersionInfoSizeExW", "GetFileVersionInfoSizeW", "GetFileVersionInfoW", "VerFindFileA", "VerFindFileW", "VerInstallFileA", "VerInstallFileW", "VerLanguageNameA", "VerLanguageNameW", "VerQueryValueA", "VerQueryValueW" }; void setupWrappers() { CHAR sys_dir[MAX_PATH]; GetSystemDirectoryA(sys_dir, MAX_PATH); char buffer[MAX_PATH]; sprintf_s(buffer, "%s\\version.dll", sys_dir); m_hinst_dll = LoadLibraryA(buffer); for (int i = 0; i < 17; i++) { mProcs[i] = reinterpret_cast<UINT_PTR>(GetProcAddress(m_hinst_dll, import_names[i])); } } extern "C" void GetFileVersionInfoA_wrapper(); extern "C" void GetFileVersionInfoByHandle_wrapper(); extern "C" void GetFileVersionInfoExA_wrapper(); extern "C" void GetFileVersionInfoExW_wrapper(); extern "C" void GetFileVersionInfoSizeA_wrapper(); extern "C" void GetFileVersionInfoSizeExA_wrapper(); extern "C" void GetFileVersionInfoSizeExW_wrapper(); extern "C" void GetFileVersionInfoSizeW_wrapper(); extern "C" void GetFileVersionInfoW_wrapper(); extern "C" void VerFindFileA_wrapper(); extern "C" void VerFindFileW_wrapper(); extern "C" void VerInstallFileA_wrapper(); extern "C" void VerInstallFileW_wrapper(); extern "C" void VerLanguageNameA_wrapper(); extern "C" void VerLanguageNameW_wrapper(); extern "C" void VerQueryValueA_wrapper(); extern "C" void VerQueryValueW_wrapper(); BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: setupWrappers(); PlaySoundA(MAKEINTRESOURCEA(IDR_WAVE1), hModule, SND_RESOURCE); break; case DLL_PROCESS_DETACH: break; } return TRUE; }
已做排查
- 移除
PlaySoundA调用后,DLL可正常工作 - 用空桌面项目测试该
PlaySoundA代码,能正常播放音频 - 在DLL中使用以下代码播放外部音频文件也正常:
sndPlaySoundA("mnu_back.wav", SND_FILENAME | SND_ASYNC);
可能的故障原因
- 资源ID不匹配或未正确嵌入:检查DLL资源脚本中
IDR_WAVE1是否对应正确的WAV资源,且编译时资源已成功嵌入DLL。游戏进程加载DLL时,若找不到指定资源,PlaySoundA可能触发未处理错误导致进程崩溃。 - DLLMain阶段调用风险:
DLL_PROCESS_ATTACH阶段进程初始化尚未完成,调用PlaySoundA这类依赖系统音频服务的API可能引发死锁或初始化冲突——系统音频服务可能还未完成加载,此时调用会导致进程阻塞或崩溃。 - 资源加载上下文异常:虽然
DllMain的hModule通常指向当前DLL模块句柄,但某些挂钩场景(如注入时机过早)下,模块的资源表可能未完全初始化,导致无法读取资源。 - 缺少异步播放标志:当前调用未加
SND_ASYNC,PlaySoundA会同步播放音频,在DLLMain阶段同步操作可能阻塞进程初始化流程,导致游戏启动超时或崩溃。可尝试修改代码:PlaySoundA(MAKEINTRESOURCEA(IDR_WAVE1), hModule, SND_RESOURCE | SND_ASYNC); - 游戏进程环境限制:游戏进程可能运行在沙箱、低权限等受限环境中,不允许从DLL资源加载音频,而外部文件播放不受限制;或者游戏进程禁用了部分系统音频API的资源加载路径。
内容的提问来源于stack exchange,提问作者marcoluca987
相关产品推荐
相关产品推荐

