The MASM Forum Archive 2004 to 2012

General Forums => The Campus => Topic started by: Robert Collins on December 23, 2004, 12:31:40 AM

Title: Using the invoke statement
Post by: Robert Collins on December 23, 2004, 12:31:40 AM
In C/C++ I can do this:

MessageBox, 0, "This is the body text", "This is the Caption text", MB_OK;

So, how come in Assembly I have to use variable names:

invoke  MessageBox, 0, TextMsg, CaptionMsg, MB_OK

Cannot the MASM deal with inline data?

Title: Re: Using the invoke statement
Post by: donkey on December 23, 2004, 12:50:22 AM
I believe that there is a macro in the masm32 project that does that (CSTR or something like that). If not then GoAsm handles them inherently, even Unicode if that is necessary...

Quote from: From the GoAsm manualGoAsm supports an extension of the PUSH mnemonic which is very helpful when programming in Windows. Often in Windows you need to send to an API a parameter which is a pointer to a null-terminated string for example:-
MBTITLE   DB 'Hello',0
MBMESSAGE DB 'Click OK',0
PUSH 40h, ADDR MBTITLE, ADDR MBMESSAGE, [hwnd]
CALL MessageBoxA

To make this easier GoAsm permits the use of PUSH like this:-
PUSH 40h,'Hello','Click OK',[hwnd]
CALL MessageBoxA

or if you prefer to use INVOKE:-
INVOKE MessageBoxA, [hwnd],'Click OK','Hello',40h

You can also use this with Unicode strings as follows:-
PUSH 40h,L'Hello',L'Click OK',[hwnd]
CALL MessageBoxW
INVOKE MessageBoxW, [hwnd],L'Click OK',L'Hello',40h

The strings are added to the data section if there is one, if not then to the const section. This is in order that it does not create any new sections, adding 512 bytes to your executable. I imagine the MASM macro will add them to the data section regardless of whether one exists or not.
Title: Re: Using the invoke statement
Post by: raymond on December 23, 2004, 12:57:26 AM
When you code it in C/C++, whatever you put between quotation marks gets compiled as data in memory and code is then added to access that data through a pointer because that is what is required by the function.

Some people have written macros to simulate that behaviour, but if you disassemble the produced code and study it, you would find that a pointer has been pushed for the parameter.

Raymond
Title: Re: Using the invoke statement
Post by: John on December 23, 2004, 01:21:32 AM
There is a well known and widely use macro called szText that will allow you to create a new string at the procedure level. It looks like this:
szText MACRO Name, Text:VARARG
  LOCAL lbl
    jmp lbl
      Name db Text,0
    lbl:
ENDM

And is used like so:
szText TheMsg,"Assembler, Pure & Simple"
invoke MessageBox,hWin,ADDR TheMsg,ADDR szDisplayName,MB_OK

There is also the MsgBox macro that allows you to use VB style code for your message box. You can find that in Macros.asm from the MASM32 package.

John
Title: Re: Using the invoke statement
Post by: Robert Collins on December 23, 2004, 01:32:15 AM
Quote from: John on December 23, 2004, 01:21:32 AM
There is a well known and widely use macro called szText that will allow you to create a new string at the procedure level. It looks like this:
szText MACRO Name, Text:VARARG
  LOCAL lbl
    jmp lbl
      Name db Text,0
    lbl:
ENDM

And is used like so:
szText TheMsg,"Assembler, Pure & Simple"
invoke MessageBox,hWin,ADDR TheMsg,ADDR szDisplayName,MB_OK

I hope this helps you.

Well, it's not bad, but still the invoke statement uses a named variable. I guess from what I have seen posted that the bottom line is that one cannot use in-line qouted data in the invoke statement.

By the way, is it possible to use a macro within a macro? Such as in the following:

invoke MessageBox, 0, szText TheMsg, 'Assembler, Pure & Simple', szText DisplayName 'My Message Box', MB_OK ?

