MB#SJCS 2026-05-01 19:38 采纳率: 50%
浏览 7

hook窗口化单机游戏

目前在c++做一个剑侠情缘二白金版这个20年前的老游戏的一个游戏启动器。这个老游戏在启动后会独占全屏。想要实现就是去掉这个占全屏,然后将其窗口化设置窗口。被指定的分辨率大小,并且游戏内画布也可以设置我想要的。大小。
有没有做过这一方面的给点思路。我没有图形这一块的经验。
这个游戏好像是c++和dx框架写的。

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2026-05-01 19:39
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    要实现将《剑侠情缘二白金版》这样的老游戏从全屏模式切换为窗口化模式,并能自定义分辨率和画布大小,你需要掌握一些图形编程和Windows API的基础知识。虽然你没有图形方面的经验,但通过以下步骤可以逐步实现目标。


    一、核心思路

    1. 确定游戏的图形框架

    根据你的描述,游戏使用的是 C++ + DirectX(DX),因此我们需要关注 DirectX 的显示模式设置

    • DirectX 9/10/11 是常见的版本。
    • 游戏可能在启动时直接调用 SetDisplayMode() 或类似函数来设置全屏。

    2. 针对性修改游戏逻辑

    你需要修改游戏的 显示模式初始化代码,使其支持窗口化自定义分辨率


    二、具体解决方案(详细步骤)

    1. 获取游戏源码或反编译分析

    • 如果你是开发者,有游戏的源码,可以直接修改。
    • 如果没有源码,可以通过 逆向工程工具(如 IDA Pro、Ghidra)分析游戏的可执行文件,找到控制显示模式的函数。

    重点: 找到负责初始化 DirectDraw 或 Direct3D 的函数,通常会调用 SetDisplayModeCreateDevice


    2. 修改显示模式设置为窗口化

    方法一:修改游戏源码(推荐)

    如果你有源码,可以找到如下类似的代码段:

    // 假设是 DirectDraw 的代码
    DDSURFACEDESC ddsd;
    ZeroMemory(&ddsd, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
    
    // 设置全屏
    ddsd.dwWidth = 800;
    ddsd.dwHeight = 600;
    ddsd.ddpfPixelFormat = ...;
    
    // 创建全屏显示模式
    lpDD->SetDisplayMode(800, 600, 32, 0, 0);
    

    将其改为窗口化模式:

    // 设置窗口化
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    
    // 设置窗口尺寸(例如 800x600)
    ddsd.dwWidth = 800;
    ddsd.dwHeight = 600;
    
    // 不再调用 SetDisplayMode,而是创建窗口
    lpDD->CreateSurface(&ddsd, &lpPrimarySurface, NULL);
    

    注意: 有些游戏会在启动时自动检测系统分辨率,你可以通过修改这些值来强制设定窗口大小。


    方法二:Hook 显示模式函数(无源码情况下)

    如果无法修改源码,可以使用 API Hook 技术 来拦截 SetDisplayModeCreateDevice 函数,强制改写参数。

    使用工具:
    • Detours(微软官方的 Hook 框架)
    • EasyHook(跨平台、简单易用)
    示例代码(使用 EasyHook):
    #include <windows.h>
    #include "easyhook.h"
    
    typedef HRESULT (WINAPI *SetDisplayModeFunc)(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwReserved1, DWORD dwReserved2);
    
    SetDisplayModeFunc OriginalSetDisplayMode = NULL;
    
    HRESULT WINAPI MySetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwReserved1, DWORD dwReserved2) {
        // 强制设置为窗口模式(这里只是示例,实际需结合游戏逻辑)
        return OriginalSetDisplayMode(800, 600, 32, 0, 0); // 800x600 分辨率
    }
    
    void HookFunction() {
        HMODULE hModule = GetModuleHandle("ddraw.dll");
        if (hModule) {
            OriginalSetDisplayMode = (SetDisplayModeFunc)GetProcAddress(hModule, "SetDisplayMode");
            if (OriginalSetDisplayMode) {
                EH_SetHook((LPVOID*)OriginalSetDisplayMode, MySetDisplayMode, NULL);
            }
        }
    }
    

    说明: 此方式需要你对游戏运行环境有一定的了解,并且需要处理多个可能的显示接口(如 D3D、DDraw、OpenGL 等)。


    3. 自定义画布大小

    如果你希望游戏内部画布(即渲染区域)也能够自定义,可以:

    • 在游戏初始化阶段,设置渲染目标为一个自定义大小的缓冲区。
    • 使用 SetViewportSetRenderTarget 调整绘制区域。

    例如,在 Direct3D 中:

    D3DVIEWPORT9 viewport;
    viewport.X = 0;
    viewport.Y = 0;
    viewport.Width = 800;   // 自定义宽度
    viewport.Height = 600;  // 自定义高度
    viewport.MinZ = 0.0f;
    viewport.MaxZ = 1.0f;
    
    device->SetViewport(&viewport);
    

    4. 支持多分辨率和缩放(可选)

    为了使游戏在不同屏幕下也能正常显示,可以添加以下功能:

    • 缩放逻辑:将游戏画面按比例缩放至窗口大小。
    • 动态调整:允许用户在启动器中选择分辨率。

    三、开发建议

    | 项目 | 说明 | |------|------| | 开发语言 | C++(推荐) | | 图形库 | DirectX(需熟悉其 API) | | 工具 | IDA Pro / Ghidra(逆向)、EasyHook / Detours(Hook) | | 学习资源 | Microsoft DirectX 官方文档、Game Programming Patterns |


    四、总结

    要实现将《剑侠情缘二白金版》窗口化并自定义分辨率,你需要:

    1. 分析游戏的图形框架(如 DirectX);
    2. 修改显示模式初始化逻辑(源码或 Hook);
    3. 设置窗口大小和画布尺寸
    4. 考虑缩放与兼容性问题

    如果你愿意,我可以提供一个完整的示例项目模板,包括如何 Hook SetDisplayMode 并强制设置窗口模式。请告诉我你是否需要这个。

    评论

报告相同问题?

问题事件

  • 创建了问题 5月1日