Почему-то я больше не могу создать окно без изменения кода

Я пытаюсь написать pong на ассемблере, чтобы лучше понять, что на самом деле происходит на моем компьютере.

Я отключил свой антивирус, который помечал бы его как вредоносный, и перезагрузил компьютер с отключенным антивирусом, и код работал раньше, и я ничего не менял. Это могло быть по какой-то глупой оплошности, но, как обычно программисту высокого уровня, действительно странно, что код просто перестал работать после перезагрузки моего компьютера. Я не получаю никаких ошибок.

я получил

hello.asm(51): предупреждение A6001: нет возврата из процедуры

это как ошибка, но я мог игнорировать это раньше, и он компилируется, и, как я уже сказал, он работал раньше.

.386
.model flat, stdcall
option casemap:none

include C:\MASM32\include\masm32rt.inc
includelib user32.lib
includelib kernel32.lib

.data
    txClass db "MyWinClass", 0
    wcx     WNDCLASSEX <WNDCLASSEX, CS_HREDRAW or CS_VREDRAW, WndProc, 0, 0, 1, 2, 3, COLOR_BTNFACE+1, 0, txClass, 4>
    rect    RECT <20, 0, 40, 100> ; Rectangle to hold the client area dimensions
    ball    RECT <200, 200, 210,210> ; Rectangle to hold the client area dimensions
    ballMX  DWORD 5
    ballMY  DWORD 5
.data? ; uninitialised data - use for handles etc
    hMenu   dd ?
    ps PAINTSTRUCT<?>
    dwStartTime DWORD ?
    dwElapsedTime DWORD ?
    hWnd2  DWORD ?
.code
WinMain proc uses ebx
    LOCAL msg:MSG

    
    
    mov ebx, offset wcx
    wc equ [ebx.WNDCLASSEX]
    mov wc.hInstance, rv(GetModuleHandle, 0)
    mov wc.hIcon, rv(LoadIcon, NULL, IDI_APPLICATION)
    mov wc.hIconSm, eax

    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx, NULL, wc.lpszClassName, chr$("Pong"),
        WS_OVERLAPPEDWINDOW or WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, wc.hInstance, NULL

    mov hWnd2, eax
    invoke SetTimer, hWnd2, 1, 8, NULL

    .While 1
        invoke GetMessage, ADDR msg, NULL, 0, 0
        .Break .if !eax
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .Endw
    
    exit msg.wParam
WinMain endp

WndProc proc uses esi edi ebx hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
    LOCAL hdc: HDC

    
    SWITCH uMsg

    CASE WM_CREATE
    ret
    CASE WM_KEYDOWN
        mov eax, wParam
        SWITCH eax
        CASE VK_S
            add dword ptr [rect.top], 5
            add dword ptr [rect.bottom], 5
        CASE VK_W
            sub dword ptr [rect.top], 5
            sub dword ptr [rect.bottom], 5
            ret
    ret
    ENDSW
    invoke InvalidateRect, hWnd, NULL, TRUE ; Force the window to repaint
    ret 

    CASE WM_TIMER
        push ebx
        mov eax, ball.bottom
        mov ebx, ps.rcPaint.bottom
        cmp eax,ebx
        jb cont
        neg  ballMY
    cont:
        mov eax,ballMY
        add ball.top, eax     
        add ball.bottom, eax
        
        xor ebx, ebx
        
        mov eax, ball.right
        mov ebx, ps.rcPaint.right
        cmp eax,ebx
        jb cont2
        neg  ballMX
    cont2:
        mov eax,ballMX
        add ball.left, eax     
        add ball.right, eax    
        
        pop ebx
        
        
        
        
        invoke InvalidateRect, hWnd, NULL, TRUE  ; Request a repaint

    CASE WM_PAINT
    
        invoke BeginPaint, hWnd, ADDR ps ; Start painting the window
        mov hdc, eax                   ; Store the device context handle
        invoke CreateSolidBrush, 0000000
        invoke FillRect, hdc, ADDR ps.rcPaint, eax


        invoke CreateSolidBrush, 0FFFFFFh
        invoke FillRect, hdc, ADDR rect, eax
        
        
        invoke CreateSolidBrush, 0FFFFFFh
        invoke FillRect, hdc, ADDR ball, eax

        invoke EndPaint, hWnd, ADDR ps   ; End painting
        ret

    CASE WM_DESTROY
        invoke PostQuitMessage, NULL

    ENDSW
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret
WndProc endp

end WinMain

