You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++内嵌汇编图形模式代码适配与技术咨询(Win11/VS2022)

DOS图形模式代码在现代Windows环境的问题解答

1. 如何让该代码正常运行?

你提供的代码是DOS实模式下的16位VGA图形代码,现代Windows 11运行在保护模式,完全不支持直接调用BIOS中断(int 0x10)和直接访问物理显存地址(0xA0000000),直接在VS2022里编译运行必然崩溃。可行方案有两个:

  • 用DOSBox模拟器:把代码编译成16位DOS可执行程序(可使用Turbo C++ 3.0、OpenWatcom等老式编译器),在DOSBox中模拟DOS实环境即可正常执行。
  • 重构代码改用现代Windows图形API(对应第三个问题的方案),放弃老式BIOS/显存直接操作逻辑。

2. 该代码在处理器指令层面的执行逻辑是什么?

这段代码完全依赖DOS实模式的硬件特性,指令逻辑如下:

  • SetGr函数:
    1. asm mov AX, 0x13:将寄存器AX设为0x13,其中AH=0(BIOS显示服务的"设置显示模式"功能号),AL=0x13(对应VGA 320x200分辨率、256色的图形模式)。
    2. asm int 0x10:触发BIOS视频服务中断,调用BIOS内置驱动切换到指定图形模式。
  • CloseGr函数:
    1. asm mov AX, 3:AX=0x0003,AH=0,AL=3(对应标准80x25文本模式)。
    2. asm int 0x10:再次调用BIOS视频中断,切换回文本模式。
  • PutPixel函数:
    实模式下VGA 256色图形模式的显存物理起始地址是0xA0000(段地址0xA000+偏移0),代码里的0xA0000000是错误的(混淆了保护模式线性地址)。正确计算应为0xA0000 + y*320 + x,通过指针直接给显存地址写入颜色值,就能在屏幕对应坐标画出像素——因为实模式下程序可直接访问物理内存。

3. 不依赖第三方库的简便逐像素绘制方法

在现代Windows环境下,用Win32 API就能实现无第三方库的逐像素绘制,推荐两种方式:

方式1:用SetPixel直接绘制(适合入门学习)

这是最直观的方式,通过窗口的设备上下文(HDC)调用系统API画像素,核心示例代码如下:

#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    const wchar_t CLASS_NAME[] = L"GraphicsWindowClass";

    WNDCLASS wc = {};
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Pixel Drawing", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, nullptr, nullptr, hInstance, nullptr);
    if (hwnd == nullptr) return 0;

    ShowWindow(hwnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);
            // 在(100,100)绘制红色像素
            SetPixel(hdc, 100, 100, RGB(255,0,0));
            // 循环绘制一条绿色直线
            for(int x=0;x<200;x++) SetPixel(hdc, x, 150, RGB(0,255,0));
            EndPaint(hwnd, &ps);
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

方式2:用DIB位图(效率更高,适合大量像素绘制)

如果需要绘制大量像素,SetPixel效率较低,可以创建DIB位图,直接操作内存中的像素数据再绘制到窗口:

// 在WM_PAINT消息处理中替换为以下代码
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);

BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 320;
bmi.bmiHeader.biHeight = -200; // 负数值表示从上到下的像素顺序
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 8; // 256色,和原VGA模式一致
bmi.bmiHeader.biCompression = BI_RGB;

unsigned char* pixels;
HBITMAP hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&pixels, nullptr, 0);
// 填充整个屏幕为蓝色(0x1F是VGA蓝色调色板索引,对应RGB(0,0,255))
memset(pixels, 0x1F, 320*200);
// 将DIB绘制到窗口
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, hbmp);
BitBlt(hdc, 0, 0, 320, 200, memdc, 0, 0, SRCCOPY);

SelectObject(memdc, oldbmp);
DeleteDC(memdc);
DeleteObject(hbmp);
EndPaint(hwnd, &ps);

内容的提问来源于stack exchange,提问作者boozda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 05:23:22