Stuck trying to convert Petzolds sysmets C code to Goasm

Started by Dogim, November 10, 2010, 03:25:08 PM

Previous topic - Next topic

Dogim

Hello my name is Dogcim,
I'm currently learning  assembly language pure as a hobby,  but seems that i,m doing it the hard way, but  it's very fun and challenging to do.
I don't  have  that much experience with higher programming languages, I have read some books about almost everything, eg basic, php, c / c + + java, and made some of the  examples in the books, but I found assembly language a bit more exciting and challenging.
Ok to make my introduction short, I am what they call a n00b.
I have a Petzold (heavy) book, purchased  this several years ago, and thought , let me try to convert the sysmet  program  into assembly, in this case a goasm version.
I did manage to get my hands on a MASM  version of the second sysmet version , the one where he introduces the scrollbar, so i cheated from that program. :red
The Problem I have is with the structure that I created for this program.

My problems are in fact, two things, how do you declare or create the structure in goasm, because the goasm manual give a good example of this, but i can't seem to get it working.
My second problem is i don't know how to traverse true the structure, because of the syntax difference..

I also came across a strange problem, when i declare my variables as local, i get no output on the screen, could someone  explain why ?? if it's not to much hassle.
I know i'm asking to much of you guys, but i,m against the wall here, and help is much appreciated.


This is how i declared  the structure
DATA SECTION

items STRUCT
iIndex dd 0
szLabel db 22 dup (?)
szDesc   db 42 dup (?)
  ENDS
sysmetrics  items <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels'>
  items <SM_CYSCREEN,              'SM_CYSCREEN' , 'Screen height in pixels'>
  items <SM_CXVSCROLL,             'SM_CXVSCROLL' , 'Vertical scroll width'>             
  items <SM_CYHSCROLL,   'SM_CYHSCROLL' , 'Horizontal scroll height'>
  items <SM_CYCAPTION,             'SM_CYCAPTION' , 'Caption bar height'>
cut-------



And my WM_PAINT looks like this.
.WMPAINT
cmp eax,WM_PAINT
jne >>.WMDESTROY
invoke BeginPaint,[hWnd],ADDR ps
mov [hdc],eax
mov esi,0

;for (i = 0 ; i < NUMLINES ; i++)
4_LOOP:
; TextOut (hdc, 0, cyChar * i,                     
    ;                    sysmetrics[i].szLabel,
    ;                    lstrlen (sysmetrics[i].szLabel)) ;
   
mov eax,esi ; esi as i counter
mov edx,0
mov ecx,[cyChar]
mul ecx ;cyChar * i
mov [cyChar_i],eax ; save it

invoke lstrlen,ADDR sysmetrics.szLabel
invoke TextOut,[hdc],0,[cyChar_i],ADDR sysmetrics.szLabel,eax

;--------------------------------------------------------------------
; TextOut (hdc, 22 * cxCaps, cyChar * i,     
;                        sysmetrics[i].szDesc,
;                        lstrlen (sysmetrics[i].szDesc)) ;

;               SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;

mov eax,[cxCaps]
mov edx,0
mov ecx,22
mul ecx ;cxCaps * 22
mov [cxCaps_22],eax ; save it for later use


invoke lstrlen,ADDR sysmetrics.szDesc     
invoke TextOut,[hdc],[cxCaps_22],[cyChar_i],ADDR sysmetrics.szDesc,eax
        invoke SetTextAlign,[hdc],TA_RIGHT |TA_TOP
;----------------------------------------------------------------------
       
;        TextOut (hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer,
;                        wsprintf (szBuffer, TEXT ("%5d"),
;                                  GetSystemMetrics (sysmetrics[i].iIndex))) ;;

;               SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
;

mov eax,[cxChar]
mov ecx,40
xor edx,edx
mul ecx ; 40 * cxChar

add eax,[cxCaps_22] ; 22 * cxCaps + 40 * cxChar

mov [Caps_Char],eax ;22*cxCaps+40   

