News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Question about MACRO

Started by mabdelouahab, November 09, 2013, 10:28:42 AM

Previous topic - Next topic

mabdelouahab

Hello everyone
First, I'm sorry for my English  :biggrin:
I put Struct:

ItemType Struct
hName        dd     ?     
hParent        dd     ?         
hPrevItem        dd     ?         
hNextItem        dd     ?         
hObject        dd     ?         
ItemType ENDS


Then I added VAR..:
  FirstItem dd ? 
and ..

invoke GetProcessHeap
invoke HeapAlloc, eax, NULL, SIZEOF ItemType

    mov FirstItem ,eax
    mov  esi, FirstItem
    assume esi:PTR ItemType
m2m [esi].hName ,chr$("My First Item")
    assume esi: nothing

so
I think that the first dword is hName

If I used

mov edx, FirstItem
mov ecx ,dword ptr [edx]
        fn MessageBox,0,ecx,0,MB_OK

I get the result
my Question ?
What is the way to get this result by Macro ?

Set_ macro C_:req
    ??P InStr <C_>, <:>
    if ??P ne 0
??Name SubStr <C_>, 1, ??P - 1
ifdef ??Name
    mov edx, ??Name
    mov ecx ,dword ptr [edx]
; ??TMP TEXTEQU @CatStr(ecx) I test this the result is "ecx"
;         @CatStr(<fn MessageBox,0,>,@CatStr(!",@SubStr(%??TMP,1),!"),<,0,MB_OK >)
   @CatStr(<fn MessageBox,0,>,@CatStr(!",@SubStr(%ecx,1),!"),<,0,MB_OK >)
    endif
    else
    .err <Set error syntax  !" : " missing >
    endif
endm


I want to get the text that is in the PTR ecx
fn MessageBox,0,"My First Item",0,MB_OK
I do not want one of the following results
fn MessageBox,0,"ecx",0,MB_OK
or : fn MessageBox,0,ecx,0,MB_OK

Thank you

qWord

Quote from: mabdelouahab on November 09, 2013, 10:28:42 AMIf I used

mov edx, FirstItem
mov ecx ,dword ptr [edx]
        fn MessageBox,0,ecx,0,MB_OK

I get the result
my Question ?
yes, ECX will be loaded with the pointer to your string "My First Item". This pointer is then passed to MessageBox().
Quote from: mabdelouahab on November 09, 2013, 10:28:42 AM
What is the way to get this result by Macro ?
actual a macro is not really needed here, bcause MASM has already a simple method to access structure members:
e.g.:
   mov ecx,pointer to structure
   mov eax,[ecx].StructureName.MemberName
or
   invoke Fnc,[ecx].StructureName.MemberName,...


Quote from: mabdelouahab on November 09, 2013, 10:28:42 AMI want to get the text that is in the PTR ecx
fn MessageBox,0,"My First Item",0,MB_OK
I do not want one of the following results
fn MessageBox,0,"ecx",0,MB_OK
or : fn MessageBox,0,ecx,0,MB_OK

that is not possible - macros are expanded while assembling and not when the code is executed.
MREAL macros - when you need floating point arithmetic while assembling!

mabdelouahab

Thank you qWord
Quote from: qWord on November 09, 2013, 10:59:21 AM
that is not possible - macros are expanded while assembling and not when the code is executed.
Important information
I've been using one of two methods

mov  edx, pointer to structure
assume edx:PTR StructureName
mov eax , [edx].MemberName
assume edx: nothing
    or: ...
mov  edx, pointer to structure
mov eax ,(StructureName ptr [edx]).MemberName


but I want to use the name of the Structure, variable, save it in the first DWORD
To be used as a variable, Like :

....
[esi].hName ,chr$("StructureName")
....
mov  edx, pointer to structure
mov ecx ,DWORD PTR [EDX] ;<==[esi].hName     "StructureName"
assume edx:PTR [ecx]
mov eax , [edx].MemberName
assume edx: nothing
    or: ...
mov  edx, pointer to structure
mov ecx ,DWORD PTR [EDX] ;<==[esi].hName     "StructureName"
mov eax ,([ecx] ptr [edx]).MemberName

Is that possible?

mabdelouahab

More simply,
I want to use

Set_ macro C_:req ,Arg
    ??P InStr <C_>, <:>
    if ??P ne 0