Probably not, that looks kind of funky.
Title: Re: Using the invoke statement
Post by: John on December 23, 2004, 01:46:46 AM
Sorry for editing my post on you there, I tend to do that alot for some reason. :)

The MsgBox macro will allow you to use plain text in the call and if you find any other APIs where you need to do something like that you can write your own macro following the MsgBox macro as an example. Then add it to your own custom macros.asm file that you include in all your programs.

IIRC invoke is actually just a built in macro that does type (parameter?) checking on a prototyped function. Vortex wrote his own version of the invoke macro and posted it in the Laboratory. Maybe that will interest you.
Title: Re: Using the invoke statement
Post by: Jimg on December 23, 2004, 01:54:02 AM
I normally use these macros:
literal MACRO quoted_text:VARARG
LOCAL local_text
.data
  local_text db quoted_text,0
.code
EXITM <local_text>
ENDM

sadd MACRO quoted_text:VARARG
EXITM <ADDR literal(quoted_text)>
ENDM
sadd equ SADD


Then you just
    invoke  MessageBox,hwin,sadd ("This is a test"),sadd("Did we pass???"),MB_ICONWARNING
Title: Re: Using the invoke statement
Post by: MANT on December 23, 2004, 04:20:41 AM
I use pretty much the same macro, but I call it _T to simulate the _T macro used in VC++/MFC.

    invoke MessageBox, hwin, _T("This is a test"), _T("Did we pass???"), MB_ICONWARNING
Title: Re: Using the invoke statement
Post by: Robert Collins on December 23, 2004, 04:47:54 AM
Quote from: John on December 23, 2004, 01:46:46 AM
Sorry for editing my post on you there, I tend to do that alot for some reason. :)

The MsgBox macro will allow you to use plain text in the call and if you find any other APIs where you need to do something like that you can write your own macro following the MsgBox macro as an example. Then add it to your own custom macros.asm file that you include in all your programs.

IIRC invoke is actually just a built in macro that does type (parameter?) checking on a prototyped function. Vortex wrote his own version of the invoke macro and posted it in the Laboratory. Maybe that will interest you.

I tried using the MsgBox macro as you indicated, MsgBox, 0, "text1", "text2", MB_OK but still got assembler syntax errors on it.
Also, I tried using Vortex's _include macro but again had assembler syntax errors _include MessageBox, 0, "text1", "text2", MB_OK
Title: Re: Using the invoke statement
Post by: hutch-- on December 23, 2004, 06:46:29 AM
MASM using a macro included in the MASM32 project.

fn MessageBox, 0, "This is the body text", "This is the Caption text", MB_OK

MASM is a MACRO assembler, it is designed to do this type of thing.
Title: Re: Using the invoke statement
Post by: drarem on December 24, 2004, 07:11:11 AM
There's also the CTEXT macro which can be used with invoke:


CTEXT MACRO y:VARARG
   LOCAL sym, dummy
   dummy EQU $   ;; MASM error fix
   CONST segment
      IFIDNI <y>,<>
         sym db 0
      ELSE
         sym db y,0
      ENDIF
   CONST ends
   EXITM <OFFSET sym>
ENDM


invoke MessageBox, NULL, CTEXT("This is a test"), CTEXT("TITLE"), MB_OK
Title: Re: Using the invoke statement
Post by: Vortex on December 24, 2004, 10:50:00 AM
Hi Robert,

There are some macro tricks enabling you to use the statements below with Masm:
MessageBox,0,ADDR msg,ADDR capt,MB_OK
Title: Re: Using the invoke statement
Post by: Vortex on December 24, 2004, 07:23:47 PM
Here is an example:

.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include stcall.inc
include kernel32.inc
include user32.inc
include ctext.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.code
start:
MessageBox, NULL,CTEXT("MsgBoxText"), CTEXT("MsgCaption"), MB_OK
ExitProcess,NULL
END start

[attachment deleted by admin]
Title: Re: Using the invoke statement
Post by: Robert Collins on December 24, 2004, 08:10:19 PM
Quote from: Vortex on December 24, 2004, 07:23:47 PM
Here is an example:

.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include stcall.inc
include kernel32.inc
include user32.inc
include ctext.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.code
start:
MessageBox, NULL,CTEXT("MsgBoxText"), CTEXT("MsgCaption"), MB_OK
ExitProcess,NULL
END start


I got it to work without the include stdcall.inc file. Is there some reasom why you are including it?
Title: Re: Using the invoke statement
Post by: pbrennick on December 24, 2004, 10:56:29 PM
Vortex,
In my opinion, this is a lot simpler:

Quote.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

CTEXT MACRO y:VARARG
LOCAL sym, dummy
dummy EQU $ ;; MASM error fix
CONST segment
IFIDNI <y>,<>
sym db 0
ELSE
sym db y,0
ENDIF
CONST ends
EXITM <OFFSET sym>
ENDM

.code
start:
invoke MessageBox, NULL,CTEXT("MsgBoxText"), CTEXT("MsgCaption"), MB_OK
invoke ExitProcess,NULL
END start

I am not sure why someone would want to go through all that trouble just to remove to invokes.  This is done all in one file as opposed to eleven files using over 100k.  Maybe I am missing the big picture?
Paul

Title: Re: Using the invoke statement
Post by: Vortex on December 25, 2004, 09:56:27 AM
Hi pbrennick,

One you create the necessary include files, you can use them to call API functions without needing of invoke macro. The ide behind removing invoke is to call functions like in HLLs. This macro system is a good programming exercise for me, it's a matter of personal preference to use this methode.

Hi Robert,

I am not sure that you can build the executable without the stcall macro as it's used extensively in my macro system:

EXTERNDEF MessageBoxA@16:proc
MessageBox equ <stcall MessageBoxA@16,4>
Title: Re: Using the invoke statement
Post by: Robert Collins on December 25, 2004, 05:18:53 PM
Quote from: Vortex on December 25, 2004, 09:56:27 AM
Hi pbrennick,

One you create the necessary include files, you can use them to call API functions without needing of invoke macro. The ide behind removing invoke is to call functions like in HLLs. This macro system is a good programming exercise for me, it's a matter of personal preference to use this methode.

Hi Robert,

I am not sure that you can build the executable without the stcall macro as it's used extensively in my macro system:

EXTERNDEF MessageBoxA@16:proc
MessageBox equ <stcall MessageBoxA@16,4>


Hi Vortex,

Well, unless it is hidden from my view I can't see where the usage of the stdcall macro is. I don't think it is in the MACROS.ASM file. But below is the simple code to use the CTEXT macro and it works fine.


.386
.model flat, stdcall
option casemap:none

ExitProcess PROTO  :DWORD 
                         
include    \masm32\include\windows.inc
include    \masm32\include\kernel32.inc
include    \masm32\include\user32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
;
; Include only for the switch macro
;
include MACROS.ASM                 

CTEXT MACRO y:VARARG
   LOCAL sym, dummy
   dummy EQU $   ;; MASM error fix
   CONST segment
      IFIDNI <y>,<>
         sym db 0
      ELSE
         sym db y,0
      ENDIF
   CONST ends
   EXITM <OFFSET sym>
ENDM

.data
myvalue          dd     25     

.code
start:
      mov eax,myvalue
               
      switch (myvalue)
        case 20
          invoke MessageBox, 0, CTEXT("myvalue == 20"), CTEXT("The Answer Is"), MB_OK
        case 23
          invoke MessageBox, 0, CTEXT("myvalue == 23"), CTEXT("The Answer Is"), MB_OK
        case 25
          invoke MessageBox, 0, CTEXT("myvalue == 25"), CTEXT("The Answer Is"), MB_OK
      endsw   

invoke ExitProcess,0
END start
Title: Re: Using the invoke statement
Post by: pbrennick on December 25, 2004, 08:13:56 PM
Robert,
Nice job and the case logic works very nicely.  That is a method worth remembering.  The following line is not necessary because it is already declared in kernel32.inc:

QuoteExitProcess PROTO  :DWORD

Paul