invoke GetSystemMetrics,[sysmetrics.iIndex]
invoke wsprintf,ADDR szBuffer, ADDR szFMT,eax
invoke TextOut,[hdc],[Caps_Char],[cyChar_i],ADDR szBuffer,eax

inc esi ; increment COUNTER
cmp esi,NUMLINES
je >.END_LOOP

invoke SetTextAlign,[hdc],TA_LEFT | TA_TOP
;int3
jmp << 4_LOOP
.END_LOOP
        invoke EndPaint,[hWnd],ADDR ps



dedndave

welcome to the forum   :U
all the structures for system metrics should be pre-defined in windows.inc

Dogim

Thanks for that fast reply dedndave.
But could i get an example on how to use them in windows.inc.
Thank  you.

dedndave

i am familiar with MASM - not GoAsm
it should be pretty much compatible, though

i see that GetSystemMetrics does not fill a structure, as i had thought
let me try making a MASM example
give me a few minutes....

dedndave

right off, i see a few things

1) sysmetrics is not a structure - it refers only to the first element of what you want to be a structure

2) the total size of an items structure is 68 bytes
it might be nice to reduce it by 4 bytes, to simplify calculation of indexes into sysmetrics

3) i see that MS has added a few definitions that i do not see in windows.inc from the masm32 package
they are probably defined only for win7

give me a few more minutes...

Yuri

This seems to work. I used EDI to keep the address of the current items structure. Also, don't forget to balance the stack after you have used wsprintf, because it doesn't do that itself.

dedndave

ok - there are 2 ways you can go with this

1) define and access sysmetrics as an array, rather than as a structure
this is how you have currently defined the data, in a mannar of speaking
however, you are trying to access it as though it is a structure
again - it would simplify it if it were 64 bytes per element   :P
you can also simplify the define like this...
items STRUCT
 iIndex  dd 0
 szLabel db 22 dup (?)
 szDesc  db 42 dup (?)
     ENDS

sysmetrics items <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels'>,
                <SM_CYSCREEN,'SM_CYSCREEN','Screen height in pixels'>,
                <SM_CXVSCROLL,'SM_CXVSCROLL','Vertical scroll width'>,
                <SM_CYHSCROLL,'SM_CYHSCROLL','Horizontal scroll height'>,
                <SM_CYCAPTION,'SM_CYCAPTION','Caption bar height'>


2) define and access sysmetrics as a structure
the problem you are having is that you are trying to access elements in the sysmetrics array as though it were a structure
the way you are using it, that shouldn't be necessary
if you wanted to do that, each element in the sysmetrics structure should be named (item0, item1, item2, and so on)
but, let's do it that way as an example, so that you can see what i mean...
items STRUCT
 iIndex  dd 0
 szLabel db 22 dup (?)
 szDesc  db 42 dup (?)
     ENDS

;define the sysStruct type as 5 "items" structures

sysStruct STRUCT
 items 5 dup<>
         ENDS

;now, the sysmetrics structure is type sysStruct

sysmetrics sysStruct <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels',
                        SM_CYSCREEN,'SM_CYSCREEN','Screen height in pixels',
                        SM_CXVSCROLL,'SM_CXVSCROLL','Vertical scroll width',
                        SM_CYHSCROLL,'SM_CYHSCROLL','Horizontal scroll height',
                        SM_CYCAPTION,'SM_CYCAPTION','Caption bar height'>


at this point, not really much different from an array
but, if we want to access individual elements with the "label.lable.label" method...

sysStruct STRUCT
 item0 item <>
 item1 item <>
 item2 item <>
 item3 item <>
 item4 item <>
         ENDS

;now, the sysmetrics structure is type sysStruct

sysmetrics sysStruct <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels',
                        SM_CYSCREEN,'SM_CYSCREEN','Screen height in pixels',
                        SM_CXVSCROLL,'SM_CXVSCROLL','Vertical scroll width',
                        SM_CYHSCROLL,'SM_CYHSCROLL','Horizontal scroll height',
                        SM_CYCAPTION,'SM_CYCAPTION','Caption bar height'>


