flat assembler
Message board for the users of flat assembler.

Index > Windows > Text/Number Output routines

Author
Thread Post new topic Reply to topic
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 05 Jun 2011, 23:16
Ok, I'm new to this forum, and I am not sure how active
it is. I have been looking for some good I/O routines
but to no avail. I did find one of the windows functions
'WriteConsole', but it only outputed strings, and you
had to specify the number of character to output. I then
searched through this forum and found a topic that used
the 'wsprintf' macro, (this is the reason I even signed
onto this forum, I saw it actualy had some use).

After that I found a cool way to get the length of a string. With
all of this information I created two macros. One outputs a
string, and the other a number.
String: WRITESTRING "Hello ", "World"
Number: WRITENUMBER 34, 45
These are how the macros are used

I am new to assembly, but I am exeptional while using
C++, and it dose not take a genius to see that my
output macros are bulky and inefficent. If you could
help, please do.

Also, my code dose not emit newlines, at all. I have
tried to just emit the ASCII code (13), this did nothing.
I even tried some of the DOS commands (int 21h ect.) but
this not only did not print anything, it crashed my
program, though it's not unreasonable seeing as how I'm
programming in Windows. Again if you can tell me how to
fix this, please do.

For my last question/request, I want to create a driver
macro that will recive numerical and string arguments and
call the appropriate macro. The problem is that I dont know
how to determin the data type (due to my lack of assembly
syntax knowladge) If you could tell me how to do this, please
dont hold back.

Code:
;\\_______Output.inc_______//
MACRO INIT {
        ; This macro just
        ;    1) opens the console
        ;    2) gets I/O handles
        invoke  AllocConsole
        invoke  GetStdHandle,STD_OUTPUT_HANDLE
        mov [outhandle],eax
        invoke  GetStdHandle,STD_INPUT_HANDLE
        mov [inhandle],eax
}
MACRO INITSTR {
        invoke  wsprintf,OPTS,'%s', ''; ----Reset string
}
MACRO WRITESTRING [char] {
        PUSH ECX;\
        PUSH EDI; ----Saves register values
        PUSH EAX;/
        INITSTR; ----Clears string
        invoke  wsprintf,OPTS,'%d', char; ----Convert array to string
        xor ecx,ecx;    -----\
        not ecx;              \
        xor al,al;             \
        MOV EDI,OPTS;; ----Calculate length of string
        repne scasb;           /
        not ecx;              /
        dec ecx;        -----/
        MOV EAX,ECX; ----Moves length into eax (unnessesary, though useful if used in expressions)
        invoke  WriteConsole,[outhandle],OPTS,EAX,0,0; ---Prints string
        POP EAX; \
        POP EDI;  ----Reset register values
        POP ECX;
}

MACRO WRITENUMBER [num] {
        PUSH ECX;\
        PUSH EDI; ----Saves register values
        PUSH EAX;/
        INITSTR; ----Clears string
        invoke  wsprintf,OPTS,'%d', num; ----Convert number to string
        xor ecx,ecx;    -----\
        not ecx;              \
        xor al,al;             \
        MOV EDI,OPTS;; ----Calculate length of string
        repne scasb;           /
        not ecx;              /
        dec ecx;        -----/
        MOV EAX,ECX; ----Moves length into eax (unnessesary, though useful if used in expressions)
        invoke  WriteConsole,[outhandle],OPTS,EAX,0,0; ---Prints string
        POP EAX; \
        POP EDI;  ----Reset register values
        POP ECX; /
}
    



That was the code for the macros that I am using

Code:
;\\_______Example.inc_______//
include 'C:\Users\owner\Desktop\fasmw16931\INCLUDE\win32ax.inc'; ---- Windows functions/macros
include 'output.inc'; ---- The include file

.data
  ;/////====These three variables ARE required
  outhandle  DD ?;   Output handle
  inhandle   DD ?;   Input handle
  OPTS       DD 20h; Output string, variable to hold string data

.code  
  start:
        INIT; Set up console
        ;----------------------------------------------;
        WRITESTRING, 'HELLO WORLD! '; Write the string
        WRITENUMBER, 34; Write the number
        ;----------------------------------------------;

        invoke  ReadConsole,[inhandle],0,1,0,0; Waits until done
        invoke  ExitProcess,0; Close

.end start
    

And that was an example of how to use the macros

_________________
He is no fool who gives what he cannot
keep to gain what he cannot loose.
Post 05 Jun 2011, 23:16
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 05 Jun 2011, 23:29
Hi,

First things first:

1. Do not use 'invoke wsprintf'. It should be 'cinvoke wsprintf' because of calling convention.

2. wsprintf return value is the number of characters stored in the output buffer, not counting the terminating null character. No need to re-calculate the size of the string.

3. To add a new line you must send a CRLF. CRLF = 0x1013 or 0x1310, try both. I don't remember the correct one.

