---------------------------------------------------------------------------
    -----------------------------------------------------------------------
            - A L W A Y S   U N D E R    C O N S T R U C T I O N -

           $$$$$$$$   $$$$$$$$  $$$$$$$$$$$$$   $$$$$$$$   $$$$$$$$
          $$$$$ $$$$ $$$$$ $$$$ $$$$$ $$$$ $$$ $$$$$ $$$$ $$$$$ $$$$
          $$$$$ $$$$ $$$$$      $$$$$ $$$$ $$$       $$$$       $$$$
          $$$$$$$$$$  $$$$$$$$  $$$$$ $$$$ $$$  $$$$$$$$   $$$$$$$$
          $$$$$ $$$$       $$$$ $$$$$ $$$$ $$$       $$$$ $$$$$
          $$$$$ $$$$ $$$$$ $$$$ $$$$$ $$$$ $$$ $$$$$ $$$$ $$$$$ $$$$
          $$$$$ $$$$  $$$$$$$$  $$$$$ $$$$ $$$  $$$$$$$$  $$$$$$$$$$

                     How to program for windows 95 in asm32
                          Lesson 1 : your first program
                    by _HaK_ and corrected by Nemrod and ReN

    -----------------------------------------------------------------------
  ---------------------------------------------------------------------------


  1.Introduction :
  ----------------

    This  lesson  will try to show you how  to  do a stupid message box for
    windows.



  2.How we gonna do that ?
  ------------------------

    The  main API used here in the  prog (see below) is the MessageBoxA. By
    viewing the API Reference we can see :

      int MessageBox(
        HWND hWnd,            // handle of owner window
        LPCTSTR lpText,       // address of test in message box
        LPCTSTR lpCaption,    // address of title of message box
        UINT uType            // style of message box
      );

    Before  calling the API we have to push every value on the stack with a
    push  instruction. But not in any orders : the last parameter at first,
    then the third, followed by the second and at last the first parameter.

    This  order  is always to be respected  :  always the last parameter at
    first, and finish with the first !

    All the types here are DWORD so it correspond to LARGE PUSH.
    The "uType" parameters defines the type of the dialog box.

    It can have for main value :

      MB_OK               equ 00000000h ; create a simple OK button
      MB_OKCANCEL         equ 00000001h ; two buttons: OK and Cancel
      MB_ABORTRETRYIGNORE equ 00000002h ; 3 buttons: Abort, Retry and ignore
      MB_YESNOCANCEL      equ 00000003h ; 3 buttons: Yes, No and Cancel
      MB_YESNO            equ 00000004h ; 2 buttons: Yes and No
      MB_RETRYCANCEL      equ 00000005h ; 2 buttons: Retry and Cancel

    If  we  want a special icon on the left  of the text we must add one of
    the value :

      MB_ICONHAND         equ 00000010h ; test them to find to
      MB_ICONQUESTION     equ 00000020h ; what they correspond !
      MB_ICONEXCLAMATION  equ 00000030h
      MB_ICONASTERISK     equ 00000040h

    And we can select the default button by adding one of the value :

      MB_DEFBUTTON1       equ 00000000h ; for default button = the first
      MB_DEFBUTTON2       equ 00000100h ; the second
      MB_DEFBUTTON3       equ 00000200h ; the third
      MB_DEFBUTTON4       equ 00000300h ; and the fourth !

    Other value (I didn't test them so try them by yourself) :

      MB_APPLMODAL        equ 00000000h
      MB_SYSTEMMODAL      equ 00001000h
      MB_TASKMODAL        equ 00002000h
      MB_HELP             equ 00004000h ; add a Help button (send WM_HELP)
      MB_RIGHT            equ 00080000h
      MB_RTLREADING       equ 00100000h

      MB_NOFOCUS          equ 00008000h
      MB_SETFOREGROUND    equ 00010000h
      MB_DEFAULT_DESKTOP_ONLY equ 00020000h
      MB_SERVICE_NOTIFICATION equ 00040000h

      MB_TYPEMASK         equ 0000000Fh
      MB_USERICON         equ 00000080h
      MB_ICONMASK         equ 000000F0h
      MB_DEFMASK          equ 00000F00h
      MB_MODEMASK         equ 00003000h
      MB_MISCMASK         equ 0000C000h

    Ok after having pushed the uType value, we must push two long pointer :

      - lpCaption : points to the title of the windows : It's showed in
                    the Caption Bar, which is at the top of the windows.

      - lpContent : points to the content of the message box.

    This  are  two  pointer  so only  push  the  offset  pointing the first
    character  of  the string. This string  must  be null terminated (shows
    windows where to stop).

    If  you want to display a message on more than one line use : ,13,10 at
    the  End  of  the  line instead of  zero  which  define  the end of the
    message. The 13 character defines the carriage return and the 10 define
    Line feed !

    The  last parameter to push is a HWND : a application handle : it's for
    Windows,  it  uses  it  to recognize  who  is  linked  to who (personal
    supposition).  So  before push this value we  have to get it (see below
    for how to).

    Now  we have pushed all the value on the stack. We can call the Windows
    API to create the message box with our given parameters.


    Once  called, the message box wait the user to push a button. Meanwhile
    it doesn't give you back the hand and the execution stop at the call.

    Once  the user choose a button,  Windows destroy the message box, gives
    the  value  of  the  pushed button by  the  user  in  the eax processor
    register  and the execution of the  program continues. The value in eax
    can be :

      IDOK     =   1
      IDCANCEL =   2
      IDABORT  =   3
      IDRETRY  =   4
      IDIGNORE =   5
      IDYES    =   6
      IDNO     =   7

    To get the application handle we use the GetModuleHandleA. This API has
    to get the hwnd of an application.

    We  can push a long pointer, pointing  to a string, null terminated and
    defining  the name of the module we wants  to get the handle. But if we
    want the handle Windows assigned to our application, only push the null
    value  and  as  return  in  eax, we  get  the  current  file hwnd which
    corresponds  to  the  Application hwnd. I  think  that when the program
    starts, Windows gives this application handle, but I don't know where !

    Once  we  have finish, we wants to quit  our program. To do this we use
    the  API : ExitProcess. Before calling it we have to push a value : the
    exit code which is tha same as the int 21h fonction 4Ch exit code. 



  3.General information.
  -----------------------

    Before  being called, any API must be defined in the .asm file as being
    an  external procedure. This is used by  the assembler : creates a type
    of  jumptable.  And  by  the linker :  fills  the  table by the correct
    address defined in the imports32.lib



  4.The Main File : .ASM
  ----------------------

    ;--- Start of TUT_01.ASM -->8

              .386
              locals
              jumps
              .model flat,STDCALL

      ; All APIs have to be defined before being called

              extrn GetModuleHandleA:Proc
              extrn MessageBoxA:Proc
              extrn ExitProcess:Proc

      ; here we store the data !
              .data

      AppHWnd       dd 0            ; here we store the application Handle !

      MsgBoxCaption db "Lesson 1",0 ; The message box title (or caption)

      MsgBoxContent db "Just saying Hello,",13,10 ; The message box content
                    db "To Yourself !!!",0

      ; here starts the code
              .code

      Start:
              push    0h                      ; 0 = current application
              call    GetModuleHandleA        ; give us the handle !
              mov     [AppHWnd],eax           ; and store it.

              push    20h                     ; type of the message box
                                              ; (MB_ICONQUESTION and MB_OK)
              push    offset MsgBoxCaption    ; msgbox title
              push    offset MsgBoxContent    ; msgbox content
              push    [AppHWnd]               ; Application handle
              call    MessageBoxA             ; display the message box

              push    0h                      ; no return code
              call    ExitProcess             ; exit all process

      End Start                               ; end of the code.

    ;8<- EOF TUT_01.ASM ---



  5.The definitions file : .DEF
  -----------------------------

    ;--- Start of TUT_01.DEF -->8

      NAME           TUT_01
      DESCRIPTION    'ASM program'
      EXETYPE        WINDOWS
      CODE           PRELOAD MOVEABLE
      DATA           PRELOAD MOVEABLE MULTIPLE

    ;8<- EOF TUT_01.DEF ---



  6.The makefile file :
  ---------------------

    ;--- Start of MakeFile -->8

      # make -B            Will build .EXE
      # make -B -DDEBUG    Will build the debug version.

      NAME = TUT_01
      OBJS = $(NAME).obj
      DEF  = $(NAME).def

      !if $d(DEBUG)
      TASMDEBUG=/zi
      LINKDEBUG=/v
      !else
      TASMDEBUG=
      LINKDEBUG=
      !endif

      !if $d(MAKEDIR)
      IMPORT=$(MAKEDIR)\..\lib\import32
      !else
      IMPORT=import32
      !endif


      $(NAME).EXE: $(OBJS) $(DEF)
        tlink32 /Tpe /aa /c $(LINKDEBUG) $(OBJS),$(NAME),, $(IMPORT), $(DEF)

      .asm.obj:
         tasm32 $(TASMDEBUG) /ml /m2 $&.asm

    ;8<- EOF MakeFile ---



  7.How to assemble.
  ------------------

    To make the TUT_01.EXE
    Just create TUT_01.ASM, TUT_01.DEF and the MAKEFILE with the above data.
    Put the tasm\bin directory in your path.
    And just type : MAKE



  8.The Greetz :
  --------------

    _Masta_ : when does your next lesson come out ?
    Nemrod  : your punishment continues !! :)
    ReN     : Which university ?

    To contact myself : try the sunday afternoon on #Win32asm on EFNET.

    Next lesson : your first Window !