home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fwktl101.zip / HELOWRLD.ASM < prev    next >
Assembly Source File  |  1996-05-28  |  22KB  |  561 lines

  1.  
  2.  
  3.         TITLE   HELOWRLD
  4.         NAME    HELOWRLD
  5.         .386
  6.         .387
  7.  
  8. ; HELOWRLD.ASM can be assembled using IBM's ALP 3.00.004 assembler,
  9. ; linked to make a pseudo .DLL using LINK386, and
  10. ; stripped to leave only the FWKTL_format program using FWKTRIM.
  11.  
  12. TEXT32  SEGMENT DWORD PUBLIC 'CODE'
  13.         ASSUME  CS:FLAT, DS:FLAT
  14.         ALIGN   4
  15. MAIN:
  16.  
  17. ; This is a "Hello, world!" program for loading and execution in
  18. ; OS/2 Warp protected mode, using the FWKTL(TM) Text_program Loader,
  19. ; Version 1.01, to load it.
  20. ;
  21. ; (C)Copyright Frederick W. Kantor 1996. All rights reserved.
  22. ;
  23. ; programs loaded by FWKTL can modify themselves, and can modify
  24. ;   their source (the file from which the program was loaded)
  25. ;
  26. ;
  27. ; To assemble in an OS/2 session using IBM's ALP 3.00.004, run
  28. ;
  29. ;   MK_HWASM.CMD
  30. ;
  31. ; (enclosed in this package) and follow the instructions on the screen
  32. ; to make HELOWLD2.COM;
  33. ;
  34. ; the .COM extension can then be changed or removed, to help avoid
  35. ; error.  FWKTL loads it independent of extension.
  36. ;
  37. ; if the resulting .COM program is executed directly in a DOS or OS/2
  38. ; environment, it returns to the command line: the first byte is RET.
  39. ;
  40. ; There are 3 examples in this "Hello, world." program. The only
  41. ; parameter you need to set to use them is EXAMPLE :
  42. ;   EXAMPLE EQU 1
  43. ;   EXAMPLE EQU 2
  44. ;   EXAMPLE EQU 3
  45.  
  46. EXAMPLE EQU 1     ; current setting
  47.  
  48. ;
  49. ; EXAMPLE EQU 1
  50. ;   uses PSETUP = 0 in initialization; HELOWLD2.COM is 69 bytes long;
  51. ;   this configuration shows how to get an API's address when you
  52. ;   already have the module handle; it gets a specific address for a
  53. ;   single procedure, DOS32WRITE (DOSCALLS.282) (see also P_ STRUC);
  54. ;   the handle for the DOSCALLS module is provided by FWKTL as part
  55. ;   of the initial data.
  56. ;
  57. ; EXAMPLE EQU 2
  58. ;   sets PSETUP = 1; HELOWRLD.COM is 41 bytes long; this uses a simple
  59. ;   SHOW procedure in FWKTL to send an ASCIIZ string up to, but not
  60. ;   including, its terminal 00 to 'standard output' (defaults to
  61. ;   screen), and append a terminal carriage_return line_feed. (to save
  62. ;   space, the exit errorlevel is not set to zero: the errorlevel
  63. ;   returned is the low 16 bits of the DWORD for the program's entry
  64. ;   point.)
  65. ;
  66. ; EXAMPLE EQU 3
  67. ;   sets PSETUP = 0; HELOWLD2.COM is 142 bytes long;
  68. ;   this illustrates how functions can be easily added; it gets
  69. ;   addresses for a list of 25 APIs and uses two of them, one to write
  70. ;   "Hello, world!",0d,0a to "standard output" (the screen), and the
  71. ;   other to sound a tone. The APIs loaded in example 3 include tools
  72. ;   for loading and freeing other dynamic link library modules,
  73. ;   allocating and freeing memory, some semaphore procedures, etc.
  74.  
  75.  
  76. ; To run the assembled HELOWLD2.COM in an OS/2 session:
  77. ;
  78. ; Format:  FWKTL HELOWLD2.COM <enter>
  79.  
  80. ; Initialization:
  81. ;
  82. ; FWKTL loads a program and sets
  83. ;
  84. ;   EAX = entry point for execution
  85. ;   EBX = 0 if no free memory requested
  86. ;     ELSE EBX  DWORD aligned, after code
  87. ;   ECX = number of DWORDs in initialization requested (see P_ STRUC)
  88. ;   ESI points to start of initialization_data source (matching start
  89. ;         of P_)
  90. ;   EDI = 0 if no free memory requested
  91. ;     ELSE EDI = EBX = start of free memory, in case you wish to put
  92. ;         initialization data there
  93. ;   the "direction flag" (decrement flag) is cleared (CLD)
  94. ;
  95. ; FWKTL provides initial values, and several procedures;
  96. ;   see P_ STRUC, below, for initial values and procedure addresses.
  97. ;   These values are easily copied, with ESI, EDI, ECX, and CLD from
  98. ;   FWKTL. If free memory was requested (done in HELOWRLD.1), use
  99. ;     REP MOVSD
  100.  
  101. ;   If no free memory was requested, save values in STACK. For saving
  102. ;   EBX in STACK, I suggest you modify J_ STRUC and put J_EBX at the
  103. ;   beginning, and load EDI with the effective address of the beginning
  104. ;   of the standard FWKTL initialization values: e.g.,
  105. ;     SUB ESP,TYPE J_
  106. ;     MOV EBP,ESP
  107. ;     LEA EDI,[EBP].P_LOADEDAT ; where to put initialization data
  108. ;     REP MOVSD                ; using ESI, ECX, and CLD from FWKTL
  109.  
  110. ; FWKTL calls the program as a routine in Thread 1:
  111. ;
  112. ;   on entry, the stack will not return an exception until 0ABAh dwords
  113. ;     are pushed (= 02AE8h bytes = 10984 (decimal) bytes)
  114. ;
  115. ;   on return to FWKTL:  CS, SS, and ESP must be correct when RET
  116. ;      is executed
  117. ;
  118. ;   EAX, EBX, ECX, EDX, ESI, EDI, EBP, DS, ES, FS, GS can be changed
  119. ;
  120. ;   EAX is used to return an exit errorlevel, of which the low 16 bits
  121. ;       (AX) is returned by OS/2 Warp at the command line.
  122.  
  123. ; to display exit errorlevels, you can use  PROMPT=[$p $r]
  124.  
  125. ;-------------------------------------------------------
  126.  
  127. KEEP_EBX EQU 00   ; set to 1 to store EBX in stack, so that it can
  128.                   ; be recovered by MOV EBX,[EBP] (e.g., in case a
  129.                   ; procedure called changes it); EBP may be less
  130.                   ; likely to be changed than EBX during such calls.
  131.                   ; All calls used in these 3 examples preserve EBX,
  132.                   ; so this is not used.
  133. ;-------------------------------------------------------
  134.                   ; PSETUP is used to control P_ STRUC and to set
  135.                   ;   bit00 in second DWORD in the program header
  136.                   ; = 0 to get the shorter initial setup data;
  137.                   ; = 1 to get the longer initial setup data which
  138.                   ;   has the addresses for the SHOW and USWORDCAPS
  139.                   ;   utilities
  140.  
  141. IF EXAMPLE EQ 1 OR EXAMPLE EQ 3
  142. PSETUP EQU 0
  143. ELSEIF EXAMPLE EQ 2
  144. PSETUP EQU 1
  145. ENDIF
  146.  
  147. ;-------------------------------------------------------
  148.  
  149. ; structure for initial data:
  150.  
  151. P_ STRUC          ; these are provided by FWKTL for initialization,
  152.                   ;  according to file header settings:
  153.  
  154. P_LOADEDAT DD ?   ; start of this memory block
  155. P_PWHENCE DD ?    ; points to ASCIIZ string re where program was found
  156. P_PCOMTAIL DD ?   ; points to ASCIIZ command tail
  157.  
  158. P_GETFN DD ?      ; address for indirect call to FWKTL GETFN function:
  159.                   ; Input:
  160.                   ;     EAX = ProcedureOrdinal
  161.                   ;         (maximum permitted OS/2 ordinal <= 65533)
  162.                   ;         if EAX > 0, ESI is ignored
  163.                   ;   OR
  164.                   ;     EAX = 0
  165.                   ;     ESI points to ASCIIZ procedure_name
  166.                   ;
  167.                   ;   EDX = module handle
  168.                   ;   EDI points to target DWORD to receive
  169.                   ;         procedure address
  170.                   ;
  171.                   ; Output:
  172.                   ;  if successful,
  173.                   ;     zero_flag is set
  174.                   ;     procedure address is in target DWORD
  175.                   ;     EAX = 0
  176.                   ;
  177.                   ;  if error
  178.                   ;     zero_flag is cleared
  179.                   ;     EAX contains error number:
  180.                   ;              6  ERROR_INVALID_HANDLE
  181.                   ;            123  ERROR_INVALID_NAME
  182.                   ;          65079  ERROR_ENTRY_IS_CALLGATE
  183.                   ;
  184.                   ; all other CPU registers and flags are preserved
  185.  
  186. P_GETFNLIST DD ?  ; address for indirect call to FWKTL GETFNLIST
  187.                   ;   function, to get the addresses for a list of
  188.                   ;   procedures in the same module:
  189.                   ;
  190.                   ; EBX, EDX, EBP are preserved across this function
  191.                   ;
  192.                   ; Input:
  193.                   ;   EAX = 0 if list is ASCIIZ procedure_names
  194.                   ;         2 if list is WORD ordinals
  195.                   ;         4 if list is DWORD ordinals
  196.                   ;         (maximum permitted OS/2 ordinal = 65533)
  197.                   ;   ECX = number of items in procedure list
  198.                   ;   EDX = module handle
  199.                   ;   ESI points to start of list of WORDs, DWORDs,
  200.                   ;         or series of ASCIIZ procedure_names
  201.                   ;   EDI points to start of target DWORDs to receive
  202.                   ;         the corresponding procedure addresses
  203.                   ;
  204.                   ; Output:
  205.                   ; if no error:
  206.                   ;   zero_flag is set
  207.                   ;   each target DWORD contains its procedure address
  208.                   ;   ESI:
  209.                   ;      if EAX = 0
  210.                   ;           ESI points to terminal 00h of last ASCIIZ
  211.                   ;              string;
  212.                   ;      ELSE if EAX > 0
  213.                   ;           ESI points to first byte after source;
  214.                   ;   EDI points to first byte after last target DWORD
  215.                   ;
  216.                   ; if error:
  217.                   ;   zero_flag is cleared
  218.                   ;   EAX contains error number:
  219.                   ;            6  ERROR_INVALID_HANDLE
  220.                   ;          123  ERROR_INVALID_NAME
  221.                   ;        65079  ERROR_ENTRY_IS_CALLGATE
  222.                   ;   ECX is not decremented on failed step
  223.                   ;   ESI points to list item identifying the procedure
  224.                   ;         for which the failure occurred
  225.  
  226. P_HDOSCALLS DD ?  ; handle for DOSCALLS module as loaded by FWKTL,
  227.                   ;   can be used in EDX for P_GETFN or P_GETFNLIST.
  228.  
  229.        ;------------------------- end of setup for PSETUP EQ 0
  230.  
  231. IF PSETUP EQ 1
  232.  
  233.     ; two additional procedures are optionally available from FWKTL:
  234.  
  235. P_SHOW DD ?        ; address for FWKTL SHOW function;
  236.                    ;
  237.                    ; usage:
  238.                    ;
  239.                    ; ESI points to ASCIIZ string to show on screen
  240.                    ;       using 'standard error' handle=2;
  241.                    ;   this procedure drops terminal 00 and adds 0D,0A;
  242.                    ; all CPU registers and flags are preserved.
  243.  
  244. P_USWORDCAPS DD ?  ; address for FWKTL capitalization function;
  245.                    ;
  246.                    ; usage:
  247.                    ;
  248.                    ; ESI points to contiguous string > ' ' to
  249.                    ;   capitalize, US English;
  250.                    ; all CPU registers and flags are preserved.
  251.                    ;
  252.                    ; (e.g., this procedure can be used when '/' or '-'
  253.                    ; is found in command tail, for case_insensitive
  254.                    ; options when you don't capitalize whole tail)
  255.  
  256. ENDIF  ;------------------------- end of setup for PSETUP EQ 1
  257.  
  258. IF EXAMPLE EQ 1 OR EXAMPLE EQ 3  ; these are used with an API:
  259.  
  260. P_WROTE DD ?       ; used with the DOS32WRITE API
  261.  
  262. P_WRITE DD ?       ; to hold address for OS/2 DOS32WRITE API
  263.                    ; Note: P_WRITE is also the first entry in the
  264.                    ;       address targets used in EXAMPLE EQ 3:
  265.                    ;       P_WROTE must not be inserted directly
  266.                    ;       below P_WRITE, because it would offset
  267.                    ;       the rest of the address targets in
  268.                    ;       EXAMPLE EQ 3
  269. ENDIF
  270.                ; other material can be inserted here:
  271.  
  272. IF EXAMPLE EQ 3   ; addresses for 24 more APIs
  273.  
  274. P_SCANENV        DD ?
  275. P_SEARCHPATH     DD ?
  276. P_SLEEP          DD ?
  277. P_EXIT           DD ?
  278. P_SETFILEPTR     DD ?
  279. P_CLOSE          DD ?
  280. P_OPEN           DD ?
  281. P_READ           DD ?
  282. P_BEEP           DD ? ; see note on using BEEP for diagnostics, below
  283. P_ALLOCMEM       DD ?
  284. P_FREEMEM        DD ?
  285. P_CREATETHREAD   DD ?
  286. P_GETINFOBLOCKS  DD ?
  287. P_LOADMODULE     DD ?
  288. P_QUERYPROCADDR  DD ?
  289. P_FREEMODULE     DD ?
  290. P_CREATEEVENTSEM DD ?
  291. P_OPENEVENTSEM   DD ?
  292. P_CLOSEEVENTSEM  DD ?
  293. P_RESETEVENTSEM  DD ?
  294. P_POSTEVENTSEM   DD ?
  295. P_WAITEVENTSEM   DD ?
  296. P_QUERYEVENTSEM  DD ?
  297. P_QUERYSYSINFO   DD ?
  298.  
  299. ENDIF ; EXAMPLE EQ 3
  300.  
  301. P_ ENDS    ; end of P_ STRUC
  302.  
  303. ;-------------------------------------------------------
  304.  
  305.       ; Note: BEEP is convenient for simple diagnostics;
  306.       ; e.g., you can insert code blocks like this to make a tone
  307.       ; when each such place is reached, and set different values
  308.       ; for frequency and/or duration to distinguish the beeps;
  309.       ; registers and flags are preserved across this function:
  310.  
  311.  
  312.       ; put this before the first beep call you want turned on:
  313.       ;
  314.       ; rundb equ 01 ; 01 to insert them (and remove initial ";"),
  315.       ;              ; 00 to exclude them
  316.  
  317.  
  318.       ; if rundb                                   ;debug
  319.       ; pushfd                                     ;debug
  320.       ; pushad                                     ;debug
  321.       ; pushd 0100h ; duration, milliseconds       ;debug
  322.       ; pushd 0100h ; frequency, cycles per second ;debug
  323.       ; call [ebx].p_beep                          ;debug
  324.       ; add esp,08                                 ;debug
  325.       ; popad                                      ;debug
  326.       ; popfd                                      ;debug
  327.       ; endif                                      ;debug
  328.  
  329. ;-------------------------------------------------------
  330.  
  331. ; Here is the code header:
  332.  
  333. ; the first byte of the header is a RET, in case the program has
  334. ; a .COM extension and someone accidentally tries to run it directly
  335. ; in a DOS or OS/2 session.
  336.  
  337. CODESTART:   ; used as a reference point
  338.  
  339. RET          ; 4_byte header identification string
  340. DB 'FWK'     ;
  341.  
  342. DD PSETUP    ; bit00 = 0 for PSETUP=0 (see P_ STRUC)
  343.              ; bit00 = 1 for PSETUP=1 (see P_ STRUC)
  344.              ; bits 31...01 are reserved, and must be zero for use with
  345.              ;   FWKTL version 1.00.
  346.  
  347. DD TYPE P_   ; amount of free memory requested after code;
  348.              ;   in these examples, just enough to hold a P_ STRUC;
  349.              ;   PSETUP affects the size of P_ STRUC used
  350.              ;   to hold standard FWKTL initialization data;
  351.              ;   storage of any other data there also affects the
  352.              ;   size of P_ STRUC; e.g., P_ can contain buffers.
  353.              ; the free memory starts DWORD aligned, zeroed.
  354.  
  355.              ; more memory than used in P_ STRUC can be requested;
  356.              ; note that memory requested in this way is committed
  357.              ; when allocated.
  358.  
  359.              ; for efficiency and flexibility, programs which need a
  360.              ; lot of memory can use API procedures to allocate and
  361.              ; free memory, rather than asking for it as part of
  362.              ; installation. EXAMPLE EQ 3 loads the addresses for
  363.              ; calling some memory management procedures.
  364.  
  365.              ; Note that this kind of program can write new code into
  366.              ; the memory and then run it, or can relocate or modify
  367.              ; itself and continue to run.
  368.  
  369.  
  370. ; Here is where the executable code starts;
  371.  
  372. JMP SHORT LL0  ; this is the execution entry point.
  373.  
  374.          ; at this point, the STACK from FWKTL provides working space
  375.          ;       for 0400h (1024 decimal) dwords, not counting space
  376.          ;         allowed for system use;
  377.          ;       the STACK will not return an exception until more than
  378.          ;         0ABAh dwords are on the stack (2746 decimal)
  379.          ; EAX = entry point for execution
  380.          ; EBX = start of free memory, DWORD aligned, after code
  381.          ; ECX = number of initialization DWORDs requested (P_ STRUC)
  382.          ; ESI points to start of initialization_data source (matching
  383.          ;       start of P_)
  384.          ; EDI=EBX to put initialization data there (using REP MOVSD)
  385.          ; decrement flag has been cleared (CLD) (for using REP MOVSD)
  386.  
  387. MSG:
  388. OMSG EQU $-CODESTART      ; used in calculating where this message is
  389. DB 'Hello, world!'
  390.  
  391. IF EXAMPLE EQ 2 ; the FWKTL SHOW procedure is for use with ASCIIZ strings;
  392. DB 00           ; terminal 00 to make ASCIIZ string (SHOW provides CRLF)
  393. ELSE            ;
  394. DB 0DH,0AH      ; carriage_return line_feed (for use with DOS32WRITE API)
  395. ENDIF           ;
  396.  
  397. LMSG EQU $-MSG
  398.  
  399.  
  400. IF EXAMPLE EQ 3 ; this is a flexible method, using an expandable list
  401.               ; of procedures; in this example the procedures are
  402.               ; identified using ordinal numbers (this is required for
  403.               ; DOSCALLS procedures), but this method can be used with
  404.               ; procedures identified by name, in a list of ASCIIZ
  405.               ; procedure_names.
  406.  
  407. FNLIST:       ; list of procedures (DOSCALLS ordinals).
  408. OFNLIST EQU $-CODESTART ; offset used for finding FNLIST in memory.
  409.  
  410. ; these decimal number WORDs are in the same order
  411. ; as their corresponding DD targets in P_ STRUC
  412.         ;   these are the procedures (APIs) included in EXAMPLE=3:
  413.         ;                      decimal ordinals
  414.  
  415. DW 282  ;   DOS32WRITE          (DOSCALLS.282)
  416. DW 227  ;   DOS32SCANENV        (DOSCALLS.227)
  417. DW 228  ;   DOS32SEARCHPATH     (DOSCALLS.228)
  418. DW 229  ;   DOS32SLEEP          (DOSCALLS.229)
  419. DW 234  ;   DOS32EXIT           (DOSCALLS.234)
  420. DW 256  ;   DOS32SETFILEPTR     (DOSCALLS.256)
  421. DW 257  ;   DOS32CLOSE          (DOSCALLS.257)
  422. DW 273  ;   DOS32OPEN           (DOSCALLS.273)
  423. DW 281  ;   DOS32READ           (DOSCALLS.281)
  424. DW 286  ;   DOS32BEEP           (DOSCALLS.286)
  425. DW 299  ;   DOS32ALLOCMEM       (DOSCALLS.299)
  426. DW 304  ;   DOS32FREEMEM        (DOSCALLS.304)
  427. DW 311  ;   DOS32CREATETHREAD   (DOSCALLS.311)
  428. DW 312  ;   DOS32GETINFOBLOCKS  (DOSCALLS.312)
  429. DW 318  ;   DOS32LOADMODULE     (DOSCALLS.318)
  430. DW 321  ;   DOS32QUERYPROCADDR  (DOSCALLS.321)
  431. DW 322  ;   DOS32FREEMODULE     (DOSCALLS.322)
  432. DW 324  ;   DOS32CREATEEVENTSEM (DOSCALLS.324)
  433. DW 325  ;   DOS32OPENEVENTSEM   (DOSCALLS.325)
  434. DW 326  ;   DOS32CLOSEEVENTSEM  (DOSCALLS.326)
  435. DW 327  ;   DOS32RESETEVENTSEM  (DOSCALLS.327)
  436. DW 328  ;   DOS32POSTEVENTSEM   (DOSCALLS.328)
  437. DW 329  ;   DOS32WAITEVENTSEM   (DOSCALLS.329)
  438. DW 330  ;   DOS32QUERYEVENTSEM  (DOSCALLS.330)
  439. DW 348  ;   DOS32QUERYSYSINFO   (DOSCALLS.348)
  440.  
  441. NFNLIST EQU ($-FNLIST)/2 ; number of items in FNLIST
  442.                          ;   = list_length_in_bytes / word_length
  443. ENDIF ; EXAMPLE EQ 3
  444.  
  445. ; Note that the APIs loaded in EXAMPLE EQ 3 include procedures for
  446. ; loading and freeing other modules besides DOSCALLS (which was loaded
  447. ; by FWKTL); the GETFN and GETFNLIST functions in FWKTL can be used
  448. ; with other modules than DOSCALLS, once they have been loaded and
  449. ; their handles made available.
  450.  
  451. LL0:                      ; target for JMP from entry point
  452.  
  453. IF KEEP_EBX               ; in general use, this step is used to
  454. PUSH EBX                  ; save EBX value; but every call used in this
  455. ENDIF                     ; particular program preserves EBX, so this
  456.                           ; step is not needed.
  457.  
  458. MOV EBP,ESP               ; save ESP value in EBP
  459.  
  460. REP MOVSD                 ; load EBX:P_ STRUC
  461.                           ; FWKTL preset ESI, EDI, and ECX,
  462.                           ;       and did CLD
  463.  
  464.  
  465. IF EXAMPLE EQ 1           ; get specific API: DOS32WRITE (DOSCALLS.282)
  466.  
  467. MOV EAX,282               ; 282 decimal ordinal
  468. MOV EDX,[EBX].P_HDOSCALLS ; use handle for DOSCALLS module,
  469.                           ;   already loaded by FWKTL
  470. LEA EDI,[EBX].P_WRITE     ; point EDI at DWORD for holding address
  471. CALL [EBX].P_GETFN        ; get procedure address
  472.  
  473. ENDIF
  474.  
  475.  
  476. IF EXAMPLE EQ 3           ; this is a flexible method, using an
  477.                           ;   expandable list of API procedure ordinals
  478.  
  479. MOV ESI,[EBX].P_LOADEDAT  ; calculate position of start of FNLIST
  480. ADD ESI,OFNLIST           ;   procedure list
  481.  
  482. LEA EDI,[EBX].P_WRITE     ; point EDI at first location for storing
  483.                           ;   procedure addresses
  484. MOV EAX,02                ; FNLIST list contains 2_byte ordinals
  485. MOV ECX,NFNLIST           ; number of items in list
  486. MOV EDX,[EBX].P_HDOSCALLS ; use handle for DOSCALLS module,
  487.                           ;   already loaded by FWKTL
  488. CALL [EBX].P_GETFNLIST    ; get addresses for procedures in list
  489.  
  490. ENDIF
  491.  
  492.  
  493. IF EXAMPLE EQ 2           ; this is a special_case, with a simple way
  494.                           ;   to show a message on the screen
  495.                           ;   (uses "standard error" handle=2):
  496.  
  497. MOV ESI,[EBX].P_LOADEDAT  ; point ESI at start of loaded program
  498. ADD ESI,OMSG              ; add offset to point ESI at start of message
  499. CALL [EBX].P_SHOW         ; call FWKTL SHOW function
  500.  
  501. ENDIF
  502.  
  503.  
  504. IF EXAMPLE EQ 1 OR EXAMPLE EQ 3 ; this illustrates a flexible method,
  505.                           ; using the DOS32WRITE API loaded above
  506.                           ; (see HELOWRLD.LST):
  507.  
  508. LEA EAX,[EBX].P_WROTE    ; pDWORD for amount written
  509. PUSHD EAX                ;
  510.  
  511. PUSHD LMSG               ; amount to write
  512.  
  513. MOV EAX,[EBX].P_LOADEDAT ; calculate position of message text
  514. ADD EAX,OMSG             ;
  515. PUSHD EAX                ; push address of beginning of text
  516.  
  517. PUSHD 1                  ; handle = 'standard output'
  518.  
  519. CALL [EBX].P_WRITE       ; indirect call to DOS32WRITE to write message
  520. ENDIF
  521.  
  522. IF EXAMPLE EQ 3
  523.  
  524. ;MOV ESP,EBP     ; could clear the stack first, but there's enough room
  525.  
  526. IF KEEP_EBX
  527. MOV EBX,[EBP]             ; this is a way to restore EBX
  528. ENDIF
  529.  
  530. PUSHD 0200H               ; 512 milliseconds duration (nominal)
  531. PUSHD 0100H               ; 256 cycles per second (approx)
  532. CALL [EBX].P_BEEP         ; indirect call to DOS32BEEP API loaded above
  533.  
  534. ENDIF ; EXAMPLE EQ 3
  535.  
  536. IF EXAMPLE NE 2           ; cleanup omitted in EXAMPLE EQ 2 to save space
  537.  
  538. MOV ESP,EBP               ; clean up STACK
  539.                           ;
  540. IF KEEP_EBX               ;
  541. POP EBX                   ;
  542. ENDIF                     ;
  543.  
  544. XOR EAX,EAX               ; set exit errorlevel = 0 (low 16 bits are
  545.                           ;   used in making exit errorlevel returned
  546.                           ;   to command line in OS/2 Warp)
  547. ENDIF ; EXAMPLE NE 2
  548.  
  549. RET                       ; return to FWKTL
  550.  
  551. DB 'FWKEOF',0,1           ; EOF signature for use with FWKTRIM
  552.  
  553. TEXT32 ENDS
  554. END MAIN
  555.  
  556.  
  557. ; FWKTL and FWKTRIM are trademarks of Frederick W. Kantor.
  558. ;
  559. ; IBM, OS/2, Warp, and IBM Assembly Language Processor (ALP) are trademarks
  560. ; of International Business Machines Corporation.
  561.