Sunday, September 22, 2019 | Toby Opferman
 

WIN32 Programming for TASM Part 1

Toby Opferman
http://www.opferman.net
programming@opferman.net




                         Win32 Assembly Introduction
                                (TASM v5.0)

                "Functions, Defines, and Variable Defintions"


        This tutor is for those who know Win32 API programming in
C, C++ or simular language, know the concepts of Event-Driven
programming, have a working knowledge of the basic Win32 API, and
know assembly who want to learn Win32 assembly.  If you do not know
Event Driven programming, read the tutor I wrote on GUI - Event Driven
programming OR get a book on beginning windows programming.


        First off, I want to explain that programming Assembly for
Win32 can be as easy as programming C.  So, we will start with the API
and how to use the definitions.


Before you can start programming Win32 Assembly, you need to define
structures and functions.  When using C, all this is done for you, you
just #include <windows.h> and done!  Well, in Assembly, unless you
search the web or you have an assembler other than tasm that may have
.INC's, you have to define all your prodecures & structures. Luckily,
tasm does have a WIN32.INC which does define a lot of data types
and a few functions (But not many).  Under TASM\EXAMPLES\WAP32
you will find WIN32.INC. You can use this and add on to it.  That
is a lot better than starting off with nothing.


We will start with how to define functions.  This is quite simple, just:

extrn BeginPaint:PROC


That's it! Remeber, Win32 IS case sensitive in some areas, and this is
one of them.


CALL BeginPaint   ; A Call To Begin Paint


Simple.  We will get to parameters in a bit.

But, there is one catch.

UNICODE.

UNICODE is something I do not really know a lot about.  It has something
to do with the way Character strings are stored.  There are two types:

ANSI
WIDE CHARACTER.

UniCode defines the wide character form.  If you have the C header files,
you can do a GREP (This comes with TASM) on UNICODE and you will see
how functions are redefined.  I assume ANSI for all my programs.

Wide character for (I think) means each character is 2 bytes instead of one.
But I am not sure, if someone knows UNICODE and wants to explain it totally
please email me.


So, when you define any function that has String Input, you MUST define it
with either an A on the end or a W on the end. (I always do A cause I use ANSI)


extrn TextOutA:PROC


That is how TextOut would be defined.  Now, you would have to:

CALL TextOutA  ; Call to Text Out Ansi

Of course,to avoid the annoying A/W thing you can:

 TextOut equ <TextOutA>


Then Just

CALL TextOut  ; Call To Text Out


If your program wanted to change to Wide character then, you would
only have to change the extrn and equ instead of the whole program
so this is a good idea and good practice.


Next on the list is defining the Data types/structures.
Well, that's simple.  It would be a good idea to have a API reference
with the Functions & Data type defines structures so you can define
them in your program.  Or, if you have a windows C compiler like Watcom
or Visual C you may grep -w <yourword> directory\*.h  to find structure
defines so you may define them in your WIN32.INC.

Defining Structures:

MSGSTRUCT struc
    msHWND          UINT    ?
    msMESSAGE       UINT    ?
    msWPARAM        UINT    ?
    msLPARAM        ULONG   ?
    msTIME          ULONG   ?
    msPT            ULONG   2 dup(?)
MSGSTRUCT ends

Defining Types:

 HDC equ <dd>





Now, I will show you how to pass parameters.
There is a function of TASM 5.0 to pass like high level, with all
your parms in the call:


CALL FUNC, Parms


This is a bit TOO high level for me, might as well start using
C, and Asm in Win32 is High Level Enough!!
But, if you like that way, you can use that way.  Here is the 
Manual way:

(P.S. I would do a  L equ <LONG>  so you can use on the Pushes
to make sure that dword parms are pushed as dwords if you push
a VALUE or Value Defintion like equ's. Pushing offsets, memory locations
or registers is fine since the compiler will know the size.)

PUSH L 0
PUSH L 0
PUSH L 0
PUSH OFFSET Msg
CALL GetMessage    ; Call Get Message


Now, you see that the parameters are pushed on backwards.

in C:


GetMessage(&Msg, 0, 0, 0); // 0 or NULL


Anyway, you see that the parameters are pushed on backwards.


(TIP:
  If you like the C 'NULL' idea

  NULL equ <0>   ; C Sytle Null's
)


All return values are in EAX.  So, as in our example, you know that the
GetMessage returns a ZERO when your application quits.

MessageLoop:
  PUSH L 0
  PUSH L 0
  PUSH L 0
  PUSH OFFSET Msg 
  CALL GetMessage       ; Call To GetMessage

  TEST EAX, EAX         ; Quit Loop?
  JZ SHORT EndProgram

  PUSH OFFSET Msg
  CALL TranslateMessage ; Translate Message

  PUSH OFFSET Msg
  CALL DispatchMessage  ; Dispatch Message

  JMP SHORT MessageLoop  

EndProgram:
  
  PUSH [Msg.wParam]
  CALL ExitProcess      ; End Program



As you see, the Return value of GetMessage is in EAX.



That is the jist of getting started.  All you need to know from this tutor is:

 1. How to define variables & API Function Definitions including ANSI/WIDE character modes.
 
 2. How to successfully pass parameters, call and get a return value from an API function


If you have accomplished these, you are ready to move on to my Win32 Intermediate programming
tutor which tells how to create a Win32 Program.

 
About Toby Opferman

Professional software engineer with over 15 years...

Learn more »
Codeproject Articles

Programming related articles...

Articles »
Resume

Resume »
Contact

Email: codeproject(at)opferman(dot)com