with this method, you can access an individual inner element as "sysmetrics.item3.iIndex"

personally, i would define it similar to what you already have - an array of structures
i would modify them so that each element in the array was 64 bytes
then i would calculate the array index with simple binary math   :bg

Dogim

Quote from: Yuri on November 10, 2010, 05:14:01 PM
This seems to work. I used EDI to keep the address of the current items structure. Also, don't forget to balance the stack after you have used wsprintf, because it doesn't do that itself.

Thanks Yuri, i forgot about wsprintf function not balancing the stack after you call it, nice tip, your help is much appreciated  :dance:

Dogim

Quote from: dedndave on November 10, 2010, 05:18:01 PM
ok - there are 2 ways you can go with this

1) define and access sysmetrics as an array, rather than as a structure
this is how you have currently defined the data, in a mannar of speaking
however, you are trying to access it as though it is a structure
again - it would simplify it if it were 64 bytes per element   :P
you can also simplify the define like this...
items STRUCT
 iIndex  dd 0
 szLabel db 22 dup (?)
 szDesc  db 42 dup (?)
     ENDS

sysmetrics items <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels'>,
                <SM_CYSCREEN,'SM_CYSCREEN','Screen height in pixels'>,
                <SM_CXVSCROLL,'SM_CXVSCROLL','Vertical scroll width'>,
                <SM_CYHSCROLL,'SM_CYHSCROLL','Horizontal scroll height'>,
                <SM_CYCAPTION,'SM_CYCAPTION','Caption bar height'>


2) define and access sysmetrics as a structure
the problem you are having is that you are trying to access elements in the sysmetrics array as though it were a structure
the way you are using it, that shouldn't be necessary
if you wanted to do that, each element in the sysmetrics structure should be named (item0, item1, item2, and so on)
but, let's do it that way as an example, so that you can see what i mean...
items STRUCT
 iIndex  dd 0
 szLabel db 22 dup (?)
 szDesc  db 42 dup (?)
     ENDS

;define the sysStruct type as 5 "items" structures

sysStruct STRUCT
 items 5 dup<>
         ENDS

;now, the sysmetrics structure is type sysStruct

sysmetrics sysStruct <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels',
                        SM_CYSCREEN,'SM_CYSCREEN','Screen height in pixels',
                        SM_CXVSCROLL,'SM_CXVSCROLL','Vertical scroll width',
                        SM_CYHSCROLL,'SM_CYHSCROLL','Horizontal scroll height',
                        SM_CYCAPTION,'SM_CYCAPTION','Caption bar height'>


at this point, not really much different from an array
but, if we want to access individual elements with the "label.lable.label" method...

sysStruct STRUCT
 item0 item <>
 item1 item <>
 item2 item <>
 item3 item <>
 item4 item <>
         ENDS

;now, the sysmetrics structure is type sysStruct

sysmetrics sysStruct <SM_CXSCREEN,'SM_CXSCREEN','Screen width in pixels',
                        SM_CYSCREEN,'SM_CYSCREEN','Screen height in pixels',
                        SM_CXVSCROLL,'SM_CXVSCROLL','Vertical scroll width',
                        SM_CYHSCROLL,'SM_CYHSCROLL','Horizontal scroll height',
                        SM_CYCAPTION,'SM_CYCAPTION','Caption bar height'>


with this method, you can access an individual inner element as "sysmetrics.item3.iIndex"

personally, i would define it similar to what you already have - an array of structures
i would modify them so that each element in the array was 64 bytes
then i would calculate the array index with simple binary math   :bg
Thank you dedndave , i,m going to study this and see if i can become a assembly programmer after all, thank you very much for your help.

dedndave

also, have a look at \masm32\help\asmintro.chm (or the MS Masm reference manual/webpages)
there is some additional information regarding the use of the ASSUME directive and PTR operator that you may find useful
you can probably find more info using the forum search tool with "structure assume ptr"


