News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

MASM64 problem with if macro

Started by C3, October 22, 2022, 07:37:37 AM

Previous topic - Next topic

C3

Hi,

With MASM64 the elseif macro contents (that MessageBox call) doesn't get executed it skips to the next Window Message.

.case WM_COMMAND
.if ((wParam+4)==0)
.switch wParam
          .case ID_FILE_OPEN
.case ID_FILE_SAVE
.case ID_FILE_EXIT
rcall SendMessage,hWnd,WM_CLOSE,0,0
.case ID_EDIT_CUT
.case ID_EDIT_COPY
.case ID_EDIT_PASTE
.case ID_HELP_ABOUT
invoke DialogBoxParam,hInstance,IDD_DIALOG1,hWnd,ADDR HelpAboutDialog,NULL
.endsw
.elseif ((wParam+4)==1)
invoke MessageBox,hWnd,"TEST","TEST",MB_OK
.else
nop
.endif


Petter

NoCforMe

Hate to ask you this, but did you confirm what the value of [wParam+4] actually was at that point?

If so, then sorry, can't help you here.
Assembly language programming should be fun. That's why I do it.

jj2007

Any good reason why you call it (wParam+4) instead of lParam?

  mov eax, lParam
  mov ebx, wParam+4
  mov ecx, wParam[4]
  mov edx, [wParam+4]


Disassembly:
  mov eax, [ebp+14]
  mov ebx, [ebp+14]
  mov ecx, [ebp+14]
  mov edx, [ebp+14]


You also don't need brackets all over the place. This is Assembly, not C/C++

.if ((wParam+4)==0)

.if lParam==0   ; make it readable

hutch--

Hi Petter,

I tried to test what you have posted but I don't have all of the constants in the .if block.

Declutter the code as JJ mentioned and also remove redundant code,

         .case ID_EDIT_CUT
         .case ID_EDIT_COPY
         .case ID_EDIT_PASTE
         .case ID_HELP_ABOUT

that is not being used.

There does not seem to be any reason for the"wParam+4". Win64 does not work like Win32, stack variables are aligned at 8 bytes, not 4 and by using the names of variables in the 1st 4 args, you are using "shadow space".

For testing purposes, try using the normal "wParam" and "lParam" and you will get the correct arguments to test for a WndProc.

Attached is a simple test piece for testing the ".if" block notation.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm64\include64\masm64rt.inc

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    LOCAL num1  :QWORD
    LOCAL num2  :QWORD
    LOCAL num3  :QWORD
    LOCAL num4  :QWORD

    mov num1, 1
    mov num2, 2
    mov num3, 3
    mov num4, 4

    invoke test_num,num4
    invoke test_num,num3
    invoke test_num,num2
    invoke test_num,num1

    invoke MessageBox,0,"Thats all folks","Arrrrgh",MB_OK

    .exit

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

test_num proc arg:QWORD

    .if arg == 1
      invoke MessageBox,0,str$(arg),"Option 1",MB_OK

    .elseif arg == 2
      invoke MessageBox,0,str$(arg),"Option 2",MB_OK

    .elseif arg == 3
      invoke MessageBox,0,str$(arg),"Option 3",MB_OK

    .elseif arg == 4
      invoke MessageBox,0,str$(arg),"Option 4",MB_OK

    .else
      invoke MessageBox,0,"Number out of range","Whoops",MB_OK

    .endif

    ret

test_num endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end

jj2007

Quote from: hutch-- on October 22, 2022, 09:45:12 AMThere does not seem to be any reason for the"wParam+4". Win64 does not work like Win32, stack variables are aligned at 8 bytes, not 4

Of course... I had not thought of that, thanks Hutch. So with wParam+4 Petter gets the high DWORD of wParam, instead of the low DWORD of lParam that he presumably wants to know.

NoCforMe

Unless what they want is the high DWORD of wParam. We still don't know.
Assembly language programming should be fun. That's why I do it.

hutch--

 :biggrin:

Depending on your sense of humour, the high DWORD of wParam in 64 bit Windows is always empty as the 64 bit value passed is only ever in DWORD range. Win64 is still a hybrid that uses a lot of 32 bit code. If you have to load a variable in both low DWORD and high DWORD, it has to be done via a 64 bit register. Its a quirk of Win64.

hutch--

I just found a strange quirk that I had never seen before. With the .switch macro, if you don't have at least 1 local in the proc, it fails to recognise a single argument. You can also load num1 into a register before the switch block,

mov r11, num1


Or you can use 4 or more stack arguments. Win64 tends to have a few surprises.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

