News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

setColor and writeColor issue

Started by unsensible, February 26, 2014, 03:33:02 AM

Previous topic - Next topic

unsensible

Hello, I'm working on a program to set the forecolor and backcolor of some text. The program will debug but then crashes immediately. Because of this, it's giving me an access violation error. I'm using the Irvine.inc directory.

My code:


TITLE SetColor and WriteColorChar


SetColor PROTO forecolor:BYTE, backcolor:BYTE
WriteColorChar PROTO char:BYTE,forecolor:BYTE, backcolor:BYTE

.data
.code
main PROC
INVOKE WriteColorChar, 'A', white, blue
INVOKE WriteColorChar, 'B', blue, white
INVOKE WriteColorChar, 'C', green, black
INVOKE WriteColorChar, 'D', yellow, gray
INVOKE SetColor, lightGray, black

call Crlf
exit
main ENDP



WriteColorChar PROC, char:BYTE, forecolor:BYTE, backcolor:BYTE

         pop ebp                                                                        ; pop the ebp from the stack
        pop ecx                                                                        ; pop the ecx reg. from the stack
        pop ebx                                                                        ; pop the ebx reg. from the stack
        pop eax                                                                        ; pop the eax reg. from the stack

        push eax                                                                ; push Foreground onto the stack
        push ebx                                                                ; push background onto the stack
        push ecx                                                                ; push wChar onto the stack

        call SetColor                                                        ; call SetColor
        call WriteChar                                                        ; call WriteChar

        ret

WriteColorChar ENDP


SetColor PROC, forecolor:BYTE, backcolor:BYTE
        push ebp                                                            ; Save calling procedure base pointer
        mov ebp, esp                                                        ; Set base pointer for this procedure

        mov ecx, [ebp + 16]                                                 ; Retrieve colors
        mov eax, [ebp + 12]                                                 ; from the stack

        mov ebx, 16                                                         ; foreColor + (backColor * 16 )
        mul ebx                                                                       
        add ecx, eax                                                       

        mov eax, ecx                                                        ; move ecx reg. into eax re.
        call SetTextColor                                                   ; call SetTextColor to set the fore and back colors

        mov eax, [ ebp + 8 ]                                                ; retreive the char from the stack
pop ebp                                                             ; Restore base pointer for calling procedure

        ret

SetColor ENDP

END main



Any help would be greatly appreciated

qWord

You should reconsider your stack usage for both procedures. If you have any book, read up about calling conventions and the stack frame.
MREAL macros - when you need floating point arithmetic while assembling!

unsensible

Thank you qWord. Does this have to do with my usage of ebp?

jj2007

- Google for Masm Programmer's Guide
- Read Tips, Tricks & Traps
- more specifically: the push ebp etc gets done automatically - check with Olly. If you want to do it manually, you need to insert a specific instruction before the proc:

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
MyTest proc arg1, arg2
  ... your code ...
  retn 2*DWORD
MyTest endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

Note that you cannot use LOCAL with a manual stack frame, at least not so easily. And arguments should be DWORD (default), never BYTE. You cannot push a BYTE...

Last but not least: Welcome to the Forum :icon14:

dedndave

there is also an issue to be aware of.....
the Irvine library has functions that are named "SetTextColor" and "GetTextColor"
these names conflict with windows API functions in the gdi32 dll

unsensible

#5
Thanks a lot for all the help! I found the MASM Programmers Guide and it has a lot of useful information. I'll need to crack down on that.

I've cleaned the code up a bit and seems to work ok but I'm a little confused because my assignment requires the use of BYTE parameters. The question is as follows:

SetColor receives two byte parameters: forecolor and backcolor. It
calls the SetTextColor procedure from the Irvine32 library. (2) WriteColorChar receives three
byte parameters: char, forecolor, and backcolor. It displays a single character, using the color
attributes specified in forecolor and backcolor. It calls the SetColor procedure, and it also calls
WriteChar from the kips library. Both SetColor and WriteColorChar must contain declared
parameters. Write a short test program that tests both procedures. Be sure to create PROTO declarations
for SetColor and WriteColorChar.

But you're stating I should never use BYTE?

Quote from: jj2007 on February 26, 2014, 04:51:39 AM- Google for Masm Programmer's Guide
- Read Tips, Tricks & Traps
- more specifically: the push ebp etc gets done automatically - check with Olly. If you want to do it manually, you need to insert a specific instruction before the proc:

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
MyTest proc arg1, arg2
  ... your code ...
  retn 2*DWORD
MyTest endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

Note that you cannot use LOCAL with a manual stack frame, at least not so easily. And arguments should be DWORD (default), never BYTE. You cannot push a BYTE...

Last but not least: Welcome to the Forum :icon14:

qWord

The problem with BYTE parameters is that there is bug in the INVOKE directive for MASM v6...8, which produce bad code. However, you can use later versions (9+) or jWasm that does not have this issue.
MREAL macros - when you need floating point arithmetic while assembling!

unsensible

Thanks for the info. So after it was all said and done the program runs and shows the first "A" in white and blue like I want. However, the program then proceeds to crash before showing the rest of the letters. Any idea what could be causing this? I decided to use ebp because that's how the book explains it. Here's the updated code:


SetColor PROTO forecolor:DWORD, backcolor:DWORD
WriteColorChar PROTO char:DWORD,forecolor:DWORD, backcolor:DWORD

.data

.code
main PROC
INVOKE WriteColorChar, 'A', white, blue
INVOKE WriteColorChar, 'B', blue, white
INVOKE WriteColorChar, 'C', green, black
INVOKE WriteColorChar, 'D', yellow, gray
INVOKE SetColor, lightGray, black

call waitmsg
call Crlf
exit
main ENDP


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
WriteColorChar PROC, char:DWORD, forecolor:DWORD, backcolor:DWORD

        pop ebp                                                                        ; pop the ebp from the stack
        pop ecx                                                                        ; pop the ecx reg. from the stack
        pop ebx                                                                        ; pop the ebx reg. from the stack
        pop eax                                                                        ; pop the eax reg. from the stack
   
        push eax                                                                ; push Foreground onto the stack
        push ebx                                                                ; push background onto the stack
        push ecx                                                                ; push wChar onto the stack

        call SetColor                                                        ; call SetColor
        call WriteChar                                                        ; call WriteChar

        ret

WriteColorChar ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
SetColor PROC, forecolor:DWORD, backcolor:DWORD
        push ebp                                                            ; Save calling procedure base pointer
        mov ebp, esp                                                        ; Set base pointer for this procedure

        mov ecx, [ebp + 16]                                                 ; Retrieve colors
        mov eax, [ebp + 12]                                                 ; from the stack

        mov ebx, 16                                                         ; foreColor + (backColor * 16 )
        mul ebx                                                                       
        add ecx, eax                                                       

        mov eax, ecx                                                        ; move ecx reg. into eax re.
        call SetTextColor                                                   ; call SetTextColor to set the fore and back colors
        mov eax, [ ebp + 8 ]                                                ; retreive the char from the stack
   pop ebp                                                             ; Restore base pointer for calling procedure

        ret

SetColor ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

END main



jj2007

There are several issues here...

Inter alia, I would recommend that you use invoke instead of call. For example,
invoke SetTextColor would have choked with "error A2137: too few arguments to INVOKE" - and indeed, SetTextColor needs two DWORD arguments on the stack.

Please read the documentation for all the functions you are using. If your OS allows using *.hlp files, the Win32 help file is still available here.

unsensible

Thank you for your response jj2007. I am using the SetTextColor from the Irvine Library and not from the Windows API. The example I referred to for my program was from here: http://programming.msjc.edu/asm/help/source/irvinelib/settextcolor.htm as well as the book of course. I should have colors on the stack when using the following instructions right?

mov ecx, [ebp + 16]                                               
mov eax, [ebp + 12] 


I'm probably wrong because I'm receiving the access violation but I have not seen any errors about having too few arguments to INVOKE even when changing the call to Invoke.

dedndave

#10
no, no
SetTextColor from windows API (gdi32) requires 2 dword parameters on the stack
COLORREF SetTextColor(
  _In_  HDC hdc,
  _In_  COLORREF crColor
);

however, that function applies primarily to GUI apps

SetTextColor in the Irvine library has no stack parameters
; Receives: AX = attribute. Bits 0-3 are the foreground
; color, and bits 4-7 are the background color.

i have a modified version of kips library, in which i renamed this function to SetConTextColor
that avoids the name conflict

on another note.....

SetColor PROC, forecolor:DWORD, backcolor:DWORD
        push ebp                                                            ; Save calling procedure base pointer
        mov ebp, esp                                                        ; Set base pointer for this procedure

        mov ecx, [ebp + 16]                                                 ; Retrieve colors
        mov eax, [ebp + 12]                                                 ; from the stack
;
;
;
        mov eax, [ ebp + 8 ]                                                ; retreive the char from the stack
[EBP] holds the preserved contents of EBP on the stack
[EBP+4] holds the RETurn address
[EBP+8] holds the forecolor
[EBP+12] holds the backcolor

there are cases where it's good to disable the prologue and epilogue
however, this doesn't appear to be one of them
it might be best to leave them enabled and let the assembler sort out the EBP offsets

unsensible

Just wanted to thank everyone for their help as I got everything to work properly. I decided to not manually alter the stack as I'm obviously not experienced enough in that aspect.

Final code for those who care:


main PROC
INVOKE  WriteColorChar, 'A', white, blue
INVOKE  WriteColorChar, 'B', blue, white
INVOKE  WriteColorChar, 'C', green, black
INVOKE  WriteColorChar, 'D', yellow, gray
INVOKE  SetColor, lightGray, black

call    Crlf
call    WaitMsg
exit
main ENDP

WriteColorChar PROC, char:dword, forecolor:dword, backcolor:dword
   
    invoke  SetColor, forecolor, backcolor
    mov     eax, char
    invoke  WriteChar
    ret
   
WriteColorChar endp

SetColor PROC, forecolor:dword, backcolor:dword
   
mov     eax, backcolor
shl     eax, 4
add     eax, forecolor
call    SetTextColor

    ret
   
SetColor ENDP