【问题标题】:I Try Call Win32 API WriteConsoleOutputA use NASM我尝试调用 Win32 API WriteConsoleOutputA 使用 NASM
【发布时间】:2016-12-29 02:06:27
【问题描述】:

我尝试使用 NASM 调用 WriteConsoleOutputA

但总是显示错误信息

87 (0x57)

参数不正确。

我不知道如何解决这个问题

STD_OUTPUT_HANDLE   EQU -11
NULL                EQU 0

GLOBAL GobleyGook
EXTERN ExitProcess, GetLastError, GetStdHandle, WriteConsoleA, WriteConsoleOutputA, FormatMessageA

SECTION .data

STRUC lpBuffer
    .Char      : RESW 1
    .Attributes: RESD 1
ENDSTRUC

_lpBuffer ISTRUC lpBuffer
    at lpBuffer.Char, DW 'A'
    at lpBuffer.Attributes, DD 1H
IEND

STRUC dwBufferSize
    .X: RESW  1 
    .Y: RESW  1
ENDSTRUC

_dwBufferSize ISTRUC dwBufferSize
    at dwBufferSize.X, DW 10
    at dwBufferSize.Y, DW 10
IEND

STRUC dwBufferCoord
    .X: RESW 1
    .Y: RESW 1
ENDSTRUC

_dwBufferCoord ISTRUC dwBufferCoord
    at dwBufferCoord.X, DW 0
    at dwBufferCoord.Y, DW 0
IEND

STRUC smallRect
    .Left  : RESW 1
    .Top   : RESW 1
    .Right : RESW 1
    .Bottom: RESW 1
ENDSTRUC

_smallRect ISTRUC smallRect
IEND

SECTION .bss
dummy   RESD 1
err     RESD 1
err2    RESD 1

SECTION .text
GobleyGook: 
    PUSH    STD_OUTPUT_HANDLE
    CALL    GetStdHandle

    PUSH    _smallRect
    PUSH    _dwBufferCoord
    PUSH    _dwBufferSize
    PUSH    _lpBuffer
    PUSH    EAX
    CALL    WriteConsoleOutputA

    CALL    GetLastError

    PUSH    NULL
    PUSH    99
    PUSH    err
    PUSH    NULL
    PUSH    EAX
    PUSH    NULL
    PUSH    1000H
    CALL    FormatMessageA

    PUSH    STD_OUTPUT_HANDLE
    CALL    GetStdHandle

    push    NULL
    push    dummy
    push    32
    push    err
    push    EAX
    call    WriteConsoleA

    PUSH    NULL
    CALL    ExitProcess

链接和编译器

nasm -f win32 print.asm
golink.exe /console /entry GobleyGook print.obj kernel32.dll

在 windows 8.1 64bit 上

API 文档

https://msdn.microsoft.com/zh-tw/library/windows/desktop/ms687404(v=vs.85).aspx

请帮帮我....

【问题讨论】:

  • 我想知道您是否需要将坐标参数作为DWORD 而不是作为指向结构的指针传递;如果是这样的话,我不完全知道为什么(我只知道某些结构需要它,比如BLENDFUNCTION)。
  • 我同意@andlabs。文档显示 dwBufferSizedwBufferCoord 按值传递,而不是通过指针传递。
  • 我尝试直接push 10(size)和push 0(Coord),显示同样的错误信息...
  • 您是否尝试过查看 C 编译器输出以进行相同的函数调用?
  • 是的,我尝试了 C++ 版本...成功

标签: winapi assembly nasm


【解决方案1】:

只要修改你的代码如下,就可以了!

PUSH    STD_OUTPUT_HANDLE
CALL    GetStdHandle

PUSH    _smallRect
mov ecx, [_dwBufferCoord]
PUSH    ecx
mov edx, [_dwBufferSize]
PUSH   edx 
PUSH    _lpBuffer
PUSH    EAX
CALL    WriteConsoleOutputA