donkey

Hi Dogim,

First off welcome to the forum !

I am working nights this week so I just got a look at your questions. As Dave said, the GetSystemMetrics function does not require a structure but a constant that indicates what data you would like returned. Those constants are in the Winuser.h header file and are made available by including Windows.h, a fairly complete set of GoAsm compatible header files are available at my website (click the "Donkey's Stable" link at the bottom of this post). The Goasm headers available at my website are much more extensive than MASM32's Windows.inc, they cover both 32 and 64 bit Windows up to and including Windows 7, also they follow the naming pattern at MSDN so when MSDN advises you to include a certain header it will generally work for GoAsm as well.

Traversing a structure in GoAsm is pretty much the same as in MASM, though there is no equivalent to the ASSUME directive you can code essentially what it does directly. For example if you had a structure that consisted of the following:

items STRUCT
iIndex  dd 0
szLabel db 22 dup (?)
szDesc  db 42 dup (?)
ENDS

DATA SECTION
arrayitems items 24 DUP <?>


I would step through it as follows:

push ebx,edi // Save the registers
mov edi, offset arrayitems ; start of array
mov ebx, 0 // set the count to 0
:
mov eax,[edi+items.iIndex]
// The base address of the next item structure is in EDI
// EAX contains the value of iIndex for that structure

// Do what you want with the structure data here

// Step to the next entry
add edi, SIZEOF items
// increment the count
add ebx,1
// Is this the last one ?
cmp ebx, SIZEOF arrayitems/SIZEOF items
jl <
pop edi,ebx // restore the registers


Note that I have used SIZEOF arrayitems/SIZEOF items to calculate the number of items in the array, I could have hard coded it at 24 in this case but I generally prefer this way since I might want to change the number of items in the array and don't want to go searching through the code for references to it. This way GoAsm will calculate it for me and insert the correct number.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Dogim

Thank you for your reply Donkey,
I think i  understand how this works, but i still have to do some reading on this topic and a lot of examples.
Before i ask for help on the forum, i tried to load the adres of items into the edi register with a mov ADDR items , wich Goasm did not allow, i got the error Wrong use of 'ADDR' or 'OFFSET':-, i was doing this because i thought that  a structure begins at  in my case items, so as i see it now the struct items does not become active until you initialise it.
its just declared waiting for action. what happens to that structure if its not initialised ??, im guessing  nothing.
Maybe if i had read those C and C++ books a little better i could of known that piece of info :bg
Thank you.
You wil probably hear more of me :toothy
Excuse me for my bad english.

donkey

Hi Dogim,

Your English is fine. Yes, its a concept that some have a problem with when they start, that is that a structure simply describes a contiguous memory model, you have to set aside memory for it in your data section before it is usable.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Dogim

Good Morning to all.
With the help i have received on the forum ( thanks to all again), cooking up the devcap example was a walk in the park, but with a knowledgeable differences of course  :U.
But i stumbled on a strange problem in both the Sysmets and the Devcap1 code, when i declare the following variables WndProc FRAME hWnd, uMsg, wParam, lParam
uses esi,edi,ebx,edx
 
LOCAL         hdc:d,\
;    cxChar:d,\
;        cxCaps:d,\
;        cyChar:d,\
;      cyChar_i:d,\
;     cxCaps_14:d,\
;     Caps_Char:d,\
           ps:PAINTSTRUCT,\
    szBuffer [10]:d,\
         tm:TEXTMETRIC
         ;saveMe:d
cxChar down to Caps_Char LOCALLY in the Window Proc Frame, it does not work.
Maybe its not a big deal, i going to  use gobug  or Olly to  ( have to learn debugging anyway  :toothy), to see if i could figure out what's wrong, the manual doesn't mention any scope boundaries for LOCALS or maybe i have overlooked the topic, it looks like when WM_PAINT hits, it can't find or see the variables , I'm guessing a scope problem.
Thanks  again everyone.