【问题标题】:CreateWindowEx failing with error 1400CreateWindowEx 失败并出现错误 1400
【发布时间】:2015-12-18 23:07:37
【问题描述】:

标题说明了一切。我只是想在程序集中使用 CreateWindowEx 创建一个窗口,但调用失败并出现错误 1400(坏窗口句柄)。我已经验证没有其他 API 调用失败,并且 DefWindowProc 为 WM_CREATE 返回 0(通过)。去 CreateWindowEx 的参数对我来说很合适。

编辑:现在共享带有错误检查的代码,我之前为了可读性而删除了该代码。

extern __imp__GetModuleHandleA@4
extern __imp__RegisterClassA@4
extern __imp__ExitProcess@4
extern __imp__AdjustWindowRect@12
extern __imp__CreateWindowExA@48
extern __imp__GetSystemMetrics@4
extern __imp__GetLastError@0
extern __imp__DefWindowProcA@16

global _main

section main text align=1
_main:
    push    byte 0
    call    [__imp__GetModuleHandleA@4]
    test    eax, eax
    jz      OnError

    mov     dword [hInstance], eax
    push    dword wndclass
    call    [__imp__RegisterClassA@4]
    test    eax, eax
    jz      OnError

    ; WS_VISIBLE | WS_CAPTION | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU
    mov     ebx, 0x10000000 | 0x00C00000 | 0x04000000 | 0x02000000 | 0x00080000

    push    byte 0
    push    ebx
    push    rect
    call    [__imp__AdjustWindowRect@12]
    test    eax, eax
    jz      OnError

    push    byte 0
    push    dword [hInstance]
    push    byte 0
    push    byte 0

    ; rect.bottom - rect.top
    mov     eax, dword [rect.bottom]
    sub     eax, dword [rect.top]
    push    eax

    ; rect.right - rect.left
    mov     eax, dword [rect.right]
    sub     eax, dword [rect.left]
    push    eax

    ; ( GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top ) >> 1
    push    byte 1                      ; SM_CYSCREEN
    call    [__imp__GetSystemMetrics@4]
    sub     eax, dword [rect.bottom]
    add     eax, dword [rect.top]
    sar     eax, 1
    push    eax

    ; ( GetSystemMetrics(SM_CXSCREEN) - rect.right + rect.left ) >> 1
    push    byte 0                      ; SM_CXSCREEN
    call    [__imp__GetSystemMetrics@4]
    sub     eax, [rect.right]
    add     eax, [rect.left]
    sar     eax, 1
    push    eax

    push    ebx                         ; dwStyle
    push    byte 0                      ; lpWindowName
    push    classname                   ; lpClassName
    push    0x00040000 | 0x00000100     ; dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE
    call    [__imp__CreateWindowExA@48]
    test    eax, eax
    jz      OnError

    push    byte 0
    call    [__imp__ExitProcess@4]

OnError:
    call    [__imp__GetLastError@0]
    push    eax
    call    [__imp__ExitProcess@4]

section WinProc text align=1
WinProc:
    push    dword [esp + 20]
    push    dword [esp + 16]
    push    dword [esp + 12]
    push    dword [esp + 8]
    call    [__imp__DefWindowProcA@16]
    ret     16

section wndclass data align=1
wndclass:
    dd      0x0020 | 0x0002 | 0x0001    ; Style CS_OWNDC | CS_HREDRAW | CS_VREDRAW
    dd      WinProc                     ; lpfnWndProc
    dd      0                           ; cbClsExtra
    dd      0                           ; cbWndExtra
hInstance:
    dd      0                           ; hInstance
    dd      0                           ; hIcon
    dd      0                           ; hCursor
    dd      0                           ; hbrBackground
    dd      0                           ; lpszMenuName
    dd      classname                   ; lpszClassName
classname:
    db      '1337Class', 0

section rect data align=1
rect:
    .left:   dd      0
    .top:    dd      0
    .right:  dd      1366
    .bottom: dd      768

【问题讨论】:

  • 我不知道,但这可能是 a) push byte 0 实际上推送一个字节,而不是一个 dword,或者 b) ebx 正在被破坏。您需要调试以查看是否有可能。如果两者都不是,那么 IDK,对不起。
  • push byte 0 肯定会推送一个 dword 并且 ebx 是调用者保存,所以它不会被破坏。不过感谢您的回复。
  • *被调用者保存。我总是搞砸。
  • 我看到的一个问题是,在传递RegisterClassA() 之前,您没有将hInstance 分配给WNDCLASSA 结构。您正在将hInstance 分配给EBX 寄存器,但之后不做任何事情。但是,您正在将hInstance 传递给CreateWindowEx()。所以你有一个不匹配。
  • 好眼光。 mov eax, dword [hInstance] 应该是 mov dword [hInstance], eax(我讨厌在 Intel 和 AT&T 语法之间切换)。不幸的是,它并不能解决问题。

标签: winapi nasm


【解决方案1】:

原来问题出在我的窗口程序上。完全搞砸了。只调用 DefWindowProc 的工作窗口过程的一个很好的例子是

WinProc:
    mov     ebp, esp
    push    dword [ebp + 16]
    push    dword [ebp + 12]
    push    dword [ebp + 8]
    push    dword [ebp + 4]
    call    [__imp__DefWindowProcA@16]
    ret     16

经验教训:

  1. 在开始胡闹之前,请务必将 ESP 复制到 EBP。它使 否则代码难以维护。
  2. 始终注意调试器中堆栈的内容。
  3. DefWindowProcA 将返回零,即使您将其传递为垃圾!

【讨论】:

  • #3 - 不,不是这样,除非(不)幸运的情况。
猜你喜欢
  • 1970-01-01
  • 2011-05-17
  • 2011-05-21
  • 2018-02-24
  • 2012-09-24
  • 2013-07-18
  • 2021-10-12
  • 2020-10-23
  • 2020-07-20
相关资源
最近更新 更多