使用ReadProcessMemory读取Wesnoth游戏内存失败问题求助
问题排查与解决方法
1. 先检查所有API调用的返回状态
你的代码没有做任何错误检查,这是核心问题——FindWindow可能没找到窗口、OpenProcess可能权限不足失败,最终导致ReadProcessMemory无法正常工作。先修改代码加上错误判断:
#include <windows.h> #include <iostream> int main(int argc, char** argv) { HWND wesnoth_window = FindWindowW(nullptr, L"The Battle for Wesnoth - 1.14.9"); if (!wesnoth_window) { std::cout << "找不到游戏窗口,错误码:" << GetLastError() << std::endl; return 1; } DWORD process_id = 0; GetWindowThreadProcessId(wesnoth_window, &process_id); if (process_id == 0) { std::cout << "获取进程ID失败,错误码:" << GetLastError() << std::endl; return 1; } // 只申请需要的读权限,避免用PROCESS_ALL_ACCESS(权限过高易失败) HANDLE wesnoth_process = OpenProcess(PROCESS_VM_READ, FALSE, process_id); if (!wesnoth_process) { std::cout << "打开进程失败,错误码:" << GetLastError() << std::endl; return 1; } DWORD gold_value = 0; SIZE_T bytes_read = 0; // 注意用SIZE_T类型,匹配ReadProcessMemory的参数要求 BOOL read_ok = ReadProcessMemory(wesnoth_process, (LPCVOID)0x017EED8, &gold_value, sizeof(gold_value), &bytes_read); if (!read_ok) { std::cout << "读取内存失败,错误码:" << GetLastError() << std::endl; } else { std::cout << "读取成功:字节数=" << bytes_read << ",金币值=" << gold_value << std::endl; } CloseHandle(wesnoth_process); return 0; }
2. 排查32位/64位兼容性问题
如果游戏是64位程序,但你的调试程序编译为32位:
- 32位程序无法正确访问64位进程的地址空间,必须把自己的程序改成64位编译。
- 地址类型改用
uintptr_t或DWORD_PTR,避免32位类型截断64位地址。
3. 确认内存地址是否为固定绝对地址
CheatEngine里显示的0x017EED8大概率不是固定绝对地址,而是游戏主模块(比如wesnoth.exe)的偏移量。每次重启游戏,模块加载基址会变化,导致绝对地址失效。需要先获取模块基址再计算真实地址:
// 获取进程主模块基址的工具函数 uintptr_t GetModuleBaseAddress(DWORD processId, const wchar_t* moduleName) { uintptr_t baseAddr = 0; HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId); if (hSnapshot != INVALID_HANDLE_VALUE) { MODULEENTRY32W moduleEntry; moduleEntry.dwSize = sizeof(MODULEENTRY32W); if (Module32FirstW(hSnapshot, &moduleEntry)) { do { if (_wcsicmp(moduleEntry.szModule, moduleName) == 0) { baseAddr = (uintptr_t)moduleEntry.modBaseAddr; break; } } while (Module32NextW(hSnapshot, &moduleEntry)); } CloseHandle(hSnapshot); } return baseAddr; } // 在main函数中调用 uintptr_t moduleBase = GetModuleBaseAddress(process_id, L"wesnoth.exe"); if (moduleBase == 0) { std::cout << "获取模块基址失败" << std::endl; CloseHandle(wesnoth_process); return 1; } // 假设CheatEngine里的数值是相对于模块基址的偏移 uintptr_t goldAddr = moduleBase + 0x017EED8; // 用goldAddr作为ReadProcessMemory的地址参数
4. 权限问题处理
- 确保你的程序以管理员权限运行,否则可能无法打开游戏进程。
- 不要用
PROCESS_ALL_ACCESS权限,这个权限需要特殊系统权限,普通用户默认没有,用PROCESS_VM_READ足够完成内存读取。
常见错误码说明
- 错误码5:权限不足,需管理员权限运行程序,或降低OpenProcess请求的权限。
- 错误码299:32位程序访问64位进程内存,需切换到64位编译。
- 错误码12B:地址无效,说明你使用的地址不是游戏进程的有效内存地址。
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