【讨论】:

    【解决方案2】:

    您在代码中犯了几个错误:

    • 正如 cmets 中指出的,您需要按值传递 COORD 参数
    • 您需要传递一个等于缓冲区大小的dwBufferSize
    • 您需要传递一个lpWriteRegion 结构(通过引用),该结构使用您希望缓冲区显示在屏幕上的位置的坐标进行初始化。
    • 需要查看WriteConsoleOutputA的返回值来判断是否失败。您无法可靠地使用 GetLastError 来确定它是否失败。
    • 您对lpBuffer 结构的定义不正确。对应 CHAR_INFO 结构的第二个成员 Attributes 是 16 位 WORD 而不是 32 位 DWORD

    您的缓冲区只有一个字符,使其成为 1x1 缓冲区,但您尝试传递的缓冲区大小为 10x10。由于您没有初始化_smallRect,它的值是 0,0,0,0,这会将输出放在控制台缓冲区的左上角。这意味着当您的程序完成并打印命令提示符时,您的单字符输出可能会立即滚出屏幕,而您将永远看不到它。

    这是您的程序版本,已修复所有这些问题:

    STD_OUTPUT_HANDLE   EQU -11
    NULL                EQU 0
    
    GLOBAL GobleyGook
    EXTERN _ExitProcess@4, _GetLastError@0, _GetStdHandle@4, _WriteConsoleA@20, _WriteConsoleOutputA@20, _FormatMessageA@28
    
    SECTION .data
    
    STRUC lpBuffer
        .Char      : RESW 1
        .Attributes: RESW 1
    ENDSTRUC
    
    _lpBuffer ISTRUC lpBuffer
        at lpBuffer.Char, DW 'A'
        at lpBuffer.Attributes, DW 2H | 8H
    IEND
    
    STRUC smallRect
        .Left  : RESW 1
        .Top   : RESW 1
        .Right : RESW 1
        .Bottom: RESW 1
    ENDSTRUC
    
    _smallRect ISTRUC smallRect
        at smallRect.Left, DW 40
        at smallRect.Top, DW 12
        at smallRect.Right, DW 41
        at smallRect.Bottom, DW 13
    IEND
    
    SECTION .bss
    dummy   RESD 1
    err     RESD 1
    err2    RESD 1
    
    SECTION .text
    GobleyGook: 
        PUSH    STD_OUTPUT_HANDLE
        CALL    _GetStdHandle@4
    
        PUSH    _smallRect
        PUSH    (0 << 16) | 0  ; dwBufferCoord = 0,0
        PUSH    (1 << 16) | 1  ; dwBufferSize  = 1,1
        PUSH    _lpBuffer
        PUSH    EAX
        CALL    _WriteConsoleOutputA@20
    
        cmp     eax, 0
        jnz     .exit
    
        CALL    _GetLastError@0
    
        PUSH    NULL
        PUSH    99
        PUSH    err
        PUSH    NULL
        PUSH    EAX
        PUSH    NULL
        PUSH    1000H
        CALL    _FormatMessageA@28
    
        PUSH    STD_OUTPUT_HANDLE
        CALL    _GetStdHandle@4
    
        push    NULL
        push    dummy
        push    32
        push    err
        push    EAX
        call    _WriteConsoleA@20
    
    .exit:
        PUSH    0
        CALL _ExitProcess@4
    

    我已更改您的程序,使其在 40,12 处显示单个字符缓冲区,并将其设为亮绿色而不是深蓝色,以便在黑色背景上显示得更好。我还将 API 函数的名称更改为它们的实际程序集名称,以便它可以与 Microsoft 链接器链接。

    【讨论】:

    • 感谢您的帮助〜但@Sam Shaw首先解决了我的问题,您是对的,属性是word而不是dword
    • 如果我成功调用该函数,GetLastError 将返回成功消息
    • @Michael 不,正如我所说,你不能依赖它。正如GetLastError 的文档所说,“一些函数在成功时将最后一个错误代码设置为 0,而其他函数则没有。”。 msdn.microsoft.com/en-us/library/windows/desktop/…
    猜你喜欢
    • 2020-11-01
    • 1970-01-01
    • 2016-11-13
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多