News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Declarations

Started by alanrr, September 20, 2007, 07:52:19 AM

Previous topic - Next topic

alanrr

Hi,

I've only just started looking at Assembly for the first time today so please forgive the basic nature of my question...

I am trying to work through Bill Aitken's great tutorials on the http://www.easycoder.org site but am wanting to use the MASM rather than goAsm which the tutorial is written for.

In the second example of the Tutorial Bill includes the following declaration in the .Data section

clientRect      RECT

What is the equivalent of this in MASM as I get a "syntax error in structure" message if I include it.  I have been able to get around this by creating a local variable specific to a given subroutine using

Local clientRect:RECT

but I haven't been able to work out what the equivalent syntax is for the .Data section.

Thanks

Alan

BogdanOntanu

Well, If you want to use MASM then I sugeest that you take the time an properly learn MASM syntax ...
Otherwise you will be frustrated by incomprehensible problems although "it used to work yesterday"...

A data definition in MASM is made like this:

<variable_name> <type_name> <initial value>

for example:


my_var dd 0


"my_var" is variable name
"dd" is type name ( Define DWORD, 32 bits unsigned integer)
"0" is the initial value

In MASM structures get automatically promoted as "types" and then:

in a similar way in your statement:

my_rect RECT


... misses an initial value for the variable

one of the right versions would be:

my_rect RECT <?>


I am sure you will seek what "<>" and "?" initializers means in MASM documentation...
IF not you might make it work for now... but you will have problems in the future ;)


Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

alanrr

Thanks!  I'd tried ? but hadn't realized I needed <> as well.  I had tried to trawl through the MASM docs but when you don't know what anything is called it's hard to find what you're looking for!  In fact, even knowing what I'm looking for I still haven't been able to find it in the MASM Reference file I have!  I'll keep digging.

Alan

TNick

Hello and welcome!

If you want to start learning Assembly for Windows using MASM, I would say that a great place to start are  Iczelion's Turorials (in Win32 Assembly section). And you may ask any question here, but you will have a better chance to get an answer if you will prove that you have done your search before posting.

Best Regards,
Nick

Vortex


Ramon Sala

Hi alanrr,

Welcome and thanks for using Easy Code.

I think your question has been widely answered. You may also have a look at the Easy Code tutorials (a dedicated child board in this subforum).

Regards,

Ramon
Greetings from Catalonia

alanrr

Thanks for the links guys.  I feel a bit like I'm drowning in concepts and jargon however so can anyone help me get a few concepts straight?  I'm having to think of things at a much lower level than my VB/C# programming demands and am getting a little confused with handles, pointers etc.  I think my main problem is knowing when I am dealing with data and when with a memory address for the data.

Here are some example I could really do with a hand in clearing up...

having defined clientRect as follows

clientRect   RECT <?>

then the statement

Invoke GetClientRect, hWnd, Addr clientRect

calls the GetClientRect API with the hWnd of my window (as provided by the hWnd parameter of wndMainProcedure created by easycode) and asks it to store the results in the location I have created to hold the clientRect data.

I understand (I hope this is right) that the Addr clientRect statement returns the address of the memory location where the clientRect variable has been stored (I believe this is called a pointer). 

I've realised, however, that I'm not exactly sure what hWnd is.  When using it in higher languages I've just thought "yeah it's a handle to a window" but what does that actually mean?  Is the value in hWnd a pointer as well or is it the data contained in the handle structure itself?  I've noticed from the tutorial that I am working through that goAsm requires this to be surrounded by square brackets.  What do these signify?

In a similar manner the tutorial includes the following routing written for assembly by goAsm.  It is hooked to the resize event of a window and replaces the windows caption the the current right and bottom values for the windows size in the format "right, left".

clientDimensions   DB 11 Dup(0) ; from .Data

   OnResize:

      ; Get the event loop data (to get hWnd)
      UseData winMainProcedure

      ; Get the dimensions of winMain's client rectangle
      Invoke GetClientRect, [hWnd], Addr clientRect

      ; Convert the width into a string and store it in clientDimensions
      Invoke String, [clientRect.right], Addr clientDimensions, ecDecimal

      ; Append a comma and space to the string "clientDimensions"
      Mov Ebx, ", "
      Mov [clientDimensions + Eax], Ebx

      ; Calculate where in the string the height should be stored
      Add Eax, Addr clientDimensions + 2

      ; Convert the width into a string and append it to clientDimensions
      Invoke String, [clientRect.bottom], Eax, ecDecimal

      ; Now set the caption of winMain to clientDimensions
      Invoke SetText, [hWnd], Addr clientDimensions

      ; All done - return to the main event loop
      Return (TRUE)
   EndU
   ; End OnResize



