News:

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

unable to output numbers properly in windows functions

Started by Rainstorm, September 14, 2006, 07:39:24 AM

Previous topic - Next topic

Rainstorm

hi.

I get the ascii value of a number in the message box, if after 32, otherwise some unknown
character if the number is less (like 2 suqare brackets joined) or just a blamk message box

if the number has quotes then the double digit nos get inverted
like 43 becomes 34

here's an example of the code..
  .data?
total dw ?

    .data

  MsgBoxTitle  db  "Assembly msgbox",0

    .code

start:
     mov ax, "16"
     mov total, ax

    invoke MessageBox, NULL, addr total,addr MsgBoxTitle, MB_OK
    invoke ExitProcess, NULL

end start

the  numbeer displayed in the msgbox for that is 61

How do i pass numbers properly to the message box.


sinsi

Quote from: Rainstorm on September 14, 2006, 07:39:24 AM
    invoke MessageBox, NULL, addr total,addr MsgBoxTitle, MB_OK

The 2nd param (addr total) should be a pointer to a null-terminated string.
If you want to show a number, you need to convert it to a string first.
Light travels faster than sound, that's why some people seem bright until you hear them.

TNick

Search about these key words: Big Endian and Small Endian

Hint: In memory (and in registers) values are stored in reverse order.

QuoteIf you want to show a number, you need to convert it to a string first.

To convert a number to a string, you can use <dw2hex> and <dwtoa>, wich can be found in masm32.lib.

Or you can write your own ... just for fun. :U

gabor

Hello!


The MessageBox function expects a string that is put out in the small window, like:


.data
szCaption      db 'Message',0
szText         db 'Hello world!',0

.code
...
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
invoke ExitProcess,0



This little code will display a message box with the text 'Hello world!' and an Ok button.

In your code you did not write a number into ax, but a 2-character string. The meaning of the double quotes is take the ASCII codes of each character. If you want to write a number into ax you have to leave the " sign off.


mov ax,"16" ; value in ax is 3136h
mov ax,16   ; value in ax is 0016h


When ax is written into memory variable, the lower part is written first, and then the higher part is written into the next byte, this is the Intel way of handling bigger than 1 byte memory reads/writes:


mov total,ax
;is
mov total,al   ; lower byte
mov total+1,ah ; higher byte


That's why the digits got swapped.

The variable 'total' was taken by MessageBox function as a string. So, instead the number in ax some brackets appeared since the characters for the value 16 is a control character not a visible character.

If you want to display numbers you have to convert the digits into ASCII codes just like TNick advised.
To convert you can use many methods, I personally use either masm library functions or the Win32 API's wsprintf method:


int wsprintf(
    LPTSTR  lpOut,       // address of buffer for output
    LPCTSTR  lpFmt       // address of format-control string
    ...                  // optional arguments
   );


It has a format control very similar to C's printf function and it is really easy to mix normal strings and variables with it.
Here is a complete example:


.386
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib


.data
  szCaption      db 'Message',0
  total          dd 0
  szFormat       db 'Total: %ld',0
  szBuffer       db 64 dup(0)

.code
start:
  mov eax,16
  mov total,eax
  invoke wsprintf,offset szBuffer,offset szFormat,total
  invoke MessageBox,NULL,offset szBuffer,offset szCaption,MB_OK
  invoke ExitProcess,0
end start



I hope this was not an anoying too detailed explanation.  :toothy

Greets, Gábor

Rainstorm

I was about to post with a number of questions, when I seen your post in the
reply window ;)...& you had already answered most of the questions.
thanks,..your post was extremely helpful.

gabor wrote..
QuoteWhen ax is written into memory variable, the lower part is written first, and then the higher part is written into the next byte

just to be clear,.. it doesn't get reversed in this instruction itself, mov ax, 16  when the value is written into the register;..but only  just when ax writes the value
to a memory variable ?

..got some more questions, but will ask in subsequent posts..

ty.

-

gabor

Hello!

I am glad to have been able to help you!

Quote from: Rainstorm on September 14, 2006, 02:20:17 PM
.. it doesn't get reversed in this instruction itself, mov ax, 16 when the value is written into the register;..but only just when ax writes the value to a memory variable ?

First of all, when we speak of accessing (writing, reading) more than 1 byte (word, dword,qword) in memory it is more comfortable to use hexadecimal numbers. In hexdecimal numbers a digit represents 4 bits (a nibble), 2 digits represent a full byte. It is more clearly to see what values are matched to which byte.
Nibbles are not really important any more, they had a bigger role in the C64 and XT era when every bit was important.  :bg
Example:


mov al,08h    ; al = 0*16+8*1=8
mov al,18h    ; al = 1*16+8*1=24