??Name SubStr <C_>, 1, ??P - 1
??MemberName  SubStr <C_>, ??P + 1
ifdef ??Name
    mov edx, ??Name
    mov ecx ,dword ptr [edx] ;<==[esi].hName     "StructureName"
    assume edx:PTR @CatStr( @SubStr(%ecx,1) )
    m2m [edx].??MemberName,Arg
    assume edx: nothing
    endif
    else
    .err <Set error syntax  !" : " missing >
    endif
endm


For:

Set_ FirstItem:MemberName,5

What a way to use PTR to structname: variable ?
For Ex: in ObjAsm32 ==> " OCall "

I do not want to use fresh code, because I perfected the VB.NAT, and I would like to re-create my projects using MASM32, I have not used it before, but I want mastery
Thank you all ...

mabdelouahab

I modified  CLASS , located in the Objects.INC, as follows:

CLASS_ MACRO CName:REQ , Abiv:VARARG
   IFNB <Abiv>
     AbvNa TEXTEQU <Abiv>
   ELSE
     AbvNa TEXTEQU <CName>
   ENDIF

     Class TEXTEQU <CName>
.data
    @CatStr(<Interface_>, CName, <  db  >, @CatStr(!",@SubStr(%Class,1),!"),<,0>)    ;<==== StructureName
     @CatStr( CName, < STRUC >)
    Interface__    dd    ?                                ;<=========================== ptr to StructureName
ENDM

The same for,

BEGIN_INIT_ MACRO 
    LOCAL sz1
    LOCAL sInterf
 
     sz1 CATSTR Class,<_initdata LABEL BYTE>
     sInterf CATSTR < dd OFFSET Interface_>,Class          ;<==== init PTR To StructureName=============
     sz1
     sInterf                                 ;<================================================
ENDM 

To be able to use  FirstItem:MemberName without StructureName, like Set_ Macro
Set_ FirstItem:MemberName,5

jj2007

Quote from: mabdelouahab on November 09, 2013, 05:20:49 PM
To be used as a variable, Like :

....
[esi].hName ,chr$("StructureName")
....
mov  edx, pointer to structure
mov ecx ,DWORD PTR [EDX] ;<==[esi].hName     "StructureName"
assume edx:PTR [ecx]
mov eax , [edx].MemberName
assume edx: nothing
    or: ...
mov  edx, pointer to structure
mov ecx ,DWORD PTR [EDX] ;<==[esi].hName     "StructureName"
mov eax ,([ecx] ptr [edx]).MemberName

Is that possible?

Yes, but I'd suggest a persistent register like ebx:

  mov ebx, eax                ; eax=pointer to RECT structure
  rc equ <[ebx.RECT]>     ; from now on you can use rc.member
  mov rc.left, 123
  mov rc.bottom, ecx

No assume needed, and it works for all kinds of structures.

mabdelouahab

Quote from: jj2007 on November 09, 2013, 07:18:59 PM

Yes, but I'd suggest a persistent register like ebx:

  mov ebx, eax                ; eax=pointer to RECT structure
  rc equ <[ebx.RECT]>     ; from now on you can use rc.member
  mov rc.left, 123
  mov rc.bottom, ecx

No assume needed, and it works for all kinds of structures.
hi jj2007

If I have to create: (  for ex ... )

CLASS_ TestO
      CMETHOD First    ;
      CMETHOD NextM    ;
      A     dd    ?
TestO ENDS
 
CLASS_ ItemType
hName        dd     ?     
hParent        dd     ?         
hPrevItem        dd     ?         
hNextItem        dd     ?         
hObject        dd     ?         
ItemType ENDS




And also:

FirstItem dd ? ;<== ItemType
test_ dd ? ;<== TestO

The result that I want to be accessed ( Without the use of Structname) is

set_  FirstItem: hObject,10       
set _ test_:A,33

I want to use a then hidden ( Interface__ ) in  CLASS_,and  I put the name of Struct, and used it in the set_ MACRO

qWord

Is there any reason to not use ObjAsm32? It also supports the COM ABI.
What you are trying to do is possible, as long as working with correctly typed variables and expressions. The types (class/structure name and the corresponding pointer type) must be recorded for later compare.
??_glbl_cntr = 0
class macro name:req,ptrName
    ??_current_class TEXTEQU <name>
    ??_class_ptr_name TEXTEQU <ptrName>
    name struct
endm