Once we have the window's dimensions stored in to clientRect we call

Invoke String, [clientRect.right], Addr clientDimensions, ecDecimal

Now looking at the easycode help it states that the first parameter is the number to be converted in to a string.  This suggests that the square brackets in goAsm indicate that we are refering to data rather than a memory address, is that correct?  How does MASM know what we want to refer to?  Does it assume data unless we use the Addr option?  Alternatively, what would clientRect.right (without the brackets) return in goASM?  My thinking has definite holes in it though because if in goAsm [] means data and no [] means address, why would you need the Addr command?  I'm really totally confused at this point  :red

The next statement,

Mov Ebx, ", "

seems to move the string ", " to the EBX register?  Does EBX actually hold the string or just a pointer to it?

The next line

Mov [clientDimensions + Eax], Ebx

won't compile under MASM and I'm not sure why.  I assume it's trying to calculate a memory location for the start of the clientDimensions variable and then add Eax to it (which holds the number of bytes shifted by Invoke String) before finally copying the string ", " to that calculated address but I'm not sure how it works, why we didn't need to use Addr clientDimensions and how to get it to work under MASM.  Why is the whole thing surrounded in square brackets?

Sorry for being so ignorant but any help would be greatly appreciated as at the moment I just seem to be getting more confused the more I read  :red

Thanks

Alan

BogdanOntanu

It is not about "reading"... instead it is all about "understanding"...

Quote

having defined clientRect as follows

clientRect   RECT <?>

then the statement
Invoke GetClientRect, hWnd, Addr clientRect

calls the GetClientRect API with the hWnd of my window (as provided by the hWnd parameter of wndMainProcedure created by easycode) and asks it to store the results in the location I have created to hold the clientRect data.


Slightly wrong...

The ADDR keyword / operator is needed when Client_Rect is defined as a LOCAL variable in a procedure and used in an INVOKE high level construct.

That is because the location is not known until runtime... and even then in multiple invocations of the upper enclosing procedure it could be that the STACK is different and because of this Client_Rect end up at different addresses every now and then.

Hence the ADDR is a helper for INVOKE statements.

Usually MASM will translate this to LEA EAX,Client_Rect and use this EAX value instead of ADDR Client_Rect when performing the invoke (aka the push xxx push yyy push zzz Call API kind of thing ...) This can be of help but also dangerous since one of your precious register is made "dirty" by ADDR and invoke and you do not know or understand this.

IF the Client_Rect is defined in .data section then it's memory address is well known at compile time and the keyword / operator OFFSET can be used to insert this address in code. Hence the "correct" version would be OFFSET if the variable is global or ADDR if the variable is LOCAL to a specific procedure and used in INVOKE.

This is why I consider that beginners should NOT jump into '"easy" IDE's and using "easy" macro's and features like INVOKE when they do start learning.

It is far more better to start by using Notepad and doing the PROC and INVOKE "by hand" for a few 100 times... After that you shall know and understand the difference between global and local variables and even more you will appreciate the "EASY CODE" part that an IDE does for you and the easy part that INVOKE, PROC, LOCAL and other MASM friends perform for you...  BUT if you use them directly (without understanding first) then you will "appreciate" the confusion and problems that appear at every corner...

... but beginners never listen and always "know better" how and what they should learn ... so let us return to CODE:

Quote
I've realised, however, that I'm not exactly sure what hWnd is.  When using it in higher languages I've just thought "yeah it's a handle to a window" but what does that actually mean?  Is the value in hWnd a pointer as well or is it the data contained in the handle structure itself?  I've noticed from the tutorial that I am working through that goAsm requires this to be surrounded by square brackets.  What do these signify?

"hwnd" is the name given for a memory location where the value of the window handle will be stored.

As discussed above this location could be LOCAL and on STACK and hence movable and subject to ADDR or it could be global and thus kind of fixed and subject to OFFSET issues.

Apparently "hwnd" is not a structure, neither a pointer, it is merely a simple DWORD that will contain a value. But you might want to send a pointer to it as a parameter to some functions.

The value to be stored at "hwnd" location is decided by the OS and we can do nothing to disagree about it... however we can sometimes place "hwnd" where we like...unless...

Unless the OS already decided that "hwnd" will be a PARAMETER to one of the CALLBACKs we have to provide. In this case our hands are tied and we have to obey the relative location of "hwnd" on stack according to the calling conventions of the callback... (STDCALL comes to my hands...) and the standard imposed by the API description.


In other assemblers:


mov eax, [hwnd]

means move to EAX register the content (data) at address that we like to name "hwnd"
and

mov eax,offset hwnd

