I have tried using structures in the past and have failed; so i just gave up. I understand that when the API is called it is filled in or the data is used in some way. Is the point of a structure just a quicker way of doing a whole load or parameters? I have got by in the past by just avoiding API's that use structures. This is getting annoying so i thought i might as well try and understand them.
if anyone has any tutorials or examples of how to use a structure (that is explained) then that would be very useful to me.
thanks in advance. skud.
Dont get hung up on structures.. they are not a hassle at all...
The point of structures is yes, to localize alot of data under one premise (or tag name). However, they are still a bit abstract from ASM programming, which is why i suspect you have been having problems in the past. They are simply a template to help organize data, but they are NOT data in themselves. I better go to examples at this point :)
I could say..
Point1_x dd 0
Point1_y dd 0
Point2_x dd 0
Point2_y dd 0 etc. etc.
And in using them i would have to reference each member directly:
mov eax, Point2_y
or
lea ebx, Point1_x
mov eax, ; 12'th byte after the first as defined above
This is ok, but it would be easier to use data if they are grouped together as one type of data:
My_Point struc
x dd ?
y dd ?
My_Point ends
and in .data
Point1 My_Point <0,0> ; initialize x,y to 0,0
Point2 My_Point <2,0> ; initialize x,y to 2,0
or in .data?
Point3 My_Point <> ; uninitialized data ,?>
Point4 My_Point <>
The in the data segments, the stucture is used as a template to allocate the amount of memory (dd's) in the order they appear in the template. This is why i say stucts are NOT data in themselves. Now, if i were to disassemble the data segment of this one or the pervious above, they data would be in the same order (point1's x data, point1's y data, point2's x data, point2's y data). The difference is by simply telling MASM this will by a structured define, you can skip the redundancy of typing it all out in order.
The code to use these are now:
mov eax, Point2.y
; y is the structure member that masm used to determin the offset
; this is the same as
; lea ebx, Point2
; mov eax, ; 4 bytes after the first (y data)
One of the benifits is the fact the data HAS to be grouped together as prescibed in the structure template.. my origional example of separated data IS grouped together, but doesnt has to be. It could be a random like such:
Point1_x dd 0
MyFlag dd 0
Point1_y dd 0
Point2_x dd 0
IsOn dd 0
Point2_y dd 0
If i were asked to have the address to a point in this setup, you couldnt do it, because MyFlag is inbetween Point1_x and Point1_y:
invoke SomeFunct, addr Point1_x
will be used as:
mov ebx, Point1_x ; base address of a point
mov eax, ; get the x data
mov eax, ; get the y data (assumed 4 bytes after the base)
The problem here is, 4 bytes after the first is MyFlag!!!! Using structures insures this problem is always taken care of (assuming the structure is defined in the correct order).
Taking this a step further, you can also NEST structures to build more complex bounded data:
My_Circle sturct
Center My_Point <>
Radius dd ?
My_Circle ends
Colored_Circle struct
Circle My_Circle <>
Color dd ?
Colored_Circle ends
By simple defining in .data?
RGB_Circle Colored_Circle <>
i have allocated memory in the data segment in this order:
RGB_Circle: 4 bytes, Referenced as (this).Circle.Center.x
+4 bytes, Referenced as (this).Circle.Center.y
+4 bytes, Referenced as (this).Circle.Raduis
+4 bytes, Referenced as (this).Color
NOTE: (this) refers to the name of the defined data for 'this' structure type,
in this case it would be RGB_Circle.Circle.Center.x
ALSO NOTE: the 'SIZEOF Colored_Circle' command would return the above
evaluation = 16 bytes.
As a final thought, the use of stuctures are also advantageous when dealin with them as pointer, by simply passing a simple 4 byte pointer, it can be used to directly reference (in the above case) 16 bytes of data. (this speeds up your function calling, because less is being pushed on the stack).
; my fuction used a colored circle...
My_Fuction proc lpColored
I think this kind of reply's should be saved somewhere for further reference...
Hiro? Are you listening?
Good work NaN !
Everything Nan said he said well and true. However, a few thoughts on using assume.
We all know, when you ASSUME something, you make an ASS of U and ME. Trite, but still true.
If you assume a register, then forget to unassume it, you can get strange results. Or, the assume could be so far from the line that needs it the meaning is left unclear (to the human reading the code). I'm not a big fan of weird "action at a distance" operators like this.
I am a devoted user of structures, they are just so handy. I used to use the syntax Nan stated, until I found a slightly more compace (but just as readable) form MASM accepts:
mov ebx, lpColoredCircle
mov eax, (Colored_Circle PTR ).Circle.Center.x ;get x
mov edx, (Colored_Circle PTR ).Circle.Center.y ;get y
mov esi, (Colored_Circle PTR ).Radius ;get Rad
mov edi, (Colored_Circle PTR ).Color ;get Color
may also be stated as:
mov ebx, lpColoredCircle
mov eax, .Colored_Circle.Circle.Center.x ;get x
mov edx, .Colored_Circle.Circle.Center.y ;get y
mov esi, .Colored_Circle.Radius ;get Rad
mov edi, .Colored_Circle.Color ;get Color
To my eyes, either is just as clear in it's meaning, but the 2nd is slightly less typing.skud,
Conceptually a structure is very similar to an array in that the
data that they can hold is sequential in memory. Where they differ
is that you can have different size pieces of data in a structure.
Much of Windows and especially NT4 and Win2k was written by programmers
with a VAX/VMS background so you get different code than traditional
stack based parameters used regularly.
Structures can be used in a number of different ways, when you create a
window, you first allocate a WNDCLASSEX structure, fill it with the attributes
that you need and then use that structure when you register the
window class.
Another technique widely used is to allocate an empty structure
and call a function that fills it for you.
LOCAL Rct:RECT
This allocates a rectangle structure on the stack in a procedure.
You then make an API call like GetWindowRect() that fills the RECT
structure with the dimensions of the window. You access the info
returned by using Rct.left, Rct.top etc ... and they are treated
as memory operands in code.
NAN has given you some good examples of how structures are used and
how they are often nested. The trick with nested structures is to
go backwards to see what you need to allocate and what structures
need to be filled in with values first if needed.
Ernie has shown the difference between two methods of handling
structures passed as addresses, the ASSUME syntax is well suited
for block structure handling where the other method of individually
type casting the members is more flexible in single instances.
Once you get the feel of how they work, you will find them very
useful in the code you write.
Regards,
hutch@pbq.com.au
Is there a way to allocate a structure with,let's say GlobalAlloc?
The idea of a structure is purely for us the programmer.
All the computer sees is data, for example:
MyStruct STRUCT
a DWORD ?
b BYTE ?
c WORD ?
d BYTE 3 DUP (?)
MyStruct ENDS
As far as memory allocation is concerned this is 10 bytes, nothing else. To the assembler, it is also a method of formating accesses to that data, and it is possible to apply that formating to any piece of memory.
This allows the following code:
FourLetterWord STRUCT
FirstLetter BYTE ?
SecondLetter BYTE ?
ThirdLetter BYTE ?
FourthLetter BYTE ?
NullTerminator BYTE ?
FourLetterWord ENDS
.data
Word1 db "spam",0
Word2 db "clam",0
.code
start:
mov edx, ADDR Word1
mov (FourLetterWord PTR ).FirstLetter, 'c'
invoke ExitProcess, 0
end start
Although we declared Word1 as a string of bytes, we can apply the formating of the FourLetterWord structure to it.
So in the case of GlobalAlloc, you need to do something like:
invoke GlobalAlloc, ACCESS_TYPE, SIZEOF MyStruct * number_needed
This will create enough data to apply the format of MyStruct without causing errors.
MirnoExactly, your simply allocating a bunch of bytes.. but if you keep control of all your allocated bytes of data (ie, add proper offsets to your global data pointer), then you can use the above methods with pointers as Ernie outlined.
Structures are simply masks or templates to make your memory 'look' organized... as Mirno demonstrates (good example BTW).
I could still allocate 5 bytes of heap memory, and use my above structure (size 16 bytes templated) to reference it! The catch is, i would only be able to access:
mov ebx, GlobalDataPointer
mov eax, (Colored_Circle PTR ).Cricle.Center.x
Because this is the first 4 bytes templated by my structure. To try to go to 'y' would violate the heap space alocated, since in my example i have only allocated 5 bytes in all. This is why Mirno suggests 'N * sizeof Colored_Circle' where N is Integers > 1. That way you will always have just enough data, to imply an array of N Colored_Cirlce structures, and know you have enough data set asside for each memeber!
NaN
ok. thanks for all the response :)
i understand all this but what i dont get now is how to move any data to the structure.
how does it know which sub-section part of the structure to add the data to?
an example of how to do this would be great.
btw; i am trying to use the sockaddr_in STRUCT
with the connect API (winsock)
thanks again; skud.
Ok last thought...
If i wrote an API function, with one of the parameters being "lpSOMETHING: DWORD" tp which it does this:
AFunction proc lpSOMETHING:DWORD
push ebx
mov ebx, lpSOMETHING
mov , eax
mov , ch
mov , dx
mov , esi
mov , cl
pop ebx
ret
AFunction endp
The lpSOMETHING (which is just an address to memory) will end up having memory filled with "eax, ch, dx, esi, cl" sequentially in order. Now, lets say i wanted to better access that. Then using a structure (DESIGNED IN SEQUETIAL ORDER TO HOW THE MEMORY IS PARTITIONED (4 bytes)(1 BYTE)(2 BYTES)(4 BTYES)(1 BYTE) ) will allow me to access the modified memory locations individually.
DONTCAREFORANAME STUCT
Name1 DWORD ?
Name2 BTYE ?
Name3 WORD ?
Name4 DWORD ?
Name5 BTYE ?
DONTCAREFORANAME STUCT
So, if i use this API in a program like so:
.data?
SOMEMEM BYTE 12 DUP (?) ; api modifies 12 bytes in all
.code
invoke AFunction, addr SOMEMEM
lea ebx, SOMEMEM
mov eax,
; eax has the value of ESI that AFunction had
OR, I COULD USE A STUCT
.code
invoke AFunction, addr SOMEMEM
lea ebx, SOMEMEM
mov eax, (DONTCAREFORANAME PTR ).Name4
Since the stucture KNOWS that Name4 is defined 7 bytes from the first entry.
BOTTOM LINE, API's that fill structures, are designed FOR the stuctures, not the other way around.
NaNThanks NaN and mirno that example "spam" clarified it for me.
I always thought that the struct 'tags' were included in the struct.