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
相关产品推荐
相关产品推荐

