Struct Operations:

 A structure is made up of members that have a specified data size. In a commonly used structure RECT, you have four DWORD size members.
    RECT STRUCT
      left    DWORD  ?
      top     DWORD  ?
      right   DWORD  ?
      bottom  DWORD  ?
    RECT ENDS

In most instances, the specifier is ? which means the member is not initialised to a value.

 

1: If it is allocated in the .DATA section, it can be initialised to preset values but if it is allocated on the stack as a LOCAL value within a procedure, the values have to be coded into the structure.
    LOCAL Rct :RECT

    ; code
    mov Rct.left,   1
    mov Rct.top,    2
    mov Rct.right,  3
    mov Rct.bottom, 4

It should be noted that a structure member is a memory operand so you cannot directly move another memory operand into it, you must either use a register to copy it or the stack mnemonics, push / pop.

 

Then, you can refer to the filled structure as a single unit with ADDR Rct in an invoke directive procedure call. If an API call requires the address of a structure, you fill the structure with the values you require and call the API,
          invoke APIcall,parameter1,parameter2,ADDR Rct

 

2: If you write a procedure where you want the values in a structure passed to it, you can pass the structure by using the structures data type in the procedure.

MyProc proc par1:DWORD,par2:DWORD,MyRect:RECT

Then:  mov eax, MyRect.left    ; copy first member into EAX

 

The individual members can then be accessed by their names in the procedure that receives the RECT as a parameter. You call the proc as follows,
          invoke MyProc,par1, par2, Rct

 

Nested structures
A method common to 32 bit Windows is the use of nested structures. MASM has a notation for dealing with this type of construction. If you needed a structure that had multiple structures in it,
    MyNestedStruct STRUCT
        item1 RECT  <>
        item2 POINT <>
    MyNestedStruct ENDS

This structure uses the above
RECT struct and the following POINT struct.
    POINT STRUCT
      x  DWORD ?
      y  DWORD ?
    POINT ENDS

There are six members in this structure, four from the RECT structure and two from the POINT structure. Allocated on the stack it looks like this,

    LOCAL mns:MyNestedStruct

The six members are,

    mns.item1.left
    mns.item1.top
    mns.item1.right
    mns.item1.bottom
    mns.item2.x
    mns.item2.y

 

 

Advanced Structure Handling
Increasingly, there is a need to be able to handle structures that are passed as an address and this type of code is becoming more common in Windows code design. MASM has a specialised notation to make this process a lot easier to handle.

If for example you needed to pass the adress of a RECT structure to a procedure, you would normally make the call in the following manner,

invoke MyFunction,ADDR Rct

At the procedure end of this function call you would normally have something like the following,

MyFunction proc lpRect:DWORD

With a simple structure like RECT you can address the seperate parameters manually by putting the address into a register and write to the location of each member,

    mov eax, lpRct

    mov [eax],    DWORD PTR 10
    mov [eax+4],  DWORD PTR 12
    mov [eax+8],  DWORD PTR 14
    mov [eax+12], DWORD PTR 16

This works fine but with more complex structures this becomes much harder to work with and far more error prone.

The alternative is to use a method that MASM has to address the individual members by using the ASSUME directive.

    ASSUME eax:PTR RECT
    mov eax, lpRct

    mov [eax].left,   10
    mov [eax].top,    12
    mov [eax].right,  14
    mov [eax].bottom, 16

    ASSUME eax:nothing

This works by telling the assembler that the EAX register is to be treated like a RECT structure. The ASSUME eax:nothing tells the assembler that the register is no longer being used in this manner.

There is an alternative notation where you can individually "type cast" each member.

    mov eax, lpRct

    mov (RECT PTR [eax]).left,   10
    mov (RECT PTR [eax]).top,    12
    mov (RECT PTR [eax]).right,  14
    mov (RECT PTR [eax]).bottom, 16

The advantages of these techniques is that they use the convenience and reliability of a structure so that you do not have to calculate the offsets of each member and it also uses the normal member names. The downside of these techniques is that they use a register which is not always a desirable consequence. If the register usage is a problem, you will need to allocate LOCAL variables and copy the data from each required member to the variables.