switchtst proc num1:QWORD

    LOCAL empty :QWORD

    .switch num1
      .case 0
        invoke MessageBox,0,str$(num1),"0",MB_OK

      .case 1
        invoke MessageBox,0,str$(num1),"1",MB_OK

      .case 2
        invoke MessageBox,0,str$(num1),"2",MB_OK

    .endsw

    ret

switchtst endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

zedd151

Quote from: hutch-- on October 22, 2022, 12:49:47 PMWin64 tends to have a few surprises.
Hence, my reluctance to .switch (pun intended  :tongue: ) from Windows 7 32 bit to 64 full time.   :biggrin:

NoCforMe

I think they're talking about Win64 programming, not the OS.
Assembly language programming should be fun. That's why I do it.

zedd151

#10
Quote from: NoCforMe on October 22, 2022, 05:03:09 PM
I think they're talking about Win64 programming, not the OS.
Um 64 bit programs require a 64 bit OS to run.  :tongue:  No sense in writing for 64 bit unless you can also run and test it.  :biggrin:

jj2007


C3

Hello,

The problem is with the Keyboard Accelerators. I have done the resources and LoadAccelerators and put TranslateAccelerator to message loop.
I re-wrote the WM_COMMAND to do logic with the wParam, not lParam. The first .if checks is the message for Menu and .ifelse is the message for Accelerator, .else would be Control-defined notification code, as Windows API Documents the WM_COMMAND.

I was lazy at night when I posted the code. I have tried use the register and shift the register to get Accelerator Key to work. Messages for the Menu pass on, but messages for Accelerators execute only to the .ifelse, not to the what I expect it do for after compare.

Have to do some testing.

EDIT: I have maybe tought WM_COMMAND wrong, as the API Docs say there is wParam high word and wParam low word. I was using wParam as 64bit but docs point to use that as 32bit.

Petter

jj2007

Quote from: hutch-- on October 22, 2022, 12:49:47 PMWith the .switch macro, if you don't have at least 1 local in the proc, it fails to recognise a single argument.

I recommend .switching the macro :cool:

include \Masm32\MasmBasic\Res\JBasic.inc ; ## console demo, builds in 32- or 64-bit mode with UAsm, ML, AsmC ##
.code
switchtst proc num1:QWORD
; LOCAL empty :QWORD ; works fine, with and without a local
    Switch_ num1
      Case_ 100
        jinvoke MessageBox, 0, Str$("Result=%i", num1), Chr$("Expected: 100"), MB_OK
      Case_ 101
        jinvoke MessageBox, 0, Str$("Result=%i", num1), Chr$("Expected: 101"), MB_OK
      Case_ 102
        jinvoke MessageBox, 0, Str$("Result=%i", num1), Chr$("Expected: 102"), MB_OK
    Endsw_
    ret
switchtst endp
Init ; OPT_64 1 ; put 0 for 32 bit, 1 for 64 bit assembly
  PrintLine Chr$("This program was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format.")
  jinvoke switchtst, 100
  jinvoke switchtst, 101
  jinvoke switchtst, 102
EndOfCode


Output:
This program was assembled with ml64 in 64-bit format.
(plus three correct MessageBoxes)

hutch--

Its tuff when you build at 1.5k.  :biggrin:

The .switch macro is usually only used in higher level code that uses LOCAL variables but there are a number of options.

1. LOCAL anyvar :QWORD
2. mov r15, r15  :Any reg will do
3. switchtst proc num1:QWORD,dummy1:QWORD,dummy2:QWORD,dummy3:QWORD
4. Put it after any code.
        mov rax, 16
      lbl:
        sub rax, 1
        jnz lbl

I may track it down one day but in most contexts it does not matter. It may be that the macro should not be the first code run in a standard stack frame procedure. Anywhere else and it works correctly.

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

    include \masm64\include64\masm64rt.inc

    .code

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

entry_point proc

    rcall switchtst,0
    rcall switchtst,1
    rcall switchtst,2

    .exit

entry_point endp

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

switchtst proc num1:QWORD           ; ,dummy1:QWORD,dummy2:QWORD,dummy3:QWORD

    ; LOCAL dummy :QWORD

    ; mov r15, r15

    mov rax, 16
  lbl:
    sub rax, 1
    jnz lbl

    .switch num1
      .case 0
        rcall MessageBox,0,str$(num1),"Zero",MB_OK

      .case 1
        rcall MessageBox,0,str$(num1),"One",MB_OK

      .case 2
        rcall MessageBox,0,str$(num1),"Two",MB_OK

    .endsw

    ret

switchtst endp

; «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»

    end