end_class macro
    ??_current_class ends
   
    ;/**
    ; * create textmacros that holds the class name (structure name)
    ; * and the pointer type (PT typedef ptr Class)
    ; */
    @CatStr(<glbl_class_name_>,%??_glbl_cntr) TEXTEQU ??_current_class
    IFB ??_class_ptr_name
        ;/* default name: class name prefixed by "P" */
        @CatStr(<P>,%??_current_class) typedef ptr ??_current_class
        @CatStr(<glbl_class_ptrType_>,%??_glbl_cntr) TEXTEQU @CatStr(<P>,%??_current_class)
    ELSE
        ;/* user defined name */
        ??_class_ptr_name typedef ptr ??_current_class
        @CatStr(<glbl_class_ptrType_>,%??_glbl_cntr) TEXTEQU ??_class_ptr_name
    ENDIF
    ??_glbl_cntr = ??_glbl_cntr + 1
endm

; do not use EAX and ECX as value
set macro item,value
    ??_pos1 INSTR <&item>,<:>
    IFE ??_pos1
        .err <syntax error: missing colon>
        EXITM   
    ENDIF
    ??_object SUBSTR <&item>,1,??_pos1-1
    ??_member SUBSTR <&item>,??_pos1+1

    ??_result = 0
    ??_cntr = 0
    REPEAT ??_glbl_cntr
        ;/* compare recorded types */
        IF (type ??_object) EQ (type @CatStr(<glbl_class_name_>,%??_cntr))
            ??_result = 1 ; ??_object is a structure
            EXITM
        ELSEIF (type ??_object) EQ (type @CatStr(<glbl_class_ptrType_>,%??_cntr))
            ??_result = 2 ; ??_object is a pointer to structure
            EXITM
        ENDIF
        ??_cntr = ??_cntr + 1
    ENDM
   
    IFE ??_result
        .err <unkown class>
    ELSEIF ??_result EQ 1
        IF (opattr value) AND 1010y
            ;/* value is a memory operator */
            mov eax,value
        %   mov &??_object&.&??_member&,eax
        ELSE
            ;/* value is an immediate expression or register */
        %   mov &??_object&.&??_member&,value
        ENDIF
    ELSEIF ??_result EQ 2
        ??_class_name TEXTEQU @CatStr(<glbl_class_name_>,%??_cntr)
        mov ecx,??_object
        IF (opattr value) AND 1010y
            mov eax,value
        %   mov [ecx].&??_class_name&.&??_member&,eax
        ELSE
        %   mov [ecx].&??_class_name&.&??_member&,value
        ENDIF
    ENDIF
endm

class Item
        hName               dd     ?     
        hParent             dd     ?         
        hPrevItem           dd     ?         
        hNextItem           dd     ?         
        hObject             dd     ?         
end_class

; example usage
.data?
    item PItem ?        ; ptr to Item structure
    item2 Item <>       ; Item structure
.code

main proc
   
   
    set item:hName,123
    set item2:hObject,edx
   
    mov ebx,item
    ;/* some syntax variations accepted by MASM */
    set PItem ptr ebx:hParent,edx
    set (Item ptr [ebx]):hParent,123
    set [PItem ptr ebx]:hParent,456
   
   
    exit
main endp

MREAL macros - when you need floating point arithmetic while assembling!

mabdelouahab

Thank you very much qWord
Always provide us with ideas
so
Through your help,
Do not I change the CLASS MACRO, and no other ...
I managed to reach the following method SET
To create a new object case:

    SET hNew = NEW TestO
or:
    SET hNew = NEW TestO,14 ; If TESTO.INIT = Args

To give a value to a variable

    SET hNew.A = 88
    SET hNew.A = eax

To a function call
    SET hNew.First,235,333

All this without a name StructName
..

SET macro  Str_:req, Args:vararg
??_posEQ INSTR <&Str_>,<=>
    IFE ??_posEQ
??_posDot INSTR 1, <&Str_>,<.> ;<=================== INVOKE PROC
IFE  ??_posDot 
        .err <syntax error: missing  .  >
    ELSE
    ??_object SUBSTR <&Str_>,1,??_posDot-1
    ??_Proc SUBSTR <&Str_>,??_posDot+1
% IFNDEF @CatStr(??_object)
    % .err <syntax error: &??_object& indefined >
    % ELSEIFNDEF  @CatStr(<Class_Of_>,&??_object)  
    % .err < Object not create by " SET NEW" >
    ELSE
Class__ TEXTEQU @CatStr(<Class_Of_>,&??_object)
    % @CatStr(<mov ecx ,>, %??_object)
    % invoke ( &Class__&  PTR [ecx]).&??_Proc&,&??_object&,Args
    ENDIF
    ENDIF 
    ELSE
    ??_posNEW INSTR <&Str_>,< NEW > ;<=================== SET VALUE
    IFE ??_posNEW
