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

GdipDrawLine调用无报错但无显示的NASM汇编问题排查

NASM汇编实现GdipDrawLine无显示问题

我用NASM汇编语言尝试实现GdipDrawLine功能,通过Olly调试器单步执行时,所有指令的EAX寄存器均返回0(表示执行成功),但屏幕始终无内容显示。GdiplusStartup在Winmain的CreateWindowEx后立即调用,其余GDI+函数均响应WM_PAINT消息调用。系统配置为AMD Ryzen 5 5600G、Radeon Graphics 3.90GHz、16GB内存、基于x86的64位操作系统,完整代码如下:

;GDIPlus.asm  ; GDI+ / DrawLine

;Assemble with:
;nasm -f win32 GDIPlus.asm -o GDIPlus.obj

;Link with:
;golink.exe /entry:start GDIPlus.obj kernel32.dll user32.dll gdiplus.dll 

%include '\nasm32\inc\win32\windows.inc'
%include '\nasm32\inc\win32\kernel32.inc'
%include '\nasm32\inc\win32\user32.inc'
%include '\nasm32\inc\nasm32.inc'
%include '\nasm32\inc\win32\gdiplus.inc'    

[section .data] 

;STRUCS
wcx times WNDCLASSEX_size db 0
msg times MSG_size db 0
ps times PAINTSTRUCT_size dd 0

;GDI+ Variables
gdiplusStartupInput dd 1, 0, 0, 0

penColor    dd 0xFF0000FF     ; Alpha=255, Red=0, Green=0, Blue=255
penWidth    dd 2.0
gdiplusToken dd 0
graphicsPtr dd 0
penPtr    dd 0
x1 dd 10.0 
y1 dd 10.0 
x2 dd 100.0
y2 dd 200.0

;Handles
hDC dd 0       ; Handle to the Device Context
hInstance dd 0
hWnd dd 0      

;Various labels
szTitle db 'GDIPlus :GDI+ /DrawLine',0x0
szClass db 'GDIPlus',0x0

[section .text]
start:

proc GDIPlus
      invoke GetModuleHandleA, dword NULL
      mov [hInstance], eax
      invoke WinMain,dword [hInstance],dword NULL,dword NULL,dword SW_SHOWNORMAL
      invoke ExitProcess,dword NULL
ret
endproc ;GDIPlus


proc WinMain ,hInst,hPinst,CmdLn,dwShow

;Load WNDCLASSEX
push dword WNDCLASSEX_size
pop dword [wcx + WNDCLASSEX.cbSize]

push dword argv(hInst)      
pop dword [wcx + WNDCLASSEX.hInstance]

push dword szClass
pop dword [wcx + WNDCLASSEX.lpszClassName]

push dword WndProc    
pop dword [wcx + WNDCLASSEX.lpfnWndProc]

push dword COLOR_BTNFACE +1
pop dword [wcx + WNDCLASSEX.hbrBackground]

push dword CS_VREDRAW +CS_HREDRAW
pop dword [wcx + WNDCLASSEX.style]


;Register the window class
      invoke RegisterClassExA, wcx

;Load window
    invoke CreateWindowExA,\
     WS_EX_OVERLAPPEDWINDOW,\
                    szClass,\
                    szTitle,\
          WS_OVERLAPPEDWINDOW +WS_VISIBLE ,\
            10, 10, 1200, 700,\
                          NULL,\
                         NULL,\
     [wcx + WNDCLASSEX.hInstance],\
                        NULL
     mov [hWnd], eax     

;GDIPlus Startup
    invoke GdiplusStartup, gdiplusToken, gdiplusStartupInput, NULL  

;Message Pump
MsgGet:
    invoke GetMessageA, dword msg, dword NULL, dword NULL, dword NULL
    cmp eax,0
        jnz MsgProcess
        jmp MsgEnd
MsgProcess:
      invoke TranslateMessage, dword msg
      invoke DispatchMessageA, dword msg
      jmp MsgGet