4. You're resetting the buffer by 'invoke wsprintf,OPTS,'%s', ''; ----Reset string '. It is the same as 'mov [OPTS],0'. If you want to zero all the buffer memory, use 'invoke RtlZeroMemory,OPTS,sizeofbuffer'.

5. If OPTS is an array buffer to a string, and it's size is 20h, then you should use 'OPTS rb 20h'. 'rb' means reserved byte. This will reserve 20h bytes.

6. I don't recommend the use of macros for 'WRITESTRING' and 'WRITENUMBER'. Use 'proc' (function) instead. Every time you call these macros, all it's commands are going to be written into the executable file. If you call it 10 times, it will be written 10 times. Competely unnecessary.

ctl3d32


Last edited by ctl3d32 on 05 Jun 2011, 23:48; edited 1 time in total
Post 05 Jun 2011, 23:29
View user's profile Send private message Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 05 Jun 2011, 23:44
Wow, thanks for the quick reply, i never had to use assembly befor the project I am working on so I thought it was a dead language and a dead forum, guess not. Thanks I will try the new line hex code, and fix the 'invoke' instruction. Although I dont understand what you mean by 'returns' as I thought assembly did not have functions, much less returnable values. Could you show me how so throw said value into EAX, thanks. Very Happy

_________________
He is no fool who gives what he cannot
keep to gain what he cannot loose.
Post 05 Jun 2011, 23:44
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 05 Jun 2011, 23:47
I forgot to metion, on the last part of your responce you told me how to reserve memory, but how do I compir this to another type to determine whether or not the argument is a number or a string?
Post 05 Jun 2011, 23:47
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 05 Jun 2011, 23:57
I forgot to mention, you told me how to reserve 20h bytes of room, but how would i compare the data type of the argument sent so that I can determine which macro to call.
eg
Code:
WRITE, "I am ",14," years old"    

rather than a STRING/NUMBER aproch to this i would have a over all WRITE macro.
eg.
Code:
if argument data type = number
     WRITENUMBER, arument
else if argument data type = string
     WRITESTRING, argument
...
    

_________________
He is no fool who gives what he cannot
keep to gain what he cannot loose.
Post 05 Jun 2011, 23:57
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
Gunner



Joined: 28 Jul 2003
Posts: 17
Location: In my head
Gunner 06 Jun 2011, 00:00
as ctl3d32 said you are better off not using macros because if you call the macro 10 times, then that macro is expanded in your source/exe 10 times... bloat.. rather you should use procs/labels

_________________
~Rob (Gunner)
Forum Spam List Checker
Window Error Lookup Tool
and MORE!
Post 06 Jun 2011, 00:00
View user's profile Send private message Visit poster's website Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 06 Jun 2011, 00:02
NanoBytes wrote:
I forgot to metion, on the last part of your responce you told me how to reserve memory, but how do I compir this to another type to determine whether or not the argument is a number or a string?


Looking an ASCII table, you will see that the hexadecimal representation of a string that represents a number equals:

0 = 30h
1 = 31h
2 = 32h
3 = 33h
4 = 34h
.
.
.
9 = 39h

You must loop every byte of your input string and check if it is a number or not.
Example:
Code:
proc checknumber
push ebx
xor eax,eax
.loop:
movzx ebx,[number+eax]
test ebx,ebx
je .end_string
cmp ebx,30h
jl .not_a_string
cmp ebx,39h
jg .not_a_string
inc eax
jmp .loop
.not_a_string:
xor eax,eax
jmp .end
.end_string:
mov eax,1
.end:
pop ebx
ret
endp
    


The return value of the proc is at eax. If eax = 0, than it is not an integer number. Else, it is a number.


Last edited by ctl3d32 on 06 Jun 2011, 01:20; edited 5 times in total
Post 06 Jun 2011, 00:02
View user's profile Send private message Reply with quote
l_inc



Joined: 23 Oct 2009
Posts: 881
l_inc 06 Jun 2011, 00:03
Quote:
I have been looking for some good I/O routines but to no avail.

Could you please explain, why you need them? Because what you're doing is not very rational (especially including such code into macros instead of making it to functions/procedures).
Post 06 Jun 2011, 00:03
View user's profile Send private message Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 06 Jun 2011, 00:04
Sorry about the multiple post, i was trying to delete it when i found out the both got put on
Post 06 Jun 2011, 00:04
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 06 Jun 2011, 00:10
NanoBytes wrote:
I forgot to mention, you told me how to reserve 20h bytes of room, but how would i compare the data type of the argument sent so that I can determine which macro to call.
eg
Code:
WRITE, "I am ",14," years old"    

rather than a STRING/NUMBER aproch to this i would have a over all WRITE macro.
eg.
Code:
if argument data type = number
     WRITENUMBER, arument
else if argument data type = string
     WRITESTRING, argument