Похоже, вы не устанавливаете возвращаемое значение из вашего WndProc. Например. WM_CREATE требует, чтобы вы вернули 0, чтобы продолжить создание окна. У вас также есть утечка ресурсов в вашем обработчике WM_PAINT.

Jonathan Potter 01.08.2023 06:04

Я добавил вызов DeleteObject, вызов hBlackBrush DeleteObject, вызов hWhiteBrush DeleteObject, hWhiteBrush2, чтобы избежать утечки ресурсов, и добавил возвращаемое значение в WM_CREATE CASE WM_CREATE mov eax, 0 ret также добавил случай по умолчанию DEFAULT ; Обрабатывать случаи необработанных сообщений, вызывать DefWindowProc, hWnd, uMsg, wParam, lParam mov eax, 0 ret, но он по-прежнему не создает окно, но компилируется, и если я его запускаю, он не падает

Jannis 01.08.2023 13:52

В случае по умолчанию, когда вы вызываете DefWindowProc, вы должны вернуть значение, возвращаемое этой функцией, поэтому оно должно следовать за ret без mov eax, 0.

rodrigo 01.08.2023 21:07
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

RegisterClassEx не удалось

invoke RegisterClassEx, addr wc

Заменен исходный код новым кодом, который заполняет структуру WNDCLASSEX необходимыми переменными.

Запуск кода создает это окно

pong.asm

.386
.model flat, stdcall
option casemap:none

include C:\MASM32\include\masm32rt.inc
includelib user32.lib
includelib kernel32.lib

.data
    txClass db "MyWinClass", 0
    rect    RECT <20, 0, 40, 100> ; Rectangle to hold the client area dimensions
    ball    RECT <200, 200, 210,210> ; Rectangle to hold the client area dimensions
    ballMX  DWORD 5
    ballMY  DWORD 5
.data? ; uninitialised data - use for handles etc
    hMenu   dd ?
    ps PAINTSTRUCT<?>
    dwStartTime DWORD ?
    dwElapsedTime DWORD ?
    hWnd2  DWORD ?


.code
WinMain proc hInst     :DWORD,
             hPrevInst :DWORD,
             CmdLine   :DWORD,
             CmdShow   :DWORD   
    
        ;====================
        ; Put LOCALs on stack
        ;====================

        LOCAL wc   :WNDCLASSEX
        LOCAL msg  :MSG

        LOCAL Wwd  :DWORD
        LOCAL Wht  :DWORD
        LOCAL Wtx  :DWORD
        LOCAL Wty  :DWORD

        ;==================================================
        ; Fill WNDCLASSEX structure with required variables
        ;==================================================

        mov wc.cbSize,         sizeof WNDCLASSEX
        mov wc.style,          CS_HREDRAW or CS_VREDRAW \
                               or CS_BYTEALIGNWINDOW
        mov wc.lpfnWndProc,    offset WndProc
        mov wc.cbClsExtra,     NULL
        mov wc.cbWndExtra,     NULL
        m2m wc.hInstance,      hInst   ;<< NOTE: macro not mnemonic
        mov wc.hbrBackground,  COLOR_BTNFACE+1
        mov wc.lpszMenuName,   NULL
        mov wc.lpszClassName,  offset txClass
        invoke LoadIcon,hInst,500    ; icon ID
        mov wc.hIcon,          eax
        invoke LoadCursor,NULL,IDC_ARROW
        mov wc.hCursor,        eax
        mov wc.hIconSm,        0

        invoke RegisterClassEx, ADDR wc
        test eax, eax
        jnz regOk

        invoke MessageBox,0,SADD("RegistrationFailed"),
                            SADD("Oops"),
                            MB_OK or MB_ICONINFORMATION
        jmp done
                                 
regOk:
    invoke CreateWindowEx, NULL, wc.lpszClassName, chr$("Pong"),
        WS_OVERLAPPEDWINDOW or WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, wc.hInstance, NULL

    mov hWnd2, eax
    invoke ShowWindow,hWnd2,SW_SHOWNORMAL
    invoke UpdateWindow,hWnd2

    invoke SetTimer, hWnd2, 1, 8, NULL

    .While 1
        invoke GetMessage, ADDR msg, NULL, 0, 0
        .Break .if !eax
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .Endw

done:
    exit msg.wParam
WinMain endp