mov ax,1234h  ; ax = 1*4096+2*256+3*16+4*1=4660
              ; splitted into bytes
              ; ah = 1*16+2*1=18
              ; al = 2*16+4*1=52



So, when you write ax into memory first the low byte (al) is written out then the high byte (ah). This causes:

.data
total  dw 0

.code
mov ax,1234h
mov total,ax

The content of the memory at the variable 'total' will be: 34h,12h; in decimal:  52,18.
This can be checked by reading the memory bytewise:

mov al,BYTE PTR total   ; al should be 34h or 52
mov al,BYTE PTR total+1 ; al should be 12h or 18


When you write characters into ax it will hold the ASCII codes of those characters. When you write ax into memory the order of the characters gets reversed:

.data
szText db 0,0,0
szCaption db "Message",0

.code
mov ax,"AB" ; ax = 4142h
mov WORD PTR szText,ax
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
mov al,text   ; al = "B" = 42h
mov al,text+1 ; al = "A" = 41h


With dwords it becomes really mixed up  :bg because not only the bytes are stored reversed but the words as well, so the result is a totally reversed string:

.data
szText db 5 dup (0)
szCaption db "Message",0

.code
mov eax,"ABCD"
mov DWORD PTR szText,eax
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
mov al,text   ; al = "D" = 44h
mov al,text+1 ; al = "C" = 43h
mov al,text+2   ; al = "B" = 42h
mov al,text+3 ; al = "A" = 41h


Just for to be complete:
mov DWORD PTR,eax will store the value of eax in the following order:
1. low word low byte, 2. low word high byte, 3. high word low byte, 4. high word high byte

I hope I was clear enough and not to boring  :toothy

Greets, Gábor

Rainstorm

#6
not boring at all.. \;)
thanks for that clear explanation.

I have some more questions.

1.  could you explain the buffer decleration  szText db 5 dup (0)

2.  is it possible to declare zero terminated strings in the .data? section too if so how ?
     what's the importance of the .data? section ....since variables declared in the data section can be replaced later in the code.

3. Could you elaborate some, on zero terminated strings ? - I know they are a string of bytes(or words etc) & terminated with a 0.....- but like, why is a terminating zero used in the string.. ?

===

4 .  I know that they are pointers & are the addresses of the variables containing data & that STR is string; - but what do the initials LPTSTR & LPCTSTR exactly stand for ?

Thanks!
-

gabor

Hello!


I may not always be able to answer your questions, so sometime it is very usefull to search on the Internet  :U

Quote from: Rainstorm on September 16, 2006, 02:48:32 PM
1. could you explain the buffer decleration szText db 5 dup (0)
A buffer is an array of bytes.
szText - name of variable
db - data type is byte (db stands for defined byte I guess)
5 - the count of bytes (the size of the array)
dup - stands for duplicate, since the bytes are duplicated
(0) - init value of bytes in buffer

Another example that defines an array of double words filled with -1 (0FFFFFFFFh):

dwNumbers dd 8 dup (-1)

This will allocate 8*4=32 bytes in the generated executable filled with values of 0FFh.

Quote from: Rainstorm on September 16, 2006, 02:48:32 PM
2. is it possible to declare zero terminated strings in the .data? section too if so how ?
what's the importance of the .data? section ....since variables declared in the data section can be replaced later in the code.
The .data? section is for uninitialized data, so a null-terminated string cannot be defined there (because the terminating 0 must be set, cannot be undefined).
The .data section is for initialized data, this is where a null-terminated string can be declared.
Or you can declare an unititialized buffer in the .data? section and write the terminating 0 from code.

Quote from: Rainstorm on September 16, 2006, 02:48:32 PM
3. Could you elaborate some, on zero terminated strings ? - I know they are a string of bytes(or words etc) & terminated with a 0.....- but like, why is a terminating zero used in the string.. ?
It must be possible to detect the end of a string. It can be done either by storing the length of the string or appending a terminating symbol. Both solutions are used, Windows sticks to the null-terminated strings.

Quote from: Rainstorm on September 16, 2006, 02:48:32 PM
4 . I know that they are pointers & are the addresses of the variables containing data & that STR is string; - but what do the initials LPTSTR & LPCTSTR exactly stand for ?
From win32.hlp:
TCHAR    Unicode character or Windows character.
LPTSTR   Pointer to a null-terminated Windows or Unicode character string.
LPCTSTR  Pointer to a constant null-terminated Unicode or Windows character string.

LP is the abreviation of Long Pointer which is a 32 bit pointer, C stands for constant.
Constant means it must not be changed (at least in C or C++ programs...).

Greets, Gábor

Rainstorm

#8
hi.

I really appreciate all the help Gabor.

thanks for clarifying those questions. :)

Rainstorm

-