??_posDot INSTR 1, <&Str_>,<.>
IF   (??_posDot  eq 0) or  (??_posDot  gt ??_posEQ)
        .err <syntax error: missing  .  >
    ELSE
    ??_object SUBSTR <&Str_>,1,??_posDot-1
    ??_MEMBER SUBSTR <&Str_>,??_posDot+1,??_posEQ-??_posDot-1
      ??_Value    SUBSTR <&Str_>,??_posEQ + 1
% IFNDEF @CatStr(??_object)
    % .err <syntax error: &??_object& indefined >
    % ELSEIFNDEF  @CatStr(<Class_Of_>,&??_object)  
    % .err < Object not create by " SET NEW" >
    ELSE
Class__ TEXTEQU @CatStr(<Class_Of_>,&??_object)
    % mov ecx,&??_object&
    % mov eax, &??_Value&
    % mov ( Class__  PTR [ecx]).&??_MEMBER&, eax
    ENDIF
    ENDIF 
    ELSE
    ??_object SUBSTR <&Str_>,1,??_posEQ-1 ;<=================== NEW Object
    ??_Class  SUBSTR <&Str_>,??_posNEW+4
    % IFNDEF @CatStr(??_Class)
    % .err <syntax error: &??_Class& indefined >
    % ELSEIFNDEF  @CatStr(??_object)  
    % .err <syntax error:  &??_object& indefined >
    ELSE
    % Class_Of_&??_object& TEXTEQU <&??_Class&>
  IFNB <Args>
    % mov eax,$NEW(%??_Class,Args)
  ELSE
    % mov eax,$NEW(%??_Class)
  ENDIF
    % mov &??_object&,eax
    ENDIF
    ENDIF
    ENDIF
endm


Thank you all

mabdelouahab

Hello all
I was able to add GET macro, but I have a small problem ;)
If it is used:
    GET eax =hNew.A
, the result is: OK
But if it is used,
    GET eax   =   hNew.A
, the result is: error
What a way to remove the SPACE, to avoid this


GET macro  Str_:req, Args:vararg
??_posEQ INSTR <&Str_>,<=>
    IFE ??_posEQ
    .err <syntax error: missing  =  >
    ELSE
??_posDot INSTR 1, <&Str_>,<.>
IF   (??_posDot  eq 0) ;or  (??_posDot  lt ??_posEQ)
        .err <syntax error: missing  .  >
    ELSE
    ??_object SUBSTR <&Str_>,??_posEQ+1,??_posDot-??_posEQ-1
    ??_MEMBER SUBSTR <&Str_>,??_posDot+1
      ??_Value    SUBSTR <&Str_>,1,??_posEQ + -1
     
% IFNDEF @CatStr(??_object)
    % .err <syntax error: &??_object& indefined >
    % ELSEIFNDEF  @CatStr(<Class_Of_>,&??_object)  
    % .err < Object not create by " SET NEW" >
    ELSE
Class__ TEXTEQU @CatStr(<Class_Of_>,&??_object)
    % mov ecx,&??_object&
    % mov eax,( Class__  PTR [ecx]).&??_MEMBER&
    ENDIF
    ENDIF 
    ENDIF
endm

But for SET macro succeeded with me.

    SET hNew = NEW TestO,14
    SET  hNew.A = 332
    GET eax =hNew.A
    fn MessageBox,0,str$(eax),0,MB_OK

    SET hNew.First,235,333


I want only to add CHECK
If I used with the CLASS or just Struct , the difference between the two, is that CLASS, a INIT call startup
How can I know that in the struct, there is a INIT proc
I want to use IFDEF, but give me the same result
IFDEF hNew.init <== OK, IFDEF hNEW.H0254555454__ <== OK

When I could make sure INIT Proc
I can use with CLASS (For Ex: TestO)

mov eax,$NEW(TestO)

and With simple STRUCT use (For ex: RECT)

invoke GetProcessHeap
invoke HeapAlloc, eax, NULL, SIZEOF RECT
mov hNew,eax

Here is SET macro

SET macro  Str_:req, Args:vararg
??_posEQ INSTR <&Str_>,<=>
    IFE ??_posEQ
??_posDot INSTR 1, <&Str_>,<.> ;<=================== INVOKE PROC
IFE  ??_posDot 
        .err <syntax error: missing  .  >
    ELSE
    ??_object SUBSTR <&Str_>,1,??_posDot-1
    ??_Proc SUBSTR <&Str_>,??_posDot+1