WndProc proc uses esi edi ebx hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
    LOCAL hdc: HDC

    
    SWITCH uMsg

    CASE WM_CREATE
    ret
    CASE WM_KEYDOWN
        mov eax, wParam
        SWITCH eax
        CASE VK_S
            add dword ptr [rect.top], 5
            add dword ptr [rect.bottom], 5
        CASE VK_W
            sub dword ptr [rect.top], 5
            sub dword ptr [rect.bottom], 5
            ret
    ret
    ENDSW
    invoke InvalidateRect, hWnd, NULL, TRUE ; Force the window to repaint
    ret 

    CASE WM_TIMER
        push ebx
        mov eax, ball.bottom
        mov ebx, ps.rcPaint.bottom
        cmp eax,ebx
        jb cont
        neg  ballMY
    cont:
        mov eax,ballMY
        add ball.top, eax     
        add ball.bottom, eax
        
        xor ebx, ebx
        
        mov eax, ball.right
        mov ebx, ps.rcPaint.right
        cmp eax,ebx
        jb cont2
        neg  ballMX
    cont2:
        mov eax,ballMX
        add ball.left, eax     
        add ball.right, eax    
        
        pop ebx
        
        
        
        
        invoke InvalidateRect, hWnd, NULL, TRUE  ; Request a repaint

    CASE WM_PAINT
    
        invoke BeginPaint, hWnd, ADDR ps ; Start painting the window
        mov hdc, eax                   ; Store the device context handle
        invoke CreateSolidBrush, 0000000
        invoke FillRect, hdc, ADDR ps.rcPaint, eax


        invoke CreateSolidBrush, 0FFFFFFh
        invoke FillRect, hdc, ADDR rect, eax
        
        
        invoke CreateSolidBrush, 0FFFFFFh
        invoke FillRect, hdc, ADDR ball, eax

        invoke EndPaint, hWnd, ADDR ps   ; End painting
        ret

    CASE WM_DESTROY
        invoke PostQuitMessage, NULL

    ENDSW
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret
WndProc endp

end WinMain

В C:\masm32\tools и C:\masm32\examples есть много примеров, которые используют этот код для правильной регистрации класса Windows.

RegisterWinClass proc lpWndProc:DWORD, lpClassName:DWORD,
                      Icon:DWORD, Cursor:DWORD, bColor:DWORD

    LOCAL wc:WNDCLASSEX

    mov wc.cbSize,         sizeof WNDCLASSEX
    mov wc.style,          CS_BYTEALIGNCLIENT or \
                           CS_BYTEALIGNWINDOW
    m2m wc.lpfnWndProc,    lpWndProc
    mov wc.cbClsExtra,     NULL
    mov wc.cbWndExtra,     NULL
    m2m wc.hInstance,      hInstance
    m2m wc.hbrBackground,  bColor
    mov wc.lpszMenuName,   NULL
    m2m wc.lpszClassName,  lpClassName
    m2m wc.hIcon,          Icon
    m2m wc.hCursor,        Cursor
    m2m wc.hIconSm,        Icon

    invoke RegisterClassEx, ADDR wc

    ret

RegisterWinClass endp

Я очень благодарен за этот ответ, но по какой-то причине он все еще не показывает никаких окон. Я понятия не имею, почему он ничего не показывает. Знаете ли вы, почему код работает на вашем компьютере, а на моем не отображаются окна?

Jannis 01.08.2023 21:38

Обновил код... ошибка invoke RegisterClassEx, addr wc. Вероятно, следует добавить проверки ошибок вокруг большего количества вызовов оконных функций.

vengy 01.08.2023 22:30

но я точно скопировал код, и он работал, прежде чем я перезагрузил свой компьютер

Jannis 01.08.2023 22:48

Скорее всего, нам обоим повезло с окном, появляющимся случайным образом. Вероятно, какое-то причудливое внутреннее состояние программы. Работает ли новый код сейчас? Если это так, вы можете сузить его, чтобы найти причину сбоя. Спасибо.

vengy 01.08.2023 22:51

@Jannis: Программы с ошибками, которые оставляют некоторые вещи неинициализированными, не обязательно сломаются, они могут работать в зависимости от случайного состояния, например, того, что попадает в определенный участок памяти стека. В ассемблере очень легко допустить ошибку, например, оставить что-то неинициализированным, в отличие от C. Поэтому тот факт, что он работал раньше, не доказывает, что он был правильным и перспективным. Да, перезагрузки может быть достаточно, чтобы повторно рандомизировать адрес или размер среды или что-то, что заставляло вашу программу работать.

Peter Cordes 01.08.2023 23:26

Другие вопросы по теме