...
    


Do not use macros.
Just use:
Code:
cinvoke wsprintf,buff,"I am %d years old",[number]
    
Post 06 Jun 2011, 00:10
View user's profile Send private message Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 06 Jun 2011, 00:16
I didnt even know that assembly supported functions, i thought every thing wa global scope. Henceforth macros where the way to go. although when ctl3d32 posted that rather than using macros I should use labels I took right to it. Thank all of you for your help, you guys have 'debloated' my program, helped me compair data types, and possibly helped me with my newline problem (havent tryed it yet) Smile THANKS
Post 06 Jun 2011, 00:16
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 06 Jun 2011, 03:33
You could also use 'scanf', like here:
http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
Post 06 Jun 2011, 03:33
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 06 Jun 2011, 22:17
Just for reference CR is 13 or 0x0D and LF is 10 or 0x0A so you'd do "...,0x0D,0x0A,..." (if you merged these it'd be 0x0A0D because x86 is little endian)
Post 06 Jun 2011, 22:17
View user's profile Send private message Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 06 Jun 2011, 23:21
cod3b453 wrote:
Just for reference CR is 13 or 0x0D and LF is 10 or 0x0A so you'd do "...,0x0D,0x0A,..." (if you merged these it'd be 0x0A0D because x86 is little endian)


Of course, may bad in previous post (0x1013), hehehe...
Post 06 Jun 2011, 23:21
View user's profile Send private message Reply with quote
garystampa



Joined: 25 May 2011
Posts: 52
Location: Central FLorida
garystampa 07 Jun 2011, 02:03
NanoBytes wrote:
... i never had to use assembly before the project I am working on so I thought it was a dead language...
No, not dead, your C++ compiler writes assembler every time you run it. So if you can do it in C++ you can do it in assembler.
Post 07 Jun 2011, 02:03
View user's profile Send private message Reply with quote
NanoBytes



Joined: 02 Jun 2011
Posts: 57
Location: Iowa, United States
NanoBytes 09 Jun 2011, 05:07
Ok, new problem, I was trying to output Y (a variable), then a string and then Y again, but it screws up. I have deduced that when I am writing the string in the middle of the output is changes the value of Y. Why dose this happen, and how do I fix it?
Thanks.
Code:
include 'win32ax.inc'; ---- Windows functions/macros

.data
  ;/////====These three variables ARE required
  outhandle  DD ?;   Output handle
  inhandle   DD ?;  Input handle
  OPTS      DB ?
  Y             DD ?
  X             DD ?

.code  
  start:
    invoke  AllocConsole
        invoke  GetStdHandle,STD_OUTPUT_HANDLE
      mov [outhandle],eax
 invoke  GetStdHandle,STD_INPUT_HANDLE
       mov [inhandle],eax
  ;----------------------------------------------;
    ; Move 34 into Y
    mov [Y],34
  ;Print Y
    PUSH [Y]
    cinvoke  wsprintf,OPTS,'%d',[Y]
   invoke   WriteConsole,[outhandle],OPTS,EAX,0,0; ---Prints string
    POP  [Y]
    ; Print Hello
       cinvoke  wsprintf,OPTS,'%s','Hello'
     invoke   WriteConsole,[outhandle],OPTS,EAX,0,0; ---Prints string
    ; Print Y
   PUSH [Y]
    cinvoke  wsprintf,OPTS,'%d',[Y]
   invoke   WriteConsole,[outhandle],OPTS,EAX,0,0; ---Prints string
    POP  [Y]
    ;----------------------------------------------;
    invoke  ReadConsole,[inhandle],0,1,0,0; Waits until done
    invoke  ExitProcess,0; Close

.end start 
    

_________________
He is no fool who gives what he cannot
keep to gain what he cannot loose.
Post 09 Jun 2011, 05:07
View user's profile Send private message Send e-mail Visit poster's website Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1417
Location: Piraeus, Greece
Picnic 09 Jun 2011, 10:26
No need to save Y variable. It's value won't be changed by the function.
The fourth parameter of WriteConsole must be a pointer to a variable, see ReadConsole documentation also.

most critical, wsprintf needs a buffer to receive the formatted output like this
Code:
OPTS       RB 256     
Post 09 Jun 2011, 10:26
View user's profile Send private message Visit poster's website Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 09 Jun 2011, 18:29
As Picnic said, there's no such thing of 'push [Y] or pop[Y]' in your case.

Remove them and change 'OPTS DB ?' to as Picnic said. OPTS is the buffer that will recieve the string. It must be an array of bytes to recieve each char of the string. So 'OPTS RB 256' means it is reserving 256 bytes for all the chars of the string, including the null terminator, and the address of the beginning of these allocated bytes are going to be stored at OPTS. So,

OPTS -> Address of the beginning of reserved memory -> Reserved memory
Post 09 Jun 2011, 18:29
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.