... means: move to EAX register the addres of that variable that we like to name "hwnd"

Now this will result in the programmer "loosing" many time because of writing: "[<something>]" and "offset <something>" Apparently the biggest concern of programmers is typing less :P (like a typewritter).

Then MASM does try to "help" in it's own way, and whenever you write:

mov eax,hwnd


MASM will understand it as:

mov eax,[hwnd]

and you do not have to type in the brackets (but you can for added confusion)

However if you want the address of "hwnd" you will have to type:

mov eax,offset hwnd


Mixing one assembler with the other (MASM with GoASM and FASM and NASM and ..etc) is NOT a very good idea because assemblers have similar but "slightly" different syntax. This "slightly" can be very very confusing because of "similar"...if you know what I mean :P

My advise would be to stick with one assembler until you have understand it profoundly and then check others until you recognize the differences and evaluate the advantages/disadvantages. Mixing tutorials is priceless...

Also learning other programming languages first (lke VB, C C++ C#) can be very damaging to your ASM knowledge. You will have to empty your mind from other language's "concepts" first... A kind of ZEN: empty your mind.

Quote
My thinking has definite holes in it though because if in goAsm [] means data and no [] means address, why would you need the Addr command?  I'm really totally confused at this point

Because sometimes the variable is located on STACK and we do not know the position until the run-time. Hence we do need LEA or ADDR helper. You send to another API function the current address of your local variable on your PROCEDURE and expect it to write something in there.

How convenient and how dangerous in the same time!

And remember that every assembler does things slightly different but similar. To be on ironical side: I am writing my own assembler that performs actions in a slightly different but similar way.

Quote
Mov Ebx, ", "

seems to move the string ", " to the EBX register?  Does EBX actually hold the string or just a pointer to it?

Hmmmm, well, EBX is 4 bytes long so it can hold the data for a string of maximum 4 ASCII characters OR it can hold a pointer toward a string of any length (if the string is null terminated).

In this case apparently EBX holds the data for the string ",<space>"


Quote
The next line

Mov [clientDimensions + Eax], Ebx

won't compile under MASM and I'm not sure why.  I assume it's trying to calculate a memory location for the start of the clientDimensions variable and then add Eax to it (which holds the number of bytes shifted by Invoke String) before finally copying the string ", " to that calculated address but I'm not sure how it works, why we didn't need to use Addr clientDimensions and how to get it to work under MASM.  Why is the whole thing surrounded in square brackets?

As much as you and MASM try you can not avoid square brackets. Complex address expressions using [base + scale*index + constant] do require the square brackets anyway. But you did read about that in INTEL manuals and in MASM manuals ... or did you not?

Things like this:

mov eax,[esi + my_structure.stru_member1 + 1234h]
or
mov eax,[esi +4*ecx + 2735h]


And if you look carefully you will notice that the expression EAX + "Client_Dimensions" does fall into this category.

ADDR is mostly needed to inform INVOKE about a need for LEA.

MASM can access LOCAL variables directly but the reader should try and learn how this is done in a PROC. It is something about stack frames and calling conventions and [EBP+8]...

Besides "making the thing work" is useless ... FIRST the truth seeker must understand and make his own work... sometimes with bare hands and without "easy xxx" 

And only LATER things will fall into places and you will be able to make things work even against all ods ... otherwise it will work today but the pupil will be back with more and more questions... and more and more unsolved problems...

And things that "used to work yesterday" will stop working today for no apparent reason.
But trust me ... there is always a a reason.
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

alanrr

Thanks for taking the time for such a detailed reply BogdanOntanu.  I think I have a better understanding of Addr and Offset now.

I will try and find a simple tutorial to guide me through the (non ide) basics!  I initially settled on MASM as the code looked closer to what I was use to with .IF blocks etc.  Unfortunatley the nice introductory tutorial I found was for goASM, hence my attempts to try and convert between the 2.  I will see if I can find a nice simple MASM tutorial but so far I have been out of luck!

Thanks again

MichaelW

From Iczelion's tutorial:

"You can think of a handle as a number that represents the window you're referrring to. Its value is not important to you. You only remember that it represents the window. When you want to do anything with the window, you must refer to it by its handle."

From the PSDK:

"After creating a window, the creation function returns a window handle that uniquely identifies the window. A window handle has the HWND data type; an application must use this type when declaring a variable that holds a window handle. An application uses this handle in other functions to direct their actions to the window."

Handles are used by Windows to identify many objects other than windows, and at least for the vast majority of them the same concepts apply. For some examples, scroll down to the data types that start with "H":

Windows Data Types

For learning how to call a function a good place to start is the Microsoft documentation, for example:

GetClientRect

eschew obfuscation