% IFNDEF @CatStr(??_object)
    % .err <syntax error: &??_object& indefined >
    % ELSEIFNDEF  @CatStr(<Class_Of_>,&??_object)  
    % .err < Object not create by " SET NEW" >
    ELSE
Class__ TEXTEQU @CatStr(<Class_Of_>,&??_object)
    % @CatStr(<mov ecx ,>, %??_object)
    % invoke ( &Class__&  PTR [ecx]).&??_Proc&,&??_object&,Args
    ENDIF
    ENDIF 
    ELSE
    ??_posNEW INSTR <&Str_>,< NEW > ;<=================== SET VALUE
    IFE ??_posNEW
??_posDot INSTR 1, <&Str_>,<.>
IF   (??_posDot  eq 0) or  (??_posDot  gt ??_posEQ)
        .err <syntax error: missing  .  >
    ELSE
    ??_object SUBSTR <&Str_>,1,??_posDot-1
    ??_MEMBER SUBSTR <&Str_>,??_posDot+1,??_posEQ-??_posDot-1
      ??_Value    SUBSTR <&Str_>,??_posEQ + 1
% IFNDEF @CatStr(??_object)
    % .err <syntax error: &??_object& indefined >
    % ELSEIFNDEF  @CatStr(<Class_Of_>,&??_object)  
    % .err < Object not create by " SET NEW" >
    ELSE
Class__ TEXTEQU @CatStr(<Class_Of_>,&??_object)
    % mov ecx,&??_object&
    % mov eax, &??_Value&
    % mov ( Class__  PTR [ecx]).&??_MEMBER&, eax
    ENDIF
    ENDIF 
    ELSE
    ??_object SUBSTR <&Str_>,1,??_posEQ-1 ;<=================== NEW Object
    ??_Class  SUBSTR <&Str_>,??_posNEW+4
    % IFNDEF @CatStr(??_Class)
    % .err <syntax error: &??_Class& indefined >
    % ELSEIFNDEF  @CatStr(??_object)  
    % .err <syntax error:  &??_object& indefined >
    ELSE
    % Class_Of_&??_object& TEXTEQU <&??_Class&>
  IFNB <Args>
    % mov eax,$NEW(%??_Class,Args)
  ELSE
    % mov eax,$NEW(%??_Class)
  ENDIF
    % mov &??_object&,eax
    ENDIF
    ENDIF
    ENDIF
endm


jj2007

Hi mabdelouahab,

No offense, but perhaps you could use the LOCAL keyword instead of all these ?? labels? Your macros would become much more readable...

Also, the ampersand as in <&Str_> is not necessary - <Str_> does the same. Use it only in situations like print "The object &Str_ is undefined"

I have tried to reproduce your problem, but it seems to work with and without spaces:

include \masm32\include\masm32rt.inc
include SetMac.asm

GET macro Str_:req, Args:vararg
LOCAL ins, PosDot, obj, member, val
  ins INSTR <Str_>, <=>
  IFE ins
        .err <syntax error: missing = >

  ELSE
        PosDot INSTR <Str_>, <.>
        IFE PosDot
                .err <syntax error: missing . >

        ELSE
                % IFNDEF @SubStr(<Str_>, ins+1, PosDot-ins-1)
                         % echo ## syntax error: [@SubStr(<Str_>, ins+1, PosDot-ins-1)] is undefined, sorry ##
                        .err

                 % ELSEIFNDEF @CatStr(<Class_Of_>, &obj)
                         % echo ## [@SubStr(<Str_>, ins+1, PosDot-ins-1)] object not created by " SET NEW" ##
                        .err

                ELSE
                        member SUBSTR <Str_>, PosDot+1
                        val SUBSTR <Str_>, 1, ins + -1        ; should be plus 1, i.e. after "="?
                        Class__ TEXTEQU @CatStr(<Class_Of_>,&obj)
                        mov ecx, obj
                        ; mov eax, ( Class__ PTR [ecx]). member
                        mov eax, val
                        mov ( Class__ PTR [ecx]).member, eax
                ENDIF
        ENDIF
  ENDIF
ENDM

MyStruct STRUCT
A        dd ?
B        dd ?
MyStruct ENDS

.data?
hNew        MyStruct <>

.code
if 0
        The three GET calls generate these error messages:
        ## syntax error: [hUndefined] is undefined, sorry ##
        ## [hNew] object not created by " SET NEW" ##
        ## [   hNew] object not created by " SET NEW" ##
endif

start:
        GET eax =hUndefined.A
        GET eax =hNew.A
        GET eax   =   hNew.A
        exit

end start


Code attached.