MsgEnd:
   ret
endproc ;WinMain


;==========================================================  WNDPROC
proc WndProc, hWin, uMsg, wParam, lParam

IsDestroy?:     
        cmp dword argv(uMsg), WM_DESTROY 
            jnz  IsKey?         
        jmp wpExit  
IsKey?:
        cmp dword argv(uMsg), WM_KEYDOWN
            jz wpIsEsc?
IsPaint?:
        cmp dword argv(uMsg), WM_PAINT   
            jnz DefWndProc
        invoke GDIPaint, dword argv(hWin)
ret     

;Key pressed
wpIsEsc?:
        cmp dword argv(wParam), VK_ESCAPE   
            jz near wpEsc
ret            

;Escape key hit
wpEsc:
        invoke SendMessageA, argv(hWin),WM_CLOSE,NULL,NULL
        xor eax,eax
ret

DefWndProc:
    invoke DefWindowProcA, dword argv(hWin), dword argv(uMsg), dword argv(wParam), dword argv(lParam)
    ret

;Exit procecure
wpExit:
    
    invoke GdipDeleteGraphics, dword [graphicsPtr]
    invoke GdipDeletePen, dword [penPtr]    
    invoke GdiplusShutdown, dword [gdiplusToken]

    invoke PostQuitMessage,dword NULL
    xor eax,eax
ret
endproc     ;WndProc

;----------------------------------
proc GDIPaint, gdiphWin

;Get hDC
    invoke BeginPaint, dword argv(gdiphWin), ps
    mov dword [hDC],eax

;GDI+ instructions
    invoke GdipCreateFromHDC, dword [hDC],dword graphicsPtr
    invoke GdipSetPageUnit, dword [graphicsPtr], 2      
    invoke GdipCreatePen1,dword [penColor], dword [penWidth], 6, penPtr
    invoke GdipDrawLine, dword [graphicsPtr],dword [penPtr], dword [x1], dword [y1], dword [x2], dword [y2]

    invoke EndPaint, dword argv(gdiphWin), ps
ret 4

问题排查与修复

1. Pen单位与PageUnit不匹配

代码中调用GdipSetPageUnit设置绘图单位为UnitPixel(值为2),但创建Pen时传入的单位是6(对应UnitMillimeter),单位不统一会导致线条位置或尺寸被错误缩放,甚至超出可视区域。

修复:将GdipCreatePen1的第三个参数改为2,与PageUnit保持一致:

invoke GdipCreatePen1,dword [penColor], dword [penWidth], 2, penPtr

2. 未及时释放GDI+资源

每次WM_PAINT中创建的Graphics和Pen对象需要在绘制完成后立即释放,否则会导致资源泄漏,且可能影响后续绘图命令的提交。

修复:在GDIPaint过程中,绘制完成后添加资源释放代码:

invoke GdipDrawLine, dword [graphicsPtr],dword [penPtr], dword [x1], dword [y1], dword [x2], dword [y2]
; 新增资源释放步骤
invoke GdipDeletePen, dword [penPtr]
invoke GdipDeleteGraphics, dword [graphicsPtr]
invoke EndPaint, dword argv(gdiphWin), ps

同时,WM_DESTROY中的资源释放可以保留,但因为每次WM_PAINT已经释放了本次创建的对象,这里的graphicsPtr和penPtr可能已经是无效值,建议移除这两行避免重复释放:

; 移除以下两行
; invoke GdipDeleteGraphics, dword [graphicsPtr]
; invoke GdipDeletePen, dword [penPtr]    
invoke GdiplusShutdown, dword [gdiplusToken]

3. 优化浮点数声明

虽然代码中用dd定义浮点数可行(x86中dd和real4长度相同),但显式用real4声明更清晰,避免歧义:

penWidth    real4 2.0
x1 real4 10.0 
y1 real4 10.0 
x2 real4 100.0
y2 real4 200.0

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:14:50