home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / watc11up.zip / core_hlp_os2.zip / binp / help / pguide.inf (.txt) < prev    next >
OS/2 Help File  |  2001-08-28  |  505KB  |  14,711 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Watcom C/C++ Application Development ΓòÉΓòÉΓòÉ
  3.  
  4.  
  5.  
  6. This document contains guides to application development for several 
  7. environments including 16-bit DOS, 32-bit extended DOS, Windows 3.x, 32-bit 
  8. extended Windows 3.x, Windows NT, OS/2, AutoCAD and Novell NLMs.  It also 
  9. describes mixed language (C, FORTRAN) application development.  It concludes 
  10. with a chapter on some general questions and the answers to them. 
  11.  
  12. This document covers the following topics: 
  13.  
  14.      DOS Programming Guide 
  15.       Creating 16-bit DOS Applications 
  16.  
  17.       Creating 32-bit Phar Lap 386|DOS-Extender Applications 
  18.  
  19.       Creating 32-bit DOS/4GW Applications 
  20.  
  21.       32-bit Extended DOS Application Development 
  22.  
  23.      The DOS/4GW DOS Extender 
  24.       The Tenberry Software DOS/4GW DOS Extender 
  25.  
  26.       Linear Executables 
  27.  
  28.       Configuring DOS/4GW 
  29.  
  30.       VMM 
  31.  
  32.       Interrupt 21H Functions 
  33.  
  34.       Interrupt 31H DPMI Functions 
  35.  
  36.       Utilities 
  37.  
  38.       Error Messages 
  39.  
  40.       DOS/4GW Commonly Asked Questions 
  41.  
  42.      Windows 3.x Programming Guide 
  43.       Creating 16-bit Windows 3.x Applications 
  44.  
  45.       Porting Non-GUI Applications to 16-bit Windows 3.x 
  46.  
  47.       Creating 32-bit Windows 3.x Applications 
  48.  
  49.       Porting Non-GUI Applications to 32-bit Windows 3.x 
  50.  
  51.       The WATCOM 32-bit Windows Extender 
  52.  
  53.       Windows 3.x 32-bit Programming Overview 
  54.  
  55.       Windows 32-Bit Dynamic Link Libraries 
  56.  
  57.       Interfacing Visual Basic and Watcom C/C++ DLLs 
  58.  
  59.       WIN386 Library Functions and Macros 
  60.  
  61.       32-bit Extended Windows Application Development 
  62.  
  63.       Special Variables for Windows Programming 
  64.  
  65.       Definitions of Windows Terms 
  66.  
  67.       Special Windows API Functions 
  68.  
  69.      Windows NT Programming Guide 
  70.       Windows NT Programming Overview 
  71.  
  72.       Creating Windows NT GUI Applications 
  73.  
  74.       Porting Non-GUI Applications to Windows NT GUI 
  75.  
  76.       Windows NT Multi-threaded Applications 
  77.  
  78.       Windows NT Dynamic Link Libraries 
  79.  
  80.      OS/2 Programming Guide 
  81.       Creating 16-bit OS/2 1.x Applications 
  82.  
  83.       Creating 32-bit OS/2 Applications 
  84.  
  85.       OS/2 Multi-threaded Applications 
  86.  
  87.       OS/2 Dynamic Link Libraries 
  88.  
  89.       Programming for OS/2 Presentation Manager 
  90.  
  91.       Using the IBM OS/2 WorkFrame/2 
  92.  
  93.      AutoCAD ADS Programming Guide 
  94.       Creating AutoCAD Applications 
  95.  
  96.      Novell NLM Programming Guide 
  97.       Creating NetWare 386 NLM Applications 
  98.  
  99.      Mixed Language Programming 
  100.       Inter-Language calls:  C and FORTRAN 
  101.  
  102.      Common Problems 
  103.       Commonly Asked Questions and Answers 
  104.  
  105.  
  106. ΓòÉΓòÉΓòÉ 2. DOS:  Creating 16-bit DOS Applications ΓòÉΓòÉΓòÉ
  107.  
  108.  
  109. This chapter describes how to compile and link 16-bit DOS applications simply 
  110. and quickly. 
  111.  
  112. We will illustrate the steps to creating 16-bit DOS applications by taking a 
  113. small sample application and showing you how to compile, link, run and debug 
  114. it. 
  115.  
  116.  
  117. ΓòÉΓòÉΓòÉ 2.1. DOS:  The Sample Application ΓòÉΓòÉΓòÉ
  118.  
  119.  
  120. To demonstrate the creation of 16-bit DOS applications using command-line 
  121. oriented tools, we introduce a simple sample program.  For our example, we are 
  122. going to use the famous "hello" program. 
  123.  
  124.  
  125.    #include <stdio.h> 
  126.  
  127.    void main() 
  128.     { 
  129.      printf( "Hello world\n" ); 
  130.     } 
  131.  
  132. The C++ version of this program follows: 
  133.  
  134.  
  135.    #include <iostream.h> 
  136.    #include <iomanip.h> 
  137.  
  138.    void main() 
  139.    { 
  140.      cout << "Hello world" << endl; 
  141.    } 
  142.  
  143. The goal of this program is to display the message "Hello world" on the screen. 
  144. The C version uses the C library printf routine to accomplish this task.  The 
  145. C++ version uses the "iostream" library to accomplish this task.  We will take 
  146. you through the steps necessary to produce this result. 
  147.  
  148.  
  149. ΓòÉΓòÉΓòÉ 2.2. DOS:  Building and Running the Sample DOS Application ΓòÉΓòÉΓòÉ
  150.  
  151.  
  152. To compile and link our example program which is stored in the file HELLO.C, 
  153. enter the following command: 
  154.  
  155.  
  156.    C>wcl /l=dos hello.c 
  157.  
  158. The typical messages that appear on the screen are shown in the following 
  159. illustration. 
  160.  
  161.  
  162.    C>wcl /l=dos hello.c 
  163.    WATCOM C/C++16 Compile and Link Utility 
  164.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  165.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  166.        wcc hello.c 
  167.    WATCOM C16 Optimizing Compiler 
  168.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  169.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  170.    hello.c: 6 lines, included 155, 0 warnings, 0 errors 
  171.    Code size: 17 
  172.  
  173.    WATCOM Linker 
  174.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  175.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  176.    loading object files 
  177.    searching libraries 
  178.    creating a DOS executable 
  179.  
  180. Provided that no errors were encountered during the compile or link phases, the 
  181. "hello" program may now be run. 
  182.  
  183.  
  184.    C>hello 
  185.    Hello world 
  186.  
  187. If you examine the current directory, you will find that two files have been 
  188. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  189. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  190. It is HELLO.EXE that is run by DOS when you enter the "hello" command. 
  191.  
  192.  
  193. ΓòÉΓòÉΓòÉ 2.3. DOS:  Debugging the Sample DOS Application ΓòÉΓòÉΓòÉ
  194.  
  195.  
  196. Let us assume that you wish to debug your application in order to locate an 
  197. error in programming.  In the previous section, the "hello" program was 
  198. compiled with default compile and link options.  When debugging an application, 
  199. it is useful to refer to the symbolic names of routines and variables.  It is 
  200. also convenient to debug at the source line level rather than the machine 
  201. language level.  To do this, we must direct both the compiler and linker to 
  202. include additional debugging information in the object and executable files. 
  203. Using the WCL command, this is fairly straightforward.  WCL recognizes the 
  204. Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  205. directives for the Watcom Linker. 
  206.  
  207. For example, to compile and link the "hello" program with debugging 
  208. information, the following command may be issued. 
  209.  
  210.  
  211.    C>wcl /l=dos /d2 hello.c 
  212.  
  213. The typical messages that appear on the screen are shown in the following 
  214. illustration. 
  215.  
  216.  
  217.    C>wcl /l=dos /d2 hello.c 
  218.    WATCOM C/C++16 Compile and Link Utility 
  219.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  220.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  221.        wcc hello.c  /d2 
  222.    WATCOM C16 Optimizing Compiler 
  223.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  224.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  225.    hello.c: 6 lines, included 155, 0 warnings, 0 errors 
  226.    Code size: 23 
  227.  
  228.    WATCOM Linker 
  229.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  230.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  231.    loading object files 
  232.    searching libraries 
  233.    creating a DOS executable 
  234.  
  235. The "d2" option requests the maximum amount of debugging information that can 
  236. be provided by the Watcom C/C++ compiler.  WCL will make sure that this 
  237. debugging information is included in the executable file that is produced by 
  238. the linker. 
  239.  
  240. The "Code size" value is larger than in the previous example since selection of 
  241. the "d2" option results in fewer code optimizations by default.  You can 
  242. request more optimization by specifying the appropriate options.  However, you 
  243. do so at the risk of making it more difficult for yourself to determine the 
  244. relationship between the object code and the original source language code. 
  245.  
  246. To request the Watcom Debugger to assist in debugging the application, the 
  247. following command may be issued. 
  248.  
  249.  
  250.    C>wd hello 
  251.  
  252. It would be too ambitious to describe the debugger in this introductory chapter 
  253. so we refer you to the book entitled Watcom Debugger User's Guide. 
  254.  
  255.  
  256. ΓòÉΓòÉΓòÉ 3. Phar Lap:  Creating 32-bit Phar Lap 386|DOS-Extender Applications ΓòÉΓòÉΓòÉ
  257.  
  258.  
  259. This chapter describes how to compile and link 32-bit Phar Lap 386|DOS-Extender 
  260. applications simply and quickly. 
  261.  
  262. We will illustrate the steps to creating 32-bit Phar Lap 386|DOS-Extender 
  263. applications by taking a small sample application and showing you how to 
  264. compile, link, run and debug it. 
  265.  
  266.  
  267. ΓòÉΓòÉΓòÉ 3.1. Phar Lap:  The Sample Application ΓòÉΓòÉΓòÉ
  268.  
  269.  
  270. To demonstrate the creation of 32-bit Phar Lap 386|DOS-Extender applications 
  271. using command-line oriented tools, we introduce a simple sample program.  For 
  272. our example, we are going to use the famous "hello" program. 
  273.  
  274.  
  275.    #include <stdio.h> 
  276.  
  277.    void main() 
  278.     { 
  279.      printf( "Hello world\n" ); 
  280.     } 
  281.  
  282. The C++ version of this program follows: 
  283.  
  284.  
  285.    #include <iostream.h> 
  286.    #include <iomanip.h> 
  287.  
  288.    void main() 
  289.    { 
  290.      cout << "Hello world" << endl; 
  291.    } 
  292.  
  293. The goal of this program is to display the message "Hello world" on the screen. 
  294. The C version uses the C library printf routine to accomplish this task.  The 
  295. C++ version uses the "iostream" library to accomplish this task.  We will take 
  296. you through the steps necessary to produce this result. 
  297.  
  298.  
  299. ΓòÉΓòÉΓòÉ 3.2. Phar Lap:  Building and Running the Sample 386|DOS-Extender Application ΓòÉΓòÉΓòÉ
  300.  
  301.  
  302. To compile and link our example program which is stored in the file HELLO.C, 
  303. enter the following command: 
  304.  
  305.  
  306.    C>wcl386 /l=pharlap hello.c 
  307.  
  308. The typical messages that appear on the screen are shown in the following 
  309. illustration. 
  310.  
  311.  
  312.    C>wcl386 /l=pharlap hello.c 
  313.    WATCOM C/C++32 Compile and Link Utility 
  314.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  315.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  316.        wcc386 hello.c 
  317.    WATCOM C32 Optimizing Compiler 
  318.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  319.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  320.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  321.    Code size: 24 
  322.  
  323.    WATCOM Linker 
  324.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  325.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  326.    loading object files 
  327.    searching libraries 
  328.    creating a Phar Lap simple executable 
  329.  
  330. Provided that no errors were encountered during the compile or link phases, the 
  331. "hello" program may now be run. 
  332.  
  333.  
  334.    C>run386 hello 
  335.    Hello world 
  336.  
  337. If you examine the current directory, you will find that two files have been 
  338. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXP 
  339. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  340. It is HELLO.EXP that is run by DOS when you enter the "run386 hello" command. 
  341.  
  342.  
  343. ΓòÉΓòÉΓòÉ 3.3. Phar Lap:  Debugging the Sample 386|DOS-Extender Application ΓòÉΓòÉΓòÉ
  344.  
  345.  
  346. Let us assume that you wish to debug your application in order to locate an 
  347. error in programming.  In the previous section, the "hello" program was 
  348. compiled with default compile and link options.  When debugging an application, 
  349. it is useful to refer to the symbolic names of routines and variables.  It is 
  350. also convenient to debug at the source line level rather than the machine 
  351. language level.  To do this, we must direct both the compiler and linker to 
  352. include additional debugging information in the object and executable files. 
  353. Using the WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  354. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  355. directives for the Watcom Linker. 
  356.  
  357. For example, to compile and link the "hello" program with debugging 
  358. information, the following command may be issued. 
  359.  
  360.  
  361.    C>wcl386 /l=pharlap /d2 hello.c 
  362.  
  363. The typical messages that appear on the screen are shown in the following 
  364. illustration. 
  365.  
  366.  
  367.    C>wcl386 /l=pharlap /d2 hello.c 
  368.    WATCOM C/C++32 Compile and Link Utility 
  369.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  370.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  371.        wcc386 hello.c  /d2 
  372.    WATCOM C32 Optimizing Compiler 
  373.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  374.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  375.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  376.    Code size: 45 
  377.  
  378.    WATCOM Linker 
  379.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  380.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  381.    loading object files 
  382.    searching libraries 
  383.    creating a Phar Lap simple executable 
  384.  
  385. The "d2" option requests the maximum amount of debugging information that can 
  386. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  387. debugging information is included in the executable file that is produced by 
  388. the linker. 
  389.  
  390. The "Code size" value is larger than in the previous example since selection of 
  391. the "d2" option results in fewer code optimizations by default.  You can 
  392. request more optimization by specifying the appropriate options.  However, you 
  393. do so at the risk of making it more difficult for yourself to determine the 
  394. relationship between the object code and the original source language code. 
  395.  
  396. To request the Watcom Debugger to assist in debugging the application, the 
  397. following command may be issued. 
  398.  
  399.  
  400.    C>wd/trap=pls hello 
  401.  
  402. It would be too ambitious to describe the debugger in this introductory chapter 
  403. so we refer you to the book entitled Watcom Debugger User's Guide. 
  404.  
  405.  
  406. ΓòÉΓòÉΓòÉ 4. DOS/4GW:  Creating 32-bit DOS/4GW Applications ΓòÉΓòÉΓòÉ
  407.  
  408.  
  409. This chapter describes how to compile and link 32-bit DOS/4GW applications 
  410. simply and quickly. 
  411.  
  412. We will illustrate the steps to creating 32-bit DOS/4GW applications by taking 
  413. a small sample application and showing you how to compile, link, run and debug 
  414. it. 
  415.  
  416.  
  417. ΓòÉΓòÉΓòÉ 4.1. DOS/4GW:  The Sample Application ΓòÉΓòÉΓòÉ
  418.  
  419.  
  420. To demonstrate the creation of 32-bit DOS/4GW applications using command-line 
  421. oriented tools, we introduce a simple sample program.  For our example, we are 
  422. going to use the famous "hello" program. 
  423.  
  424.  
  425.    #include <stdio.h> 
  426.  
  427.    void main() 
  428.     { 
  429.      printf( "Hello world\n" ); 
  430.     } 
  431.  
  432. The C++ version of this program follows: 
  433.  
  434.  
  435.    #include <iostream.h> 
  436.    #include <iomanip.h> 
  437.  
  438.    void main() 
  439.    { 
  440.      cout << "Hello world" << endl; 
  441.    } 
  442.  
  443. The goal of this program is to display the message "Hello world" on the screen. 
  444. The C version uses the C library printf routine to accomplish this task.  The 
  445. C++ version uses the "iostream" library to accomplish this task.  We will take 
  446. you through the steps necessary to produce this result. 
  447.  
  448.  
  449. ΓòÉΓòÉΓòÉ 4.2. DOS/4GW:  Building and Running the Sample DOS/4GW Application ΓòÉΓòÉΓòÉ
  450.  
  451.  
  452. To compile and link our example program which is stored in the file HELLO.C, 
  453. enter the following command: 
  454.  
  455.  
  456.    C>wcl386 /l=dos4g hello.c 
  457.  
  458. The typical messages that appear on the screen are shown in the following 
  459. illustration. 
  460.  
  461.  
  462.    C>wcl386 /l=dos4g hello.c 
  463.    WATCOM C/C++32 Compile and Link Utility 
  464.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  465.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  466.        wcc386 hello.c 
  467.    WATCOM C32 Optimizing Compiler 
  468.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  469.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  470.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  471.    Code size: 24 
  472.  
  473.    WATCOM Linker 
  474.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  475.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  476.    loading object files 
  477.    searching libraries 
  478.    creating a DOS/4G executable 
  479.  
  480. Provided that no errors were encountered during the compile or link phases, the 
  481. "hello" program may now be run. 
  482.  
  483.  
  484.    C>hello 
  485.    Hello world 
  486.  
  487. If you examine the current directory, you will find that two files have been 
  488. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  489. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  490. It is HELLO.EXE that is run by DOS when you enter the "hello" command. 
  491.  
  492.  
  493. ΓòÉΓòÉΓòÉ 4.3. DOS/4GW:  Debugging the Sample DOS/4GW Application ΓòÉΓòÉΓòÉ
  494.  
  495.  
  496. Let us assume that you wish to debug your application in order to locate an 
  497. error in programming.  In the previous section, the "hello" program was 
  498. compiled with default compile and link options.  When debugging an application, 
  499. it is useful to refer to the symbolic names of routines and variables.  It is 
  500. also convenient to debug at the source line level rather than the machine 
  501. language level.  To do this, we must direct both the compiler and linker to 
  502. include additional debugging information in the object and executable files. 
  503. Using the WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  504. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  505. directives for the Watcom Linker. 
  506.  
  507. For example, to compile and link the "hello" program with debugging 
  508. information, the following command may be issued. 
  509.  
  510.  
  511.    C>wcl386 /l=dos4g /d2 hello.c 
  512.  
  513. The typical messages that appear on the screen are shown in the following 
  514. illustration. 
  515.  
  516.  
  517.    C>wcl386 /l=dos4g /d2 hello.c 
  518.    WATCOM C/C++32 Compile and Link Utility 
  519.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  520.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  521.        wcc386 hello.c  /d2 
  522.    WATCOM C32 Optimizing Compiler 
  523.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  524.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  525.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  526.    Code size: 45 
  527.  
  528.    WATCOM Linker 
  529.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  530.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  531.    loading object files 
  532.    searching libraries 
  533.    creating a DOS/4G executable 
  534.  
  535. The "d2" option requests the maximum amount of debugging information that can 
  536. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  537. debugging information is included in the executable file that is produced by 
  538. the linker. 
  539.  
  540. The "Code size" value is larger than in the previous example since selection of 
  541. the "d2" option results in fewer code optimizations by default.  You can 
  542. request more optimization by specifying the appropriate options.  However, you 
  543. do so at the risk of making it more difficult for yourself to determine the 
  544. relationship between the object code and the original source language code. 
  545.  
  546. To request the Watcom Debugger to assist in debugging the application, the 
  547. following command may be issued. 
  548.  
  549.  
  550.    C>wd/trap=rsi hello 
  551.  
  552. It would be too ambitious to describe the debugger in this introductory chapter 
  553. so we refer you to the book entitled Watcom Debugger User's Guide. 
  554.  
  555.  
  556. ΓòÉΓòÉΓòÉ 5. 32-bit Extended DOS Application Development ΓòÉΓòÉΓòÉ
  557.  
  558.  
  559. The purpose of this chapter is to anticipate common programming questions for 
  560. 32-bit extended DOS application development.  Note that these programming 
  561. solutions may be DOS-extender specific and therefore may not work for other DOS 
  562. extenders. 
  563.  
  564. The following topics are discussed in this chapter: 
  565.  
  566.      How can I write directly to video memory using a DOS extender? 
  567.      How do I get information about free memory in the 32-bit environment? 
  568.      How do I access the first megabyte in the extended DOS environment? 
  569.      How do I spawn a protected-mode application? 
  570.      How can I use the mouse interrupt (0x33) with DOS/4GW? 
  571.      How do I simulate a real-mode interrupt with DOS/4GW? 
  572.      How do you install a bi-modal interrupt handler with DOS/4GW? 
  573.  
  574.  Please refer to the DOS Protected-Mode Interface (DPMI) Specification for 
  575.  information on DPMI services.  In the past, the DPMI specification could be 
  576.  obtained free of charge by contacting Intel Literature JP26 at 800-548-4725 or 
  577.  by writing to the address below.  We have been advised that the DPMI 
  578.  specification is no longer available in printed form. 
  579.  
  580.     Intel Literature JP26 
  581.     3065 Bowers Avenue 
  582.     P.O. Box 58065 
  583.     Santa Clara, California 
  584.     U.S.A. 95051-8065 
  585.  
  586.  However, the DPMI 1.0 specification can be obtained from the Intel ftp site. 
  587.  Here is the URL. 
  588.  
  589.  
  590.     ftp://ftp.intel.com/pub/IAL/software_specs/dpmiv1.zip 
  591.  
  592.  This ZIP file contains a Postscript version of the DPMI 1.0 specification. 
  593.  
  594.  
  595. ΓòÉΓòÉΓòÉ 5.1. How can I write directly to video memory using a DOS extender? ΓòÉΓòÉΓòÉ
  596.  
  597.  
  598. Many programmers require access to video RAM in order to directly manipulate 
  599. data on the screen.  Under DOS, it was standard practice to use a far pointer, 
  600. with the segment part of the far pointer set to the screen segment.  Under DOS 
  601. extenders, this practice is not so standard.  Each DOS extender provides its 
  602. own method for accessing video memory. 
  603.  
  604.  
  605. ΓòÉΓòÉΓòÉ 5.1.1. Writing to Video Memory under Tenberry Software DOS/4GW ΓòÉΓòÉΓòÉ
  606.  
  607.  
  608. Under DOS/4GW, the first megabyte of physical memory is mapped as a shared 
  609. linear address space.  This allows your application to access video RAM using a 
  610. near pointer set to the screen's linear address.  The following program 
  611. demonstrates this method. 
  612.  
  613.  
  614.    /* 
  615.      SCREEN.C - This example shows how to write directly 
  616.      to screen memory under the DOS/4GW dos-extender. 
  617.  
  618.      Compile & Link: wcl386 /l=dos4g SCREEN 
  619.    */ 
  620.    #include <stdio.h> 
  621.    #include <dos.h> 
  622.  
  623.    /* 
  624.     Under DOS/4GW, the first megabyte of physical memory 
  625.     (real-mode memory) is mapped as a shared linear address 
  626.     space. This allows your application to access video RAM 
  627.     using its linear address.  The DOS segment:offset of 
  628.     B800:0000 corresponds to a linear address of B8000. 
  629.    */ 
  630.    #define SCREEN_AREA 0xb800 
  631.    #define SCREEN_LIN_ADDR ((SCREEN_AREA) << 4) 
  632.    #define SCREEN_SIZE 80*25 
  633.  
  634.    void main() 
  635.    { 
  636.      char    *ptr; 
  637.      int     i; 
  638.  
  639.      /* Set the pointer to the screen's linear address */ 
  640.      ptr = (char *)SCREEN_LIN_ADDR; 
  641.      for( i = 0; i < SCREEN_SIZE - 1; i++ ) { 
  642.        *ptr = '*'; 
  643.        ptr += 2 * sizeof( char ); 
  644.      } 
  645.    } 
  646.  
  647. Please refer to the chapter entitled DOS/4GW:  Linear Executables for more 
  648. information on how DOS/4GW maps the first megabyte. 
  649.  
  650.  
  651. ΓòÉΓòÉΓòÉ 5.1.2. Writing to Video Memory under the Phar Lap 386|DOS-Extender ΓòÉΓòÉΓòÉ
  652.  
  653.  
  654. The Phar Lap DOS extender provides screen access through the special segment 
  655. selector 0x1C.  This allows far pointer access to video RAM from a 32-bit 
  656. program.  The following example illustrates this technique. 
  657.  
  658.  
  659.    /* 
  660.      SCREENPL.C - This example shows how to write directly 
  661.      to screen memory under the Phar Lap DOS extender. 
  662.  
  663.      Compile & Link: wcl386 /l=pharlap SCREENPL 
  664.    */ 
  665.    #include <stdio.h> 
  666.    #include <dos.h> 
  667.  
  668.    /* 
  669.      Phar Lap allows access to screen memory through a 
  670.      special selector.  Refer to "Hardware Access" in 
  671.      Phar Lap's documentation for details. 
  672.    */ 
  673.    #define PL_SCREEN_SELECTOR 0x1c 
  674.    #define SCREEN_SIZE 80*25 
  675.  
  676.    void main() 
  677.    { 
  678.      /* Need a far pointer to use the screen selector */ 
  679.      char far  *ptr; 
  680.      int     i; 
  681.  
  682.      /* Make a far pointer to screen memory */ 
  683.      ptr = MK_FP( PL_SCREEN_SELECTOR, 0 ); 
  684.      for( i = 0; i < SCREEN_SIZE - 1; i++ ) { 
  685.        *ptr = '*'; 
  686.        ptr += 2 * sizeof( char ); 
  687.      } 
  688.    } 
  689.  
  690. It is also possible to map screen memory into your near memory using Phar Lap 
  691. system calls.  Please refer to the chapter entitled "386|DOS-Extender System 
  692. Calls" in Phar Lap's 386|DOS-Extender Reference Manual for details. 
  693.  
  694.  
  695. ΓòÉΓòÉΓòÉ 5.2. How do I get information about free memory in the 32-bit environment? ΓòÉΓòÉΓòÉ
  696.  
  697.  
  698. Under a virtual memory system, programmers are often interested in the amount 
  699. of physical memory they can allocate.  Information about the amount of free 
  700. memory that is available is always provided under a DPMI host, however, the 
  701. manner in which this information is provided may differ under various 
  702. environments.  Keep in mind that in a multi-tasking environment, the 
  703. information returned to your task from the DPMI host can easily become obsolete 
  704. if other tasks allocate memory independently of your task. 
  705.  
  706.  
  707. ΓòÉΓòÉΓòÉ 5.2.1. Getting Free Memory Information under DOS/4GW ΓòÉΓòÉΓòÉ
  708.  
  709.  
  710. DOS/4GW provides a DPMI interface through interrupt 0x31.  This allows you to 
  711. use DPMI service 0x0500 to get free memory information.  The following program 
  712. illustrates this procedure. 
  713.  
  714.  
  715.    /* 
  716.      MEMORY.C - This example shows how to get information 
  717.      about free memory using DPMI call 0500h under DOS/4GW. 
  718.      Note that only the first field of the structure is 
  719.      guaranteed to contain a valid value; any field that 
  720.      is not returned by DOS/4GW is set to -1 (0FFFFFFFFh). 
  721.  
  722.      Compile & Link: wcl386 /l=dos4g memory 
  723.    */ 
  724.    #include <i86.h> 
  725.    #include <dos.h> 
  726.    #include <stdio.h> 
  727.  
  728.    #define DPMI_INT     0x31 
  729.  
  730.    struct meminfo { 
  731.      unsigned LargestBlockAvail; 
  732.      unsigned MaxUnlockedPage; 
  733.      unsigned LargestLockablePage; 
  734.      unsigned LinAddrSpace; 
  735.      unsigned NumFreePagesAvail; 
  736.      unsigned NumPhysicalPagesFree; 
  737.      unsigned TotalPhysicalPages; 
  738.      unsigned FreeLinAddrSpace; 
  739.      unsigned SizeOfPageFile; 
  740.      unsigned Reserved[3]; 
  741.    } MemInfo; 
  742.  
  743.    void main() 
  744.    { 
  745.      union REGS regs; 
  746.      struct SREGS sregs; 
  747.  
  748.      regs.x.eax = 0x00000500; 
  749.      memset( &sregs, 0, sizeof(sregs) ); 
  750.      sregs.es = FP_SEG( &MemInfo ); 
  751.      regs.x.edi = FP_OFF( &MemInfo ); 
  752.  
  753.      int386x( DPMI_INT, ®s, ®s, &sregs ); 
  754.      printf( "Largest available block (in bytes): %lu\n", 
  755.          MemInfo.LargestBlockAvail ); 
  756.      printf( "Maximum unlocked page allocation: %lu\n", 
  757.          MemInfo.MaxUnlockedPage ); 
  758.      printf( "Pages that can be allocated and locked: " 
  759.          "%lu\n", MemInfo.LargestLockablePage ); 
  760.      printf( "Total linear address space including " 
  761.          "allocated pages: %lu\n", 
  762.          MemInfo.LinAddrSpace ); 
  763.      printf( "Number of free pages available: %lu\n", 
  764.          MemInfo.NumFreePagesAvail ); 
  765.      printf( "Number of physical pages not in use: %lu\n", 
  766.          MemInfo.NumPhysicalPagesFree ); 
  767.      printf( "Total physical pages managed by host: %lu\n", 
  768.          MemInfo.TotalPhysicalPages ); 
  769.      printf( "Free linear address space (pages): %lu\n", 
  770.          MemInfo.FreeLinAddrSpace ); 
  771.      printf( "Size of paging/file partition (pages): %lu\n", 
  772.          MemInfo.SizeOfPageFile ); 
  773.    } 
  774.  
  775. Please refer to the chapter entitled DOS/4GW:  Interrupt 31H DPMI Functions for 
  776. more information on DPMI services. 
  777.  
  778.  
  779. ΓòÉΓòÉΓòÉ 5.2.2. Getting Free Memory Information under the Phar Lap 386|DOS-Extender ΓòÉΓòÉΓòÉ
  780.  
  781.  
  782. Phar Lap provides memory statistics through 386|DOS-Extender System Call 
  783. 0x2520.  The following example illustrates how to use this system call from a 
  784. 32-bit program. 
  785.  
  786.  
  787.    /* 
  788.      MEMPLS40.C - This is an example of how to get the 
  789.      amount of physical memory present under Phar Lap 
  790.      386|DOS-Extender v4.0. 
  791.  
  792.      Compile & Link: wcl386 /l=pharlap MEMPLS40 
  793.    */ 
  794.    #include <dos.h> 
  795.    #include <stdio.h> 
  796.  
  797.    typedef struct { 
  798.      unsigned data[25]; 
  799.    } pharlap_mem_status; 
  800.  
  801.    /* Names suggested in Phar Lap documentation */ 
  802.    #define APHYSPG   5 
  803.    #define SYSPHYSPG  7 
  804.    #define NFREEPG   21 
  805.  
  806.    unsigned long memavail( void ) 
  807.    { 
  808.      pharlap_mem_status status; 
  809.      union REGS regs; 
  810.      unsigned long amount; 
  811.  
  812.      regs.h.ah = 0x25; 
  813.      regs.h.al = 0x20; 
  814.      regs.h.bl = 0; 
  815.      regs.x.edx = (unsigned int) &status; 
  816.      intdos( ®s, ®s ); 
  817.      /* equation is given in description for nfreepg */ 
  818.      amount = status.data[ APHYSPG ]; 
  819.      amount += status.data[ SYSPHYSPG ]; 
  820.      amount += status.data[ NFREEPG ]; 
  821.      return( amount * 4096 ); 
  822.    } 
  823.  
  824.    void main() 
  825.    { 
  826.      printf( "%lu bytes of memory available\n", 
  827.          memavail() ); 
  828.    } 
  829.  
  830. Please refer to the chapter entitled "386|DOS-Extender System Calls" in Phar 
  831. Lap's 386|DOS-Extender Reference Manual for more information on 
  832. 386|DOS-Extender System Calls. 
  833.  
  834.  
  835. ΓòÉΓòÉΓòÉ 5.2.3. Getting Free Memory Information in the 32-bit Environment under Windows 3.x ΓòÉΓòÉΓòÉ
  836.  
  837.  
  838. Windows 3.x provides a DPMI host that you can access from a 32-bit program. 
  839. The interface to this host is a 16-bit interface, hence there are some 
  840. considerations involved when calling Windows 3.x DPMI services from 32-bit 
  841. code.  If a pointer to a data buffer is required to be passed in ES:DI, for 
  842. example, an AllocAlias16() may be used to get a 16-bit far pointer that can be 
  843. passed to Windows 3.x through these registers.  Also, an int86() call should be 
  844. issued rather than an int386() call.  The following program demonstrates the 
  845. techniques mentioned above. 
  846.  
  847.  
  848.    /* 
  849.      MEMWIN.C - This example shows how to get information 
  850.      about free memory with DPMI call 0x0500 using Windows 
  851.      as a DPMI host.  Note that only the first field of the 
  852.      structure is guaranteed to contain a valid value; any 
  853.      field that is not returned by the DPMI implementation 
  854.      is set to -1 (0FFFFFFFFh). 
  855.  
  856.      Compile & Link: wcl386 /l=win386 /zw memwin 
  857.      Bind: wbind -n memwin 
  858.    */ 
  859.    #include <windows.h> 
  860.    #include <i86.h> 
  861.    #include <dos.h> 
  862.    #include <stdio.h> 
  863.  
  864.    struct meminfo { 
  865.      unsigned LargestBlockAvail; 
  866.      unsigned MaxUnlockedPage; 
  867.      unsigned LargestLockablePage; 
  868.      unsigned LinAddrSpace; 
  869.      unsigned NumFreePagesAvail; 
  870.      unsigned NumPhysicalPagesFree; 
  871.      unsigned TotalPhysicalPages; 
  872.      unsigned FreeLinAddrSpace; 
  873.      unsigned SizeOfPageFile; 
  874.      unsigned Reserved[3]; 
  875.    } MemInfo; 
  876.  
  877.    #define DPMI_INT     0x31 
  878.  
  879.    void main() 
  880.    { 
  881.      union REGS regs; 
  882.      struct SREGS sregs; 
  883.      DWORD mi_16; 
  884.  
  885.      regs.w.ax = 0x0500; 
  886.      mi_16 = AllocAlias16( &MemInfo ); 
  887.      sregs.es = HIWORD( mi_16 ); 
  888.      regs.x.di = LOWORD( mi_16 ); 
  889.  
  890.      int86x( DPMI_INT, ®s, ®s, &sregs ); 
  891.      printf( "Largest available block (in bytes): %lu\n", 
  892.          MemInfo.LargestBlockAvail ); 
  893.      printf( "Maximum unlocked page allocation: %lu\n", 
  894.          MemInfo.MaxUnlockedPage ); 
  895.      printf( "Pages that can be allocated and locked: " 
  896.          "%lu\n", MemInfo.LargestLockablePage ); 
  897.      printf( "Total linear address space including " 
  898.          "allocated pages: %lu\n", 
  899.          MemInfo.LinAddrSpace ); 
  900.      printf( "Number of free pages available: %lu\n", 
  901.          MemInfo.NumFreePagesAvail ); 
  902.      printf( "Number of physical pages not in use: %lu\n", 
  903.          MemInfo.NumPhysicalPagesFree ); 
  904.      printf( "Total physical pages managed by host: %lu\n", 
  905.          MemInfo.TotalPhysicalPages ); 
  906.      printf( "Free linear address space (pages): %lu\n", 
  907.          MemInfo.FreeLinAddrSpace ); 
  908.      printf( "Size of paging/file partition (pages): %lu\n", 
  909.          MemInfo.SizeOfPageFile ); 
  910.      FreeAlias16( mi_16 ); 
  911.    } 
  912.  
  913. Please refer to the DOS Protected-Mode Interface (DPMI) Specification for 
  914. information on DPMI services.  In the past, the DPMI specification could be 
  915. obtained free of charge by contacting Intel Literature JP26 at 800-548-4725 or 
  916. by writing to the address below.  We have been advised that the DPMI 
  917. specification is no longer available in printed form. 
  918.  
  919.    Intel Literature JP26 
  920.    3065 Bowers Avenue 
  921.    P.O. Box 58065 
  922.    Santa Clara, California 
  923.    U.S.A. 95051-8065 
  924.  
  925. However, the DPMI 1.0 specification can be obtained from the Intel ftp site. 
  926. Here is the URL. 
  927.  
  928.  
  929.    ftp://ftp.intel.com/pub/IAL/software_specs/dpmiv1.zip 
  930.  
  931. This ZIP file contains a Postscript version of the DPMI 1.0 specification. 
  932.  
  933.  
  934. ΓòÉΓòÉΓòÉ 5.3. How do I access the first megabyte in the extended DOS environment? ΓòÉΓòÉΓòÉ
  935.  
  936.  
  937. Many programmers require access to the first megabyte of memory in order to 
  938. look at key low memory addresses.  Under DOS, it was standard practice to use a 
  939. far pointer, with the far pointer set to the segmented address of the memory 
  940. area that was being inspected.  Under DOS extenders, this practice is not so 
  941. standard.  Each DOS extender provides its own method for accessing the first 
  942. megabyte of memory. 
  943.  
  944.  
  945. ΓòÉΓòÉΓòÉ 5.3.1. Accessing the First Megabyte under Tenberry Software DOS/4GW ΓòÉΓòÉΓòÉ
  946.  
  947.  
  948. Under DOS/4GW, the first megabyte of physical memory - the real memory - is 
  949. mapped as a shared linear address space.  This allows your application to 
  950. access the first megabyte of memory using a near pointer set to the linear 
  951. address.  The following program demonstrates this method.  This example is 
  952. similar to the screen memory access example. 
  953.  
  954.  
  955.    /* 
  956.      KEYSTAT.C - This example shows how to get the keyboard 
  957.      status under DOS/4GW by looking at the ROM BIOS 
  958.      keyboard status byte in low memory. 
  959.  
  960.      Compile & Link: wcl386 /l=dos4g keystat 
  961.    */ 
  962.    #include <stdio.h> 
  963.    #include <dos.h> 
  964.  
  965.    /* 
  966.      Under DOS, the keyboard status byte has a segmented 
  967.      address of 0x0040:0x0017.  This corresponds to a 
  968.      linear address of 0x417. 
  969.    */ 
  970.    #define LOW_AREA 0x417 
  971.  
  972.    void main() 
  973.    { 
  974.      /* Only need a near pointer in the flat model */ 
  975.      char *ptr; 
  976.  
  977.      /* Set pointer to linear address of the first 
  978.       status byte */ 
  979.      ptr = (char *)LOW_AREA; 
  980.  
  981.      /* Caps lock state is in bit 6 */ 
  982.      if( *ptr & 0x40 ) { 
  983.        puts( "Caps Lock on" ); 
  984.      } 
  985.  
  986.      /* Num lock state is in bit 5 */ 
  987.      if( *ptr & 0x20 ) { 
  988.        puts( "Num Lock on" ); 
  989.      } 
  990.  
  991.      /* Scroll lock state is in bit 4 */ 
  992.      if( *ptr & 0x10 ) { 
  993.        puts( "Scroll Lock on" ); 
  994.      } 
  995.    } 
  996.  
  997. Please refer to the chapter entitled DOS/4GW:  Linear Executables for more 
  998. information on how DOS/4GW maps the first megabyte. 
  999.  
  1000.  
  1001. ΓòÉΓòÉΓòÉ 5.3.2. Accessing the First Megabyte under the Phar Lap 386|DOS-Extender ΓòÉΓòÉΓòÉ
  1002.  
  1003.  
  1004. The Phar Lap DOS extender provides access to real memory through the special 
  1005. segment selector 0x34.  This allows far pointer access to the first megabyte 
  1006. from a 32-bit program.  The following example illustrates this technique. 
  1007.  
  1008.  
  1009.    /* 
  1010.      KEYSTAPL.C - This example shows how to get the keyboard 
  1011.      status under 386|DOS-Extender by looking at the ROM 
  1012.      BIOS keyboard status byte in low memory. 
  1013.  
  1014.      Compile & Link: wcl386 /l=pharlap keystapl 
  1015.    */ 
  1016.    #include <stdio.h> 
  1017.    #include <dos.h> 
  1018.  
  1019.    /* 
  1020.      Under DOS, the keyboard status byte has a segmented 
  1021.      address of 0x0040:0x0017.  This corresponds to a 
  1022.      linear address of 0x417. 
  1023.    */ 
  1024.  
  1025.    void main() 
  1026.    { 
  1027.      /* We require a far pointer to use selector 
  1028.       for 1st megabyte */ 
  1029.      char far *ptr; 
  1030.  
  1031.      /* Set pointer to segmented address of the first 
  1032.       status byte */ 
  1033.      ptr = MK_FP( 0x34, 0x417 ); 
  1034.  
  1035.      /* Caps lock state is in bit 6 */ 
  1036.      if( *ptr & 0x40 ) { 
  1037.        puts( "Caps Lock on" ); 
  1038.      } 
  1039.  
  1040.      /* Num lock state is in bit 5 */ 
  1041.      if( *ptr & 0x20 ) { 
  1042.        puts( "Num Lock on" ); 
  1043.      } 
  1044.  
  1045.      /* Scroll lock state is in bit 4 */ 
  1046.      if( *ptr & 0x10 ) { 
  1047.        puts( "Scroll Lock on" ); 
  1048.      } 
  1049.    } 
  1050.  
  1051. Please refer to the chapter entitled "Program Environment" in Phar Lap's 
  1052. 386|DOS-Extender Reference Manual for more information on segment selectors 
  1053. available to your program. 
  1054.  
  1055.  
  1056. ΓòÉΓòÉΓòÉ 5.4. How do I spawn a protected-mode application? ΓòÉΓòÉΓòÉ
  1057.  
  1058.  
  1059. Sometimes applications need to spawn other programs as part of their execution. 
  1060. In the extended DOS environment, spawning tasks is much the same as under DOS, 
  1061. however it should be noted that the only mode supported is P_WAIT.  The 
  1062. P_OVERLAY mode is not supported since the DOS extender cannot be removed from 
  1063. memory by the application (this is also the reason why the exec() functions are 
  1064. unsupported).  The other modes are for concurrent operating systems only. 
  1065.  
  1066. Also, unless the application being spawned is bound or stubbed, the DOS 
  1067. extender must be spawned with the application and its arguments passed in the 
  1068. parameter list. 
  1069.  
  1070.  
  1071. ΓòÉΓòÉΓòÉ 5.4.1. Spawning Protected-Mode Applications Under Tenberry Software DOS/4GW ΓòÉΓòÉΓòÉ
  1072.  
  1073.  
  1074. In the case of DOS/4GW, some real-mode memory must be set aside at run time for 
  1075. spawning the DOS extender, otherwise the spawning application could potentially 
  1076. allocate all of system memory.  The real memory can be reserved from within 
  1077. your program by assigning the global variable __minreal the number of bytes to 
  1078. be set aside.  This variable is referenced in <stdlib.h>.  The following two 
  1079. programs demonstrate how to spawn a DOS/4GW application. 
  1080.  
  1081.  
  1082.    /* 
  1083.      SPWNRD4G.C - The following program demonstrates how to 
  1084.      spawn another DOS/4GW application. 
  1085.  
  1086.      Compile and link: wcl386 /l=dos4g spwnrd4g 
  1087.    */ 
  1088.    #include <process.h> 
  1089.    #include <stdio.h> 
  1090.    #include <stdlib.h> 
  1091.  
  1092.    /* DOS/4GW var for WLINK MINREAL option */ 
  1093.    unsigned __near __minreal = 100*1024; 
  1094.  
  1095.    void main() 
  1096.    { 
  1097.      int app2_exit_code; 
  1098.  
  1099.      puts( "Spawning a protected-mode application..." 
  1100.         "using spawnlp() with P_WAIT" ); 
  1101.      app2_exit_code = spawnlp( P_WAIT, "dos4gw", 
  1102.                  "dos4gw", "spwndd4g", NULL ); 
  1103.      printf( "Application #2 returned with exit code %d\n", 
  1104.                  app2_exit_code ); 
  1105.    } 
  1106.  
  1107.  
  1108.    /* 
  1109.      SPWNDD4G.C - Will be spawned by the SPWNRD4G program. 
  1110.  
  1111.      Compile & Link: wcl386 /l=dos4g spwndd4g 
  1112.    */ 
  1113.    #include <stdio.h> 
  1114.    #include <stdlib.h> 
  1115.  
  1116.    void main() 
  1117.    { 
  1118.      puts( "\nApplication #2 spawned\n" ); 
  1119.      /* Send back exit code 59 */ 
  1120.      exit( 59 ); 
  1121.    } 
  1122.  
  1123.  
  1124. ΓòÉΓòÉΓòÉ 5.4.2. Spawning Protected-Mode Applications Under Phar Lap 386|DOS-Extender ΓòÉΓòÉΓòÉ
  1125.  
  1126.  
  1127. In the case of the Phar Lap 386|DOS-Extender, some real-mode memory must be set 
  1128. aside at link time for spawning the DOS extender, otherwise the spawning 
  1129. application will be assigned all the system memory at startup.  This is done at 
  1130. link time by specifying the runtime minreal and runtime maxreal options, as 
  1131. demonstrated by the following programs. 
  1132.  
  1133.  
  1134.    /* 
  1135.      SPWNRPLS.C - The following program demonstrates how to 
  1136.      spawn a Phar Lap application. 
  1137.  
  1138.      Compile & Link: 
  1139.      wcl386 /l=pharlap /"runt minr=300K,maxr=400K" spwnrpls 
  1140.    */ 
  1141.    #include <process.h> 
  1142.    #include <stdio.h> 
  1143.  
  1144.    void main() 
  1145.    { 
  1146.      int app2_exit_code; 
  1147.  
  1148.      puts( "Spawning a protect-mode application..." 
  1149.         "using spawnlp() with P_WAIT" ); 
  1150.      puts( "Spawning application #2..." ); 
  1151.      app2_exit_code = spawnlp( P_WAIT, "run386", 
  1152.                  "run386", "spwndpls", NULL ); 
  1153.  
  1154.      printf( "Application #2 returned with exit code %d", 
  1155.            app2_exit_code ); 
  1156.    } 
  1157.  
  1158.  
  1159.    /* 
  1160.      SPWNDPLS.C - Will be spawned by the SPWNRPLS program. 
  1161.  
  1162.      Compile & Link: wcl386 /l=pharlap spwndpls 
  1163.    */ 
  1164.    #include <stdio.h> 
  1165.    #include <stdlib.h> 
  1166.  
  1167.    void main() 
  1168.    { 
  1169.      puts( "\nApplication #2 spawned\n" ); 
  1170.      /* Exit with error code 59 */ 
  1171.      exit( 59 ); 
  1172.    } 
  1173.  
  1174.  
  1175. ΓòÉΓòÉΓòÉ 5.5. How Can I Use the Mouse Interrupt (0x33) with DOS/4GW? ΓòÉΓòÉΓòÉ
  1176.  
  1177.  
  1178. Several commonly used interrupts are automatically supported in protected mode 
  1179. with DOS/4GW.  The DOS extender handles the switch from protected mode to real 
  1180. mode and manages any intermediate real-mode data buffers that are required.  To 
  1181. use a supported interrupt, set up the register information as required for the 
  1182. interrupt and use one of the int386() or int386x() library functions to execute 
  1183. the interrupt.  For calls that are not supported by DOS/4GW, you can use the 
  1184. DPMI function, Simulate a Real-Mode Interrupt (0x0300).  This process is 
  1185. described in the next section. 
  1186.  
  1187. Since the mouse interrupt (0x33) is quite commonly used, DOS/4GW provides 
  1188. protected-mode support for the interrupt and any mouse data buffer that is 
  1189. required.  The following example demonstrates how a programmer could use the 
  1190. Microsoft standard mouse interrupt (0x33) from within a DOS/4GW application. 
  1191.  
  1192.  
  1193.    /* 
  1194.      MOUSE.C - The following program demonstrates how 
  1195.      to use the mouse interrupt (0x33) with DOS/4GW. 
  1196.  
  1197.      Compile and link: wcl386 /l=dos4g mouse 
  1198.    */ 
  1199.    #include <stdio.h> 
  1200.    #include <dos.h> 
  1201.    #include <i86.h> 
  1202.  
  1203.    int right_button = 0; 
  1204.    int mouse_event = 0; 
  1205.    int mouse_code = 0; 
  1206.    int mouse_cx = 0; 
  1207.    int mouse_dx = 0; 
  1208.  
  1209.    /* Set up data buffer for mouse cursor bitmap */ 
  1210.    unsigned short cursor[] = 
  1211.    { 
  1212.      0x0001, 0x0200, 0x0000, 0x0000, 
  1213.      0x0001, 0x0200, 0x0000, 0x0000, 
  1214.      0x0001, 0x0200, 0x0000, 0x0000, 
  1215.      0x0001, 0x0200, 0x0000, 0x0000, 
  1216.      0x0001, 0x0200, 0x0000, 0x0000, 
  1217.      0x0001, 0x0200, 0x0000, 0x0000, 
  1218.      0x0001, 0x0200, 0x0000, 0x0000, 
  1219.      0x0001, 0x0200, 0x0000, 0x0000, 
  1220.      0x0001, 0x0200, 0x0000, 0x0000, 
  1221.      0x0001, 0x0200, 0x0000, 0x0000, 
  1222.      0x0001, 0x0200, 0x0000, 0x0000, 
  1223.      0x0001, 0x0200, 0x0000, 0x0000, 
  1224.      0x0001, 0x0200, 0x0000, 0x0000, 
  1225.      0x0001, 0x0200, 0x0000, 0x0000, 
  1226.      0x0001, 0x0200, 0x0000, 0x0000, 
  1227.      0x0001, 0x0200, 0x0000, 0x0000 
  1228.    }; 
  1229.  
  1230.    #pragma off (check_stack) 
  1231.    void _loadds far click_handler (int max, int mcx, int mdx) 
  1232.    { 
  1233.    #pragma aux click_handler parm [EAX] [ECX] [EDX] 
  1234.        mouse_event = 1; 
  1235.        mouse_code = max; 
  1236.        mouse_cx = mcx; 
  1237.        mouse_dx = mdx; 
  1238.        if( mouse_code & 8 ) right_button = 1; 
  1239.    } 
  1240.    #pragma on (check_stack) 
  1241.  
  1242.    void main( void ) 
  1243.    { 
  1244.      struct SREGS sregs; 
  1245.      union REGS inregs, outregs; 
  1246.      int installed = 0; 
  1247.      int orig_mode = 0; 
  1248.      int far *ptr; 
  1249.      int (far *function_ptr)(); 
  1250.  
  1251.      segread(&sregs); 
  1252.  
  1253.      /* get original video mode */ 
  1254.  
  1255.      inregs.w.ax = 0x0f00; 
  1256.      int386( 0x10, &inregs, &outregs ); 
  1257.  
  1258.      printf( "Current Mode = %u\n", 
  1259.          orig_mode=outregs.h.al ); 
  1260.  
  1261.      /* check for mouse driver */ 
  1262.  
  1263.      inregs.w.ax = 0; 
  1264.      int386 (0x33, &inregs, &outregs); 
  1265.      if( installed = (outregs.w.ax == -1) ) 
  1266.        printf( "Mouse installed...\n" ); 
  1267.      else 
  1268.        printf( "Mouse NOT installed...\n" ); 
  1269.  
  1270.      if( installed ) { 
  1271.  
  1272.        /* goto graphics mode */ 
  1273.  
  1274.        inregs.h.ah = 0x00; 
  1275.        inregs.h.al = 0x4; 
  1276.        int386( 0x10, &inregs, &outregs ); 
  1277.  
  1278.        /* show mouse cursor */ 
  1279.  
  1280.        inregs.w.ax = 0x1; 
  1281.        int386( 0x33, &inregs, &outregs ); 
  1282.  
  1283.        /* set mouse cursor form */ 
  1284.  
  1285.        inregs.w.ax = 0x9; 
  1286.        inregs.w.bx = 0x0; 
  1287.        inregs.w.cx = 0x0; 
  1288.        ptr = cursor; 
  1289.        inregs.x.edx = FP_OFF( ptr ); 
  1290.        sregs.es   = FP_SEG( ptr ); 
  1291.        int386x( 0x33, &inregs, &outregs, &sregs ); 
  1292.  
  1293.        /* install click watcher */ 
  1294.  
  1295.        inregs.w.ax = 0xC; 
  1296.        inregs.w.cx = 0x0002 + 0x0008; 
  1297.        function_ptr = click_handler; 
  1298.        inregs.x.edx = FP_OFF( function_ptr ); 
  1299.        sregs.es   = FP_SEG( function_ptr ); 
  1300.        int386x( 0x33, &inregs, &outregs, &sregs ); 
  1301.  
  1302.        while( !right_button ) { 
  1303.          if( mouse_event ) { 
  1304.            printf( "Event = %x : CX = %u DX = %u\n", 
  1305.                mouse_code, mouse_cx, mouse_dx ); 
  1306.            mouse_event = 0; 
  1307.          } 
  1308.        } 
  1309.      } 
  1310.  
  1311.      /* check installation again (to clear watcher) */ 
  1312.  
  1313.      inregs.w.ax = 0; 
  1314.      int386( 0x33, &inregs, &outregs ); 
  1315.      if( outregs.w.ax == -1 ) 
  1316.        printf( "DONE : Mouse still installed...\n" ); 
  1317.      else 
  1318.        printf( "DONE : Mouse NOT installed...\n" ); 
  1319.  
  1320.      inregs.h.ah = 0x00; 
  1321.      inregs.h.al = orig_mode; 
  1322.      int386( 0x10, &inregs, &outregs ); 
  1323.    } 
  1324.  
  1325.  
  1326. ΓòÉΓòÉΓòÉ 5.6. How Do I Simulate a Real-Mode Interrupt with DOS/4GW? ΓòÉΓòÉΓòÉ
  1327.  
  1328.  
  1329. Some interrupts are not supported in protected mode with DOS/4GW but they can 
  1330. still be called using the DPMI function, Simulate Real-Mode Interrupt (0x0300). 
  1331. Information that needs to be passed down to the real-mode interrupt is 
  1332. transferred using an information data structure that is allocated in the 
  1333. protected-mode application.  The address to this protected-mode structure is 
  1334. passed into DPMI function 0x0300.  DOS/4GW will then use this information to 
  1335. set up the real-mode registers, switch to real mode and then execute the 
  1336. interrupt in real mode. 
  1337.  
  1338. If your protected-mode application needs to pass data down into the real-mode 
  1339. interrupt, an intermediate real-mode buffer must be used.  This buffer can be 
  1340. created using DPMI function 0x0100 to allocate real-mode memory.  You can then 
  1341. transfer data from the protected-mode memory to the real-mode memory using a 
  1342. far pointer as illustrated in the "SIMULATE.C" example. 
  1343.  
  1344. The following example illustrates how to allocate some real-mode memory, 
  1345. transfer a string of characters from protected mode into the real-mode buffer, 
  1346. then set up and call the Interrupt 0x0021 function to create a directory.  The 
  1347. string of characters are used to provide the directory name.  This example can 
  1348. be adapted to handle most real-mode interrupt calls that aren't supported in 
  1349. protected mode. 
  1350.  
  1351.  
  1352.    /* 
  1353.      SIMULATE.C - Shows how to issue a real-mode interrupt 
  1354.      from protected mode using DPMI call 300h.  Any buffers 
  1355.      to be passed to DOS must be allocated in DOS memory 
  1356.      This can be done with DPMI call 100h.  This program 
  1357.      will call DOS int 21, function 39h, "Create 
  1358.      Directory". 
  1359.  
  1360.      Compile & Link: wcl386 /l=dos4g simulate 
  1361.    */ 
  1362.    #include <i86.h> 
  1363.    #include <dos.h> 
  1364.    #include <stdio.h> 
  1365.    #include <string.h> 
  1366.  
  1367.    static struct rminfo { 
  1368.      long EDI; 
  1369.      long ESI; 
  1370.      long EBP; 
  1371.      long reserved_by_system; 
  1372.      long EBX; 
  1373.      long EDX; 
  1374.      long ECX; 
  1375.      long EAX; 
  1376.      short flags; 
  1377.      short ES,DS,FS,GS,IP,CS,SP,SS; 
  1378.    } RMI; 
  1379.  
  1380.    void main() 
  1381.    { 
  1382.      union REGS regs; 
  1383.      struct SREGS sregs; 
  1384.      int interrupt_no=0x31; 
  1385.      short selector; 
  1386.      short segment; 
  1387.      char far *str; 
  1388.  
  1389.      /* DPMI call 100h allocates DOS memory */ 
  1390.      memset(&sregs,0,sizeof(sregs)); 
  1391.      regs.w.ax=0x0100; 
  1392.      regs.w.bx=0x0001; 
  1393.      int386x( interrupt_no, ®s, ®s, &sregs); 
  1394.      segment=regs.w.ax; 
  1395.      selector=regs.w.dx; 
  1396.  
  1397.      /* Move string to DOS real-mode memory */ 
  1398.      str=MK_FP(selector,0); 
  1399.      _fstrcpy( str, "myjunk" ); 
  1400.  
  1401.      /* Set up real-mode call structure */ 
  1402.      memset(&RMI,0,sizeof(RMI)); 
  1403.      RMI.EAX=0x00003900; /* call service 39h ah=0x39  */ 
  1404.      RMI.DS=segment;   /* put DOS seg:off into DS:DX*/ 
  1405.      RMI.EDX=0;      /* DOS ignores EDX high word */ 
  1406.  
  1407.      /* Use DPMI call 300h to issue the DOS interrupt */ 
  1408.      regs.w.ax = 0x0300; 
  1409.      regs.h.bl = 0x21; 
  1410.      regs.h.bh = 0; 
  1411.      regs.w.cx = 0; 
  1412.      sregs.es = FP_SEG(&RMI); 
  1413.      regs.x.edi = FP_OFF(&RMI); 
  1414.      int386x( interrupt_no, ®s, ®s, &sregs ); 
  1415.    } 
  1416.  
  1417.  
  1418. ΓòÉΓòÉΓòÉ 5.7. How do you install a bi-modal interrupt handler using DOS/4GW? ΓòÉΓòÉΓòÉ
  1419.  
  1420.  
  1421. Due to the nature of the protected-mode/real-mode interface, it is often 
  1422. difficult to handle high speed communications with hardware interrupt handlers. 
  1423. For example, if you install your communications interrupt handler in protected 
  1424. mode, you may find that some data is lost when transmitting data from a remote 
  1425. machine at the rate of 9600 baud.  This occurs because the data arrived at the 
  1426. communication port while the machine was in the process of transferring the 
  1427. previous interrupt up to protected mode.  Data will also be lost if you install 
  1428. the interrupt handler in real mode since your program, running in protected 
  1429. mode, will have to switch down into real mode to handle the interrupt.  The 
  1430. reason for this is that the data arrived at the communication port while the 
  1431. DOS extender was switching between real mode and protected mode, and the 
  1432. machine was not available to process the interrupt. 
  1433.  
  1434. To avoid the delay caused by switching between real-mode and protected mode to 
  1435. handle hardware interrupts, install interrupt handlers in both real-mode and 
  1436. protected-mode.  During the execution of a protected-mode program, the system 
  1437. often switches down into real-mode for DOS system calls.  If a communications 
  1438. interrupt occurs while the machine is in real-mode, then the real-mode 
  1439. interrupt handler will be used.  If the interrupt occurs when the machine is 
  1440. executing in protected-mode, then the protected-mode interrupt handler will be 
  1441. used.  This enables the machine to process the hardware interrupts faster and 
  1442. avoid the loss of data caused by context switching. 
  1443.  
  1444. Installing the interrupt handlers in both protected-mode and real-mode is 
  1445. called bi-modal interrupt handling.  The following program is an example of how 
  1446. to install both handlers for Interrupt 0x0C (also known as COM1 or IRQ4).  The 
  1447. program writes either a 'P' to absolute address 0xB8002 or an 'R' to absolute 
  1448. address 0xB8000.  These locations are the first two character positions in 
  1449. screen memory for a color display.  As the program runs, you can determine 
  1450. which interrupt is handling the COM1 port by the letter that is displayed.  A 
  1451. mouse attached to COM1 makes a suitable demo.  Type on the keyboard as you move 
  1452. the mouse around.  The ESC key can be used to terminate the program. 
  1453. Transmitted data from a remote machine at 9600 baud can also be used to test 
  1454. the COM1 handling. 
  1455.  
  1456.  
  1457.    /* 
  1458.      BIMODAL.C - The following program demonstrates how 
  1459.      to set up a bi-modal interrupt handler for DOS/4GW 
  1460.  
  1461.      Compile and link: wcl386 /l=dos4g bimodal bimo.obj 
  1462.    */ 
  1463.  
  1464.    #include <stdio.h> 
  1465.    #include <conio.h> 
  1466.    #include <dos.h> 
  1467.  
  1468.    #define D32RealSeg(P)  ((((DWORD) (P)) >> 4) & 0xFFFF) 
  1469.    #define D32RealOff(P)  (((DWORD) (P)) & 0xF) 
  1470.  
  1471.    typedef unsigned int WORD; 
  1472.    typedef unsigned long DWORD; 
  1473.  
  1474.    extern void com1_init (void); 
  1475.    extern void __interrupt pmhandler (void); 
  1476.    extern void __interrupt __far rmhandler (void); 
  1477.  
  1478.    void *D32DosMemAlloc (DWORD size) 
  1479.    { 
  1480.      union REGS r; 
  1481.  
  1482.      r.x.eax = 0x0100;      /* DPMI allocate DOS memory */ 
  1483.      r.x.ebx = (size + 15) >> 4; /* Number of paragraphs requested */ 
  1484.      int386 (0x31, &r, &r); 
  1485.  
  1486.      if( r.x.cflag )  /* Failed */ 
  1487.        return ((DWORD) 0); 
  1488.      return (void *) ((r.x.eax & 0xFFFF) << 4); 
  1489.    } 
  1490.  
  1491.    void main (void) 
  1492.    { 
  1493.      union REGS    r; 
  1494.      struct SREGS   sr; 
  1495.      void      *lowp; 
  1496.      void far    *fh; 
  1497.      WORD       orig_pm_sel; 
  1498.      DWORD      orig_pm_off; 
  1499.      WORD       orig_rm_seg; 
  1500.      WORD       orig_rm_off; 
  1501.      int       c; 
  1502.  
  1503.    /*  Save the starting protected-mode handler address */ 
  1504.      r.x.eax = 0x350C;  /* DOS get vector (INT 0Ch) */ 
  1505.      sr.ds = sr.es = 0; 
  1506.      int386x (0x21, &r, &r, &sr); 
  1507.      orig_pm_sel = (WORD) sr.es; 
  1508.      orig_pm_off = r.x.ebx; 
  1509.  
  1510.    /* 
  1511.      Save the starting real-mode handler address using DPMI 
  1512.      (INT 31h). 
  1513.    */ 
  1514.      r.x.eax = 0x0200;  /* DPMI get real mode vector */ 
  1515.      r.h.bl = 0x0C; 
  1516.      int386 (0x31, &r, &r); 
  1517.      orig_rm_seg = (WORD) r.x.ecx; 
  1518.      orig_rm_off = (WORD) r.x.edx; 
  1519.  
  1520.    /* 
  1521.      Allocate 128 bytes of DOS memory for the real-mode 
  1522.      handler, which must of course be less than 128 bytes 
  1523.      long.  Then copy the real-mode handler into that 
  1524.      segment. 
  1525.    */ 
  1526.      if(! ( lowp = D32DosMemAlloc(128) ) ) { 
  1527.        printf ("Couldn't get low memory!\n"); 
  1528.        exit (1); 
  1529.      } 
  1530.      memcpy (lowp, (void *) rmhandler, 128); 
  1531.  
  1532.    /* 
  1533.      Install the new protected-mode vector.  Because INT 0Ch 
  1534.      is in the auto-passup range, its normal "passdown" 
  1535.      behavior will change as soon as we install a 
  1536.      protected-mode handler.  After this next call, when a 
  1537.      real mode INT 0Ch is generated, it will be resignalled 
  1538.      in protected mode and handled by pmhandler. 
  1539.    */ 
  1540.      r.x.eax = 0x250C;  /* DOS set vector (INT 0Ch) */ 
  1541.      fh = (void far *) pmhandler; 
  1542.      r.x.edx = FP_OFF (fh); 
  1543.      /* DS:EDX == &handler */ 
  1544.      sr.ds = FP_SEG (fh); 
  1545.      sr.es = 0; 
  1546.      int386x (0x21, &r, &r, &sr); 
  1547.  
  1548.    /* 
  1549.      Install the new real-mode vector.  We do this after 
  1550.      installing the protected-mode vector in order to 
  1551.      override the "passup" behavior.  After the next call, 
  1552.      interrupts will be directed to the appropriate handler, 
  1553.      regardless of which mode we are in when they are 
  1554.      generated. 
  1555.    */ 
  1556.      r.x.eax = 0x0201; 
  1557.      r.h.bl = 0x0C; 
  1558.      /* CX:DX == real mode &handler */ 
  1559.      r.x.ecx = D32RealSeg(lowp); 
  1560.      r.x.edx = D32RealOff(lowp); 
  1561.      int386 (0x31, &r, &r); 
  1562.  
  1563.    /* 
  1564.      Initialize COM1. 
  1565.    */ 
  1566.      com1_init (); 
  1567.  
  1568.      puts( "Move mouse, transmit data; ESC to quit\n" ); 
  1569.  
  1570.      while( 1 ) { 
  1571.        if( kbhit() ) { 
  1572.          if( ( (c = getch ()) & 0xff ) == 27 ) 
  1573.              break; 
  1574.          putch (c); 
  1575.        } 
  1576.      delay( 1 ); 
  1577.      } 
  1578.  
  1579.    /* 
  1580.      Clean up. 
  1581.    */ 
  1582.      r.x.eax = 0x250C;  /* DOS set vector (INT 0Ch) */ 
  1583.      r.x.edx = orig_pm_off; 
  1584.      sr.ds = orig_pm_sel;   /* DS:EDX == &handler */ 
  1585.      sr.es = 0; 
  1586.      int386x (0x21, &r, &r, &sr); 
  1587.  
  1588.      r.x.eax = 0x0201;  /* DPMI set real mode vector */ 
  1589.      r.h.bl = 0x0C; 
  1590.      /* CX:DX == real mode &handler */ 
  1591.      r.x.ecx = (DWORD) orig_rm_seg; 
  1592.      r.x.edx = (DWORD) orig_rm_off; 
  1593.      int386 (0x31, &r, &r); 
  1594.    } 
  1595.  
  1596. You will also need to create the following assembler code module.  The first 
  1597. part provides the interrupt handling routine for the real-mode interrupt 
  1598. handler.  The second provides the protected-mode version of the interrupt 
  1599. handler. 
  1600.  
  1601.  
  1602.    ;** 
  1603.    ;** bimo.asm: 
  1604.    ;** Assembler code for real-mode and protected-mode 
  1605.    ;** INT 0xC interrupt handlers to support the INT 0xC 
  1606.    ;** interrupt in both modes 
  1607.    ;** 
  1608.    .386 
  1609.    ;** 
  1610.    ;** The real-mode interrupt handler is in a 16-bit code 
  1611.    ;** segment so that the assembler will generate the right 
  1612.    ;** code.  We will copy this code down to a 16-bit segment 
  1613.    ;** in low memory rather than executing it in place. 
  1614.    ;** 
  1615.  
  1616.    _TEXT16 SEGMENT BYTE PUBLIC USE16 'CODE' 
  1617.      ASSUME  cs:_TEXT16 
  1618.  
  1619.      PUBLIC  rmhandler_ 
  1620.    rmhandler_: 
  1621.      push   es 
  1622.      push   bx 
  1623.      mov   bx,0B800h 
  1624.      mov   es,bx          ; ES = 0xB800 
  1625.      sub   bx,bx          ; BX = 0 
  1626.      mov   WORD PTR es:[bx],0720h  ; Clear 2 char cells 
  1627.      mov   WORD PTR es:[bx+2],0720h 
  1628.      mov   BYTE PTR es:[bx],'R'   ; Write R to memory 
  1629.      pop   bx 
  1630.      pop   es 
  1631.      push   ax 
  1632.      push   dx 
  1633.      mov   dx,03FAh 
  1634.      in    al,dx          ; Read ports so 
  1635.      mov   dx,03F8h         ; interrupts can 
  1636.      in    al,dx          ; continue to be 
  1637.      mov   dx,020h         ; generated 
  1638.      mov   al,dl 
  1639.      out   dx,al          ; Send EOI 
  1640.      pop   dx 
  1641.      pop   ax 
  1642.      iret 
  1643.    _TEXT16 ENDS 
  1644.    ;** 
  1645.    ;** The protected-mode interrupt handler is in a 32-bit code 
  1646.    ;** segment.  Even so, we have to be sure to force an IRETD 
  1647.    ;** at the end of the handler, because MASM doesn't generate 
  1648.    ;** one.  This handler will be called on a 32-bit stack by 
  1649.    ;** DOS/4GW. 
  1650.    ;** 
  1651.    ;** _DATA is the flat model data segment, which we load into 
  1652.    ;** ES so we can write to absolute address 0xB8000.  (In the 
  1653.    ;** flat model, DS is based at 0.) 
  1654.    ;** 
  1655.    _DATA  SEGMENT BYTE PUBLIC USE32 'DATA' 
  1656.    _DATA  ENDS 
  1657.  
  1658.    DGROUP GROUP _DATA 
  1659.  
  1660.    _TEXT  SEGMENT BYTE PUBLIC USE32 'CODE' 
  1661.      ASSUME  cs:_TEXT 
  1662.  
  1663.      PUBLIC  com1_init_ 
  1664.    com1_init_: 
  1665.      mov   ax,0F3h         ; 9600,n,8,1 
  1666.      mov   dx,0           ; com1 
  1667.      int   14h           ; Initialize COM1 
  1668.      mov   bx,03F8h         ; COM1 port space 
  1669.      lea   dx,[bx+5]        ; line status reg 
  1670.      in    al,dx 
  1671.      lea   dx,[bx+4]        ; modem control reg 
  1672.      in    al,dx 
  1673.      or    al,8           ; enable OUT2 int 
  1674.      out   dx,al 
  1675.      lea   dx,[bx+2]        ; int id register 
  1676.      in    al,dx 
  1677.      mov   dx,bx          ; data receive reg 
  1678.      in    al,dx 
  1679.      in    al,21h          ; interrupt mask reg 
  1680.      and   al,0EFh         ; force IRQ4 unmask 
  1681.      out   21h,al 
  1682.      lea   dx,[bx+1]        ; int enable reg 
  1683.      mov   al,1 
  1684.      out   dx,al          ; enable received int 
  1685.      ret 
  1686.  
  1687.      PUBLIC  pmhandler_ 
  1688.    pmhandler_: 
  1689.      push   es 
  1690.      push   bx 
  1691.      mov   bx,DGROUP 
  1692.      mov   es,bx 
  1693.      mov   ebx,0B8000h       ; ES:EBX=flat:0B8000h 
  1694.      mov   DWORD PTR es:[ebx],07200720h  ; Clear cells 
  1695.      mov   BYTE PTR es:[ebx+2],'P' ; Write P to memory 
  1696.      pop   bx 
  1697.      pop   es 
  1698.      push   ax 
  1699.      push   dx 
  1700.      mov   dx,03FAh 
  1701.      in    al,dx          ; Read ports so 
  1702.      mov   dx,03F8h         ; interrupts can 
  1703.      in    al,dx          ; continue to be 
  1704.      mov   dx,020h         ; generated 
  1705.      mov   al,dl 
  1706.      out   dx,al          ; Send EOI 
  1707.      pop   dx 
  1708.      pop   ax 
  1709.      iretd 
  1710.    _TEXT  ENDS 
  1711.      END 
  1712.  
  1713.  
  1714. ΓòÉΓòÉΓòÉ 6. DOS/4GW:  The Tenberry Software DOS/4GW DOS Extender ΓòÉΓòÉΓòÉ
  1715.  
  1716.  
  1717.  
  1718. The chapters in this section describe the 32-bit Tenberry Software DOS/4GW DOS 
  1719. Extender which is provided with the Watcom C/C++ package.  DOS/4GW is a subset 
  1720. of Tenberry Software's DOS/4G product.  DOS/4GW is customized for use with the 
  1721. Watcom C/C++ package.  Key differences are: 
  1722.  
  1723.      DOS/4GW will only execute programs built with a WATCOM 32-bit compiler 
  1724.       such as Watcom C/C++ and linked with its run-time libraries. 
  1725.      The DOS/4GW virtual memory manager (VMM), included in the package, is 
  1726.       restricted to 32MB of memory. 
  1727.      DOS/4GW does not provide extra functionality such as TSR capability and 
  1728.       VMM performance tuning enhancements. 
  1729.  
  1730.  If your application has requirements beyond those provided by DOS/4GW, you may 
  1731.  wish to acquire DOS/4GW Professional or DOS/4G from: 
  1732.  
  1733.     Tenberry Software, Inc., 
  1734.     220 No. Main St., 
  1735.     Natick, Massachusetts, 
  1736.     U.S.A. 01760. 
  1737.  
  1738.     Telephone:    (508)653-6006 
  1739.     Facsimile:    (508)655-2753 
  1740.     Internet:    dos4gw@ratsys.com 
  1741.     CompuServe:   73667,1753 
  1742.  
  1743.  Programs developed to use the restricted version of DOS/4GW which is included 
  1744.  in the Watcom C/C++ package can be distributed on a royalty-free basis, 
  1745.  subject to the licensing terms of the product. 
  1746.  
  1747.  
  1748. ΓòÉΓòÉΓòÉ 7. DOS/4GW:  Linear Executables ΓòÉΓòÉΓòÉ
  1749.  
  1750.  
  1751. To build a linear executable, compile and link it as described in the chapter 
  1752. entitled "Creating 32-bit DOS/4GW Executables".  The resulting file will not 
  1753. run independently:  you can run it under the Watcom Debugger, Tenberry Software 
  1754. Instant-D debugger, or with the standalone "DOS4GW.EXE". 
  1755.  
  1756.  
  1757. ΓòÉΓòÉΓòÉ 7.1. DOS/4GW:  The Linear Executable Format ΓòÉΓòÉΓòÉ
  1758.  
  1759.  
  1760.  DOS/4GW works with files that use the Linear Executable (LE) file format.  The 
  1761. format represents a protected-mode program in the context of a 32-bit 386 
  1762. runtime environment with linear to physical address translation hardware 
  1763. enabled.  It uses a flat address space. 
  1764.  
  1765. This file format is similar to the Segmented Executable (NE) format used in 
  1766. OS/2 1.x and MS Windows.  Both support Dynamic Linking, Resources, and are 
  1767. geared toward protected-mode programs.  Both formats use tables of "counted 
  1768. ASCII" names, and they use similar relocation formats. 
  1769.  
  1770. Both formats begin with a DOS style stub program that sophisticated loaders 
  1771. skip.  This stub program executes when the DOS/4GW loader is not present, 
  1772. displaying the message, This program cannot run in DOS mode. 
  1773.  
  1774. When the Watcom Linker is used to link a DOS/4GW application, it automatically 
  1775. replaces the default stub program with one that calls DOS4GW. 
  1776.  
  1777.  
  1778. ΓòÉΓòÉΓòÉ 7.1.1. DOS/4GW:  The Stub Program ΓòÉΓòÉΓòÉ
  1779.  
  1780.  
  1781. The stub at the beginning of a linear executable is a real-mode program that 
  1782. you can modify as you like.  For example, you can: 
  1783.  
  1784.      make the stub program do a checksum on the "DOS4GW.EXE" file to make sure 
  1785.       it's the correct version. 
  1786.      copy protect your program. 
  1787.      specify a search path for the "DOS4GW.EXE" file. 
  1788.      add command line arguments. 
  1789.  
  1790.  The SRC directory contains source code for a sample stub program.  "WSTUB.C" 
  1791.  is a simple example, a good base to start from when you construct your own 
  1792.  stub.  Please note that you will require a 16-bit C compiler to compile a new 
  1793.  stub program.  Following is the code in "WSTUB.C": 
  1794.  
  1795.  
  1796.     #include <stdio.h> 
  1797.     #include <stdlib.h> 
  1798.     #include <process.h> 
  1799.     #include <errno.h> 
  1800.     #include <string.h> 
  1801.  
  1802.     /* Add environment strings to be searched here */ 
  1803.     char *paths_to_check[] = { 
  1804.         "DOS4GPATH", 
  1805.         "PATH"}; 
  1806.  
  1807.     char *dos4g_path() 
  1808.     { 
  1809.       static char fullpath[80]; 
  1810.       int i; 
  1811.  
  1812.       for( i = 0; 
  1813.         i < sizeof( paths_to_check ) / sizeof( paths_to_check[0] ); 
  1814.         i++ ) { 
  1815.         _searchenv( "dos4gw.exe", paths_to_check[i], fullpath ); 
  1816.         if( fullpath[0] ) return( &fullpath ); 
  1817.       } 
  1818.       for( i = 0; 
  1819.         i < sizeof( paths_to_check ) / sizeof( paths_to_check[0] ); 
  1820.         i++ ) { 
  1821.         _searchenv( "dos4g.exe", paths_to_check[i], fullpath ); 
  1822.         if( fullpath[0] ) return( &fullpath ); 
  1823.       } 
  1824.       return( "dos4gw.exe" ); 
  1825.     } 
  1826.  
  1827.     main( int argc, char *argv[] ) 
  1828.     { 
  1829.       char     *av[4]; 
  1830.       auto char  cmdline[128]; 
  1831.  
  1832.       av[0] = dos4g_path();        /* Locate the DOS/4G loader */ 
  1833.       av[1] = argv[0];           /* name of executable to run */ 
  1834.       av[2] = getcmd( cmdline );      /* command line */ 
  1835.       av[3] = NULL;            /* end of list */ 
  1836.     #ifdef QUIET 
  1837.       putenv( "DOS4G=QUIET" );   /* disables DOS/4G Copyright banner */ 
  1838.     #endif 
  1839.       execvp( av[0], av ); 
  1840.       puts( "Stub exec failed:" ); 
  1841.       puts( av[0] ); 
  1842.       puts( strerror( errno ) ); 
  1843.       exit( 1 );          /* indicate error */ 
  1844.     } 
  1845.  
  1846.  
  1847. ΓòÉΓòÉΓòÉ 7.2. DOS/4GW:  Memory Use ΓòÉΓòÉΓòÉ
  1848.  
  1849.  
  1850. This section explains how a DOS/4GW application uses the memory on a 386-based 
  1851. PC/AT.  The basic memory layout of an AT machine consists of 640KB of DOS 
  1852. memory, 384KB of upper memory, and an undetermined amount of extended memory. 
  1853. DOS memory and upper memory together compose real memory, the memory that can 
  1854. be addressed when the processor is running in real mode. 
  1855.  
  1856.  
  1857. Figure 1. Basic Memory Layout 
  1858.  
  1859. Under DOS/4GW, the first megabyte of physical memory - the real memory - is 
  1860. mapped as a shared linear address space.  This allows your application to use 
  1861. absolute addresses in real memory, to access video RAM or BIOS ROM, for 
  1862. example.  Because the real memory is available to all processes, you are not 
  1863. guaranteed to be able to allocate a particular area in real memory:  another 
  1864. process may have allocated it already. 
  1865.  
  1866. Most code and data is placed in a paged linear address space starting at 4MB. 
  1867. The linear address space starts at 4MB, the first address in the second page 
  1868. table, to avoid conflicts with VCPI system software. 
  1869.  
  1870. This split mapping - an executable that is linked to start at 4MB in the linear 
  1871. address space, with the first MB in the address space mapped to the first MB of 
  1872. physical memory - is called a split flat model. 
  1873.  
  1874. The illustration below shows the layout of physical memory on the left, and the 
  1875. layout of the linear address space on the right. 
  1876.  
  1877.  
  1878. Figure 2. Physical Memory/Linear Address Space 
  1879.  
  1880. The 1KB label in the diagram indicates the top of the real-mode interrupt 
  1881. vectors.  4KB marks the end of the first page. 
  1882.  
  1883.  
  1884. ΓòÉΓòÉΓòÉ 8. DOS/4GW:  Configuring DOS/4GW ΓòÉΓòÉΓòÉ
  1885.  
  1886.  
  1887. This chapter explains various options that can be specified with the DOS4G 
  1888. environment variable including how to suppress the banner that is displayed by 
  1889. DOS/4GW at startup.  It also explains how to use the DOS16M environment 
  1890. variable to select the switch mode setting, if necessary, and to specify the 
  1891. range of extended memory in which DOS/4GW will operate.  DOS/4GW is based on 
  1892. Tenberry Software's DOS/16M 16-bit Protected-Mode support; hence the DOS16M 
  1893. environment variable name remains unchanged. 
  1894.  
  1895.  
  1896. ΓòÉΓòÉΓòÉ 8.1. DOS/4GW:  The DOS4G Environment Variable ΓòÉΓòÉΓòÉ
  1897.  
  1898.  
  1899. A number of options can be selected by setting the DOS4G environment variable. 
  1900. The syntax for setting options is: 
  1901.  
  1902.  
  1903.    set DOS4G=option1,option2,... 
  1904.  
  1905. Do not insert a space between DOS4G and the equal sign.  A space to the right 
  1906. of the equal sign is optional. 
  1907.  
  1908.  Options: 
  1909.  
  1910.  QUIET 
  1911.       Use this option to suppress the DOS/4GW banner. 
  1912.  
  1913.       The banner that is displayed by DOS/4GW at startup can be suppressed by 
  1914.       issuing the following command: 
  1915.  
  1916.  
  1917.          set DOS4G=quiet 
  1918.  
  1919.       Note:  Use of the quiet switch is only permitted pursuant to the terms 
  1920.       and conditions of the WATCOM Software License Agreement and the 
  1921.       additional redistribution rights described in the Getting Started manual. 
  1922.       Under these terms, suppression of the copyright by using the quiet switch 
  1923.       is not permitted for applications which you distribute to others. 
  1924.  
  1925.  VERBOSE 
  1926.       Use this option to maximize the information available for postmortem 
  1927.       debugging. 
  1928.  
  1929.       Before running your application, issue the following command: 
  1930.  
  1931.  
  1932.          set DOS4G=verbose 
  1933.  
  1934.       Reproduce the crash and record the output. 
  1935.  
  1936.  NULLP 
  1937.       Use this option to trap references to the first sixteen bytes of physical 
  1938.       memory. 
  1939.  
  1940.       Before running your application, issue the following command: 
  1941.  
  1942.  
  1943.          set DOS4G=nullp 
  1944.  
  1945.  To select a combination of options, list them with commas as separators. 
  1946.  
  1947.  Example: 
  1948.  
  1949.     set DOS4G=nullp,verbose 
  1950.  
  1951.  
  1952. ΓòÉΓòÉΓòÉ 8.2. DOS/4GW:  Changing the Switch Mode Setting ΓòÉΓòÉΓòÉ
  1953.  
  1954.  
  1955. In almost all cases, DOS/4GW programs can detect the type of machine that is 
  1956. running and automatically choose an appropriate real- to protected-mode switch 
  1957. technique.  For the few cases in which this default setting does not work we 
  1958. provide the DOS16M DOS environment variable, which overrides the default 
  1959. setting. 
  1960.  
  1961. Change the switch mode settings by issuing the following command: 
  1962.  
  1963.  
  1964.    set DOS16M=value 
  1965.  
  1966. Do not insert a space between DOS16M and the equal sign.  A space to the right 
  1967. of the equal sign is optional. 
  1968.  
  1969. The table below lists the machines and the settings you would use with them. 
  1970. Many settings have mnemonics, listed in the column "Alternate Name", that you 
  1971. can use instead of the number.  Settings that you must set with the DOS16M 
  1972. variable have the notation req'd in the first column.  Settings you may use are 
  1973. marked option, and settings that will automatically be set are marked auto. 
  1974.  
  1975.                               Alternate 
  1976.  Status       Machine  Setting Name           Comment 
  1977.  
  1978.  auto        386/486 w/ DPMI  0            None 
  1979.  Set automatically if DPMI is active 
  1980.  req'd       NEC 98-series   1            9801 
  1981.  Must be set for NEC 98-series 
  1982.  auto        PS/2   2    None           Set automatically for 
  1983. PS/2 
  1984.  auto        386/486  3    386, 80386        Set automatically for 386 or 
  1985. 486 
  1986.  auto        386    INBOARD None           386 with Intel 
  1987. Inboard 
  1988.  req'd       Fujitsu FMR-70  5            None 
  1989.  Must be set for Fujitsu FMR-70 
  1990.  auto        386/486 w/ VCPI  11            None 
  1991.  Set automatically if VCPI detected 
  1992.  req'd       Hitachi B32    14            None 
  1993.  Must be set for Hitachi B32 
  1994.  req'd       OKI if800     15            None 
  1995.  Must be set for OKI if800 
  1996.  option       IBM PS/55     16            None 
  1997.  May be needed for some PS/55s 
  1998.  
  1999. The following procedure shows you how to test the switch mode setting. 
  2000.  
  2001.    1. If you have one of the machines listed below, set the DOS16M environment 
  2002.       variable to the value shown for that machine and specify a range of 
  2003.       extended memory.  For example, if your machine is a NEC 98-series, set 
  2004.       DOS16M=1 @2M-4M.  See the section entitled DOS/4GW:  Fine Control of 
  2005.       Memory Usage in this chapter for more information about setting the 
  2006.       memory range. 
  2007.  
  2008.            Machine     Setting 
  2009.  
  2010.            NEC 98-series  1 
  2011.            Fujitsu FMR-60,-70 
  2012.            5 
  2013.            Hitachi B32   14 
  2014.            OKI if800    15 
  2015.  
  2016.       Before running DOS/4GW applications, check the switch mode setting by 
  2017.       following this procedure: 
  2018.  
  2019.    2. Run PMINFO and note the switch setting reported on the last line of the 
  2020.       display.  (PMINFO, which reports on the protected-mode resources 
  2021.       available to your programs, is described in more detail in the chapter 
  2022.       entitled DOS/4GW:  Utilities) 
  2023.  
  2024.       If PMINFO runs, the setting is usable on your machine. 
  2025.  
  2026.    3. If you changed the switch setting, add the new setting to your 
  2027.       AUTOEXEC.BAT file. 
  2028.  
  2029.  Note:  PMINFO will run successfully on 286 machines.  If your DOS/4GW 
  2030.  application does not run, and PMINFO does, check the CPU type reported on the 
  2031.  first line of the display. 
  2032.  
  2033.  You are authorized (and encouraged) to distribute PMINFO to your customers. 
  2034.  You may also include a copy of this section in your documentation. 
  2035.  
  2036.  
  2037. ΓòÉΓòÉΓòÉ 8.3. DOS/4GW:  Fine Control of Memory Usage ΓòÉΓòÉΓòÉ
  2038.  
  2039.  
  2040. In addition to setting the switch mode as described above, the DOS16M 
  2041. environment variable enables you to specify which portion of extended memory 
  2042. DOS/4GW will use.  The variable also allows you to instruct DOS/4GW to search 
  2043. for extra memory and use it if it is present. 
  2044.  
  2045.  
  2046. ΓòÉΓòÉΓòÉ 8.3.1. DOS/4GW:  Specifying a Range of Extended Memory ΓòÉΓòÉΓòÉ
  2047.  
  2048.  
  2049. Normally, you don't need to specify a range of memory with the DOS16M variable. 
  2050. You must use the variable, however, in the following cases: 
  2051.  
  2052.      You are running on a Fujitsu FMR-series, NEC 98-series, OKI if800-series 
  2053.       or Hitachi B-series machine. 
  2054.      You have older programs that use extended memory but don't follow one of 
  2055.       the standard disciplines. 
  2056.      You want to shell out of DOS/4GW to use another program that requires 
  2057.       extended memory. 
  2058.  
  2059.  If none of these conditions applies to you, you can skip this section. 
  2060.  
  2061.  The general syntax is: 
  2062.  
  2063.  
  2064.     set DOS16M= [switch_mode] [@start_address [- end_address]] [:size] 
  2065.  
  2066.  In the syntax shown above, start_address, end_address and size represent 
  2067.  numbers, expressed in decimal or in hexadecimal (hex requires a 0x prefix). 
  2068.  The number may end with a K to indicate an address or size in kilobytes, or an 
  2069.  M to indicate megabytes.  If no suffix is given, the address or size is 
  2070.  assumed to be in kilobytes.  If both a size and a range are specified, the 
  2071.  more restrictive interpretation is used. 
  2072.  
  2073.  The most flexible strategy is to specify only a size.  However, if you are 
  2074.  running with other software that does not follow a convention for indicating 
  2075.  its use of extended memory, and these other programs start before DOS/4GW, you 
  2076.  will need to calculate the range of memory used by the other programs and 
  2077.  specify a range for DOS/4GW programs to use. 
  2078.  
  2079.  DOS/4GW ignores specifications (or parts of specifications) that conflict with 
  2080.  other information about extended memory use.  Below are some examples of 
  2081.  memory usage control: 
  2082.  
  2083.  set DOS16M= 1 @2m-4m 
  2084.       Mode 1, for NEC 98-series machines, and use extended memory between 2.0 
  2085.       and 4.0MB. 
  2086.  
  2087.  set DOS16M= :1M 
  2088.       Use the last full megabyte of extended memory, or as much as available 
  2089.       limited to 1MB. 
  2090.  
  2091.  set DOS16M= @2m 
  2092.       Use any extended memory available above 2MB. 
  2093.  
  2094.  set DOS16M= @ 0 - 5m 
  2095.       Use any available extended memory from 0.0 (really 1.0) to 5.0MB. 
  2096.  
  2097.  set DOS16M= :0 
  2098.       Use no extended memory. 
  2099.  
  2100.  As a default condition DOS/4GW applications take all extended memory that is 
  2101.  not otherwise in use.  Multiple DOS/4GW programs that execute simultaneously 
  2102.  will share the reserved range of extended memory.  Any non-DOS/4GW programs 
  2103.  started while DOS/4GW programs are executing will find that extended memory 
  2104.  above the start of the DOS/4GW range is unavailable, so they may not be able 
  2105.  to run.  This is very safe.  There will be a conflict only if the other 
  2106.  program does not check the BIOS configuration call (Interrupt 15H function 
  2107.  88H, get extended memory size). 
  2108.  
  2109.  To create a private pool of extended memory for your DOS/4GW application, use 
  2110.  the PRIVATXM program, described in the chapter entitled DOS/4GW:  Utilities. 
  2111.  
  2112.  The default memory allocation strategy is to use extended memory if available, 
  2113.  and overflow into DOS (low) memory. 
  2114.  
  2115.  In a VCPI or DPMI environment, the start_address and end_address arguments are 
  2116.  not meaningful.  DOS/4GW memory under these protocols is not allocated 
  2117.  according to specific addresses because VCPI and DPMI automatically prevent 
  2118.  address conflicts between extended memory programs.  You can specify a size 
  2119.  for memory managed by VCPI or DPMI, but DOS/4GW will not necessarily allocate 
  2120.  this memory from the highest available extended memory address, as it does for 
  2121.  memory managed under other protocols. 
  2122.  
  2123.  
  2124. ΓòÉΓòÉΓòÉ 8.3.2. DOS/4GW:  Using Extra Memory ΓòÉΓòÉΓòÉ
  2125.  
  2126.  
  2127. Some machines contain extra non-extended, non-conventional memory just below 
  2128. 16MB.  When DOS/4GW runs on a Compaq 386, it automatically uses this memory 
  2129. because the memory is allocated according to a certain protocol, which DOS/4GW 
  2130. follows.  Other machines have no protocol for allocating this memory.  To use 
  2131. the extra memory that may exist on these machines, set DOS16M with the + 
  2132. option. 
  2133.  
  2134.  
  2135.    set DOS16M=+ 
  2136.  
  2137. Setting the + option causes DOS/4GW to search for memory in the range from 
  2138. FA0000 to FFFFFF and determine whether the memory is usable.  DOS/4GW does this 
  2139. by writing into the extra memory and reading what it has written.  In some 
  2140. cases, this memory is mapped for DOS or BIOS usage, or for other system uses. 
  2141. If DOS/4GW finds extra memory that is mapped this way, and is not marked 
  2142. read-only, it will write into that memory.  This will cause a crash, but won't 
  2143. have any other effect on your system. 
  2144.  
  2145.  
  2146. ΓòÉΓòÉΓòÉ 8.4. DOS/4GW:  Setting Runtime Options ΓòÉΓòÉΓòÉ
  2147.  
  2148.  
  2149. The DOS16M environment variable sets certain runtime options for all DOS/4GW 
  2150. programs running on the same system. 
  2151.  
  2152. To set the environment variable, the syntax is: 
  2153.  
  2154.  
  2155.    set DOS16M=[switch_mode_setting]^options. 
  2156.  
  2157. Note:  Some command line editing TSRs, such as CED, use the caret (^) as a 
  2158. delimiter.  If you want to set DOS16M using the syntax above while one of these 
  2159. TSRs is resident, modify the TSR to use a different delimiter. 
  2160.  
  2161. These are the options: 
  2162.  
  2163.  0x01 
  2164.        check A20 line -- This option forces DOS/4GW to wait until the A20 line 
  2165.       is enabled before switching to protected mode.  When DOS/4GW switches to 
  2166.       real mode, this option suspends your program's execution until the A20 
  2167.       line is disabled, unless an XMS manager (such as HIMEM.SYS) is active. 
  2168.       If an XMS manager is running, your program's execution is suspended until 
  2169.       the A20 line is restored to the state it had when the CPU was last in 
  2170.       real mode.  Specify this option if you have a machine that runs DOS/4GW 
  2171.       but is not truly AT-compatible.  For more information on the A20 line, 
  2172.       see the section entitled DOS/4GW:  Controlling Address Line 20. 
  2173.  
  2174.  0x02 
  2175.        prevent initialization of VCPI -- By default, DOS/4GW searches for a 
  2176.       VCPI server and, if one is present, forces it on.  This option is useful 
  2177.       if your application does not use EMS explicitly, is not a resident 
  2178.       program, and may be used with 386-based EMS simulator software. 
  2179.  
  2180.  0x04 
  2181.        directly pass down keyboard status calls -- When this option is set, 
  2182.       status requests are passed down immediately and unconditionally.  When 
  2183.       disabled, pass-downs are limited so the 8042 auxiliary processor does not 
  2184.       become overloaded by keyboard polling loops. 
  2185.  
  2186.  0x10 
  2187.        restore only changed interrupts -- Normally, when a DOS/4GW program 
  2188.       terminates, all interrupts are restored to the values they had at the 
  2189.       time of program startup.  When you use this option, only the interrupts 
  2190.       changed by the DOS/4GW program are restored. 
  2191.  
  2192.  0x20 
  2193.        set new memory to 00 -- When DOS/4GW allocates a new segment or 
  2194.       increases the size of a segment, the memory is zeroed.  This can help you 
  2195.       find bugs having to do with uninitialized memory.  You can also use it to 
  2196.       provide a consistent working environment regardless of what programs were 
  2197.       run earlier.  This option only affects segment allocations or expansions 
  2198.       that are made through the DOS/4GW kernel (with DOS function 48H or 4AH). 
  2199.       This option does not affect memory allocated with a compiler's malloc 
  2200.       function. 
  2201.  
  2202.  0x40 
  2203.        set new memory to FF -- When DOS/4GW allocates a new segment or 
  2204.       increases the size of a segment, the memory is set to 0xFF bytes.  This 
  2205.       is helpful in making reproducible cases of bugs caused by using 
  2206.       uninitialized memory.  This option only affects segment allocations or 
  2207.       expansions that are made through the DOS/4GW kernel (with DOS function 
  2208.       48H or 4AH).  This option does not affect memory allocated with a 
  2209.       compiler's malloc function. 
  2210.  
  2211.  0x80 
  2212.        new selector rotation -- When DOS/4GW allocates a new selector, it 
  2213.       usually looks for the first available (unused) selector in numerical 
  2214.       order starting with the highest selector used when the program was 
  2215.       loaded.  When this option is set, the new selector search begins after 
  2216.       the last selector that was allocated.  This causes new selectors to 
  2217.       rotate through the range.  Use this option to find references to stale 
  2218.       selectors, i.e., segments that have been cancelled or freed. 
  2219.  
  2220.  
  2221. ΓòÉΓòÉΓòÉ 8.5. DOS/4GW:  Controlling Address Line 20 ΓòÉΓòÉΓòÉ
  2222.  
  2223.  
  2224. This section explains how DOS/4GW uses address line 20 (A20) and describes the 
  2225. related DOS16M environment variable settings.  It is unlikely that you will 
  2226. need to use these settings. 
  2227.  
  2228. Because the 8086 and 8088 chips have 20-bit address spaces, their highest 
  2229. addressable memory location is one byte below 1MB.  If you specify an address 
  2230. at 1MB or over, which would require a twenty-first bit to set, the address 
  2231. wraps back to zero.  Some parts of DOS depend on this wrap, so on the 286 and 
  2232. 386, the twenty-first address bit is disabled.  To address extended memory, 
  2233. DOS/4GW enables the twenty-first address bit (the A20 line).  The A20 line must 
  2234. be enabled for the CPU to run in protected mode, but it may be either enabled 
  2235. or disabled in real mode. 
  2236.  
  2237. By default, when DOS/4GW returns to real mode, it disables the A20 line.  Some 
  2238. software depends on the line being enabled.  DOS/4GW recognizes the most common 
  2239. software in this class, the XMS managers (such as HIMEM.SYS), and enables the 
  2240. A20 line when it returns to real mode if an XMS manager is present.  For other 
  2241. software that requires the A20 line to be enabled, use the A20 option.  The A20 
  2242. option makes DOS/4GW restore the A20 line to the setting it had when DOS/4GW 
  2243. switched to protected mode.  Set the environment variable as follows: 
  2244.  
  2245.  
  2246.    set DOS16M=A20 
  2247.  
  2248. To specify more than one option on the command line, separate the options with 
  2249. spaces. 
  2250.  
  2251. The DOS16M variable also lets you to specify the length of the delay between a 
  2252. DOS/4GW instruction to change the status of the A20 line and the next DOS/4GW 
  2253. operation.  By default, this delay is 1 loop instruction when DOS/4GW is 
  2254. running on a 386 machine.  In some cases, you may need to specify a longer 
  2255. delay for a machine that will run DOS/4GW but is not truly AT-compatible.  To 
  2256. change the delay, set DOS16M to the desired number of loop instructions, 
  2257. preceded by a comma: 
  2258.  
  2259.  
  2260.    set DOS16M=,loops 
  2261.  
  2262.  
  2263. ΓòÉΓòÉΓòÉ 9. DOS/4GW:  VMM ΓòÉΓòÉΓòÉ
  2264.  
  2265.  
  2266. The Virtual Memory Manager (VMM) uses a swap file on disk to augment RAM.  With 
  2267. VMM you can use more memory than your machine actually has.  When RAM is not 
  2268. sufficient, part of your program is swapped out to the disk file until it is 
  2269. needed again.  The combination of the swap file and available RAM is the 
  2270. virtual memory. 
  2271.  
  2272. Your program can use VMM if you set the DOS environment variable, DOS4GVM , as 
  2273. follows.  To set the DOS4GVM environment variable, use the format shown below. 
  2274.  
  2275.  
  2276.    set DOS4GVM= [option[#value]] [option[#value]] 
  2277.  
  2278. A "#" is used with options that take values since the DOS command shell will 
  2279. not accept "=". 
  2280.  
  2281. If you set DOS4GVM equal to 1, the default parameters are used for all options. 
  2282.  
  2283. Example: 
  2284.  
  2285.    C>set DOS4GVM=1 
  2286.  
  2287.  
  2288. ΓòÉΓòÉΓòÉ 9.1. DOS/4GW:  VMM Default Parameters ΓòÉΓòÉΓòÉ
  2289.  
  2290.  
  2291. VMM parameters control the options listed below. 
  2292.  
  2293.  MINMEM 
  2294.       The minimum amount of RAM managed by VMM.  The default is 512KB. 
  2295.  
  2296.  MAXMEM 
  2297.       The maximum amount of RAM managed by VMM.  The default is 4MB. 
  2298.  
  2299.  SWAPMIN 
  2300.       The minimum or initial size of the swap file.  If this option is not 
  2301.       used, the size of the swap file is based on VIRTUALSIZE (see below). 
  2302.  
  2303.  SWAPINC 
  2304.       The size by which the swap file grows. 
  2305.  
  2306.  SWAPNAME 
  2307.       The swap file name.  The default name is "DOS4GVM.SWP".  By default the 
  2308.       file is in the root directory of the current drive.  Specify the complete 
  2309.       path name if you want to keep the swap file somewhere else. 
  2310.  
  2311.  DELETESWAP 
  2312.       Whether the swap file is deleted when your program exits.  By default the 
  2313.       file is not deleted.  Program startup is quicker if the file is not 
  2314.       deleted. 
  2315.  
  2316.  VIRTUALSIZE 
  2317.       The size of the virtual memory space.  The default is 16MB. 
  2318.  
  2319.  
  2320. ΓòÉΓòÉΓòÉ 9.2. DOS/4GW:  Changing the Defaults ΓòÉΓòÉΓòÉ
  2321.  
  2322.  
  2323. You can change the defaults in two ways. 
  2324.  
  2325.    1. Specify different parameter values as arguments to the DOS4GVM 
  2326.       environment variable, as shown in the example below. 
  2327.  
  2328.  
  2329.          set DOS4GVM=deleteswap maxmem#8192 
  2330.  
  2331.    2. Create a configuration file with the filetype extension ".VMC", and use 
  2332.       that as an argument to the DOS4GVM environment variable, as shown below. 
  2333.  
  2334.  
  2335.          set DOS4GVM=@NEW4G.VMC 
  2336.  
  2337.  
  2338. ΓòÉΓòÉΓòÉ 9.2.1. DOS/4GW:  The .VMC File ΓòÉΓòÉΓòÉ
  2339.  
  2340.  
  2341. A ".VMC" file contains VMM parameters and settings as shown in the example 
  2342. below.  Comments are permitted.  Comments on lines by themselves are preceded 
  2343. by an exclamation point (!).  Comments that follow option settings are preceded 
  2344. by white space.  Do not insert blank lines:  processing stops at the first 
  2345. blank line. 
  2346.  
  2347.  
  2348.    !Sample .VMC file 
  2349.    !This file shows the default parameter values. 
  2350.    minmem = 512       At least 512K bytes of RAM is required. 
  2351.    maxmem = 4096      Uses no more than 4MB of RAM 
  2352.    virtualsize = 16384   Swap file plus allocated memory is 16MB 
  2353.    !To delete the swap file automatically when the program exits, add 
  2354.    !deleteswap 
  2355.    !To store the swap file in a directory called SWAPFILE, add 
  2356.    !swapname = c:\swapfile\dos4gvm.swp 
  2357.  
  2358.  
  2359. ΓòÉΓòÉΓòÉ 10. DOS/4GW:  Interrupt 21H Functions ΓòÉΓòÉΓòÉ
  2360.  
  2361.  
  2362. When you call an Interrupt 21H function under DOS/4GW, the 32-bit registers in 
  2363. which you pass values are translated into the appropriate 16-bit registers, 
  2364. since DOS works only with 16 bits.  However, you can use 32-bit values in your 
  2365. DOS calls.  You can allocate blocks of memory larger than 64KB or use an 
  2366. address with a 32-bit offset, and DOS/4GW will translate the call 
  2367. appropriately, to use 16-bit registers.  When the Interrupt 21H function 
  2368. returns, the value is widened - placed in a 32-bit register, with the high 
  2369. order bits zeroed. 
  2370.  
  2371. DOS/4GW uses the following rules to manage registers: 
  2372.  
  2373.      When you pass a parameter to an Interrupt 21H function that expects a 
  2374.       16-bit quantity in a general register (for example, AX), pass a 32-bit 
  2375.       quantity in the corresponding extended register (for example, EAX).  When 
  2376.       a DOS function returns a 16-bit quantity in a general register, expect to 
  2377.       receive it (with high-order zero bits) in the corresponding extended 
  2378.       register. 
  2379.      When an Interrupt 21H function expects to receive a 16:16 pointer in a 
  2380.       segment:general register pair (for example, ES:BX), supply a 16:32 
  2381.       pointer using the same segment register and the corresponding extended 
  2382.       general register (ES:EBX).  DOS/4GW will copy data and translate pointers 
  2383.       so that DOS ultimately receives a 16:16 real-mode pointer in the correct 
  2384.       registers. 
  2385.      When DOS returns a 16:16 real-mode pointer, DOS/4GW translates the 
  2386.       segment value into an appropriate protected-mode selector and generates a 
  2387.       32-bit offset that results in a 16:32 pointer to the same location in the 
  2388.       linear address space. 
  2389.      Many DOS functions return an error code in AX if the function fails. 
  2390.       DOS/4GW checks the status of the carry flag, and if it is set, indicating 
  2391.       an error, zero-extends the code for EAX.  It does not change any other 
  2392.       registers. 
  2393.      If the value is passed or returned in an 8-bit register (AL or AH, for 
  2394.       example), DOS/4GW puts the value in the appropriate location and leaves 
  2395.       the upper half of the 32-bit register untouched. 
  2396.  
  2397.  The table below lists all the Interrupt 21h functions.  For each, it shows the 
  2398.  registers that are widened or narrowed.  Footnotes provide additional 
  2399.  information about some of the interrupts that require special handling. 
  2400.  Following the table is a section that provides a detailed explanation of 
  2401.  interrupt handling under DOS/4GW. 
  2402.  
  2403.   Function                   Purpose  Managed Registers 
  2404.  
  2405.   00H                Terminate Process  None 
  2406.   01H            Character Input with Echo  None 
  2407.   02H                 Character Output  None 
  2408.   03H                 Auxiliary Input  None 
  2409.   04H                 Auxiliary Output  None 
  2410.   05H                 Print Character  None 
  2411.   06H                Direct Console I/O  None 
  2412.   07H     Unfiltered Character Input Without Echo  None 
  2413.   08H           Character Input Without Echo  None 
  2414.   09H                  Display String  EDX 
  2415.   0AH             Buffered Keyboard Input  EDX 
  2416.   0BH              Check Keyboard Status  None 
  2417.   0CH           Flush Buffer, Read Keyboard  EDX 
  2418.   0DH                    Disk Reset  None 
  2419.   0EH                   Select Disk  None 
  2420.   0FH                Open File with FCB  EDX 
  2421.  
  2422.   10H               Close File with FCB  EDX 
  2423.   11H                 Find First File  EDX 
  2424.   12H                  Find Next File  EDX 
  2425.   13H                   Delete File  EDX 
  2426.   14H                 Sequential Read  EDX 
  2427.   15H                 Sequential Write  EDX 
  2428.   16H               Create File with FCB  EDX 
  2429.   17H                   Rename File  EDX 
  2430.   19H                 Get Current Disk  None 
  2431.   1AH                 Set DTA Address  EDX 
  2432.   1BH              Get Default Drive Data  Returns in EBX, ECX, and EDX 
  2433.   1CH                  Get Drive Data  Returns in EBX, ECX, and EDX 
  2434.  
  2435.   21H                   Random Read  EDX 
  2436.   22H                   Random Write  EDX 
  2437.   23H                  Get File Size  EDX 
  2438.   24H               Set Relative Record  EDX 
  2439.   25H               Set Interrupt Vector  EDX 
  2440.   26H        Create New Program Segment Prefix  None 
  2441.   27H                Random Block Read  EDX, returns in ECX 
  2442.   28H                Random Block Write  EDX, returns in ECX 
  2443.   29H                  Parse Filename  ESI, EDI, returns in EAX, ESI and EDI 
  2444.  (1.) 
  2445.   2AH                     Get Date  Returns in ECX 
  2446.   2BH                     Set Date  None 
  2447.   2CH                     Get Time  None 
  2448.   2DH                     Set Time  None 
  2449.   2EH              Set/Reset Verify Flag  None 
  2450.   2FH                 Get DTA Address  Returns in EBX 
  2451.  
  2452.   30H            Get MS-DOS Version Number  Returns in ECX 
  2453.   31H           Terminate and Stay Resident  None 
  2454.   33H           Get/Set Control-C Check Flag  None 
  2455.   34H           Return Address of InDOS Flag  Returns in EBX 
  2456.   35H               Get Interrupt Vector  Returns in EBX 
  2457.   36H               Get Disk Free Space  Returns in EAX, EBX, ECX, and EDX 
  2458.   38H             Get/Set Current Country  EDX, returns in EBX 
  2459.   39H                 Create Directory  EDX 
  2460.   3AH                 Remove Directory  EDX 
  2461.   3BH             Change Current Directory  EDX 
  2462.   3CH             Create File with Handle  EDX, returns in EAX 
  2463.   3DH              Open File with Handle  EDX, returns in EAX 
  2464.   3EH                    Close File  None 
  2465.   3FH               Read File or Device  EBX, ECX, EDX, returns in EAX (2.) 
  2466.  
  2467.   40H               Write File or Device  EBX, ECX, EDX, returns in EAX (2.) 
  2468.   41H                   Delete File  EDX 
  2469.   42H                Move File Pointer  Returns in EDX, EAX 
  2470.   43H              Get/Set File Attribute  EDX, returns in ECX 
  2471.   44H                      IOCTL  (3.) 
  2472.    00H Get Device Information     Returns in EDX 
  2473.    01H SetDevice Information           None 
  2474.    02H Read Control Data from CDD 
  2475.   EDX, returns in EAX 
  2476.    03H Write Control Data to CDD 
  2477.   EDX, returns in EAX 
  2478.    04H Read Control Data from BDD 
  2479.   EDX, returns in EAX 
  2480.    05H Write Control Data to BDD 
  2481.   EDX, returns in EAX 
  2482.    06H Check Input Status            None 
  2483.    07H Check Output Status            None 
  2484.    08H Check if Block Device is Removeable 
  2485.   Returns in EAX 
  2486.    09H Check if Block Device is Remote 
  2487.   Returns in EDX 
  2488.    0AH Check if Handle is Remote    Returns in EDX 
  2489.    0BH Change Sharing Retry Count        None 
  2490.    0CH Generic I/O Control for Character Devices EDX 
  2491.    0DH Generic I/O Control for Block Devices   EDX 
  2492.    0EH Get Logical Drive Map           None 
  2493.    0FH Set Logical Drive Map           None 
  2494.   45H              Duplicate File Handle  Returns in EAX 
  2495.   46H           Force Duplicate File Handle  None 
  2496.   47H              Get Current Directory  ESI 
  2497.   48H              Allocate Memory Block  Returns in EAX 
  2498.   49H                Free Memory Block  None 
  2499.   4AH               Resize Memory Block  None 
  2500.   4BH         Load and Execute Program (EXEC)  EBX, EDX (4.) 
  2501.   4CH        Terminate Process with Return Code  None 
  2502.   4DH         Get Return Code of Child Process  None 
  2503.   4EH                 Find First File  EDX 
  2504.   4FH                  Find Next File  None 
  2505.  
  2506.   52H                Get List of Lists  (not supported) 
  2507.   54H                 Get Verify Flag  None 
  2508.   56H                   Rename File  EDX, EDI 
  2509.   57H            Get/Set Date/Time of File  Returns in ECX, and EDX 
  2510.   58H           Get/Set Allocation Strategy  Returns in EAX 
  2511.   59H          Get Extended Error Information  Returns in EAX 
  2512.   5AH              Create Temporary File  EDX, returns in EAX and EDX 
  2513.   5BH                 Create New File  EDX, returns in EAX 
  2514.   5CH             Lock/Unlock File Region  None 
  2515.   5EH        Network Machine Name/Printer Setup 
  2516.    00H Get Machine Name              EDX 
  2517.    02H Set Printer Setup String          ESI 
  2518.    03H Get Printer Setup String  EDI, returns in ECX 
  2519.   5FH            Get/Make Assign List Entry 
  2520.    02H Get Redirection List Entry 
  2521.   ESI, EDI, returns in ECX 
  2522.    03H Redirect Device            ESI, EDI 
  2523.    04H Cancel Device Redirection         ESI 
  2524.  
  2525.   62H        Get Program Segment Prefix Address  Returns in EBX 
  2526.   63H     Get Lead Byte Table (version 2.25 only)  Returns in ESI 
  2527.   65H         Get Extended Country Information  EDI 
  2528.   66H               Get or Set Code Page  None 
  2529.   67H                 Set Handle Count  None 
  2530.  This list of functions is excerpted from The MS-DOS Encyclopedia, Copyright 
  2531.  (c) 1988 by Microsoft Press.  All Rights Reserved. 
  2532.  
  2533.    1. For Function 29H, DS:ESI and ES:EDI contain pointer values that are not 
  2534.       changed by the call. 
  2535.  
  2536.    2. You can read and write quantities larger than 64KB with Functions 3FH and 
  2537.       40H.  DOS/4GW breaks your request into chunks smaller than 64KB, and 
  2538.       calls the DOS function once for each chunk. 
  2539.  
  2540.    3. You can't transfer more than 64KB using Function 44h, subfunctions 02H, 
  2541.       03H, 04H, or 05H.  DOS/4GW does not break larger requests into DOS-sized 
  2542.       chunks, as it does for Functions 3FH and 40H. 
  2543.  
  2544.    4. When you call Function 4B under DOS/4GW, you pass it a data structure 
  2545.       that contains 16:32 bit pointers.  DOS/4GW translates these into 16:16 
  2546.       bit pointers in the structure it passes to DOS. 
  2547.  
  2548.  
  2549. ΓòÉΓòÉΓòÉ 10.1. DOS/4GW:  Functions 25H and 35H:  Interrupt Handling in Protected Mode ΓòÉΓòÉΓòÉ
  2550.  
  2551.  
  2552. By default, interrupts that occur in protected mode are passed down:  the entry 
  2553. in the IDT points to code in DOS/4GW that switches the CPU to real mode and 
  2554. resignals the interrupt.  If you install an interrupt handler using Interrupt 
  2555. 21H, Function 25H, that handler will get control of any interrupts that occur 
  2556. while the processor is in protected mode.  If the interrupt for which you 
  2557. installed the handler is in the autopassup range, your handler will also get 
  2558. control of interrupts signalled in real mode. 
  2559.  
  2560. The autopassup range runs from 08H to 2EH inclusive, but excluding 21H.  If the 
  2561. interrupt is in the autopassup range, the real-mode vector will be modified 
  2562. when you install the protected-mode handler to point to code in the DOS/4GW 
  2563. kernel.  This code switches the processor to protected mode and resignals the 
  2564. interrupt-where your protected-mode handler will get control. 
  2565.  
  2566.  
  2567. ΓòÉΓòÉΓòÉ 10.1.1. DOS/4GW:  32-Bit Gates ΓòÉΓòÉΓòÉ
  2568.  
  2569.  
  2570. The DOS/4GW kernel always assigns a 32-bit gate for the interrupt handlers it 
  2571. installs.  It does not distinguish between 16-bit and 32-bit handlers for 
  2572. consistency with DPMI. 
  2573.  
  2574. This 32-bit gate points into the DOS/4GW kernel.  When DOS/4GW handles the 
  2575. interrupt, it switches to its own 16-bit stack, and from there it calls the 
  2576. interrupt handler (yours or the default).  This translation is transparent to 
  2577. the handler, with one exception:  since the current stack is not the one on 
  2578. which the interrupt occurred, the handler cannot look up the stack for the 
  2579. address at which the interrupt occurred. 
  2580.  
  2581.  
  2582. ΓòÉΓòÉΓòÉ 10.1.2. DOS/4GW:  Chaining 16-bit and 32-bit Handlers ΓòÉΓòÉΓòÉ
  2583.  
  2584.  
  2585. If your program hooks an interrupt, write a normal service routine that either 
  2586. handles the interrupt and IRETs or chains to the previous handler.  As part of 
  2587. handling the interrupt, your handler can PUSHF/CALL to the previous handler. 
  2588. The handler must IRET (or IRETD) or chain. 
  2589.  
  2590. For each protected-mode interrupt, DOS/4GW maintains separate chains of 16-bit 
  2591. and 32-bit handlers.  If your 16-bit handler chains, the previous handler is a 
  2592. 16-bit program.  If your 32-bit handler chains, the previous handler is a 
  2593. 32-bit program. 
  2594.  
  2595. If a 16-bit program hooks a given interrupt before any 32-bit programs hook it, 
  2596. the 16-bit chain is executed first.  If all the 16-bit handlers unhook later 
  2597. and a new 16-bit program hooks the interrupt while 32-bit handlers are still 
  2598. outstanding, the 32-bit handlers will be executed first. 
  2599.  
  2600. If the first program to hook an interrupt is 32-bit, the 32-bit chain is 
  2601. executed first. 
  2602.  
  2603.  
  2604. ΓòÉΓòÉΓòÉ 10.1.3. DOS/4GW:  Getting the Address of the Interrupt Handler ΓòÉΓòÉΓòÉ
  2605.  
  2606.  
  2607. When you signal Interrupt 21H, Function 35, it always returns a non-null 
  2608. address even if no other program of your bitness (i.e., 16-bit or 32-bit) has 
  2609. hooked the interrupt.  The address points to a dummy handler that looks to you 
  2610. as though it does an IRET to end the chain.  This means that you can't find an 
  2611. unused interrupt by looking for a NULL pointer.  Since this technique is most 
  2612. frequently used by programs that are looking for an unclaimed real-mode 
  2613. interrupt on which to install a TSR, it shouldn't cause you problems. 
  2614.  
  2615.  
  2616. ΓòÉΓòÉΓòÉ 11. DOS/4GW:  Interrupt 31H DPMI Functions ΓòÉΓòÉΓòÉ
  2617.  
  2618.  
  2619. When a DOS/4GW application runs under a DPMI host, such as Windows 3.1 in 
  2620. enhanced mode, an OS/2 virtual DOS machine, 386Max (with DEBUG=DPMIXCOPY), or 
  2621. QEMM/QDPMI (with EXTCHKOFF), the DPMI host provides the DPMI services, not 
  2622. DOS/4GW.  The DPMI host also provides virtual memory, if any.  Performance 
  2623. (speed and memory use) under different DPMI hosts varies greatly due to the 
  2624. quality of the DPMI implementation. 
  2625.  
  2626. DPMI services are accessed using Interrupt 31H. 
  2627.  
  2628. The following describes the services provided by DOS/4GW and DOS/4GW 
  2629. Professional in the absence of a DPMI host.  DOS/4GW supports many of the 
  2630. common DPMI system services.  Not all of the services described below are 
  2631. supported by other DPMI hosts. 
  2632.  
  2633. Some of the information in this chapter was obtained from the the DOS 
  2634. Protected-Mode Interface (DPMI) specification.  It is no longer in print; 
  2635. however the DPMI 1.0 specification can be obtained from the Intel ftp site. 
  2636. Here is the URL. 
  2637.  
  2638.  
  2639.    ftp://ftp.intel.com/pub/IAL/software_specs/dpmiv1.zip 
  2640.  
  2641. This ZIP file contains a Postscript version of the DPMI 1.0 specification. 
  2642.  
  2643.  
  2644. ΓòÉΓòÉΓòÉ 11.1. DOS/4GW:  Using Interrupt 31H Function Calls ΓòÉΓòÉΓòÉ
  2645.  
  2646.  
  2647. Interrupt 31H DPMI function calls can be used only by protected-mode programs. 
  2648.  
  2649. The general ground rules for Interrupt 31H calls are as follows: 
  2650.  
  2651.      All Interrupt 31H calls modify the AX register.  Unsupported or 
  2652.       unsuccessful calls return an error code in AX.  Other registers are saved 
  2653.       unless they contain specified return values. 
  2654.      All Interrupt 31H calls modify flags:  Unsupported or unsuccessful calls 
  2655.       return with the carry flag set.  Successful calls clear the carry flag. 
  2656.       Only memory management and interrupt flag management calls modify the 
  2657.       interrupt flag. 
  2658.      Memory management calls can enable interrupts. 
  2659.      All calls are reentrant. 
  2660.  
  2661.  The flag and register information for each call is listed in the following 
  2662.  descriptions of supported Interrupt 31H function calls. 
  2663.  
  2664.  
  2665. ΓòÉΓòÉΓòÉ 11.2. DOS/4GW:  Int31H Function Calls ΓòÉΓòÉΓòÉ
  2666.  
  2667.  
  2668. The Interrupt 31H subfunction calls supported by DOS/4GW are listed below by 
  2669. category: 
  2670.  
  2671.      Local Descriptor Table (LDT) management services 
  2672.      DOS memory management services 
  2673.      Interrupt services 
  2674.      Translation services 
  2675.      DPMI version 
  2676.      Memory management services 
  2677.      Page locking services 
  2678.      Demand paging performance tuning services 
  2679.      Physical address mapping 
  2680.      Virtual interrupt state functions 
  2681.      Vendor specific extensions 
  2682.      Coprocessor status 
  2683.  
  2684.  Only the most commonly used Interrupt 31H function calls are supported in this 
  2685.  version. 
  2686.  
  2687.  
  2688. ΓòÉΓòÉΓòÉ 11.2.1. DOS/4GW:  Local Descriptor Table (LDT) Management Services ΓòÉΓòÉΓòÉ
  2689.  
  2690.  Function 0000H 
  2691.       This function allocates a specified number of descriptors from the LDT 
  2692.       and returns the base selector.  Pass the following information: 
  2693.  
  2694.       AX = 0000H 
  2695.  
  2696.       CX = number of descriptors to be allocated 
  2697.  
  2698.       If the call succeeds, the carry flag is clear and the base selector is 
  2699.       returned in AX.  If the call fails, the carry flag is set. 
  2700.  
  2701.       An allocated descriptor is set to the present data type, with a base and 
  2702.       limit of zero.  The privilege level of an allocated descriptor is set to 
  2703.       match the code segment privilege level of the application.  To find out 
  2704.       the privilege level of a descriptor, use the lar instruction. 
  2705.  
  2706.       Allocated descriptors must be filled in by the application.  If more than 
  2707.       one descriptor is allocated, the returned selector is the first of a 
  2708.       contiguous array.  Use Function 0003H to get the increment for the next 
  2709.       selector in the array. 
  2710.  
  2711.  Function 0001H 
  2712.       This function frees the descriptor specified.  Pass the following 
  2713.       information: 
  2714.  
  2715.       AX = 0001H 
  2716.  
  2717.       BX = the selector to free 
  2718.  
  2719.       Use the selector returned with function 0000h when the descriptor was 
  2720.       allocated.  To free an array of descriptors, call this function for each 
  2721.       descriptor.  Use Function 0003H to find out the increment for each 
  2722.       descriptor in the array. 
  2723.  
  2724.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  2725.       flag is set. 
  2726.  
  2727.       You can use this function to free the descriptors allocated for the 
  2728.       program's initial CS, DS, and SS segments, but you should not free other 
  2729.       segments that were not allocated with Function 0000H or Function 000DH. 
  2730.  
  2731.  Function 0002H 
  2732.       This function converts a real-mode segment to a descriptor that a 
  2733.       protected-mode program can address.  Pass the following information: 
  2734.  
  2735.       AX = 0002H 
  2736.  
  2737.       BX = real-mode segment address 
  2738.  
  2739.       If the call succeeds, it clears the carry flag and returns the selector 
  2740.       mapped to the real-mode segment in AX.  If the call fails, the carry flag 
  2741.       is set. 
  2742.  
  2743.       If you call this function more than once with the same real-mode segment 
  2744.       address, you get the same selector value each time.  The descriptor limit 
  2745.       is set to 64KB. 
  2746.  
  2747.       The purpose of this function is to give protected-mode programs easy 
  2748.       access to commonly used real-mode segments.  However, because you cannot 
  2749.       modify or free descriptors created by this function, it should be used 
  2750.       infrequently.  Do not use this function to get descriptors for private 
  2751.       data areas. 
  2752.  
  2753.       To examine real-mode addresses using the same selector, first allocate a 
  2754.       descriptor, and then use Function 0007H to change the linear base 
  2755.       address. 
  2756.  
  2757.  Function 0003H 
  2758.       This function returns the increment value for the next selector.  Use 
  2759.       this function to get the value you add to the base address of an 
  2760.       allocated array of descriptors to get the next selector address.  Pass 
  2761.       the following information: 
  2762.  
  2763.       AX = 0003H 
  2764.  
  2765.       This call always succeeds.  The increment value is returned in AX.  This 
  2766.       value is always a power of two, but no other assumptions can be made. 
  2767.  
  2768.  Function 0006H 
  2769.       This function gets the linear base address of a selector.  Pass the 
  2770.       following information: 
  2771.  
  2772.       AX = 0006H 
  2773.  
  2774.       BX = selector 
  2775.  
  2776.       If the call succeeds, the carry flag is clear and CX:DX contains the 
  2777.       32-bit linear base address of the segment.  If the call fails, it sets 
  2778.       the carry flag. 
  2779.  
  2780.       If the selector you specify in BX is invalid, the call fails. 
  2781.  
  2782.  Function 0007H 
  2783.       This function changes the base address of a specified selector.  Only 
  2784.       descriptors allocated through Function 0000H should be modified.  Pass 
  2785.       the following information: 
  2786.  
  2787.       AX = 0007H 
  2788.  
  2789.       BX = selector 
  2790.  
  2791.       CX:DX = the new 32-bit linear base address for the segment 
  2792.  
  2793.       If the call succeeds, the carry flag is clear; if unsuccessful, the carry 
  2794.       flag is set. 
  2795.  
  2796.       If the selector you specify in BX is invalid, the call fails. 
  2797.  
  2798.  Function 0008H 
  2799.       This function sets the upper limit of a specified segment.  Use this 
  2800.       function to modify descriptors allocated with Function 0000H only.  Pass 
  2801.       the following information: 
  2802.  
  2803.       AX = 0008H 
  2804.  
  2805.       BX = selector 
  2806.  
  2807.       CX:DX = 32-bit segment limit 
  2808.  
  2809.       If the call succeeds, the carry flag is clear; if unsuccessful, the carry 
  2810.       flag is set. 
  2811.  
  2812.       The call fails if the specified selector is invalid, or if the specified 
  2813.       limit cannot be set. 
  2814.  
  2815.       Segment limits greater than 1MB must be page-aligned.  This means that 
  2816.       limits greater than 1MB must have the low 12 bits set. 
  2817.  
  2818.       To get the limit of a segment, use the 32-bit form of lsl for segment 
  2819.       limits greater than 64KB. 
  2820.  
  2821.  Function 0009H 
  2822.       This function sets the descriptor access rights.  Use this function to 
  2823.       modify descriptors allocated with Function 0000H only.  To examine the 
  2824.       access rights of a descriptor, use the lar instruction.  Pass the 
  2825.       following information: 
  2826.  
  2827.       AX = 0009H 
  2828.  
  2829.       BX = selector 
  2830.  
  2831.       CL = Access rights/type byte 
  2832.  
  2833.       CH = 386 extended access rights/type byte 
  2834.  
  2835.       If the call succeeds, the carry flag is clear; if unsuccessful, the carry 
  2836.       flag is set.  If the selector you specify in BX is invalid, the call 
  2837.       fails.  The call also fails if the access rights/type byte does not match 
  2838.       the format and meet the requirements shown in the figures below. 
  2839.  
  2840.       The access rights/type byte passed in CL has the format shown in the 
  2841.       figure below. 
  2842.  
  2843.  
  2844.       Figure 3. Access Rights/Type 
  2845.  
  2846.       The extended access rights/type byte passed in CH has the following 
  2847.       format. 
  2848.  
  2849.  
  2850.       Figure 4. Extended Access Rights/Type 
  2851.  
  2852.  Function 000AH 
  2853.       This function creates an alias to a code segment.  This function creates 
  2854.       a data descriptor that has the same base and limit as the specified code 
  2855.       segment descriptor.  Pass the following information: 
  2856.  
  2857.       AX = 000AH 
  2858.  
  2859.       BX = code segment selector 
  2860.  
  2861.       If the call succeeds, the carry flag is clear and the new data selector 
  2862.       is returned in AX.  If the call fails, the carry flag is set.  The call 
  2863.       fails if the selector passed in BX is not a valid code segment. 
  2864.  
  2865.       To deallocate an alias to a code segment, use Function 0001H. 
  2866.  
  2867.       After the alias is created, it does not change if the code segment 
  2868.       descriptor changes.  For example, if the base or limit of the code 
  2869.       segment change later, the alias descriptor stays the same. 
  2870.  
  2871.  Function 000BH 
  2872.       This function copies the descriptor table entry for a specified 
  2873.       descriptor.  The copy is written into an 8-byte buffer.  Pass the 
  2874.       following information: 
  2875.  
  2876.       AX = 000BH 
  2877.  
  2878.       BX = selector 
  2879.  
  2880.       ES:EDI = a pointer to the 8-byte buffer for the descriptor copy 
  2881.  
  2882.       If the call succeeds, the carry flag is clear and ES:EDI contains a 
  2883.       pointer to the buffer that contains a copy of the descriptor.  If the 
  2884.       call fails, the carry flag is set.  The call fails if the selector passed 
  2885.       in BX is invalid or unallocated. 
  2886.  
  2887.  Function 000CH 
  2888.       This function copies an 8-byte buffer into the LDT for a specified 
  2889.       descriptor.  The descriptor must first have been allocated with Function 
  2890.       0000H.  Pass the following information: 
  2891.  
  2892.       AX = 000CH 
  2893.  
  2894.       BX = selector 
  2895.  
  2896.       ES:EDI = a pointer to the 8-byte buffer containing the descriptor 
  2897.  
  2898.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  2899.       flag is set.  The call fails if the descriptor passed in BX is invalid. 
  2900.       The type byte, byte 5, has the same format and requirements as the access 
  2901.       rights/type byte passed to Function 0009H in CL.  The format is shown in 
  2902.       the first figure presented with the description of Function 0009H. 
  2903.  
  2904.       The extended type byte, byte 6, has the same format and requirements as 
  2905.       the extended access rights/type byte passed to Function 0009H in CH, 
  2906.       except that the limit field can have any value, and the low order bits 
  2907.       marked reserved are used to set the upper 4 bits of the descriptor limit. 
  2908.       The format is shown in the second figure presented with the description 
  2909.       of Function 0009H. 
  2910.  
  2911.  Function 000DH 
  2912.       This function allocates a specific LDT descriptor.  Pass the following 
  2913.       information: 
  2914.  
  2915.       AX = 000DH 
  2916.  
  2917.       BX = selector 
  2918.  
  2919.       If the call succeeds, the carry flag is clear and the specified 
  2920.       descriptor is allocated.  If the call fails, the carry flag is set. 
  2921.  
  2922.       The call fails if the specified selector is already in use, or if it is 
  2923.       not a valid LDT descriptor.  The first 10h (16 decimal) descriptors are 
  2924.       reserved for this function, and should not be used by the host.  Some of 
  2925.       these descriptors may be in use, however, if another client application 
  2926.       is already loaded. 
  2927.  
  2928.       To free the descriptor, use Function 0001H. 
  2929.  
  2930.  
  2931. ΓòÉΓòÉΓòÉ 11.2.2. DOS/4GW:  DOS Memory Management Services ΓòÉΓòÉΓòÉ
  2932.  
  2933.  Function 0100H 
  2934.       This function allocates memory from the DOS free memory pool.  This 
  2935.       function returns both the real-mode segment and one or more descriptors 
  2936.       that can be used by protected-mode applications.  Pass the following 
  2937.       information: 
  2938.  
  2939.       AX = 0100H 
  2940.  
  2941.       BX = the number of paragraphs (16-byte blocks) requested 
  2942.  
  2943.       If the call succeeds, the carry flag is clear.  AX contains the initial 
  2944.       real-mode segment of the allocated block and DX contains the base 
  2945.       selector for the allocated block. 
  2946.  
  2947.       If the call fails, the carry flag is set.  AX contains the DOS error 
  2948.       code.  If memory is damaged, code 07H is returned.  If there is not 
  2949.       enough memory to satisfy the request, code 08H is returned.  BX contains 
  2950.       the number of paragraphs in the largest available block of DOS memory. 
  2951.  
  2952.       If you request a block larger than 64KB, contiguous descriptors are 
  2953.       allocated.  Use Function 0003H to find the value of the increment to the 
  2954.       next descriptor.  The limit of the first descriptor is set to the entire 
  2955.       block.  Subsequent descriptors have a limit of 64KB, except for the final 
  2956.       descriptor, which has a limit of blocksize MOD 64KB. 
  2957.  
  2958.       You cannot modify or deallocate descriptors allocated with this function. 
  2959.       Function 101H deallocates the descriptors automatically. 
  2960.  
  2961.  Function 0101H 
  2962.       This function frees a DOS memory block allocated with function 0100H. 
  2963.       Pass the following information: 
  2964.  
  2965.       AX = 0101H 
  2966.  
  2967.       DX = selector of the block to be freed 
  2968.  
  2969.       If the call succeeds, the carry flag is clear. 
  2970.  
  2971.       If the call fails, the carry flag is set and the DOS error code is 
  2972.       returned in AX.  If the incorrect segment was specified, code 09H is 
  2973.       returned.  If memory control blocks are damaged, code 07H is returned. 
  2974.  
  2975.       All descriptors allocated for the specified memory block are deallocated 
  2976.       automatically and cannot be accessed correctly after the block is freed. 
  2977.  
  2978.  Function 0102H 
  2979.       This function resizes a DOS memory block allocated with function 0100H. 
  2980.       Pass the following information: 
  2981.  
  2982.       AX = 0102H 
  2983.  
  2984.       BX = the number of paragraphs (16-byte blocks) in the resized block 
  2985.  
  2986.       DX = selector of block to resize 
  2987.  
  2988.       If the call succeeds, the carry flag is clear. 
  2989.  
  2990.       If the call fails, the carry flag is set, the maximum number of 
  2991.       paragraphs available is returned in BX, and the DOS error code is 
  2992.       returned in AX.  If memory code blocks are damaged, code 07H is returned. 
  2993.       If there isn't enough memory to increase the size as requested, code 08H 
  2994.       is returned.  If the incorrect segment is specified, code 09h is 
  2995.       returned. 
  2996.  
  2997.       Because of the difficulty of finding additional contiguous memory or 
  2998.       descriptors, this function is not often used to increase the size of a 
  2999.       memory block.  Increasing the size of a memory block might well fail 
  3000.       because other DOS allocations have used contiguous space.  If the next 
  3001.       descriptor in the LDT is not free, allocation also fails when the size of 
  3002.       a block grows over the 64KB boundary. 
  3003.  
  3004.       If you shrink the size of a memory block, you may also free some 
  3005.       descriptors allocated to the block.  The initial selector remains 
  3006.       unchanged, however; only the limits of subsequent selectors will change. 
  3007.  
  3008.  
  3009. ΓòÉΓòÉΓòÉ 11.2.3. DOS/4GW:  Interrupt Services ΓòÉΓòÉΓòÉ
  3010.  
  3011.  Function 0200H 
  3012.       This function gets the value of the current task's real-mode interrupt 
  3013.       vector for the specified interrupt.  Pass the following information: 
  3014.  
  3015.       AX = 0200H 
  3016.  
  3017.       BL = interrupt number 
  3018.  
  3019.       This call always succeeds.  All 100H (256 decimal) interrupt vectors are 
  3020.       supported by the host.  When the call returns, the carry flag is clear, 
  3021.       and the segment:offset of the real-mode interrupt handler is returned in 
  3022.       CX:DX. 
  3023.  
  3024.       Because the address returned in CX is a segment, and not a selector, you 
  3025.       cannot put it into a protected-mode segment register.  If you do, a 
  3026.       general protection fault may occur. 
  3027.  
  3028.  Function 0201H 
  3029.       This function sets the value of the current task's real-mode interrupt 
  3030.       vector for the specified interrupt.  Pass the following information: 
  3031.  
  3032.       AX = 0201H 
  3033.  
  3034.       BL = interrupt number 
  3035.  
  3036.       CX:DX = segment:offset of the real-mode interrupt handler 
  3037.  
  3038.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3039.       flag is set. 
  3040.  
  3041.       The address passed in CX:DX should be a real-mode segment:offset, such as 
  3042.       function 0200H returns.  For this reason, the interrupt handler must 
  3043.       reside in DOS addressable memory.  You can use Function 0100H to allocate 
  3044.       DOS memory.  This version does not support the real-mode callback address 
  3045.       function. 
  3046.  
  3047.       If you are hooking a hardware interrupt, you have to lock all segments 
  3048.       involved.  These segments include the segment in which the interrupt 
  3049.       handler runs, and any segment it may touch at interrupt time. 
  3050.  
  3051.  Function 0202H 
  3052.       This function gets the processor exception handler vector.  This function 
  3053.       returns the CS:EIP of the current protected-mode exception handler for 
  3054.       the specified exception number.  Pass the following information: 
  3055.  
  3056.       AX = 0202H 
  3057.  
  3058.       BL = exception/fault number (00h - 1Fh) 
  3059.  
  3060.       If the call succeeds, the carry flag is clear and the selector:offset of 
  3061.       the protected-mode exception handler is returned in CX:EDX.  If it fails, 
  3062.       the carry flag is set. 
  3063.  
  3064.       The value returned in CX is a valid protected-mode selector, not a 
  3065.       real-mode segment. 
  3066.  
  3067.  Function 0203H 
  3068.       This function sets the processor exception handler vector.  This function 
  3069.       allows protected-mode applications to intercept processor exceptions that 
  3070.       are not handled by the DPMI environment.  Programs may wish to handle 
  3071.       exceptions such as "not present segment faults" which would otherwise 
  3072.       generate a fatal error.  Pass the following information: 
  3073.  
  3074.       AX = 0203H 
  3075.  
  3076.       BL = exception/fault number (00h - 1Fh) 
  3077.  
  3078.       CX:EDX = selector:offset of the exception handler 
  3079.  
  3080.       If the call succeeds, the carry flag is clear.  If it fails, the carry 
  3081.       flag is set. 
  3082.  
  3083.       The address passed in CX must be a valid protected-mode selector, such as 
  3084.       Function 204H returns, and not a real-mode segment.  A 32-bit 
  3085.       implementation must supply a 32-bit offset in the EDX register.  If the 
  3086.       handler chains to the next handler, it must use a 32-bit interrupt stack 
  3087.       frame to do so. 
  3088.  
  3089.       The handler should return using a far return instruction.  The original 
  3090.       SS:ESP, CS:EIP and flags on the stack, including the interrupt flag, will 
  3091.       be restored. 
  3092.  
  3093.       All fault stack frames have an error code.  However the error code is 
  3094.       only valid for exceptions 08h, 0Ah, 0Bh, 0Ch, 0Dh, and 0Eh. 
  3095.  
  3096.       The handler must preserve and restore all registers. 
  3097.  
  3098.       The exception handler will be called on a locked stack with interrupts 
  3099.       disabled.  The original SS, ESP, CS, and EIP will be pushed on the 
  3100.       exception handler stack frame. 
  3101.  
  3102.       The handler must either return from the call by executing a far return or 
  3103.       jump to the next handler in the chain (which will execute a far return or 
  3104.       chain to the next handler). 
  3105.  
  3106.       The procedure can modify any of the values on the stack pertaining to the 
  3107.       exception before returning.  This can be used, for example, to jump to a 
  3108.       procedure by modifying the CS:EIP on the stack.  Note that the procedure 
  3109.       must not modify the far return address on the stack - it must return to 
  3110.       the original caller.  The caller will then restore the flags, CS:EIP and 
  3111.       SS:ESP from the stack frame. 
  3112.  
  3113.       If the DPMI client does not handle an exception, or jumps to the default 
  3114.       exception handler, the host will reflect the exception as an interrupt 
  3115.       for exceptions 0, 1, 2, 3, 4, 5 and 7.  Exceptions 6 and 8 - 1Fh will be 
  3116.       treated as fatal errors and the client will be terminated. 
  3117.  
  3118.       Exception handlers will only be called for exceptions that occur in 
  3119.       protected mode. 
  3120.  
  3121.  Function 0204H 
  3122.       This function gets the CS:EIP selector:offset of the current 
  3123.       protected-mode interrupt handler for a specified interrupt number.  Pass 
  3124.       the following information: 
  3125.  
  3126.       AX = 0204H 
  3127.  
  3128.       BL = interrupt number 
  3129.  
  3130.       This call always succeeds.  All 100H (256 decimal) interrupt vectors are 
  3131.       supported by the host.  When the call returns, the carry flag is clear 
  3132.       and CX:EDX contains the protected-mode selector:offset of the exception 
  3133.       handler. 
  3134.  
  3135.       A 32-bit offset is returned in the EDX register. 
  3136.  
  3137.  Function 0205H 
  3138.       This function sets the address of the specified protected-mode interrupt 
  3139.       vector.  Pass the following information: 
  3140.  
  3141.       AX = 0205H 
  3142.  
  3143.       BL = interrupt number 
  3144.  
  3145.       CX:EDX = selector:offset of the exception handler 
  3146.  
  3147.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3148.       flag is set. 
  3149.  
  3150.       The address passed in CX must be a valid protected-mode selector, such as 
  3151.       Function 204H returns, and not a real-mode segment.  A 32-bit 
  3152.       implementation must supply a 32-bit offset in the EDX register.  If the 
  3153.       handler chains to the next handler, it must use a 32-bit interrupt stack 
  3154.       frame to do so. 
  3155.  
  3156.  
  3157. ΓòÉΓòÉΓòÉ 11.2.4. DOS/4GW:  Translation Services ΓòÉΓòÉΓòÉ
  3158.  
  3159.  
  3160. These services are provided so that protected-mode programs can call real-mode 
  3161. software that DPMI does not support directly.  The protected-mode program must 
  3162. set up a data structure with the appropriate register values.  This "real-mode 
  3163. call structure" is shown below. 
  3164.  
  3165.      Offset  Register 
  3166.  
  3167.      00H   EDI 
  3168.  
  3169.      04H   ESI 
  3170.  
  3171.      08H   EBP 
  3172.  
  3173.      0CH   Reserved by system 
  3174.  
  3175.      10H   EBX 
  3176.  
  3177.      14H   EDX 
  3178.  
  3179.      18H   ECX 
  3180.  
  3181.      1CH   EAX 
  3182.  
  3183.      20H   Flags 
  3184.  
  3185.      22H   ES 
  3186.  
  3187.      24H   DS 
  3188.  
  3189.      26H   FS 
  3190.  
  3191.      28H   GS 
  3192.  
  3193.      2AH   IP 
  3194.  
  3195.      2CH   CS 
  3196.  
  3197.      2EH   SP 
  3198.  
  3199.      30H   SS 
  3200.  
  3201. After the call or interrupt is complete, all real-mode registers and flags 
  3202. except SS, SP, CS, and IP will be copied back to the real-mode call structure 
  3203. so that the caller can examine the real-mode return values. 
  3204.  
  3205. The values in the segment registers should be real-mode segments, not 
  3206. protected-mode selectors. 
  3207.  
  3208. The translation services will provide a real-mode stack if the SS:SP fields are 
  3209. zero.  However, the stack provided is relatively small.  If the real-mode 
  3210. procedure/interrupt routine uses more than 30 words of stack space then you 
  3211. should provide your own real-mode stack. 
  3212.  
  3213.  Function 0300H 
  3214.       This function simulates a real-mode interrupt.  This function simulates 
  3215.       an interrupt in real mode.  It will invoke the CS:IP specified by the 
  3216.       real-mode interrupt vector and the handler must return by executing an 
  3217.       iret.  Pass the following information: 
  3218.  
  3219.       AX = 0300H 
  3220.  
  3221.       BL = interrupt number 
  3222.  
  3223.       BH = flags 
  3224.                 Bit 0 = 1 resets the interrupt controller and A20 line.  Other 
  3225.                 flags are reserved and must be 0. 
  3226.  
  3227.       CX = number of words to copy from protected-mode stack to real-mode stack 
  3228.  
  3229.       ES:EDI = the selector:offset of real-mode call structure 
  3230.  
  3231.       If the call fails, the carry flag is set. 
  3232.  
  3233.       If the call succeeds, the carry flag is clear and ES:EDI contains the 
  3234.       selector:offset of the modified real-mode call structure. 
  3235.  
  3236.       The CS:IP in the real-mode call structure is ignored by this service. 
  3237.       The appropriate interrupt handler will be called based on the value 
  3238.       passed in BL. 
  3239.  
  3240.       The flags specified in the real-mode call structure will be pushed on the 
  3241.       real-mode stack iret frame.  The interrupt handler will be called with 
  3242.       the interrupt and trace flags clear. 
  3243.  
  3244.       It is up to the caller to remove any parameters that were pushed on the 
  3245.       protected-mode stack. 
  3246.  
  3247.       The flag to reset the interrupt controller and the A20 line is ignored by 
  3248.       DPMI implementations that run in Virtual 8086 mode.  It causes DPMI 
  3249.       implementations that return to real mode to set the interrupt controller 
  3250.       and A20 address line hardware to its normal real-mode state. 
  3251.  
  3252.  Function 0301H 
  3253.       (DOS/4GW Professional only) This function calls a real-mode procedure 
  3254.       with a FAR return frame.  The called procedure must execute a FAR return 
  3255.       when it completes.  Pass the following information: 
  3256.  
  3257.       AX = 0301H 
  3258.  
  3259.       BH = flags 
  3260.                 Bit 0 = 1 resets the interrupt controller and A20 line.  Other 
  3261.                 flags reserved and must be 0. 
  3262.  
  3263.       CX = Number of words to copy from protected-mode to real-mode stack 
  3264.  
  3265.       ES:EDI = selector:offset of real-mode call structure 
  3266.  
  3267.       If the call succeeds, the carry flag is clear and ES:EDI contains the 
  3268.       selector:offset of modified real-mode call structure. 
  3269.  
  3270.       If the call fails, the carry flag is set. 
  3271.  
  3272.       Notes: 
  3273.  
  3274.         1. The CS:IP in the real-mode call structure specifies the address of 
  3275.            the real-mode procedure to call. 
  3276.  
  3277.         2. The real-mode procedure must execute a FAR return when it has 
  3278.            completed. 
  3279.  
  3280.         3. If the SS:SP fields are zero then a real-mode stack will be provided 
  3281.            by the DPMI host.  Otherwise, the real-mode SS:SP will be set to the 
  3282.            specified values before the procedure is called. 
  3283.  
  3284.         4. When the Int 31h returns, the real-mode call structure will contain 
  3285.            the values that were returned by the real-mode procedure. 
  3286.  
  3287.         5. It is up to the caller to remove any parameters that were pushed on 
  3288.            the protected-mode stack. 
  3289.  
  3290.         6. The flag to reset the interrupt controller and A20 line is ignored 
  3291.            by DPMI implementations that run in Virtual 8086 mode.  It causes 
  3292.            DPMI implementations that return to real mode to set the interrupt 
  3293.            controller and A20 address line hardware to its normal real-mode 
  3294.            state. 
  3295.  
  3296.  Function 0302H 
  3297.       (DOS/4GW Professional only) This function calls a real-mode procedure 
  3298.       with an iret frame.  The called procedure must execute an iret when it 
  3299.       completes.  Pass the following information: 
  3300.  
  3301.       AX = 0302H 
  3302.  
  3303.       BH = flags 
  3304.                 Bit 0 = 1 resets the interrupt controller and A20 line.  Other 
  3305.                 flags reserved and must be 0. 
  3306.  
  3307.       CX = Number of words to copy from protected-mode to real-mode stack 
  3308.  
  3309.       ES:EDI = selector:offset of real-mode call structure 
  3310.  
  3311.       If the call succeeds, the carry flag is clear and ES:EDI contains the 
  3312.       selector:offset of modified real-mode call structure. 
  3313.  
  3314.       If the call fails, the carry flag is set. 
  3315.  
  3316.       Notes: 
  3317.  
  3318.         1. The CS:IP in the real-mode call structure specifies the address of 
  3319.            the real-mode procedure to call. 
  3320.  
  3321.         2. The real-mode procedure must execute an iret when it has completed. 
  3322.  
  3323.         3. If the SS:SP fields are zero then a real-mode stack will be provided 
  3324.            by the DPMI host.  Otherwise, the real-mode SS:SP will be set to the 
  3325.            specified values before the procedure is called. 
  3326.  
  3327.         4. When the Int 31h returns, the real-mode call structure will contain 
  3328.            the values that were returned by the real-mode procedure. 
  3329.  
  3330.         5. The flags specified in the real-mode call structure will be pushed 
  3331.            the real-mode stack iret frame.  The procedure will be called with 
  3332.            the interrupt and trace flags clear. 
  3333.  
  3334.         6. It is up to the caller to remove any parameters that were pushed on 
  3335.            the protected-mode stack. 
  3336.  
  3337.         7. The flag to reset the interrupt controller and A20 line is ignored 
  3338.            by DPMI implementations that run in Virtual 8086 mode.  It causes 
  3339.            DPMI implementations that return to real mode to set the interrupt 
  3340.            controller and A20 address line hardware to its normal real-mode 
  3341.            state. 
  3342.  
  3343.  Function 0303H 
  3344.       (DOS/4GW Professional only) This function allocates a real-mode callback 
  3345.       address.  This service is used to obtain a unique real-mode SEG:OFFSET 
  3346.       that will transfer control from real mode to a protected-mode procedure. 
  3347.  
  3348.       At times it is necessary to hook a real-mode interrupt or device callback 
  3349.       in a protected-mode driver.  For example, many mouse drivers call an 
  3350.       address whenever the mouse is moved.  Software running in protected mode 
  3351.       can use a real-mode callback to intercept the mouse driver calls.  Pass 
  3352.       the following information: 
  3353.  
  3354.       AX = 0303H 
  3355.  
  3356.       DS:ESI = selector:offset of procedure to call 
  3357.  
  3358.       ES:EDI = selector:offset of real-mode call structure 
  3359.  
  3360.       If the call succeeds, the carry flag is clear and CX:DX contains the 
  3361.       segment:offset of real-mode callback address. 
  3362.  
  3363.       If the call fails, the carry flag is set. 
  3364.  
  3365.       Callback Procedure Parameters 
  3366.  
  3367.  
  3368.                    Interrupts disabled 
  3369.                    DS:ESI = selector:offset of real-mode SS:SP 
  3370.                    ES:EDI = selector:offset of real-mode call structure 
  3371.                    SS:ESP = Locked protected-mode API stack 
  3372.                    All other registers undefined 
  3373.  
  3374.       Return from Callback Procedure 
  3375.  
  3376.  
  3377.                    Execute an IRET to return 
  3378.                    ES:EDI =  selector:offset of real-mode call structure 
  3379.                    to restore (see note) 
  3380.       Notes: 
  3381.  
  3382.         1. Since the real-mode call structure is static, you must be careful 
  3383.            when writing code that may be reentered.  The simplest method of 
  3384.            avoiding reentrancy is to leave interrupts disabled throughout the 
  3385.            entire call.  However, if the amount of code executed by the 
  3386.            callback is large then you will need to copy the real-mode call 
  3387.            structure into another buffer. You can then return with ES:EDI 
  3388.            pointing to the buffer you copied the data to - it does not have to 
  3389.            point to the original real mode call structure. 
  3390.  
  3391.         2. The called procedure is responsible for modifying the real-mode 
  3392.            CS:IP before returning.  If the real-mode CS:IP is left unchanged 
  3393.            then the real-mode callback will be executed immediately and your 
  3394.            procedure will be called again. Normally you will want to pop a 
  3395.            return address off of the real-mode stack and place it in the 
  3396.            real-mode CS:IP.  The example code in the next section demonstrates 
  3397.            chaining to another interrupt handler and simulating a real-mode 
  3398.            iret. 
  3399.  
  3400.         3. To return values to the real-mode caller, you must modify the 
  3401.            real-mode call structure. 
  3402.  
  3403.         4. Remember that all segment values in the real-mode call structure 
  3404.            will contain real-mode segments, not selectors.  If you need to 
  3405.            examine data pointed to by a real-mode seg:offset pointer, you 
  3406.            should not use the segment to selector service to create a new 
  3407.            selector.  Instead, allocate a descriptor during initialization and 
  3408.            change the descriptor's base to 16 times the real-mode segment's 
  3409.            value.  This is important since selectors allocated though the 
  3410.            segment to selector service can never be freed. 
  3411.  
  3412.         5. DPMI hosts should provide a minimum of 16 callback addresses per 
  3413.            task. 
  3414.       The following code is a sample of a real-mode interrupt hook.  It hooks 
  3415.       the DOS Int 21h and returns an error for the delete file function 
  3416.       (AH=41h).  Other calls are passed through to DOS.  This example is 
  3417.       somewhat silly but it demonstrates the techniques used to hook a real 
  3418.       mode interrupt.  Note that since DOS calls are reflected from protected 
  3419.       mode to real mode, the following code will intercept all DOS calls from 
  3420.       both real mode and protected mode. 
  3421.  
  3422.  
  3423.          ;****************************************************** 
  3424.          ; This procedure gets the current Int 21h real-mode 
  3425.          ; Seg:Offset, allocates a real-mode callback address, 
  3426.          ; and sets the real-mode Int 21h vector to the call- 
  3427.          ; back address. 
  3428.          ;****************************************************** 
  3429.          Initialization_Code: 
  3430.          ; 
  3431.          ; Create a code segment alias to save data in 
  3432.          ; 
  3433.              mov   ax, 000Ah 
  3434.              mov   bx, cs 
  3435.              int   31h 
  3436.              jc    ERROR 
  3437.              mov   ds, ax 
  3438.              ASSUMES DS,_TEXT 
  3439.          ; 
  3440.          ; Get current Int 21h real-mode SEG:OFFSET 
  3441.          ; 
  3442.              mov   ax, 0200h 
  3443.              mov   bl, 21h 
  3444.              int   31h 
  3445.              jc    ERROR 
  3446.              mov   [Orig_Real_Seg], cx 
  3447.              mov   [Orig_Real_Offset], dx 
  3448.          ; 
  3449.          ; Allocate a real-mode callback 
  3450.          ; 
  3451.              mov   ax, 0303h 
  3452.              push   ds 
  3453.              mov   bx, cs 
  3454.              mov   ds, bx 
  3455.              mov   si, OFFSET My_Int_21_Hook 
  3456.              pop   es 
  3457.              mov   di, OFFSET My_Real_Mode_Call_Struc 
  3458.              int   31h 
  3459.              jc    ERROR 
  3460.          ; 
  3461.          ; Hook real-mode int 21h with the callback address 
  3462.          ; 
  3463.              mov   ax, 0201h 
  3464.              mov   bl, 21h 
  3465.              int   31h 
  3466.              jc    ERROR 
  3467.  
  3468.          ;****************************************************** 
  3469.          ; 
  3470.          ; This is the actual Int 21h hook code.  It will return 
  3471.          ; an "access denied" error for all calls made in real 
  3472.          ; mode to delete a file.  Other calls will be passed 
  3473.          ; through to DOS. 
  3474.          ; 
  3475.          ; ENTRY: 
  3476.          ;   DS:SI -> Real-mode SS:SP 
  3477.          ;   ES:DI -> Real-mode call structure 
  3478.          ;   Interrupts disabled 
  3479.          ; 
  3480.          ; EXIT: 
  3481.          ;   ES:DI -> Real-mode call structure 
  3482.          ; 
  3483.          ;****************************************************** 
  3484.  
  3485.          My_Int_21_Hook: 
  3486.              cmp   es:[di.RealMode_AH], 41h 
  3487.              jne   Chain_To_DOS 
  3488.          ; 
  3489.          ; This is a delete file call (AH=41h).  Simulate an 
  3490.          ; iret on the real-mode stack, set the real-mode 
  3491.          ; carry flag, and set the real-mode AX to 5 to indicate 
  3492.          ; an access denied error. 
  3493.          ; 
  3494.              cld 
  3495.              lodsw          ; Get real-mode ret IP 
  3496.              mov   es:[di.RealMode_IP], ax 
  3497.              lodsw          ; Get real-mode ret CS 
  3498.              mov   es:[di.RealMode_CS], ax 
  3499.              lodsw          ; Get real-mode flags 
  3500.              or    ax, 1      ; Set carry flag 
  3501.              mov   es:[di.RealMode_Flags], ax 
  3502.              add   es:[di.RealMode_SP], 6 
  3503.              mov   es:[di.RealMode_AX], 5 
  3504.              jmp   My_Hook_Exit 
  3505.          ; 
  3506.          ; Chain to original Int 21h vector by replacing the 
  3507.          ; real-mode CS:IP with the original Seg:Offset. 
  3508.          ; 
  3509.          Chain_To_DOS: 
  3510.              mov   ax, cs:[Orig_Real_Seg] 
  3511.              mov   es:[di.RealMode_CS], ax 
  3512.              mov   ax, cs:[Orig_Real_Offset] 
  3513.              mov   es:[di.RealMode_IP], ax 
  3514.  
  3515.          My_Hook_Exit: 
  3516.              iret 
  3517.  
  3518.  Function 0304H 
  3519.       (DOS/4GW Professional only) This function frees a real-mode callback 
  3520.       address that was allocated through the allocate real-mode callback 
  3521.       address service.  Pass the following information: 
  3522.  
  3523.       AX = 0304H 
  3524.  
  3525.       CX:DX = Real-mode callback address to free 
  3526.  
  3527.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3528.       flag is set. 
  3529.  
  3530.       Notes: 
  3531.  
  3532.         1. Real-mode callbacks are a limited resource.  Your code should free 
  3533.            any break point that it is no longer using. 
  3534.  
  3535.  
  3536. ΓòÉΓòÉΓòÉ 11.2.5. DOS/4GW:  DPMI Version ΓòÉΓòÉΓòÉ
  3537.  
  3538.  Function 0400H 
  3539.       This function returns the version of DPMI services supported.  Note that 
  3540.       this is not necessarily the version of any operating system that supports 
  3541.       DPMI.  It should be used by programs to determine what calls are legal in 
  3542.       the current environment.  Pass the following information: 
  3543.  
  3544.       AX = 0400H 
  3545.  
  3546.       The information returned is: 
  3547.  
  3548.       AH = Major version 
  3549.  
  3550.       AL = Minor version 
  3551.  
  3552.       BX = Flags 
  3553.                 Bit 0 = 1 if running under an 80386 DPMI implementation.  Bit 1 
  3554.                 = 1 if processor is returned to real mode for reflected 
  3555.                 interrupts (as opposed to Virtual 8086 mode).  Bit 2 = 1 if 
  3556.                 virtual memory is supported.  Bit 3 is reserved and undefined. 
  3557.                 All other bits are zero and reserved for later use. 
  3558.  
  3559.       CL = Processor type 
  3560.  
  3561.  
  3562.                    02 = 80286 
  3563.                    03 = 80386 
  3564.                    04 = 80486 
  3565.                    05 = Pentium 
  3566.  
  3567.       DH = Current value of virtual master PIC base interrupt 
  3568.  
  3569.       DL = Current value of virtual slave PIC base interrupt 
  3570.  
  3571.       Carry flag clear (call cannot fail) 
  3572.  
  3573.  
  3574. ΓòÉΓòÉΓòÉ 11.2.6. DOS/4GW:  Memory Management Services ΓòÉΓòÉΓòÉ
  3575.  
  3576.  Function 0500H 
  3577.       This function gets information about free memory.  Pass the following 
  3578.       information: 
  3579.  
  3580.       AX = 0500H 
  3581.  
  3582.       ES:EDI = the selector:offset of a 30H byte buffer. 
  3583.  
  3584.       If the call fails, the carry flag is set. 
  3585.  
  3586.       If the call succeeds, the carry flag is clear and ES:EDI contains the 
  3587.       selector:offset of a buffer with the structure shown in the figure below. 
  3588.  
  3589.            Offset  Description 
  3590.  
  3591.            00H   Largest available block, in bytes 
  3592.  
  3593.            04H   Maximum unlocked page allocation 
  3594.  
  3595.            08H   Largest block of memory (in pages) that 
  3596.       could 
  3597.                be allocated and then locked 
  3598.  
  3599.            0CH   Total linear address space size, in pages, 
  3600.       including 
  3601.                already allocated pages 
  3602.  
  3603.            10H   Total number of free pages and pages 
  3604.       currently 
  3605.                unlocked and available for paging out 
  3606.  
  3607.            14H   Number of physical pages not in use 
  3608.  
  3609.            18H   Total number of physical pages managed by host 
  3610.  
  3611.            1CH   Free linear address space, in pages 
  3612.  
  3613.            20H   Size of paging/file partition, in pages 
  3614.  
  3615.            24H -  Reserved 
  3616.            2FH 
  3617.  
  3618.       Only the first field of the structure is guaranteed to contain a valid 
  3619.       value.  Any field that is not returned by DOS/4GW is set to -1 
  3620.       (0FFFFFFFFH). 
  3621.  
  3622.  Function 0501H 
  3623.       This function allocates and commits linear memory.  Pass the following 
  3624.       information: 
  3625.  
  3626.       AX = 0501H 
  3627.  
  3628.       BX:CX = size of memory to allocate, in bytes. 
  3629.  
  3630.       If the call succeeds, the carry flag is clear, BX:CX contains the linear 
  3631.       address of the allocated memory, and SI:DI contains the memory block 
  3632.       handle used to free or resize the block.  If the call fails, the carry 
  3633.       flag is set. 
  3634.  
  3635.       No selectors are allocated for the memory block.  The caller must 
  3636.       allocate and initialize selectors needed to access the memory. 
  3637.  
  3638.       If VMM is present, the memory is allocated as unlocked, page granular 
  3639.       blocks.  Because of the page granularity, memory should be allocated in 
  3640.       multiples of 4KB. 
  3641.  
  3642.  Function 0502H 
  3643.       This function frees a block of memory allocated through function 0501H. 
  3644.       Pass the following information: 
  3645.  
  3646.       AX = 0502H 
  3647.  
  3648.       SI:DI = handle returned with function 0501H when memory was allocated 
  3649.  
  3650.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3651.       flag is set.  You must also free any selectors allocated to point to the 
  3652.       freed memory block. 
  3653.  
  3654.  Function 0503H 
  3655.       This function resizes a block of memory allocated through the 0501H 
  3656.       function.  If you resize a block of linear memory, it may have a new 
  3657.       linear address and a new handle.  Pass the following information: 
  3658.  
  3659.       AX = 0503H 
  3660.  
  3661.       BX:CX = new size of memory block, in bytes 
  3662.  
  3663.       SI:DI = handle returned with function 0501H when memory was allocated 
  3664.  
  3665.       If the call succeeds, the carry flag is clear, BX:CX contains the new 
  3666.       linear address of the memory block, and SI:DI contains the new handle of 
  3667.       the memory block.  If the call fails, the carry flag is set. 
  3668.  
  3669.       If either the linear address or the handle has changed, update the 
  3670.       selectors that point to the memory block.  Use the new handle instead of 
  3671.       the old one. 
  3672.  
  3673.       You cannot resize a memory block to zero bytes. 
  3674.  
  3675.  
  3676. ΓòÉΓòÉΓòÉ 11.2.7. DOS/4GW:  Page Locking Services ΓòÉΓòÉΓòÉ
  3677.  
  3678.  
  3679. These services are only useful under DPMI implementations that support virtual 
  3680. memory.  Although memory ranges are specified in bytes, the actual unit of 
  3681. memory that will be locked will be one or more pages.  Page locks are 
  3682. maintained as a count.  When the count is decremented to zero, the page is 
  3683. unlocked and can be swapped to disk.  This means that if a region of memory is 
  3684. locked three times then it must be unlocked three times before the pages will 
  3685. be unlocked. 
  3686.  
  3687.  Function 0600H 
  3688.       This function locks a specified linear address range.  Pass the following 
  3689.       information: 
  3690.  
  3691.       AX = 0600H 
  3692.  
  3693.       BX:CX = starting linear address of memory to lock 
  3694.  
  3695.       SI:DI = size of region to lock (in bytes) 
  3696.  
  3697.       If the call fails, the carry flag is set and none of the memory will be 
  3698.       locked. 
  3699.  
  3700.       If the call succeeds, the carry flag is clear.  If the specified region 
  3701.       overlaps part of a page at the beginning or end of a region, the page(s) 
  3702.       will be locked. 
  3703.  
  3704.  Function 0601H 
  3705.       This function unlocks a specified linear address range that was 
  3706.       previously locked using the "lock linear region" function (0600h).  Pass 
  3707.       the following information: 
  3708.  
  3709.       AX = 0601H 
  3710.  
  3711.       BX:CX = starting linear address of memory to unlock 
  3712.  
  3713.       SI:DI = size of region to unlock (in bytes) 
  3714.  
  3715.       If the call fails, the carry flag is set and none of the memory will be 
  3716.       unlocked.  An error will be returned if the memory was not previously 
  3717.       locked or if the specified region is invalid. 
  3718.  
  3719.       If the call succeeds, the carry flag is clear.  If the specified region 
  3720.       overlaps part of a page at the beginning or end of a region, the page(s) 
  3721.       will be unlocked.  Even if the call succeeds, the memory will remain 
  3722.       locked if the lock count is not decremented to zero. 
  3723.  
  3724.  Function 0604H 
  3725.       This function gets the page size for Virtual Memory (VM) only.  This 
  3726.       function returns the size of a single memory page in bytes.  Pass the 
  3727.       following information: 
  3728.  
  3729.       AX = 0604H 
  3730.  
  3731.       If the call succeeds, the carry flag is clear and BX:CX = Page size in 
  3732.       bytes. 
  3733.  
  3734.       If the call fails, the carry flag is set. 
  3735.  
  3736.  
  3737. ΓòÉΓòÉΓòÉ 11.2.8. DOS/4GW:  Demand Paging Performance Tuning Services ΓòÉΓòÉΓòÉ
  3738.  
  3739.  
  3740. Some applications will discard memory objects or will not access objects for 
  3741. long periods of time.  These services can be used to improve the performance of 
  3742. demand paging. 
  3743.  
  3744. Although these functions are only relevant for DPMI implementations that 
  3745. support virtual memory, other implementations will ignore these functions (it 
  3746. will always return carry clear).  Therefore your code can always call these 
  3747. functions regardless of the environment it is running under. 
  3748.  
  3749. Since both of these functions are simply advisory functions, the operating 
  3750. system may choose to ignore them.  In any case, your code should function 
  3751. properly even if the functions fail. 
  3752.  
  3753.  Function 0702H 
  3754.       (DOS/4GW Professional only) This function marks a page as a demand paging 
  3755.       candidate.  This function is used to inform the operating system that a 
  3756.       range of pages should be placed at the head of the page out candidate 
  3757.       list.  This will force these pages to be swapped to disk ahead of other 
  3758.       pages even if the memory has been accessed recently.  However, all memory 
  3759.       contents will be preserved. 
  3760.  
  3761.       This is useful, for example, if a program knows that a given piece of 
  3762.       data will not be accessed for a long period of time.  That data is ideal 
  3763.       for swapping to disk since the physical memory it now occupies can be 
  3764.       used for other purposes.  Pass the following information: 
  3765.  
  3766.       AX = 0702H 
  3767.  
  3768.       BX:CX = Starting linear address of pages to mark 
  3769.  
  3770.       SI:DI = Number of bytes to mark as paging candidates 
  3771.  
  3772.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3773.       flag is set. 
  3774.  
  3775.       Notes: 
  3776.  
  3777.         1. This function does not force the pages to be swapped to disk 
  3778.            immediately. 
  3779.  
  3780.         2. Partial pages will not be discarded. 
  3781.  
  3782.  Function 0703H 
  3783.       (DOS/4GW Professional only) This function discards page contents.  This 
  3784.       function discards the entire contents of a given linear memory range.  It 
  3785.       is used after a memory object that occupied a given piece of memory has 
  3786.       been discarded. 
  3787.  
  3788.       The contents of the region will be undefined the next time the memory is 
  3789.       accessed.  All values previously stored in this memory will be lost. 
  3790.       Pass the following information: 
  3791.  
  3792.       AX = 0703H 
  3793.  
  3794.       BX:CX = Starting linear address of pages to discard 
  3795.  
  3796.       SI:DI = Number of bytes to discard 
  3797.  
  3798.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3799.       flag is set. 
  3800.  
  3801.       Notes: 
  3802.  
  3803.         1. Partial pages will not be discarded. 
  3804.  
  3805.  
  3806. ΓòÉΓòÉΓòÉ 11.2.9. DOS/4GW:  Physical Address Mapping ΓòÉΓòÉΓòÉ
  3807.  
  3808.  
  3809. Memory mapped devices such as network adapters and displays sometimes have 
  3810. memory mapped at physical addresses that lie outside of the normal 1Mb of 
  3811. memory that is addressable in real mode.  Under many implementations of DPMI, 
  3812. all addresses are linear addresses since they use the paging mechanism of the 
  3813. 80386.  This service can be used by device drivers to convert a physical 
  3814. address into a linear address.  The linear address can then be used to access 
  3815. the device memory. 
  3816.  
  3817.  Function 0800H 
  3818.       This function is used for Physical Address Mapping. 
  3819.  
  3820.       Some implementations of DPMI may not support this call because it could 
  3821.       be used to circumvent system protection.  This call should only be used 
  3822.       by programs that absolutely require direct access to a memory mapped 
  3823.       device. 
  3824.  
  3825.       Pass the following information: 
  3826.  
  3827.       AX = 0800H 
  3828.  
  3829.       BX:CX = Physical address of memory 
  3830.  
  3831.       SI:DI = Size of region to map in bytes 
  3832.  
  3833.       If the call succeeds, the carry flag is clear and BX:CX = Linear Address 
  3834.       that can be used to access the physical memory. 
  3835.  
  3836.       If the call fails, the carry flag is set. 
  3837.  
  3838.       Notes: 
  3839.  
  3840.         1. Under DPMI implementations that do not use the 80386 paging 
  3841.            mechanism, the call will always succeed and the address returned 
  3842.            will be equal to the physical address parameter passed into this 
  3843.            function. 
  3844.  
  3845.         2. It is up to the caller to build an appropriate selector to access 
  3846.            the memory. 
  3847.  
  3848.         3. Do not use this service to access memory that is mapped in the first 
  3849.            megabyte of address space (the real-mode addressable region). 
  3850.  
  3851.  Function 0801H 
  3852.       This function is used to free Physical Address Mapping.  Pass the 
  3853.       following information: 
  3854.  
  3855.       AX = 0801H 
  3856.  
  3857.       BX:CX = Linear address returned by Function 0800H. 
  3858.  
  3859.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  3860.       flag is set. 
  3861.  
  3862.       Notes: 
  3863.  
  3864.         1. The client should call this function when it is finished using a 
  3865.            device previously mapped to linear addresses with the Physical 
  3866.            Address Mapping function (Function 0800H). 
  3867.  
  3868.  
  3869. ΓòÉΓòÉΓòÉ 11.2.10. DOS/4GW:  Virtual Interrupt State Functions ΓòÉΓòÉΓòÉ
  3870.  
  3871.  
  3872. Under many implementations of DPMI, the interrupt flag in protected mode will 
  3873. always be set (interrupts enabled).  This is because the program is running 
  3874. under a protected operating system that cannot allow programs to disable 
  3875. physical hardware interrupts.  However, the operating system will maintain a 
  3876. "virtual" interrupt state for protected-mode programs.  When the program 
  3877. executes a CLI instruction, the program's virtual interrupt state will be 
  3878. disabled, and the program will not receive any hardware interrupts until it 
  3879. executes an STI to reenable interrupts (or calls service 0901h). 
  3880.  
  3881. When a protected-mode program executes a PUSHF instruction, the real processor 
  3882. flags will be pushed onto the stack.  Thus, examining the flags pushed on the 
  3883. stack is not sufficient to determine the state of the program's virtual 
  3884. interrupt flag.  These services enable programs to get and modify the state of 
  3885. their virtual interrupt flag. 
  3886.  
  3887. The following sample code enters an interrupt critical section and then 
  3888. restores the virtual interrupt state to it's previous state. 
  3889.  
  3890.  
  3891.    ; 
  3892.    ; Disable interrupts and get previous interrupt state 
  3893.    ; 
  3894.        mov   ax, 0900h 
  3895.        int   31h 
  3896.    ; 
  3897.    ; At this point AX = 0900h or 0901h 
  3898.    ; 
  3899.        . 
  3900.        . 
  3901.        . 
  3902.    ; 
  3903.    ; Restore previous state (assumes AX unchanged) 
  3904.    ; 
  3905.        int   31h 
  3906.  
  3907.  Function 0900H 
  3908.       This function gets and disables Virtual Interrupt State.  This function 
  3909.       will disable the virtual interrupt flag and return the previous state of 
  3910.       the virtual interrupt flag.  Pass the following information: 
  3911.  
  3912.       AX = 0900H 
  3913.  
  3914.       After the call, the carry flag is clear (this function always succeeds) 
  3915.       and virtual interrupts are disabled. 
  3916.  
  3917.          AL = 0 if virtual interrupts were previously disabled. 
  3918.          AL = 1 if virtual interrupts were previously enabled. 
  3919.  
  3920.       Notes: 
  3921.  
  3922.         1. AH will not be changed by this procedure.  Therefore, to restore the 
  3923.            previous state, simply execute an Int 31h. 
  3924.  
  3925.  Function 0901H 
  3926.       This function gets and enables the Virtual Interrupt State.  This 
  3927.       function will enable the virtual interrupt flag and return the previous 
  3928.       state of the virtual interrupt flag.  Pass the following information: 
  3929.  
  3930.       AX = 0901H 
  3931.  
  3932.       After the call, the carry flag is clear (this function always succeeds) 
  3933.       and virtual interrupts are enabled. 
  3934.  
  3935.          AL = 0 if virtual interrupts were previously disabled. 
  3936.          AL = 1 if virtual interrupts were previously enabled. 
  3937.  
  3938.       Notes: 
  3939.  
  3940.         1. AH will not be changed by this procedure.  Therefore, to restore the 
  3941.            previous state, simply execute an Int 31h. 
  3942.  
  3943.  Function 0902H 
  3944.       This function gets the Virtual Interrupt State.  This function will 
  3945.       return the current state of the virtual interrupt flag.  Pass the 
  3946.       following information: 
  3947.  
  3948.       AX = 0902H 
  3949.  
  3950.       After the call, the carry flag is clear (this function always succeeds). 
  3951.  
  3952.          AL = 0 if virtual interrupts are disabled. 
  3953.          AL = 1 if virtual interrupts are enabled. 
  3954.  
  3955.  
  3956. ΓòÉΓòÉΓòÉ 11.2.11. DOS/4GW:  Vendor Specific Extensions ΓòÉΓòÉΓòÉ
  3957.  
  3958.  
  3959. Some DOS extenders provide extensions to the standard set of DPMI calls.  This 
  3960. call is used to obtain an address which must be called to use the extensions. 
  3961. The caller points DS:ESI to a null terminated string that specifies the vendor 
  3962. name or some other unique identifier to obtain the specific extension entry 
  3963. point. 
  3964.  
  3965.  Function 0A00H 
  3966.       This function gets Tenberry Software's API Entry Point.  Pass the 
  3967.       following information: 
  3968.  
  3969.       AX = 0A00H 
  3970.  
  3971.       DS:ESI = Pointer to null terminated string "RATIONAL DOS/4G" 
  3972.  
  3973.       If the call succeeds, the carry flag is clear and ES:EDI = Extended API 
  3974.       entry point.  DS, FS, GS, EAX, EBX, ECX, EDX, ESI, and EBP may be 
  3975.       modified. 
  3976.  
  3977.       If the call fails, the carry flag is set. 
  3978.  
  3979.       Notes: 
  3980.  
  3981.         1. Execute a far call to call the API entry point. 
  3982.  
  3983.         2. All extended API parameters are specified by the vendor. 
  3984.  
  3985.         3. The string comparison used to return the API entry point is case 
  3986.            sensitive. 
  3987.  
  3988.  
  3989. ΓòÉΓòÉΓòÉ 11.2.12. DOS/4GW:  Coprocessor Status ΓòÉΓòÉΓòÉ
  3990.  
  3991.  Function 0E00H 
  3992.       This function gets the coprocessor status.  Pass the following 
  3993.       information: 
  3994.  
  3995.       AX = 0E00H 
  3996.  
  3997.       If the call succeeds, the carry flag is clear and AX contains the 
  3998.       coprocessor status. 
  3999.  
  4000.       0 
  4001.                 MPv (MP bit in the virtual MSW/CR0). 
  4002.  
  4003.                 0 = Numeric coprocessor is disabled for this client. 
  4004.                 1 = Numeric coprocessor is disabled for this client. 
  4005.  
  4006.       1 
  4007.                 EMv (EM bit in the virtual MSW/CR0). 
  4008.  
  4009.                 0 = Client is not emulating coprocessor instructions. 
  4010.                 1 = Client is emulating coprocessor instructions. 
  4011.  
  4012.       2 
  4013.                 MPr (MP bit from the actual MSW/CR0). 
  4014.  
  4015.                 0 = Numeric coprocessor is not present. 
  4016.                 1 = Numeric coprocessor is present. 
  4017.  
  4018.       1 
  4019.                 EMr (EM bit from the actual MSW/CR0). 
  4020.  
  4021.                 0 = Host is not emulating coprocessor instructions. 
  4022.                 1 = Host is emulating coprocessor instructions. 
  4023.  
  4024.       4-7 
  4025.                 Coprocessor type. 
  4026.  
  4027.                    00H = no coprocessor. 
  4028.                    02H = 80287 
  4029.                    03H = 80387 
  4030.                    04H = 80486 with numeric coprocessor 
  4031.                    05H = Pentium 
  4032.  
  4033.       8-15 
  4034.                 Not applicable. 
  4035.       If the call fails, the carry flag is set. 
  4036.  
  4037.       Notes: 
  4038.  
  4039.         1. If the real EM (EMr) bit is set, the host is supplying or is capable 
  4040.            of supplying floating-point emulation. 
  4041.  
  4042.         2. If the MPv bit is not set, the host may not need to save the 
  4043.            coprocessor state for this virtual machine to improve system 
  4044.            performance. 
  4045.  
  4046.         3. The MPr bit setting should be consistent with the setting of the 
  4047.            coprocessor type information.  Ignore MPr bit information if it is 
  4048.            in conflict with the coprocessor type information. 
  4049.  
  4050.         4. If the virtual EM (EMv) bit is set, the host delivers all 
  4051.            coprocessor exceptions to the client, and the client is performing 
  4052.            its own floating-point emulation (wether or not a coprocessor is 
  4053.            present or the host also has a floating-point emulator).  In other 
  4054.            words, if the EMv bit is set, the host sets the EM bit in the real 
  4055.            CR0 while the virtual machine is active, and reflects coprocessor 
  4056.            not present faults (int 7) to the virtual machine. 
  4057.  
  4058.         5. A client can determine the CPU type with int 31H Function 0400H, but 
  4059.            a client should not draw any conclusions about the presence or 
  4060.            absence of a coprocessor based on the CPU type alone. 
  4061.  
  4062.  Function 0E01H 
  4063.       This function sets coprocessor emulation.  Pass the following 
  4064.       information: 
  4065.  
  4066.       AX = 0E01H 
  4067.  
  4068.       BX = coprocessor bits 
  4069.  
  4070.                 0 
  4071.                           New value of MPv bit for client's virtual CR0. 
  4072.  
  4073.                           0 = Disable numeric coprocessor for this client. 
  4074.                           1 = Enable numeric coprocessor for this client. 
  4075.  
  4076.                 1 
  4077.                           New value of EMv bit for client's virtual CR0. 
  4078.  
  4079.                           0 = client will not supply coprocessor emulation. 
  4080.                           1 = client will supply coprocessor emulation. 
  4081.  
  4082.                 2-15 
  4083.                           Not applicable. 
  4084.       If the call succeeds, the carry flag is clear; if it fails, the carry 
  4085.       flag is set. 
  4086.  
  4087.  
  4088. ΓòÉΓòÉΓòÉ 12. DOS/4GW:  Utilities ΓòÉΓòÉΓòÉ
  4089.  
  4090.  
  4091. This chapter describes the Tenberry Software DOS/4GW utility programs provided 
  4092. with the Watcom C/C++ package.  Each program is described using the following 
  4093. format: 
  4094.  
  4095.  Purpose: 
  4096.       This is a brief statement of what the utility program does.  More 
  4097.       specific information is provided under "Notes". 
  4098.  
  4099.  Syntax: 
  4100.       This shows the syntax of the program.  The fixed portion of each command 
  4101.       is in a typewriter font, while variable parts of the command are in 
  4102.       italics.  Optional parts are enclosed in [brackets]. 
  4103.  
  4104.  Notes: 
  4105.       These are explanatory remarks noting major features and possible 
  4106.       pitfalls.  We explain anything special that you might need to know about 
  4107.       the program. 
  4108.  
  4109.  See Also: 
  4110.       This is a cross-reference to any information that is related to the 
  4111.       program. 
  4112.  
  4113.  Example: 
  4114.       You'll find one or more sample uses of the utility program with an 
  4115.       explanation of what the program is doing. 
  4116.  
  4117.  Some of the utilities are DOS/4GW-based, protected-mode programs.  To 
  4118.  determine which programs run in protected mode and which in real, run the 
  4119.  program.  If you see the DOS/4GW banner, the program runs in protected mode. 
  4120.  
  4121.  
  4122. ΓòÉΓòÉΓòÉ 12.1. DOS/4GW:  DOS4GW ΓòÉΓòÉΓòÉ
  4123.  
  4124.  Purpose: 
  4125.       Loads and executes linear executables. 
  4126.  
  4127.  Syntax: 
  4128.        linear_executable 
  4129.  
  4130.  Notes: 
  4131.       The stub program at the beginning of the linear executable invokes this 
  4132.       program, which loads the linear executable and starts up the DOS 
  4133.       extender.  The stub program must be able to find DOS4GW:  make sure it is 
  4134.       in the path. 
  4135.  
  4136.  
  4137. ΓòÉΓòÉΓòÉ 12.2. DOS/4GW:  PMINFO ΓòÉΓòÉΓòÉ
  4138.  
  4139.  Purpose: 
  4140.       Measures the performance of protected/real-mode switching and extended 
  4141.       memory. 
  4142.  
  4143.  Syntax: 
  4144.        PMINFO.EXE 
  4145.  
  4146.  Notes: 
  4147.       We encourage you to distribute this program to your users. 
  4148.  
  4149.       The time-based measurements made by PMINFO may vary slightly from run to 
  4150.       run. 
  4151.  
  4152.  Example: 
  4153.       The following example shows the output of the PMINFO program on a 386 
  4154.       AT-compatible machine. 
  4155.  
  4156.             ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  4157.  
  4158.         C>pminfo 
  4159.           Protected Mode and Extended Memory Performance Measurement -- 5.00 
  4160.               Copyright (c) Tenberry Software, Inc. 1987 - 1993 
  4161.  
  4162.         DOS memory  Extended memory  CPU performance equivalent to 67.0 MHz 
  4163.       80486 
  4164.         ----------  --------------- 
  4165.            736        8012  K bytes configured (according to BIOS). 
  4166.            640       15360  K bytes physically present (SETUP). 
  4167.            651        7887  K bytes available for DOS/16M programs. 
  4168.         22.0 (3.0)     18.9 (4.0)  MB/sec word transfer rate (wait states). 
  4169.         42.9 (3.0)     37.0 (4.0)  MB/sec 32-bit transfer rate (wait states). 
  4170.  
  4171.         Overall cpu and memory performance (non-floating point) for typical 
  4172.         DOS programs is 10.36 ╤æ 1.04 times an 8MHz IBM PC/AT. 
  4173.  
  4174.         Protected/Real switch rate = 36156/sec (27 usec/switch, 15 up + 11 
  4175.       down), 
  4176.         DOS/16M switch mode 11 (VCPI). 
  4177.  
  4178.             ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  4179.  
  4180.       The top information line shows that the CPU performance is equivalent to 
  4181.       a 67.0 MHz 80486.  Below are the configuration and timings for both the 
  4182.       DOS memory and extended memory.  If the computer is not equipped with 
  4183.       extended memory, or none is available for DOS/4GW, the extended memory 
  4184.       measurements may be omitted ("--"). 
  4185.  
  4186.       The line "according to BIOS" shows the information provided by the BIOS 
  4187.       (interrupts 12h and 15h function 88h).  The line "SETUP", if displayed, 
  4188.       is the configuration obtained directly from the CMOS RAM as set by the 
  4189.       computer's setup program.  It is displayed only if the numbers are 
  4190.       different from those in the BIOS line.  They will be different for 
  4191.       computers where the BIOS has reserved memory for itself or if another 
  4192.       program has allocated some memory and is intercepting the BIOS 
  4193.       configuration requests to report less memory available than is physically 
  4194.       configured.  The "DOS/16M memory range", if displayed, shows the low and 
  4195.       high addresses available to DOS/4GW in extended memory. 
  4196.  
  4197.       Below the configuration information is information on the memory speed 
  4198.       (transfer rate).  PMINFO tries to determine the memory architecture. 
  4199.       Some architectures will perform well under some circumstances and poorly 
  4200.       under others; PMINFO will show both the best and worst cases.  The 
  4201.       architectures detected are cache, interleaved, page-mode (or static 
  4202.       column), and direct.  Measurements are made using 32-bit accesses and 
  4203.       reported as the number of megabytes per second that can be transferred. 
  4204.       The number of wait states is reported in parentheses.  The wait states 
  4205.       can be a fractional number, like 0.5, if there is a wait state on writes 
  4206.       but not on reads.  Memory bandwidth (i.e., how fast the CPU can access 
  4207.       memory) accounts for 60% to 70% of the performance for typical programs 
  4208.       (that are not heavily dependent on floating-point math). 
  4209.  
  4210.       A performance metric developed by Tenberry Software is displayed, showing 
  4211.       the expected throughput for the computer relative to a standard 8MHz IBM 
  4212.       PC/AT (disk accesses and floating point are excluded).  Finally, the 
  4213.       speed with which the computer can switch between real and protected mode 
  4214.       is displayed, both as the maximum number of round-trip switches that can 
  4215.       occur per second, and the time for a single round-trip switch, broken out 
  4216.       into the real-to-protected (up) and protected-to-real (down) components. 
  4217.  
  4218.  
  4219. ΓòÉΓòÉΓòÉ 12.3. DOS/4GW:  PRIVATXM ΓòÉΓòÉΓòÉ
  4220.  
  4221.  Purpose: 
  4222.       Creates a private pool of memory for DOS/4GW programs. 
  4223.  
  4224.  Syntax: 
  4225.        PRIVATXM [-r] 
  4226.  
  4227.  Notes: 
  4228.       This program may be distributed to your users. 
  4229.  
  4230.       Without PRIVATXM, a DOS/4GW program that starts up while another DOS/4GW 
  4231.       program is active uses the pool of memory built by the first program. 
  4232.       The new program cannot change the parameters of this memory pool, so 
  4233.       setting DOS16M to increase the size of the pool has no effect.  To 
  4234.       specify that the two programs use different pools of memory, use 
  4235.       PRIVATXM. 
  4236.  
  4237.       PRIVATXM marks the active DOS/4GW programs as private, preventing 
  4238.       subsequent DOS/4GW programs from using the same memory pool.  The first 
  4239.       DOS/4GW program to start after PRIVATXM sets up a new pool of memory for 
  4240.       itself and any subsequent DOS/4GW programs.  To release the memory used 
  4241.       by the private programs, use the PRIVATXM -r option. 
  4242.  
  4243.       PRIVATXM is a TSR that requires less than 500 bytes of memory.  It is not 
  4244.       supported under DPMI. 
  4245.  
  4246.  Example: 
  4247.       The following example creates a 512KB memory pool that is shared by two 
  4248.       DOS/4GW TSRs.  Subsequent DOS/4GW programs use a different memory pool. 
  4249.  
  4250.       C>set DOS16M= :512 
  4251.                 Specifies the size of the memory pool. 
  4252.  
  4253.       C>TSR1 
  4254.                 Sets up the memory pool at startup. 
  4255.  
  4256.       C>TSR2 
  4257.                 This TSR shares the pool built by TSR1. 
  4258.  
  4259.       C>PRIVATXM 
  4260.                 Makes subsequent DOS/4GW programs use a new memory pool. 
  4261.  
  4262.       C>set DOS16M= 
  4263.                 Specifies an unlimited size for the new pool. 
  4264.  
  4265.       C>PROGRAM3 
  4266.                 This program uses the new memory pool. 
  4267.  
  4268.       C>PRIVATXM -R 
  4269.                 Releases the 512KB memory pool used by the TSRs.  (If the TSRs 
  4270.                 shut down, their memory is not released unless PRIVATXM is 
  4271.                 released.) 
  4272.  
  4273.  
  4274. ΓòÉΓòÉΓòÉ 12.4. DOS/4GW:  RMINFO ΓòÉΓòÉΓòÉ
  4275.  
  4276.  Purpose: 
  4277.       Supplies configuration information and the basis for real/protected-mode 
  4278.       switching in your machine. 
  4279.  
  4280.  Syntax: 
  4281.        RMINFO.EXE 
  4282.  
  4283.  Notes: 
  4284.       This program may be distributed to your users. 
  4285.  
  4286.       RMINFO starts up DOS/4GW, but stops your machine just short of switching 
  4287.       from real mode to protected mode and displays configuration information 
  4288.       about your computer.  The information shown by RMINFO can help determine 
  4289.       why DOS/4GW applications won't run on a particular machine.  Run RMINFO 
  4290.       if PMINFO does not run to completion. 
  4291.  
  4292.  Example: 
  4293.       The following example shows the output of the RMINFO program on an 386 
  4294.       AT-compatible machine. 
  4295.  
  4296.             ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  4297.  
  4298.         C>rminfo 
  4299.  
  4300.         DOS/16M Real Mode Information Program 5.00 
  4301.         Copyright (C) Tenberry Software, Inc. 1987 - 1993 
  4302.  
  4303.         Machine and Environment: 
  4304.             Processor:        i386, coprocessor present 
  4305.             Machine type:      10 (AT-compatible) 
  4306.             A20 now:         enabled 
  4307.             A20 switch rigor:    disabled 
  4308.             DPMI host found 
  4309.         Switching Functions: 
  4310.             To PM switch:      DPMI 
  4311.             To RM switch:      DPMI 
  4312.             Nominal switch mode:   0 
  4313.             Switch control flags:  0000 
  4314.         Memory Interfaces: 
  4315.             DPMI may provide:    16384K returnable 
  4316.             Contiguous DOS memory:  463K 
  4317.  
  4318.             ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  4319.  
  4320.       The information provided by RMINFO includes: 
  4321.  
  4322.       Machine and Environment: 
  4323.  
  4324.       Processor: 
  4325.                 processor type, coprocessor present/not present 
  4326.  
  4327.       Machine type: 
  4328.  
  4329.  
  4330.                    (NEC 9801) 
  4331.                    (PS/2-compatible) 
  4332.                    (AT-compatible) 
  4333.                    (FM R) 
  4334.                    (AT&T 6300+) 
  4335.                    (AT-compatible) 
  4336.                    (C&T 230 chipset) 
  4337.                    (AT-compatible) 
  4338.                    (AT-compatible) 
  4339.                    (Acer) 
  4340.                    (Zenith) 
  4341.                    (Hitachi) 
  4342.                    (Okidata) 
  4343.                    (PS/55) 
  4344.  
  4345.       A20 now: 
  4346.                 Current state of Address line 20. 
  4347.  
  4348.       A20 switch rigor: 
  4349.                 Whether DOS4GW rigorously controls enabling and disabling of 
  4350.                 Address line 20 when switching modes. 
  4351.  
  4352.       PS feature flag 
  4353.  
  4354.       XMS host found 
  4355.                 Whether your system has any software using extended memory 
  4356.                 under the XMS discipline. 
  4357.  
  4358.       VCPI host found 
  4359.                 Whether your system has any software using extended memory 
  4360.                 under the VCPI discipline. 
  4361.  
  4362.       page table 0 at:  x000h 
  4363.  
  4364.       DPMI host found 
  4365.  
  4366.       DOS/16M resident with private/public memory 
  4367.  
  4368.       Switching Functions: 
  4369.  
  4370.       A20 switching: 
  4371.  
  4372.       To PM switch: 
  4373.                 reset catch: 
  4374.  
  4375.                 pre-PM prep: 
  4376.                 post-PM-switch: 
  4377.  
  4378.       To RM switch: 
  4379.  
  4380.  
  4381.                 pre-RM prep: 
  4382.                 reset method: 
  4383.                 post-reset: 
  4384.                 reset uncatch: 
  4385.  
  4386.       Nominal switch mode:  x 
  4387.  
  4388.       Switch control flags:  xxxxh 
  4389.  
  4390.       Memory Interfaces: 
  4391.  
  4392.       (VCPI remapping in effect) 
  4393.  
  4394.       DPMI may provide:  xxxxxK returnable 
  4395.  
  4396.       VCPI may provide:  xxxxxK returnable 
  4397.  
  4398.       Top-down 
  4399.  
  4400.       Other16M 
  4401.  
  4402.       Forced 
  4403.  
  4404.       Contiguous DOS memory: 
  4405.  
  4406.  
  4407. ΓòÉΓòÉΓòÉ 13. DOS/4GW:  Error Messages ΓòÉΓòÉΓòÉ
  4408.  
  4409.  
  4410. The following lists DOS/4G error messages, with descriptions of the 
  4411. circumstances in which the error is most likely to occur, and suggestions for 
  4412. remedying the problem.  Some error messages pertaining to features - like DLLs 
  4413. - that are not supported in DOS/4GW will not arise with that product.  In the 
  4414. following descriptions, references to DOS/4G, DOS4G, or DOS4G.EXE may be 
  4415. replaced by DOS/4GW, DOS4GW, or DOS4GW.EXE should the error message arise when 
  4416. using DOS/4GW. 
  4417.  
  4418.  
  4419. ΓòÉΓòÉΓòÉ 13.1. DOS/4GW:  Kernel Error Messages ΓòÉΓòÉΓòÉ
  4420.  
  4421.  
  4422. This section describes error messages from the DOS/16M kernel embedded in 
  4423. DOS/4G.  Kernel error messages may occur because of severe resource shortages, 
  4424. corruption of DOS4GW.EXE, corruption of memory, operating system 
  4425. incompatibilities, or internal errors in DOS/4GW.  All of these messages are 
  4426. quite rare. 
  4427.  
  4428.  0.  involuntary switch to real mode 
  4429.  
  4430.  
  4431.       The computer was in protected mode but switched to real mode without 
  4432.       going through DOS/16M.  This error most often occurs because of an 
  4433.       unrecoverable stack segment exception (stack overflow), but can also 
  4434.       occur if the Global Descriptor Table or Interrupt Descriptor Table is 
  4435.       corrupted.  Increase the stack size, recompile your program with stack 
  4436.       overflow checking, or look into ways that the descriptor tables may have 
  4437.       been overwritten. 
  4438.  
  4439.  1.  not enough extended memory 
  4440.  
  4441.  2.  not a DOS/16M executable <filename> 
  4442.  
  4443.  
  4444.       DOS4G.EXE, or a bound DOS/4G application, has probably been corrupted in 
  4445.       some way.  Rebuild or recopy the file. 
  4446.  
  4447.  3.  no DOS memory for transparent segment 
  4448.  
  4449.  4.  cannot make transparent segment 
  4450.  
  4451.  5.  too many transparent segments 
  4452.  
  4453.  6.  not enough memory to load program 
  4454.  
  4455.  
  4456.       There is not enough memory to load DOS/4G.  Make more memory available 
  4457.       and try again. 
  4458.  
  4459.  7.  no relocation segment 
  4460.  
  4461.  8.  cannot open file <filename> 
  4462.  
  4463.  
  4464.       The DOS/16M loader cannot load DOS/4G, probably because DOS has run out 
  4465.       of file units.  Set a larger FILES= entry in CONFIG.SYS, reboot, and try 
  4466.       again. 
  4467.  
  4468.  9.  cannot allocate tstack 
  4469.  
  4470.  
  4471.       There is not enough memory to load DOS/4G.  Make more memory available 
  4472.       and try again. 
  4473.  
  4474.  10.  cannot allocate memory for GDT 
  4475.  
  4476.  
  4477.       There is not enough memory to load DOS/4G.  Make more memory available 
  4478.       and try again. 
  4479.  
  4480.  11.  no passup stack selectors -- GDT too small 
  4481.  
  4482.  
  4483.       This error indicates an internal error in DOS/4G or an incompatibility 
  4484.       with other software. 
  4485.  
  4486.  12.  no control program selectors -- GDT too small 
  4487.  
  4488.  
  4489.       This error indicates an internal error in DOS/4G or an incompatibility 
  4490.       with other software. 
  4491.  
  4492.  13.  cannot allocate transfer buffer 
  4493.  
  4494.  
  4495.       There is not enough memory to load DOS/4G.  Make more memory available 
  4496.       and try again. 
  4497.  
  4498.  14.  premature EOF 
  4499.  
  4500.  
  4501.       DOS4G.EXE, or a bound DOS/4G application, has probably been corrupted in 
  4502.       some way.  Rebuild or recopy the file. 
  4503.  
  4504.  15.  protected mode available only with 386 or 486 
  4505.  
  4506.  
  4507.       DOS/4G requires an 80386 (or later) CPU.  It cannot run on an 80286 or 
  4508.       earlier CPU. 
  4509.  
  4510.  16.  cannot run under OS/2 
  4511.  
  4512.  17.  system software does not follow VCPI or DPMI specifications 
  4513.  
  4514.  
  4515.       Some memory resident program has put your 386 or 486 CPU into Virtual 
  4516.       8086 mode.  This is done to provide special memory services to DOS 
  4517.       programs, such as EMS simulation (EMS interface without EMS hardware) or 
  4518.       high memory.  In this mode, it is not possible to switch into protected 
  4519.       mode unless the resident software follows a standard that DOS/16M 
  4520.       supports (DPMI, VCPI, and XMS are the most common).  Contact the vendor 
  4521.       of your memory management software. 
  4522.  
  4523.  18.  you must specify an extended memory range (SET DOS16M= ) 
  4524.  
  4525.  
  4526.       On some Japanese machines that are not IBM AT-compatible, and have no 
  4527.       protocol for managing extended memory, you must set the DOS16M 
  4528.       environment variable to specify the range of available extended memory. 
  4529.  
  4530.  19.  computer must be AT- or PS/2- compatible 
  4531.  
  4532.  20.  unsupported DOS16M switchmode choice 
  4533.  
  4534.  21.  requires DOS 3.0 or later 
  4535.  
  4536.  22.  cannot free memory 
  4537.  
  4538.  
  4539.       This error probably indicates that memory was corrupted during execution 
  4540.       of your program. 
  4541.  
  4542.  23.  no memory for VCPI page table 
  4543.  
  4544.  
  4545.       There is not enough memory to load DOS/4G.  Make more memory available 
  4546.       and try again. 
  4547.  
  4548.  24.  VCPI page table address incorrect 
  4549.  
  4550.  
  4551.       This is an internal error. 
  4552.  
  4553.  25.  cannot initialize VCPI 
  4554.  
  4555.  
  4556.       This error indicates an incompatibility with other software.  DOS/16M has 
  4557.       detected that VCPI is present, but VCPI returns an error when DOS/16M 
  4558.       tries to initialize the interface. 
  4559.  
  4560.  26.  8042 timeout 
  4561.  
  4562.  27.  extended memory is configured but it cannot be allocated 
  4563.  
  4564.  28.  memory error, avail loop 
  4565.  
  4566.  
  4567.       This error probably indicates that memory was corrupted during execution 
  4568.       of your program.  Using an invalid or stale alias selector may cause this 
  4569.       error.  Incorrect manipulation of segment descriptors may also cause it. 
  4570.  
  4571.  29.  memory error, out of range 
  4572.  
  4573.  
  4574.       This error probably indicates that memory was corrupted during execution 
  4575.       of your program.  Writing through an invalid or stale alias selector may 
  4576.       cause this error. 
  4577.  
  4578.  30.  program must be built -AUTO for DPMI 
  4579.  
  4580.  31.  protected mode already in use in this DPMI virtual machine 
  4581.  
  4582.  32.  DPMI host error (possibly insufficient memory) 
  4583.  
  4584.  33.  DPMI host error (need 64K XMS) 
  4585.  
  4586.  34.  DPMI host error (cannot lock stack) 
  4587.  
  4588.  
  4589.       Any of these errors (32, 33, 34) probably indicate insufficient memory 
  4590.       under DPMI.  Under Windows, you might try making more physical memory 
  4591.       available by eliminating or reducing any RAM drives or disk caches.  You 
  4592.       might also try editing DEFAULT.PIF so that at least 64KB of XMS memory is 
  4593.       available to non-Windows programs.  Under OS/2, you want to increase the 
  4594.       DPMI_MEMORY_LIMIT in the DOS box settings. 
  4595.  
  4596.  35.  General Protection Fault 
  4597.  
  4598.  
  4599.       This message probably indicates an internal error in DOS/4G.  Faults 
  4600.       generated by your program should cause error 2001 instead. 
  4601.  
  4602.  36.  The DOS16M.386 virtual device driver was never loaded 
  4603.  
  4604.  37.  Unable to reserve selectors for DOS16M.386 Windows driver 
  4605.  
  4606.  38.  Cannot use extended memory:  HIMEM.SYS not version 2 
  4607.  
  4608.  
  4609.       This error indicates an incompatibility with an old version of HIMEM.SYS. 
  4610.  
  4611.  39.  An obsolete version of DOS16M.386 was loaded 
  4612.  
  4613.  40.  not enough available extended memory (XMIN) 
  4614.  
  4615.  
  4616.       This message probably indicates an incompatibility with your memory 
  4617.       manager or its configuration.  Try configuring the memory manager to 
  4618.       provide more extended memory, or change memory managers. 
  4619.  
  4620.  
  4621. ΓòÉΓòÉΓòÉ 13.2. DOS/4GW:  DOS/4G Errors ΓòÉΓòÉΓòÉ
  4622.  
  4623.  1000 "can't hook interrupts" 
  4624.  
  4625.  
  4626.       A DPMI host has prevented DOS/4G from loading.  Please contact Tenberry 
  4627.       Technical Support. 
  4628.  
  4629.  1001 "error in interrupt chain" 
  4630.  
  4631.  
  4632.       DOS/4G internal error.  Please contact Tenberry Technical Support. 
  4633.  
  4634.  1003 "can't lock extender kernel in memory" 
  4635.  
  4636.  
  4637.       DOS/4G couldn't lock the kernel in physical memory, probably because of a 
  4638.       memory shortage. 
  4639.  
  4640.  1004 "syntax is DOS4G <executable.xxx>" 
  4641.  
  4642.  
  4643.       You must specify a program name. 
  4644.  
  4645.  1005 "not enough memory for dispatcher data" 
  4646.  
  4647.  
  4648.       There is not enough memory for DOS/4G to manage user-installed interrupt 
  4649.       handlers properly.  Free some memory for the DOS/4G application. 
  4650.  
  4651.  1007 "can't find file <program> to load" 
  4652.  
  4653.  
  4654.       DOS/4G could not open the specified program.  Probably the file didn't 
  4655.       exist.  It is possible that DOS ran out of file handles, or that a 
  4656.       network or similar utility has prohibited read access to the program. 
  4657.       Make sure that the file name was spelled correctly. 
  4658.  
  4659.  1008 "can't load executable format for file <filename> [<error code>]" 
  4660.  
  4661.  
  4662.       DOS/4G did not recognize the specified file as a valid executable file. 
  4663.       DOS/4G can load linear executables (LE and LX) and EXPs (BW).  The error 
  4664.       code is for Tenberry Software's use. 
  4665.  
  4666.  1009 "program <filename> is not bound" 
  4667.  
  4668.  
  4669.       This message does not occur in DOS/4G, only DOS/4GW Professional; the 
  4670.       latter requires that the DOS extender be bound to the program file.  The 
  4671.       error signals an attempt to load 
  4672.  
  4673.  1010 "can't initialize loader <loader> [<error code>]" 
  4674.  
  4675.  
  4676.       DOS/4G could not initialize the named loader, probably because of a 
  4677.       resource shortage.  Try making more memory available.  If that doesn't 
  4678.       work, please contact Tenberry Technical Support.  The error code is for 
  4679.       Tenberry Software' use. 
  4680.  
  4681.  1011 "VMM initialization error [<error code>]" 
  4682.  
  4683.  
  4684.       DOS/4G could not initialize the Virtual Memory Manager, probably because 
  4685.       of a resource shortage.  Try making more memory available.  If that 
  4686.       doesn't work, please contact Tenberry Technical Support.  The error code 
  4687.       is for Tenberry Software' use. 
  4688.  
  4689.  1012 "<filename> is not a WATCOM program" 
  4690.  
  4691.  
  4692.       This message does not occur in DOS/4G, only DOS/4GW and DOS/4GW 
  4693.       Professional.  Those extenders only support WATCOM 32-bit compilers. 
  4694.  
  4695.  1013 "int 31h initialization error" 
  4696.  
  4697.  
  4698.       DOS/4G was unable to initialize the code that handles Interrupt 31h, 
  4699.       probably because of an internal error. Please call Tenberry Technical 
  4700.       Support. 
  4701.  
  4702.  1100 "assertion \"<statement>\" failed (<file>:<line>)" 
  4703.  
  4704.  
  4705.       DOS/4G internal error.  Please contact Tenberry Technical Support. 
  4706.  
  4707.  1200 "invalid EXP executable format" 
  4708.  
  4709.  
  4710.       DOS/4G tried to load an EXP, but couldn't.  The executable file is 
  4711.       probably corrupted. 
  4712.  
  4713.  1201 "program must be built -AUTO for DPMI" 
  4714.  
  4715.  
  4716.       Under DPMI, DOS/4G can only load EXPs that have been linked with the GLU 
  4717.       -AUTO or -DPMI switch. 
  4718.  
  4719.  1202 "can't allocate memory for GDT" 
  4720.  
  4721.  
  4722.       There is not enough memory available for DOS/4G to build a Global 
  4723.       Descriptor Table.  Make more memory available. 
  4724.  
  4725.  1203 "premature EOF" 
  4726.  
  4727.  
  4728.       DOS/4G tried to load an EXP but couldn't.  The file is probably 
  4729.       corrupted. 
  4730.  
  4731.  1204 "not enough memory to load program" 
  4732.  
  4733.  
  4734.       There is not enough memory available for DOS/4G to load your program. 
  4735.       Make more memory available. 
  4736.  
  4737.  1301 "invalid linear executable format" 
  4738.  
  4739.  
  4740.       DOS/4G cannot recognize the program file as a LINEXE format.  Make sure 
  4741.       that you specified the correct file name. 
  4742.  
  4743.  1304 "file I/O seek error" 
  4744.  
  4745.  
  4746.       DOS/4G was unable to seek to a file location that should exist.  This 
  4747.       usually indicates truncated program files or problems with the storage 
  4748.       device from which your program loads.  Run CHKDSK or a similar utility to 
  4749.       begin determining possible causes. 
  4750.  
  4751.  1305 "file I/O read error" 
  4752.  
  4753.  
  4754.       DOS/4G was unable to read a file location that should contain program 
  4755.       data.  This usually indicates truncated program files or problems with 
  4756.       the storage device from which your program loads.  Run CHKDSK or a 
  4757.       similar utility to begin determining possible causes. 
  4758.  
  4759.  1307 "not enough memory" 
  4760.  
  4761.  
  4762.       As it attempted to load your program, DOS/4G ran out of memory.  Make 
  4763.       more memory available, or enable VMM. 
  4764.  
  4765.  1308 "can't load requested program" 
  4766.  
  4767.  1309 "can't load requested program" 
  4768.  
  4769.  1311 "can't load requested program" 
  4770.  
  4771.  1312 "can't load requested program" 
  4772.  
  4773.  
  4774.       DOS/4G cannot load your program for some reason.  Contact Tenberry 
  4775.       Technical Support. 
  4776.  
  4777.  1313 "can't resolve external references" 
  4778.  
  4779.  
  4780.       DOS/4G was unable to resolve all references to DLLs for the requested 
  4781.       program, or the program contained unsupported fixup types.  Use EXEHDR or 
  4782.       a similar LINEXE dump utility to see what references your program makes 
  4783.       and what special fixup records might be present. 
  4784.  
  4785.  1314 "not enough lockable memory" 
  4786.  
  4787.  
  4788.       As it attempted to load your program, DOS/4G encountered a refusal to 
  4789.       lock a virtual memory region.  Some memory must be locked in order to 
  4790.       handle demand-load page faults.  Make more physical memory available. 
  4791.  
  4792.  1315 "can't load requested program" 
  4793.  
  4794.  1316 "can't load requested program" 
  4795.  
  4796.  
  4797.       DOS/4G cannot load your program for some reason.  Contact Tenberry 
  4798.       Technical Support. 
  4799.  
  4800.  1317 "program has no stack" 
  4801.  
  4802.  
  4803.       DOS/4G reports this error when you try to run a program with no stack. 
  4804.       Rebuild your program, building in a stack. 
  4805.  
  4806.  2000 "deinitializing twice" 
  4807.  
  4808.  
  4809.       DOS/4G internal error.  Please contact Tenberry Technical Support. 
  4810.  
  4811.  2001 "exception <exception_number> (<exception_description>) at 
  4812.       <selector:offset>" 
  4813.  
  4814.       Your program has generated an exception.  For information about 
  4815.       interpreting this message, see the file COMMON.DOC. 
  4816.  
  4817.  2002 "transfer stack overflow at <selector:offset>" 
  4818.  
  4819.  
  4820.       Your program has overflowed the DOS/4G transfer stack.  For information 
  4821.       about interpreting this message, see the file COMMON.DOC. 
  4822.  
  4823.  2300 " can't find <DLL>.<ordinal> - referenced from <module>" 
  4824.  
  4825.  
  4826.       DOS/4G could not find the ordinal listed in the specified DLL, or it 
  4827.       could not find the DLL at all.  Correct or remove the reference, and make 
  4828.       sure that DOS/4G can find the DLL. 
  4829.  
  4830.       DOS/4G looks for DLLs in the following directories: 
  4831.  
  4832.           The directory specified by the Libpath32 configuration option (which 
  4833.            defaults to the directory of the main application file). 
  4834.           The directory or directories specified by the LIBPATH32 environment 
  4835.            variable. 
  4836.           Directories specified in the PATH. 
  4837.  
  4838.  2301 "can't find <DLL>.<name> - referenced from <module>" 
  4839.  
  4840.  
  4841.       DOS/4G could not find the entry point named in the specified module. 
  4842.       Correct or remove the reference, and make sure that DOS/4G can find the 
  4843.       DLL. 
  4844.  
  4845.  2302 "DLL modules not supported" 
  4846.  
  4847.  
  4848.       This DOS/4GW Professional error message arises when an application 
  4849.       references or tries to explicitly load a DLL.  DOS/4GW Professional does 
  4850.       not support DLLs. 
  4851.  
  4852.  2303 "internal LINEXE object limit reached" 
  4853.  
  4854.  
  4855.       DOS/4G currently handles a maximum of 128 LINEXE objects, including all 
  4856.       .DLL and .EXE files.  Most .EXE or .DLL files use only three or four 
  4857.       objects.  If possible, reduce the number of objects, or contact Tenberry 
  4858.       Technical Support. 
  4859.  
  4860.  2500 "can't connect to extender kernel" 
  4861.  
  4862.  
  4863.       DOS/4G internal error.  Please contact Tenberry Technical Support. 
  4864.  
  4865.  2503 "not enough disk space for swapping - <count> byes required" 
  4866.  
  4867.  
  4868.       VMM was unable to create a swap file of the required size.  Increase the 
  4869.       amount of disk space available. 
  4870.  
  4871.  2504 "can't create swap file \<filename>\"" 
  4872.  
  4873.  
  4874.       VMM was unable to create the swap file.  This could be because the swap 
  4875.       file is specified for a nonexistent drive or on a drive that is 
  4876.       read-only.  Set the SWAPNAME parameter to change the location of the swap 
  4877.       file. 
  4878.  
  4879.  2505 "not enough memory for <table>" 
  4880.  
  4881.  
  4882.       VMM was unable to get sufficient extended memory for internal tables. 
  4883.       Make more memory available.  If <table> is page buffer, make more DOS 
  4884.       memory available. 
  4885.  
  4886.  2506 "not enough physical memory (minmem)" 
  4887.  
  4888.  
  4889.       There is less physical memory available than the amount specified by the 
  4890.       MINMEM parameter.  Make more memory available. 
  4891.  
  4892.  2511 "swap out error [<error code>]" 
  4893.  
  4894.  
  4895.       Unknown disk error.  The error code is for Tenberry Software' use. 
  4896.  
  4897.  2512 "swap in error [<error code>]" 
  4898.  
  4899.  
  4900.       Unknown disk error.  The error code is for Tenberry Software' use. 
  4901.  
  4902.  2514 "can't open trace file" 
  4903.  
  4904.  
  4905.       VMM could not open the VMM.TRC file in the current directory for writing. 
  4906.       If the directory already has a VMM.TRC file, delete it.  If not, there 
  4907.       may not be enough memory on the drive for the trace file, or DOS may not 
  4908.       have any more file handles. 
  4909.  
  4910.  2520 "can't hook int 31h" 
  4911.  
  4912.  
  4913.       DOS/4G internal error.  Please contact Tenberry Technical Support. 
  4914.  
  4915.  2523 "page fault on non-present mapped page" 
  4916.  
  4917.  
  4918.       Your program references memory that has been mapped to a nonexistent 
  4919.       physical device, using DPMI function 508h.  Make sure the device is 
  4920.       present, or remove the reference. 
  4921.  
  4922.  2524 "page fault on uncommitted page" 
  4923.  
  4924.  
  4925.       Your program references memory reserved with a call to DPMI function 
  4926.  
  4927.  504h, but never committed (using a DPMI 507h or 508h call).  Commit 
  4928.       the memory before you reference it. 
  4929.  
  4930.  3301 "unhandled EMPTYFWD, GATE16, or unknown relocation" 
  4931.  
  4932.  3302 "unhandled ALIAS16 reference to unaliased object" 
  4933.  
  4934.  3304 "unhandled or unknown relocation" 
  4935.  
  4936.  
  4937.       If your program was built for another platform that supports the LINEXE 
  4938.       format, it may contain a construct that DOS/4G does not currently 
  4939.       support, such as a call gate.  This message may also occur if your 
  4940.       program has a problem mixing 16- and 32-bit code.  A linker error is 
  4941.       another likely cause. 
  4942.  
  4943.  
  4944. ΓòÉΓòÉΓòÉ 14. DOS/4GW:  DOS/4GW Commonly Asked Questions ΓòÉΓòÉΓòÉ
  4945.  
  4946.  
  4947. The following information has been provided by Tenberry Software, Inc.  for 
  4948. their DOS/4GW and DOS/4GW Professional product.  The content of this chapter 
  4949. has been edited by Watcom.  In most cases, the information is applicable to 
  4950. both products. 
  4951.  
  4952. This chapter covers the following topics: 
  4953.  
  4954.      Access to technical support 
  4955.      Differences within the DOS/4G product line 
  4956.      Addressing 
  4957.      Interrupt and exception handling 
  4958.      Memory management 
  4959.      DOS, BIOS, and mouse services 
  4960.      Virtual memory 
  4961.      Debugging 
  4962.      Compatibility 
  4963.  
  4964.  
  4965. ΓòÉΓòÉΓòÉ 14.1. DOS/4GW:  Access to Technical Support ΓòÉΓòÉΓòÉ
  4966.  
  4967.  1a.  How to reach technical support. 
  4968.  
  4969.  
  4970.       Here are the various ways you may contact Tenberry Software for technical 
  4971.       support. 
  4972.  
  4973.  
  4974.          Voice:      (508)653-6006 
  4975.          Fax:       (508)655-2753 
  4976.          Internet:    dos4gw@ratsys.com 
  4977.          CompuServe:   73667,1753 
  4978.          WATCOM BBS:   DOS/4GW Professional area 
  4979.          Mail:      Tenberry Software, Inc. 
  4980.                  220 N. Main St. 
  4981.                  Natick, MA 01760 
  4982.                  USA 
  4983.  
  4984.       PLEASE GIVE YOUR SERIAL NUMBER WHEN YOU CONTACT TENBERRY. 
  4985.  
  4986.  1b.  When to contact Watcom, when to contact Tenberry. 
  4987.  
  4988.  
  4989.       Since DOS/4GW Professional is intended to be completely compatible with 
  4990.       DOS/4GW, you may wish to ascertain whether your program works properly 
  4991.       under DOS/4GW before contacting Tenberry Software for technical support. 
  4992.       (This is likely to be the second question we ask you, after your serial 
  4993.       number.) 
  4994.  
  4995.       If your program fails under both DOS/4GW and DOS/4GW Professional, and 
  4996.       you suspect your own code or a problem compiling or linking, you may wish 
  4997.       to contact Watcom first.  Tenberry Software support personnel are not 
  4998.       able to help you with most programming questions, or questions about 
  4999.       using the Watcom tools. 
  5000.  
  5001.       If your program only fails with DOS/4GW Professional, you have probably 
  5002.       found a bug in DOS/4GW Professional, so please contact us right away. 
  5003.  
  5004.  1c.  Telephone support. 
  5005.  
  5006.  
  5007.       Tenberry Software's hours for telephone support are 9am-6pm EST.  Please 
  5008.       note that telephone support is free for the first 30 days only.  A 
  5009.       one-year contract for continuing telephone support on DOS/4GW 
  5010.       Professional is US$500 per developer, including an update subscription 
  5011.       for one year, to customers in the United States and Canada; for overseas 
  5012.       customers, the price is $600.  Site licenses may be negotiated. 
  5013.  
  5014.       There is no time limit on free support by fax, mail, or electronic means. 
  5015.  
  5016.  1d.  References. 
  5017.  
  5018.  
  5019.       The DOS/4GW documentation from Watcom is the primary reference for 
  5020.       DOS/4GW Professional as well.  Another useful reference is the DPMI 
  5021.       specification.  In the past, the DPMI specification could be obtained 
  5022.       free of charge by contacting Intel Literature JP26 at 800-548-4725 or by 
  5023.       writing to the address below.  We have been advised that the DPMI 
  5024.       specification is no longer available in printed form. 
  5025.  
  5026.          Intel Literature JP26 
  5027.          3065 Bowers Avenue 
  5028.          P.O. Box 58065 
  5029.          Santa Clara, California 
  5030.          U.S.A. 95051-8065 
  5031.  
  5032.       However, the DPMI 1.0 specification can be obtained from the Intel ftp 
  5033.       site.  Here is the URL. 
  5034.  
  5035.  
  5036.          ftp://ftp.intel.com/pub/IAL/software_specs/dpmiv1.zip 
  5037.  
  5038.       This ZIP file contains a Postscript version of the DPMI 1.0 
  5039.       specification. 
  5040.  
  5041.  
  5042. ΓòÉΓòÉΓòÉ 14.2. DOS/4GW:  Differences Within the DOS/4G Product Line ΓòÉΓòÉΓòÉ
  5043.  
  5044.  2a.  DOS/4GW Professional versus DOS/4GW 
  5045.  
  5046.  
  5047.       DOS/4GW Professional was designed to be a higher-performance version of 
  5048.       DOS/4GW suitable for commercial applications.  Here is a summary of the 
  5049.       advantages of DOS/4GW Professional with respect to DOS/4GW: 
  5050.  
  5051.           Extender binds to the application program file 
  5052.           Extender startup time has been reduced 
  5053.           Support for Watcom floating-point emulator has been optimized 
  5054.           Virtual memory manager performance has been greatly improved 
  5055.           Under VMM, programs are demand loaded 
  5056.           Virtual address space is 4 GB instead of 32 MB 
  5057.           Extender memory requirements have been reduced by more than 50K 
  5058.           Extender disk space requirements have been reduced by 40K 
  5059.           Can omit virtual memory manager to save 50K more disk space 
  5060.           Support for INT 31h functions 301h-304h and 702h-703h 
  5061.       DOS/4GW Professional is intended to be fully compatible with programs 
  5062.       written for DOS/4GW 1.9 and up.  The only functional difference is that 
  5063.       the extender is bound to your program instead of residing in a separate 
  5064.       file.  Not only does this help reduce startup time, but it eliminates 
  5065.       version-control problems when someone has both DOS/4GW and DOS/4GW 
  5066.       Professional applications present on one machine. 
  5067.  
  5068.  2b.  DOS/4GW Professional versus DOS/4G. 
  5069.  
  5070.  
  5071.       DOS/4GW Professional is not intended to provide any other new DOS 
  5072.       extender functionality.  Tenberry Software's top-of-the-line 32-bit 
  5073.       extender, DOS/4G, is not sold on a retail basis but is of special 
  5074.       interest to developers who require more flexibility (such as OEMs). 
  5075.       DOS/4G offers these additional features beyond DOS/4GW and DOS/4GW 
  5076.       Professional: 
  5077.  
  5078.           Complete documentation 
  5079.           DLL support 
  5080.           TSR support 
  5081.           Support for INT 31h functions 301h-306h, 504h-50Ah, 702h-703h 
  5082.           A C language API that offers more control over interrupt handling 
  5083.            and program loading, as well as making it easier to use the extender 
  5084.           An optional (more protected) nonzero-based flat memory model 
  5085.           Remappable error messages 
  5086.           More configuration options 
  5087.           The D32 debugger, GLU linker, and other tools 
  5088.           Support for other compilers besides Watcom 
  5089.           A higher level of technical support 
  5090.           Custom work is available (e.g., support for additional executable 
  5091.            formats, operating system API emulations, mixed 16-bit and 32-bit 
  5092.            code) 
  5093.       Please contact Tenberry Software if you have questions about other 
  5094.       products (present or future) in the DOS/4G line. 
  5095.  
  5096.  2c.  DPMI functions supported by DOS/4GW. 
  5097.  
  5098.  
  5099.       Note that when a DOS/4GW application runs under a DPMI host, such as 
  5100.       Windows 3.1 in enhanced mode, an OS/2 virtual DOS machine, 386Max (with 
  5101.       DEBUG=DPMIXCOPY), or QDPMI (with EXTCHKOFF), the DPMI host provides the 
  5102.       DPMI services, not DOS/4GW.  The DPMI host also provides virtual memory, 
  5103.       if any.  Performance (speed and memory use) under different DPMI hosts 
  5104.       varies greatly due to the quality of the DPMI implementation. 
  5105.  
  5106.       These are the services provided by DOS/4GW and DOS/4GW Professional in 
  5107.       the absence of a DPMI host. 
  5108.  
  5109.       0000 
  5110.                 Allocate LDT Descriptors 
  5111.  
  5112.       0001 
  5113.                 Free LDT Descriptor 
  5114.  
  5115.       0002 
  5116.                 Map Real-Mode Segment to Descriptor 
  5117.  
  5118.       0003 
  5119.                 Get Selector Increment Value 
  5120.  
  5121.       0006 
  5122.                 Get Segment Base Address 
  5123.  
  5124.       0007 
  5125.                 Set Segment Base Address 
  5126.  
  5127.       0008 
  5128.                 Set Segment Limit 
  5129.  
  5130.       0009 
  5131.                 Set Descriptor Access Rights 
  5132.  
  5133.       000A 
  5134.                 Create Alias Descriptor 
  5135.  
  5136.       000B 
  5137.                 Get Descriptor 
  5138.  
  5139.       000C 
  5140.                 Set Descriptor 
  5141.  
  5142.       000D 
  5143.                 Allocate Specific LDT Descriptor 
  5144.  
  5145.       0100 
  5146.                 Allocate DOS Memory Block 
  5147.  
  5148.       0101 
  5149.                 Free DOS Memory Block 
  5150.  
  5151.       0102 
  5152.                 Resize DOS Memory Block 
  5153.  
  5154.       0200 
  5155.                 Get Real-Mode Interrupt Vector 
  5156.  
  5157.       0201 
  5158.                 Set Real-Mode Interrupt Vector 
  5159.  
  5160.       0202 
  5161.                 Get Processor Exception Handler 
  5162.  
  5163.       0203 
  5164.                 Set Processor Exception Handler 
  5165.  
  5166.       0204 
  5167.                 Get Protected-Mode Interrupt Vector 
  5168.  
  5169.       0205 
  5170.                 Set Protected-Mode Interrupt Vector 
  5171.  
  5172.       0300 
  5173.                 Simulate Real-Mode Interrupt 
  5174.  
  5175.       0301 
  5176.                 Call Real-Mode Procedure with Far Return Frame (DOS/4GW 
  5177.                 Professional only) 
  5178.  
  5179.       0302 
  5180.                 Call Real-Mode Procedure with IRET Frame (DOS/4GW Professional 
  5181.                 only) 
  5182.  
  5183.       0303 
  5184.                 Allocate Real-Mode Callback Address (DOS/4GW Professional only) 
  5185.  
  5186.       0304 
  5187.                 Free Real-Mode Callback Address (DOS/4GW Professional only) 
  5188.  
  5189.       0400 
  5190.                 Get DPMI Version 
  5191.  
  5192.       0500 
  5193.                 Get Free Memory Information 
  5194.  
  5195.       0501 
  5196.                 Allocate Memory Block 
  5197.  
  5198.       0502 
  5199.                 Free Memory Block 
  5200.  
  5201.       0503 
  5202.                 Resize Memory Block 
  5203.  
  5204.       0600 
  5205.                 Lock Linear Region 
  5206.  
  5207.       0601 
  5208.                 Unlock Linear Region 
  5209.  
  5210.       0604 
  5211.                 Get Page Size (VM only) 
  5212.  
  5213.       0702 
  5214.                 Mark Page as Demand Paging Candidate (DOS/4GW Professional 
  5215.                 only) 
  5216.  
  5217.       0703 
  5218.                 Discard Page Contents (DOS/4GW Professional only) 
  5219.  
  5220.       0800 
  5221.                 Physical Address Mapping 
  5222.  
  5223.       0801 
  5224.                 Free Physical Address Mapping 
  5225.  
  5226.       0900 
  5227.                 Get and Disable Virtual Interrupt State 
  5228.  
  5229.       0901 
  5230.                 Get and Enable Virtual Interrupt State 
  5231.  
  5232.       0902 
  5233.                 Get Virtual Interrupt State 
  5234.  
  5235.       0A00 
  5236.                 Get Tenberry Software API Entry Point 
  5237.  
  5238.       0E00 
  5239.                 Get Coprocessor Status 
  5240.  
  5241.       0E01 
  5242.                 Set Coprocessor Emulation 
  5243.  
  5244.  
  5245. ΓòÉΓòÉΓòÉ 14.3. DOS/4GW:  Addressing ΓòÉΓòÉΓòÉ
  5246.  
  5247.  3a.  Converting between pointers and linear addresses. 
  5248.  
  5249.  
  5250.       Because DOS/4GW uses a zero-based flat memory model, converting between 
  5251.       pointers and linear addresses is trivial.  A pointer value is always 
  5252.       relative to the current segment (the value in CS for a code pointer, or 
  5253.       in DS or SS for a data pointer).  The segment bases for the default DS, 
  5254.       SS, and CS are all zero.  Hence a near pointer is exactly the same thing 
  5255.       as a linear address:  a null pointer points to linear address 0, and a 
  5256.       pointer with value 0x10000 points to linear address 0x10000. 
  5257.  
  5258.  3b.  Converting between code and data pointers. 
  5259.  
  5260.  
  5261.       Because DS and CS have the same base address, they are natural aliases 
  5262.       for each other.  To create a data alias for a code pointer, merely create 
  5263.       a data pointer and set it equal to the code pointer.  It's not necessary 
  5264.       for you to create your own alias descriptor.  Similarly, to create a code 
  5265.       alias for a data pointer, merely create a code pointer and set it equal 
  5266.       to the data pointer. 
  5267.  
  5268.  3c.  Converting between pointers and low memory addresses. 
  5269.  
  5270.  
  5271.       Linear addresses under 1 MB map directly to physical memory.  Hence the 
  5272.       real-mode interrupt vector table is at address 0, the BIOS data segment 
  5273.       is at address 0x400, the monochrome video memory is at address 0xB0000, 
  5274.       and the color video memory is at address 0xB8000.  To read and write any 
  5275.       of these, you can just use a pointer set to the proper address.  You 
  5276.       don't need to create a far pointer, using some magic segment value. 
  5277.  
  5278.  3d.  Converting between linear and physical addresses. 
  5279.  
  5280.  
  5281.       Linear addresses at or above 1 MB do not map directly to physical memory, 
  5282.       so you can not in general read or write extended memory directly, nor can 
  5283.       you tell how a particular block of extended memory has been used. 
  5284.  
  5285.       DOS/4GW supports the DPMI call INT 31h/800h, which maps physical 
  5286.       addresses to linear addresses.  In other words, if you have a peripheral 
  5287.       device in your machine that has memory at a physical address of 256 MB, 
  5288.       you can issue this call to create a linear address that points to that 
  5289.       physical memory.  The linear address is the same thing as a near pointer 
  5290.       to the memory and can be manipulated as such. 
  5291.  
  5292.       There is no way in a DPMI environment to determine the physical address 
  5293.       corresponding to a given linear address.  This is part of the design of 
  5294.       DPMI.  You must design your application accordingly. 
  5295.  
  5296.  3e.  Null pointer checking. 
  5297.  
  5298.  
  5299.       DOS/4GW will trap references to the first sixteen bytes of physical 
  5300.       memory if you set the environment variable DOS4G=NULLP.  This is 
  5301.       currently the only null-pointer check facility provided by DOS/4GW. 
  5302.  
  5303.       As of release 1.95, DOS/4GW traps both reads and writes.  Prior to this, 
  5304.       it only trapped writes. 
  5305.  
  5306.       You may experience problems if you set DOS4G=NULLP and use some versions 
  5307.       of the Watcom Debugger with a 1.95 or later extender.  These problems 
  5308.       have been corrected in later versions of the Watcom Debugger. 
  5309.  
  5310.  
  5311. ΓòÉΓòÉΓòÉ 14.4. DOS/4GW:  Interrupt and Exception Handling ΓòÉΓòÉΓòÉ
  5312.  
  5313.  4a.  Handling asynchronous interrupts. 
  5314.  
  5315.  
  5316.       Under DOS/4GW, there is a convenient way to handle asynchronous 
  5317.       interrupts and an efficient way to handle them. 
  5318.  
  5319.       Because your CPU may be in either protected mode (when 32-bit code is 
  5320.       executing) or real mode (a DOS or BIOS call) when a hardware interrupt 
  5321.       comes in, you have to be prepared to handle interrupts in either mode. 
  5322.       Otherwise, you may miss interrupts. 
  5323.  
  5324.       You can handle both real-mode and protected-mode interrupts with a single 
  5325.       handler, if 1) the interrupt is in the auto-passup range, 8 to 2Eh; and 
  5326.       2) you install a handler with INT 21h/25h or _dos_setvect(); 3) you do 
  5327.       not install a handler for the same interrupt using any other mechanism. 
  5328.       DOS/4GW will route both protected-mode interrupts and real-mode 
  5329.       interrupts to your protected-mode handler.  This is the convenient way. 
  5330.  
  5331.       The efficient way is to install separate real-mode and protected-mode 
  5332.       handlers for your interrupt, so your CPU won't need to do unnecessary 
  5333.       mode switches.  Writing a real-mode handler is tricky; all you can 
  5334.       reasonably expect to do is save data in a buffer and IRET.  Your 
  5335.       protected-mode code can periodically check the buffer and process any 
  5336.       queued data.  (Remember, protected-mode code can access data and execute 
  5337.       code in low memory, but real-mode code can't access data or execute code 
  5338.       in extended memory.) 
  5339.  
  5340.       For performance, it doesn't matter how you install the real-mode handler, 
  5341.       but we recommend the DPMI function INT 31h/201h for portability. 
  5342.  
  5343.       It does matter how you install the protected-mode handler.  You can't 
  5344.       install it directly into the IDT, because a DPMI provider must 
  5345.       distinguish between interrupts and exceptions and maintain separate 
  5346.       handler chains.  Installing with INT 31h/205h is the recommended way to 
  5347.       install your protected-mode handler for both performance and portability. 
  5348.  
  5349.       If you install a protected-mode handler with INT 21h/25h, both interrupts 
  5350.       and exceptions will be funneled to your handler, to mimic DOS.  Since 
  5351.       DPMI exception handlers and interrupt handlers are called with different 
  5352.       stack frames, DOS/4GW executes a layer of code to cover these differences 
  5353.       up; the same layer is used to support the DOS/4G API (not part of 
  5354.       DOS/4GW).  This layer is the reason that hooking with INT 21h/25h is less 
  5355.       efficient than hooking with INT 31h/205h. 
  5356.  
  5357.  4b.  Handling asynchronous interrupts in the second IRQ range. 
  5358.  
  5359.  
  5360.       Because the second IRQ range (normally INTs 70h-77h) is outside the 
  5361.       DOS/4GW auto-passup range (8-2Eh, excluding 21h) you may not handle these 
  5362.       interrupts with a single handler, as described above (the "convenient" 
  5363.       method).  You must install separate real-mode and protected-mode handlers 
  5364.       (the "efficient" method). 
  5365.  
  5366.       DOS/4G does allow you to specify additional passup interrupts, however. 
  5367.  
  5368.  4c.  Asynchronous interrupt handlers and DPMI. 
  5369.  
  5370.  
  5371.       The DPMI specification requires that all code and data referenced by a 
  5372.       hardware interrupt handler MUST be locked at interrupt time.  A DPMI 
  5373.       virtual memory manager can use the DOS file system to swap pages of 
  5374.       memory to and from the disk; because DOS is not reentrant, a DPMI host is 
  5375.       not required to be able to handle page faults during asynchronous 
  5376.       interrupts.  Use INT 31h/600h (Lock Linear Region) to lock an address 
  5377.       range in memory. 
  5378.  
  5379.       If you fail to lock all of your code and data, your program may run under 
  5380.       DOS/4GW, but fail under the DOS/4GW Virtual Memory Manager or under 
  5381.       another DPMI host such as Windows or OS/2. 
  5382.  
  5383.       You should also lock the code and data of a mouse callback function. 
  5384.  
  5385.  4d.  Watcom signal() function and Ctrl-Break. 
  5386.  
  5387.  
  5388.       In earlier versions of the Watcom C/C++ library, there was a bug that 
  5389.       caused signal(SIGBREAK) not to work.  Calling signal(SIGBREAK) did not 
  5390.       actually install an interrupt handler for Ctrl-Break (INT 1Bh), so 
  5391.       Ctrl-Break would terminate the application rather than invoking the 
  5392.       signal handler. 
  5393.  
  5394.       With these earlier versions of the library, you could work around this 
  5395.       problem by hooking INT 1Bh directly. With release 10.0, this problem has 
  5396.       been fixed. 
  5397.  
  5398.  4e.  More tips on writing hardware interrupt handlers. 
  5399.  
  5400.           It's more like handling interrupts in real mode than not. 
  5401.  
  5402.            The same problems arise when writing hardware interrupt handlers for 
  5403.            protected mode as arise for real mode. We assume you know how to 
  5404.            write real-mode handlers; if our suggestions don't seem clear, you 
  5405.            might want to brush up on real-mode interrupt programming. 
  5406.           Minimize the amount of time spent in your interrupt handlers. 
  5407.  
  5408.            When your interrupt handlers are called, interrupts are disabled. 
  5409.            This means that no other system tasks can be performed until you 
  5410.            enable interrupts (an STI instruction) or until your handler 
  5411.            returns.  In general, it's a good idea to handle interrupts as 
  5412.            quickly as possible. 
  5413.           Minimize the amount of time spent in the DOS extender by installing 
  5414.            separate real-mode and protected-mode handlers. 
  5415.  
  5416.            If you use a passup interrupt handler, so that interrupts received 
  5417.            in real mode are resignalled in protected mode by the extender, your 
  5418.            application has to switch from real mode to protected mode to real 
  5419.            mode once per interrupt.  Mode switching is a time-consuming 
  5420.            process, and interrupts are disabled during a mode switch. 
  5421.            Therefore, if you're concerned about performance, you should install 
  5422.            separate handlers for real-mode and protected-mode interrupts, 
  5423.            eliminating the mode switch. 
  5424.           If you can't just set a flag and return, enable interrupts (STI). 
  5425.  
  5426.            Handlers that do more than just set a flag or store data in a buffer 
  5427.            should re-enable interrupts as soon as it's safe to do so.  In other 
  5428.            words, save your registers on the stack, establish your addressing 
  5429.            conventions, switch stacks if you're going to - and then enable 
  5430.            interrupts (STI), to give priority to other hardware interrupts. 
  5431.           If you enable interrupts (STI), you should disable interrupts (CLI). 
  5432.  
  5433.            Because some DPMI hosts virtualize the interrupt flag, if you do an 
  5434.            STI in your handler, you should be sure to do a CLI before you 
  5435.            return.  (CLI, then switch back to the original stack if you 
  5436.            switched away, then restore registers, then IRET.) If you don't do 
  5437.            this, the IRET will not necessarily restore the previous interrupt 
  5438.            flag state, and your program may crash.  This is a difference from 
  5439.            real-mode programming, and it tends to show up as a problem when you 
  5440.            try running your program in a Windows or OS/2 DOS box for the first 
  5441.            time (but not before). 
  5442.           Add a reentrancy check. 
  5443.  
  5444.            If your handler doesn't complete its work by the time the next 
  5445.            interrupt is signalled, then interrupts can quickly nest to the 
  5446.            point of overflowing the transfer stack.  This is a design flaw in 
  5447.            your program, not in the DOS extender; a real-mode DOS program can 
  5448.            have exactly the same behavior.  If you can conceive of a situation 
  5449.            where your interrupt handler can be called again before the first 
  5450.            instance returns, you need to code in a reentrancy check of some 
  5451.            sort (before you switch stacks and enable interrupts (STI), 
  5452.            obviously). 
  5453.  
  5454.            Remember that interrupts can take different amounts of time to 
  5455.            execute on different machines; the CPU manufacturer, CPU speed, 
  5456.            speed of memory accesses, and CMOS settings (e.g.  "system BIOS 
  5457.            shadowing") can all affect performance in subtle ways.  We recommend 
  5458.            you program defensively and always check for unexpected reentry, to 
  5459.            avoid transfer stack overflows. 
  5460.           Switch to your own stack. 
  5461.  
  5462.            Interrupt handlers are called on a stack that typically has only a 
  5463.            small amount of stack available (512 bytes or less).  If you need to 
  5464.            use more stack than this, you have to switch to your own stack on 
  5465.            entry into the handler, and switch back before returning. 
  5466.  
  5467.            If you want to use C run-time library functions, which are compiled 
  5468.            for flat memory model (SS == DS, and the base of CS == the base of 
  5469.            DS), you need to switch back to a stack in the flat data segment 
  5470.            first. 
  5471.  
  5472.            Note that switching stacks by itself won't prevent transfer stack 
  5473.            overflows of the kind described above. 
  5474.  
  5475.  
  5476. ΓòÉΓòÉΓòÉ 14.5. DOS/4GW:  Memory Management ΓòÉΓòÉΓòÉ
  5477.  
  5478.  5a.  Using the realloc() function. 
  5479.  
  5480.  
  5481.       In versions of Watcom C/C++ prior to 9.5b, there was a bug in the library 
  5482.       implementation of realloc() under DOS/4GW and DOS/4GW Professional.  This 
  5483.       bug was corrected by Watcom in the 9.5b release. 
  5484.  
  5485.  5b.  Using all of physical memory. 
  5486.  
  5487.  
  5488.       DOS/4GW Professional is currently limited to 64 MB of physical memory. 
  5489.       We do not expect to be able to fix this problem for at least six months. 
  5490.       If you need more than 64 MB of memory, you must use virtual memory. 
  5491.  
  5492.  
  5493. ΓòÉΓòÉΓòÉ 14.6. DOS/4GW:  DOS, BIOS, and Mouse Services ΓòÉΓòÉΓòÉ
  5494.  
  5495.  6a.  Speeding up file I/O. 
  5496.  
  5497.  
  5498.       The best way to speed up DOS file I/O in DOS/4GW is to write large blocks 
  5499.       (up to 65535 bytes, or the largest number that will fit in a 16-bit int) 
  5500.       at a time from a buffer in low memory.  In this case, DOS/4GW has to copy 
  5501.       the least amount of data and make the fewest number of DOS calls in order 
  5502.       to process the I/O request. 
  5503.  
  5504.       Low memory is allocated through INT 31h/0100h, Allocate DOS Memory Block. 
  5505.       You can convert the real-mode segment address returned by INT 31h/0100h 
  5506.       to a pointer (suitable for passing to setvbuf()) by shifting it left four 
  5507.       bits. 
  5508.  
  5509.  6b.  Spawning. 
  5510.  
  5511.  
  5512.       It is possible to spawn one DOS/4GW application from another.  However, 
  5513.       two copies of the DOS extender will be loaded into memory.  DOS/4G 
  5514.       supports loading of multiple programs atop a single extender, as well as 
  5515.       DLLs. 
  5516.  
  5517.  6c.  Mouse callbacks. 
  5518.  
  5519.  
  5520.       DOS/4GW Professional now supports the INT 31h interface for managing 
  5521.       real-mode callbacks.  However, you don't need to bother with them for 
  5522.       their single most important application:  mouse callback functions.  Just 
  5523.       register your protected-mode mouse callback function as you would in real 
  5524.       mode, by issuing INT 33h/0Ch with the event mask in CX and the function 
  5525.       address in ES:EDX, and your function will work as expected. 
  5526.  
  5527.       Because a mouse callback function is called asynchronously, the same 
  5528.       locking requirement exists for a mouse callback function as for a 
  5529.       hardware interrupt handler.  See (4c) above. 
  5530.  
  5531.  6d.  VESA support. 
  5532.  
  5533.  
  5534.       While DOS/4GW automatically handles most INT 10h functions so that you 
  5535.       can you can issue them from protected mode, it does not translate the INT 
  5536.       10h VESA extensions.  The workaround is to use INT 31h/300h (Simulate 
  5537.       Real-Mode Interrupt). 
  5538.  
  5539.  
  5540. ΓòÉΓòÉΓòÉ 14.7. DOS/4GW:  Virtual Memory ΓòÉΓòÉΓòÉ
  5541.  
  5542.  7a.  Testing for the presence of VMM. 
  5543.  
  5544.  
  5545.       INT 31h/400h returns a value (BX, bit 2) that tells if virtual memory is 
  5546.       available.  Under a DPMI host such as Windows 3.1, this will be the 
  5547.       host's virtual memory manager, not DOS/4GW's. 
  5548.  
  5549.       You can test for the presence of a DOS/4G-family DOS extender with INT 
  5550.       31h/0A00h, with a pointer to the null-terminated string "RATIONAL DOS/4G" 
  5551.       in DS:ESI.  If the function returns with carry clear, a DOS/4G-family 
  5552.       extender is running. 
  5553.  
  5554.  7b.  Reserving memory for a spawned application. 
  5555.  
  5556.  
  5557.       If you spawn one DOS/4GW application from another, you should set the 
  5558.       DELETESWAP configuration option (i.e., SET DOS4GVM=deleteswap) so that 
  5559.       the two applications don't try to use the same swap file.  You should 
  5560.       also set the MAXMEM option low enough so that the parent application 
  5561.       doesn't take all available physical memory; memory that's been reserved 
  5562.       by the parent application is not available to the child application. 
  5563.  
  5564.  7c.  Instability under VMM. 
  5565.  
  5566.  
  5567.       A program that hooks hardware interrupts, and works fine without VMM but 
  5568.       crashes sporadically with it, probably needs to lock the code and data 
  5569.       for its hardware interrupt handlers down in memory.  DOS/4GW does not 
  5570.       support page faults during hardware interrupts, because DOS services may 
  5571.       not be available at that time.  See (4c) and (6c) above. 
  5572.  
  5573.       Memory can be locked down with INT 31h/600h (Lock Linear Region). 
  5574.  
  5575.  7d.  Running out of memory with a huge virtual address space. 
  5576.  
  5577.  
  5578.       Because DOS/4GW has to create page tables to describe your virtual 
  5579.       address space, we recommend that you set your VIRTUALSIZE parameter just 
  5580.       large enough to accommodate your program.  If you set your VIRTUALSIZE to 
  5581.       4 GB, the physical memory occupied by the page tables will be 4 MB, and 
  5582.       that memory will not be available to DOS/4GW. 
  5583.  
  5584.  7e.  Reducing the size of the swap file. 
  5585.  
  5586.  
  5587.       DOS/4GW will normally create a swap file equal to your VIRTUALSIZE 
  5588.       setting, for efficiency.  However, if you set the SWAPMIN parameter to a 
  5589.       size (in KB), DOS/4GW will start with a swap file of that size, and will 
  5590.       grow the swap file when it has to.  The SWAPINC value (default 64 KB) 
  5591.       controls the incremental size by which the swap file will grow. 
  5592.  
  5593.  7f.  Deleting the swap file. 
  5594.  
  5595.  
  5596.       The DELETESWAP option has two effects:  telling DOS/4GW to delete the 
  5597.       swap file when it exits, and causing DOS/4GW to provide a unique swap 
  5598.       file name if an explicit SWAPNAME setting was not given. 
  5599.  
  5600.       DELETESWAP is required if one DOS/4GW application is to spawn another; 
  5601.       see (7b) above. 
  5602.  
  5603.  7g.  Improving demand-load performance of large static arrays. 
  5604.  
  5605.  
  5606.       DOS/4GW demand-loading feature normally cuts the load time of a large 
  5607.       program drastically.  However, if your program has large amounts of 
  5608.       global, zero-initialized data (storage class BSS), the Watcom startup 
  5609.       code will explicitly zero it (version 9.5a or earlier).  Because the 
  5610.       zeroing operation touches every page of the data, the benefits of 
  5611.       demand-loading are lost. 
  5612.  
  5613.       Demand loading can be made fast again by taking advantage of the fact 
  5614.       that DOS/4GW automatically zeroes pages of BSS data as they are loaded. 
  5615.       You can make this change yourself by inserting a few lines into the 
  5616.       startup routine, assembling it (MASM 6.0 will work), and listing the 
  5617.       modified object module first when you link your program. 
  5618.  
  5619.       Here are the changes for \WATCOM\SRC\STARTUP\386\CSTART3R.ASM (startup 
  5620.       module from the C/C++ 9.5 compiler, library using register calling 
  5621.       conventions).  You can modify the workaround easily for other Watcom 
  5622.       compilers: 
  5623.  
  5624.  
  5625.              ...           ; cstart3r.asm, circa line 332 
  5626.                          ; end of _BSS segment (start of STACK) 
  5627.              mov   ecx,offset DGROUP:_end 
  5628.                          ; start of _BSS segment 
  5629.              mov   edi,offset DGROUP:_edata 
  5630.          ;-------------------------------; RSI OPTIMIZATION 
  5631.              mov   eax, edi     ; minimize _BSS initialization loop 
  5632.              or    eax, 0FFFh    ; compute address of first page after 
  5633.              inc   eax       ;  start of _BSS 
  5634.              cmp   eax, ecx     ; if _BSS extends onto that page, 
  5635.              jae   allzero     ;  then we can rely on the loader 
  5636.              mov   ecx, eax     ;  zeroing the remaining pages 
  5637.          allzero:             ; 
  5638.          ;-------------------------------; END RSI OPTIMIZATION 
  5639.              sub   ecx,edi     ; calc # of bytes in _BSS segment 
  5640.              mov   dl,cl      ; save bottom 2 bits of count in edx 
  5641.              shr   ecx,2      ; calc # of dwords 
  5642.              sub   eax,eax     ; zero the _BSS segment 
  5643.              rep   stosd      ; ... 
  5644.              mov   cl,dl      ; get bottom 2 bits of count 
  5645.              and   cl,3       ; ... 
  5646.              rep   stosb      ; ... 
  5647.              ... 
  5648.  
  5649.       Note that the 9.5b and later versions of the Watcom C library already 
  5650.       contain this enhancement. 
  5651.  
  5652.  7h.  How should I configure VM for best performance? 
  5653.  
  5654.  
  5655.       Here are some recommendations for setting up the DOS/4GW virtual memory 
  5656.       manager. 
  5657.  
  5658.       VIRTUALSIZE 
  5659.                 Set to no more than twice the total amount of memory (virtual 
  5660.                 and otherwise) your program requires.  If your program has 16 
  5661.                 MB of code and data, set to 32 MB.  (There is only a small 
  5662.                 penalty for setting this value larger than you will need, but 
  5663.                 your program won't run if you set it too low.) See (7d) above. 
  5664.  
  5665.       MINMEM 
  5666.                 Set to the minimum hardware requirement for running your 
  5667.                 application.  (If you require a 2 MB machine, set to 2048). 
  5668.  
  5669.       MAXMEM 
  5670.                 Set to the maximum amount of memory you want your application 
  5671.                 to use.  If you don't spawn any other applications, set this 
  5672.                 large (e.g., 32000) to make sure you can use all available 
  5673.                 physical memory.  If you do spawn, see (7b) above. 
  5674.  
  5675.       SWAPMIN 
  5676.                 Don't use this if you want the best possible VM performance. 
  5677.                 The trade-off is that DOS/4GW will create a swap file as big as 
  5678.                 your VIRTUALSIZE. 
  5679.  
  5680.       SWAPINC 
  5681.                 Don't use this if you want the best possible VM performance. 
  5682.  
  5683.       DELETESWAP 
  5684.                 DOS/4GW's VM will start up slightly slower if it has to create 
  5685.                 the swap file afresh each time.  However, unless your swap file 
  5686.                 is very large, DELETESWAP is a reasonable choice; it may be 
  5687.                 required if you spawn another DOS/4GW program at the same time. 
  5688.                 See (7b) above. 
  5689.  
  5690.  
  5691. ΓòÉΓòÉΓòÉ 14.8. DOS/4GW:  Debugging ΓòÉΓòÉΓòÉ
  5692.  
  5693.  8a.  Attempting to debug a bound application. 
  5694.  
  5695.  
  5696.       You can't debug a bound application.  The 4GWBIND utility (included with 
  5697.       DOS/4GW Professional) will allow you to take apart a bound application so 
  5698.       that you can debug it: 
  5699.  
  5700.  
  5701.          4GWBIND -U <boundapp.exe> <yourapp.exe> 
  5702.  
  5703.  8b.  Debugging with an old version of the Watcom debugger. 
  5704.  
  5705.  
  5706.       DOS/4GW supports versions 8.5 and up of the Watcom C, C++ and FORTRAN 
  5707.       compilers.  However, in order to debug your unbound application with a 
  5708.       Watcom debugger, you must have version 9.5a or later of the debugger. 
  5709.  
  5710.       If you have an older version of the debugger, we strongly recommend that 
  5711.       you contact Watcom to upgrade your compiler and tools.  The only way to 
  5712.       debug a DOS/4GW Professional application with an old version of the 
  5713.       debugger is to rename 4GWPRO.EXE to DOS4GW.EXE and make sure that it's 
  5714.       either in the current directory or the first DOS4GW.EXE on the DOS PATH. 
  5715.  
  5716.       Tenberry will not provide technical support for this configuration; it's 
  5717.       up to you to keep track of which DOS extender is which. 
  5718.  
  5719.  8c.  Meaning of "unexpected interrupt" message/error 2001. 
  5720.  
  5721.  
  5722.       In version 1.95 of DOS/4GW, we revised the "unexpected interrupt" message 
  5723.       to make it easier to understand. 
  5724.  
  5725.       For example, the message: 
  5726.  
  5727.  
  5728.          Unexpected interrupt 0E (code 0) at 168:10421034 
  5729.  
  5730.       is now printed: 
  5731.  
  5732.  
  5733.          error (2001): exception 0Eh (page fault) at 168:10421034 
  5734.  
  5735.       followed by a register dump, as before. 
  5736.  
  5737.       This message indicates that the processor detected some form of 
  5738.       programming error and signaled an exception, which DOS/4GW trapped and 
  5739.       reported.  Exceptions which can be trapped include: 
  5740.  
  5741.  
  5742.          00h   divide by zero 
  5743.          01h   debug exception OR null pointer used 
  5744.          03h   breakpoint 
  5745.          04h   overflow 
  5746.          05h   bounds 
  5747.          06h   invalid opcode 
  5748.          07h   device not available 
  5749.          08h   double fault 
  5750.          09h   overrun 
  5751.          0Ah   invalid TSS 
  5752.          0Bh   segment not present 
  5753.          0Ch   stack fault 
  5754.          0Dh   general protection fault 
  5755.          0Eh   page fault 
  5756.  
  5757.       When you receive this message, this is the recommended course of action: 
  5758.  
  5759.         1. Record all of the information from the register dump. 
  5760.  
  5761.         2. Determine the circumstances under which your program fails. 
  5762.  
  5763.         3. Consult your debugger manual, or an Intel 386, 486 or Pentium 
  5764.            Programmer's Reference Manual, to determine the circumstances under 
  5765.            which the processor will generate the reported exception. 
  5766.  
  5767.         4. Get the program to fail under your debugger, which should stop the 
  5768.            program as soon as the exception occurs. 
  5769.  
  5770.         5. Determine from the exception context why the processor generated an 
  5771.            exception in this particular instance. 
  5772.  
  5773.  8d.  Meaning of "transfer stack overflow" message/error 2002. 
  5774.  
  5775.  
  5776.       In version 1.95 of DOS/4GW, we added more information to the "transfer 
  5777.       stack overflow" message.  The message (which is now followed by a 
  5778.       register dump) is printed: 
  5779.  
  5780.  
  5781.          error (2002): transfer stack overflow 
  5782.          on interrupt <number> at <address> 
  5783.  
  5784.       This message means DOS/4GW detected an overflow on its interrupt handling 
  5785.       stack.  It usually indicates either a recursive fault, or a hardware 
  5786.       interrupt handler that can't keep up with the rate at which interrupts 
  5787.       are occurring.  The best way to understand the problem is to use the 
  5788.       VERBOSE option in DOS/4GW to dump the interrupt history on the transfer 
  5789.       stack; see (8e) below. 
  5790.  
  5791.  8e.  Making the most of a DOS/4GW register dump. 
  5792.  
  5793.  
  5794.       If you can't understand your problem by running it under a debugger, the 
  5795.       DOS/4GW register dump is your best debugging tool.  To maximize the 
  5796.       information available for postmortem debugging, set the environment 
  5797.       variable DOS4G to VERBOSE, then reproduce the crash and record the 
  5798.       output. 
  5799.  
  5800.       Here's a typical register dump with VERBOSE turned on, with annotations. 
  5801.  
  5802.  
  5803.        1 DOS/4GW error (2001): exception 0Eh (page fault) 
  5804.                               at 170:0042C1B2 
  5805.        2 TSF32: prev_tsf32 67D8 
  5806.        3 SS    178 DS    178 ES    178 FS     0 GS     20 
  5807.         EAX 1F000000 EBX     0 ECX  43201C EDX     E 
  5808.         ESI     E EDI     0 EBP  431410 ESP  4313FC 
  5809.         CS:IP  170:0042C1B2 ID 0E COD     0 FLG   10246 
  5810.        4 CS=  170, USE32, page granular, limit FFFFFFFF, base     0, acc CF9B 
  5811.         SS=  178, USE32, page granular, limit FFFFFFFF, base     0, acc CF93 
  5812.         DS=  178, USE32, page granular, limit FFFFFFFF, base     0, acc CF93 
  5813.         ES=  178, USE32, page granular, limit FFFFFFFF, base     0, acc CF93 
  5814.         FS=   0, USE16, byte granular, limit     0, base    15, acc  0 
  5815.         GS=  20, USE16, byte granular, limit   FFFF, base   6AA0, acc 93 
  5816.        5 CR0: PG:1 ET:1 TS:0 EM:0 MP:0 PE:1 CR2: 1F000000 CR3: 9067 
  5817.        6 Crash address (unrelocated) = 1:000001B2 
  5818.        7 Opcode stream: 8A 18 31 D2 88 DA EB 0E 50 68 39 00 43 00 E8 1D 
  5819.         Stack: 
  5820.        8 0178:004313FC 000E 0000 0000 0000 C2D5 0042 C057 0042 0170 0000 0000 
  5821.       0000 
  5822.         0178:00431414 0450 0043 0452 0043 0000 0000 1430 0043 CBEF 0042 011C 
  5823.       0000 
  5824.         0178:0043142C C568 0042 0000 0000 0000 0000 0000 0000 F248 0042 F5F8 
  5825.       0042 
  5826.         0178:00431444 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 
  5827.       0000 
  5828.         0178:0043145C 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 
  5829.       0000 
  5830.         0178:00431474 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 
  5831.       0000 
  5832.        9 Last 4 ints: 21 @ 170:42CF48/21 @ 170:42CF48/21 @ 170:42CF48/E @ 
  5833.       170:42C1B2/ 
  5834.  
  5835.         1. The error message includes a synopsis of the problem.  In this case, 
  5836.            the processor signaled a page fault exception while executing at 
  5837.            address 170:0042C1B2. 
  5838.  
  5839.         2. The prev_tsf32 field is not usually of interest. 
  5840.  
  5841.         3. These are the register values at the time of the exception.  The 
  5842.            interrupt number and error code (pushed on the stack by the 
  5843.            processor for certain exceptions) are also printed. 
  5844.  
  5845.         4. The descriptors referenced by each segment register are described 
  5846.            for your convenience.  USE32 segments in general belong to your 
  5847.            program; USE16 segments generally belong to the DOS extender.  Here, 
  5848.            CS points to your program's code segment, and SS, DS, and ES point 
  5849.            to your data segment.  FS is NULL and GS points to a DOS extender 
  5850.            segment. 
  5851.  
  5852.         5. The control register information is not of any general interest, 
  5853.            except on a page fault, when CR2 contains the address value that 
  5854.            caused the fault.  Since EAX in this case contains the same value, 
  5855.            an attempt to dereference EAX could have caused this particular 
  5856.            fault. 
  5857.  
  5858.         6. If the crash address (unrelocated) appears, it tells you where the 
  5859.            crash occurred relative to your program's link map.  You can 
  5860.            therefore tell where a crash occurred even if you can't reproduce 
  5861.            the crash in a debugger. 
  5862.  
  5863.         7. The opcode stream, if it appears, shows the next 16 bytes from the 
  5864.            code segment at the point of the exception.  If you disassemble 
  5865.            these instructions, you can tell what instructions caused the crash, 
  5866.            even without using a debugger. In this case, 8A 18 is the 
  5867.            instruction mov bl,[eax]. 
  5868.  
  5869.         8. 72 words from the top of the stack, at the point of the exception, 
  5870.            may be listed next.  You may be able to recognize function calls or 
  5871.            data from your program on the stack. 
  5872.  
  5873.         9. The four interrupts least to most recently handled by DOS/4GW in 
  5874.            protected mode are listed next.  In this example, the last interrupt 
  5875.            issued before the page fault occurred was an INT 21h (DOS call) at 
  5876.            address 170:42CF48.  Sometimes, this information provides helpful 
  5877.            context. 
  5878.       Here's an abridged register dump from a stack overflow. 
  5879.  
  5880.  
  5881.         DOS/4GW error (2002): transfer stack overflow 
  5882.                         on interrupt 70h at 170:0042C002 
  5883.         TSF32: prev_tsf32 48C8 
  5884.         SS     C8 DS    170 ES     28 FS     0 GS     20 
  5885.         EAX AAAAAAAA EBX BBBBBBBB ECX CCCCCCCC EDX DDDDDDDD 
  5886.         ESI 51515151 EDI D1D1D1D1 EBP B1B1B1B1 ESP   4884 
  5887.        1 CS:IP  170:0042C002 ID 70 COD     0 FLG     2 
  5888.         ... 
  5889.        2 Previous TSF: 
  5890.         TSF32: prev_tsf32 498C 
  5891.         SS     C8 DS    170 ES     28 FS     0 GS     20 
  5892.         EAX AAAAAAAA EBX BBBBBBBB ECX CCCCCCCC EDX DDDDDDDD 
  5893.         ESI 51515151 EDI D1D1D1D1 EBP B1B1B1B1 ESP   4960 
  5894.        3 CS:IP  170:0042C002 ID 70 COD     0 FLG     2 
  5895.         ... 
  5896.         Previous TSF: 
  5897.         TSF32: prev_tsf32 67E4 
  5898.         SS    178 DS    170 ES     28 FS     0 GS     20 
  5899.         EAX AAAAAAAA EBX BBBBBBBB ECX CCCCCCCC EDX DDDDDDDD 
  5900.         ESI 51515151 EDI D1D1D1D1 EBP B1B1B1B1 ESP  42FFE0 
  5901.        4 CS:IP  170:0042C039 ID 70 COD     0 FLG    202 
  5902.        5 Opcode stream: CF 66 B8 62 25 66 8C CB 66 8E DB BA 00 C0 42 00 
  5903.         Last 4 ints: 70 @ 170:42C002/70 @ 170:42C002/70 @ 170:42C002/70 @ 
  5904.       170:42C002/ 
  5905.  
  5906.         1. We overflowed the transfer stack while trying to process an 
  5907.            interrupt 70h at 170:0042C002. 
  5908.  
  5909.         2. The entire interrupt history from the transfer stack is printed 
  5910.            next.  The prev_tsf32 numbers increase as we progress from most 
  5911.            recent to least recent interrupt.  All of these interrupts are still 
  5912.            pending, which is why we ran out of stack space. 
  5913.  
  5914.         3. Before we overflowed the stack, we got the same interrupt at the 
  5915.            same address.  For a recursive interrupt situation, this is typical. 
  5916.  
  5917.         4. The oldest frame on the transfer stack shows the recursion was 
  5918.            touched off at a slightly different address.  Looking at this 
  5919.            address may help you understand the recursion. 
  5920.  
  5921.         5. The opcode stream and last four interrupt information comes from the 
  5922.            newest transfer stack frame, not the oldest. 
  5923.  
  5924.  
  5925. ΓòÉΓòÉΓòÉ 14.9. DOS/4GW:  Compatibility ΓòÉΓòÉΓòÉ
  5926.  
  5927.  9a.  Running DOS/4GW applications from inside Lotus 1-2-3. 
  5928.  
  5929.  
  5930.       In order to run DOS/4GW applications while "shelled out" from Lotus 
  5931.       1-2-3, you must use the PRIVATXM program included with your Watcom 
  5932.       compiler.  Otherwise, 1-2-3 will take all of the memory on your machine 
  5933.       and prevent DOS/4GW from using it. 
  5934.  
  5935.       Before starting 1-2-3, you must set the DOS16M environment variable to 
  5936.       limit Lotus' memory use (see your Watcom manual).  After shelling out, 
  5937.       you must run PRIVATXM, then clear the DOS16M environment variable before 
  5938.       running your application. 
  5939.  
  5940.  9b.  EMM386.EXE provided with DOS 6.0. 
  5941.  
  5942.  
  5943.       We know of at least three serious bugs in the EMM386.EXE distributed with 
  5944.       MS-DOS 6.0, one involving mis-counting the amount of available memory, 
  5945.       one involving mapping too little of the High Memory Area (HMA) into its 
  5946.       page tables, and one involving allocation of EMS memory.  Version 1.95 of 
  5947.       DOS/4GW contains workarounds for some of these problems. 
  5948.  
  5949.       If you are having problems with DOS/4GW and you are using an EMM386.EXE 
  5950.       dated 3-10-93 at 6:00:00, or later, you may wish to try the following 
  5951.       workarounds, in sequence, until the problem goes away. 
  5952.  
  5953.           Configure EMM386 with both the NOEMS and NOVCPI options. 
  5954.           Convert the DEVICEHIGH statements in your CONFIG.SYS to DEVICE 
  5955.            statements, and remove the LH (Load High) commands from your 
  5956.            AUTOEXEC.BAT. 
  5957.           Run in a Windows DOS box. 
  5958.           Replace EMM386 with another memory manager, such as QEMM-386, 
  5959.            386Max, or an older version of EMM386. 
  5960.           Run with HIMEM.SYS alone. 
  5961.       You may also wish to contact Microsoft Corporation to inquire about the 
  5962.       availability of a fix. 
  5963.  
  5964.  9c.  Spawning under OS/2 2.1. 
  5965.  
  5966.  
  5967.       We know of a bug in OS/2 2.1 that prevents one DOS/4GW application from 
  5968.       spawning another over and over again.  The actual number of repeated 
  5969.       spawns that are possible under OS/2 varies from machine to machine, but 
  5970.       is generally about 30. 
  5971.  
  5972.       This bug also affects programs running under other DOS extenders, and we 
  5973.       have not yet found a workaround, other than linking your two programs 
  5974.       together as a single program. 
  5975.  
  5976.  9d.  "DPMI host error:  cannot lock stack". 
  5977.  
  5978.  
  5979.       This error message almost always indicates insufficient memory, rather 
  5980.       than a real incompatibility.  If you see it under an OS/2 DOS box, you 
  5981.       probably need to edit your DOS Session settings and make 
  5982.       DPMI_MEMORY_LIMIT larger. 
  5983.  
  5984.  9e.  Bug in Novell TCPIP driver. 
  5985.  
  5986.  
  5987.       Some versions of a program from Novell called TCPIP.EXE, a real-mode 
  5988.       program, will cause the high words of EAX and EDX to be altered during a 
  5989.       hardware interrupt.  This bug breaks protected-mode software (and other 
  5990.       real-mode software that uses the 80386 registers).  Novell has released a 
  5991.       newer version of TCPIP that fixes the problem; contact Novell to obtain 
  5992.       the fix. 
  5993.  
  5994.  9f.  Bugs in Windows NT. 
  5995.  
  5996.  
  5997.       The initial release of Windows NT includes a DPMI host, DOSX.EXE, with 
  5998.       several serious bugs, some of which apparently cannot be worked around. 
  5999.       We cannot warranty operation of DOS/4GW under Windows NT at this time, 
  6000.       but we are continuing to exercise our best efforts to work around these 
  6001.       problems. 
  6002.  
  6003.       You may wish to contact Microsoft Corporation to inquire about the 
  6004.       availability of a new version of DOSX.EXE. 
  6005.  
  6006.  
  6007. ΓòÉΓòÉΓòÉ 15. 16-bit Windows:  Creating 16-bit Windows 3.x Applications ΓòÉΓòÉΓòÉ
  6008.  
  6009.  
  6010. This chapter describes how to compile and link 16-bit Windows 3.x applications 
  6011. simply and quickly.  In this chapter, we look at applications written to 
  6012. exploit the Windows 3.x Application Programming Interface (API). 
  6013.  
  6014. We will illustrate the steps to creating 16-bit Windows 3.x applications by 
  6015. taking a small sample application and showing you how to compile, link, run and 
  6016. debug it. 
  6017.  
  6018.  
  6019. ΓòÉΓòÉΓòÉ 15.1. 16-bit Windows:  The Sample Application ΓòÉΓòÉΓòÉ
  6020.  
  6021.  
  6022. To demonstrate the creation of 16-bit Windows 3.x applications, we introduce a 
  6023. simple sample program.  The following example is the "hello" program adapted 
  6024. for Windows. 
  6025.  
  6026.  
  6027.    #include <windows.h> 
  6028.  
  6029.    int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInst, 
  6030.              LPSTR lpCmdLine, int nCmdShow ) 
  6031.     { 
  6032.      MessageBox( NULL, "Hello world", 
  6033.            "Watcom C/C++ for Windows", 
  6034.            MB_OK | MB_TASKMODAL ); 
  6035.      return( 0 ); 
  6036.     } 
  6037.  
  6038. The goal of this program is to display the message "Hello world" on the screen. 
  6039. The MessageBox Windows API function is used to accomplish this task.  We will 
  6040. take you through the steps necessary to produce this result. 
  6041.  
  6042.  
  6043. ΓòÉΓòÉΓòÉ 15.2. 16-bit Windows:  Building and Running the Sample Windows 3.x Application ΓòÉΓòÉΓòÉ
  6044.  
  6045.  
  6046. To compile and link our example program which is stored in the file HELLO.C, 
  6047. enter the following command: 
  6048.  
  6049.  
  6050.    C>wcl /l=windows/bt=windows  hello.c 
  6051.  
  6052. The typical messages that appear on the screen are shown in the following 
  6053. illustration. 
  6054.  
  6055.  
  6056.    C>wcl /l=windows /bt=windows hello.c 
  6057.    WATCOM C/C++16 Compile and Link Utility 
  6058.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6059.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6060.        wcc hello.c  /bt=windows 
  6061.    WATCOM C16 Optimizing Compiler 
  6062.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6063.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6064.    hello.c: 10 lines, included 6500, 0 warnings, 0 errors 
  6065.    Code size: 37 
  6066.  
  6067.    WATCOM Linker 
  6068.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6069.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6070.    loading object files 
  6071.    searching libraries 
  6072.    creating a Windows 16-bit executable 
  6073.  
  6074. If you examine the current directory, you will find that two files have been 
  6075. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  6076. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  6077.  
  6078. The resultant 16-bit Windows 3.x application HELLO.EXE can now be run under 
  6079. Windows 3.x. 
  6080.  
  6081.  
  6082. ΓòÉΓòÉΓòÉ 15.3. 16-bit Windows:  Debugging the Sample Windows 3.x Application ΓòÉΓòÉΓòÉ
  6083.  
  6084.  
  6085. Let us assume that you wish to debug your application in order to locate an 
  6086. error in programming.  In the previous section, the "hello" program was 
  6087. compiled with default compile and link options.  When debugging an application, 
  6088. it is useful to refer to the symbolic names of routines and variables.  It is 
  6089. also convenient to debug at the source line level rather than the machine 
  6090. language level.  To do this, we must direct both the compiler and linker to 
  6091. include additional debugging information in the object and executable files. 
  6092. Using the WCL command, this is fairly straightforward.  WCL recognizes the 
  6093. Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  6094. directives for the Watcom Linker. 
  6095.  
  6096. For example, to compile and link the "hello" program with debugging 
  6097. information, the following command may be issued. 
  6098.  
  6099.  
  6100.    C>wcl /l=windows/bt=windows  /d2 hello.c 
  6101.  
  6102. The typical messages that appear on the screen are shown in the following 
  6103. illustration. 
  6104.  
  6105.  
  6106.    C>wcl /l=windows /bt=windows /d2 hello.c 
  6107.    WATCOM C/C++16 Compile and Link Utility 
  6108.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6109.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6110.        wcc hello.c  /bt=windows /d2 
  6111.    WATCOM C16 Optimizing Compiler 
  6112.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6113.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6114.    hello.c: 10 lines, included 6500, 0 warnings, 0 errors 
  6115.    Code size: 58 
  6116.  
  6117.    WATCOM Linker 
  6118.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6119.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6120.    loading object files 
  6121.    searching libraries 
  6122.    creating a Windows 16-bit executable 
  6123.  
  6124. The "d2" option requests the maximum amount of debugging information that can 
  6125. be provided by the Watcom C/C++ compiler.  WCL will make sure that this 
  6126. debugging information is included in the executable file that is produced by 
  6127. the linker. 
  6128.  
  6129. The "Code size" value is larger than in the previous example since selection of 
  6130. the "d2" option results in fewer code optimizations by default.  You can 
  6131. request more optimization by specifying the appropriate options.  However, you 
  6132. do so at the risk of making it more difficult for yourself to determine the 
  6133. relationship between the object code and the original source language code. 
  6134.  
  6135. To request the Watcom Debugger to assist in debugging the application, select 
  6136. the Watcom Debugger icon.  It would be too ambitious to describe the debugger 
  6137. in this introductory chapter so we refer you to the book entitled Watcom 
  6138. Debugger User's Guide. 
  6139.  
  6140.  
  6141. ΓòÉΓòÉΓòÉ 16. 16-bit Windows:  Porting Non-GUI Applications to 16-bit Windows 3.x ΓòÉΓòÉΓòÉ
  6142.  
  6143.  
  6144. Generally, an application that is to run in a windowed environment must be 
  6145. written in such a way as to exploit the Windows Application Programming 
  6146. Interface (API).  To take an existing character-based (i.e., non-graphical) 
  6147. application that ran under a system such as DOS and adapt it to run under 
  6148. Windows can require some considerable effort.  There is a steep learning curve 
  6149. associated with the API function libraries. 
  6150.  
  6151. This chapter describes how to create a Windows application quickly and simply 
  6152. from an application that does not use the Windows API.  The application will 
  6153. make use of WATCOM's default windowing support. 
  6154.  
  6155. Suppose you have a set of C/C++ applications that previously ran under a system 
  6156. like DOS and you now wish to run them under Windows 3.x.  To achieve this, you 
  6157. can simply recompile your application with the appropriate options and link 
  6158. with the appropriate libraries.  We provide a default windowing system that 
  6159. turns your character-mode application into a simple Windows 3.x Graphical User 
  6160. Interface (GUI) application. 
  6161.  
  6162. Normally, a Windows 3.x GUI application makes use of user-interface tools such 
  6163. as menus, icons, scroll bars, etc.  However, an application that was not 
  6164. designed as a windowed application (such as a DOS application) can run as a GUI 
  6165. application.  This is achieved by our default windowing system.  The following 
  6166. sections describe the default windowing system. 
  6167.  
  6168.  
  6169. ΓòÉΓòÉΓòÉ 16.1. 16-bit Windows:  Console Device in a Windowed Environment ΓòÉΓòÉΓòÉ
  6170.  
  6171.  
  6172. In a C/C++ application that runs under DOS, stdin (C++ cin) and stdout (C++ 
  6173. cout) are connected to the standard input and standard output devices 
  6174. respectively.  It is not a recommended practice to read directly from the 
  6175. standard input device or write to the standard output device when running in a 
  6176. windowed environment.  For this reason, a default windowing environment is 
  6177. created for C/C++ applications that read from stdin (C++ cin) or write to 
  6178. stdout (C++ cout).  When your application is started, a window is created in 
  6179. which output to stdout (C++ cout) is displayed and input from stdin (C++ cin) 
  6180. is requested. 
  6181.  
  6182. In addition to the standard I/O device, it is also possible to perform I/O to 
  6183. the console by explicitly opening a file whose name is "CON".  When this 
  6184. occurs, another window is created and displayed.  This window is different from 
  6185. the one created for standard input and standard output.  In fact, every time 
  6186. you open the console device a different window is created.  This provides a 
  6187. simple multi-windowing system for multiple streams of data to and from the 
  6188. console device. 
  6189.  
  6190.  
  6191. ΓòÉΓòÉΓòÉ 16.2. 16-bit Windows:  The Sample Non-GUI Application ΓòÉΓòÉΓòÉ
  6192.  
  6193.  
  6194. To demonstrate the creation of 16-bit Windows 3.x applications, we introduce a 
  6195. simple sample program.  For our example, we are going to use the famous "hello" 
  6196. program. 
  6197.  
  6198.  
  6199.    #include <stdio.h> 
  6200.  
  6201.    void main() 
  6202.     { 
  6203.      printf( "Hello world\n" ); 
  6204.     } 
  6205.  
  6206. The C++ version of this program follows: 
  6207.  
  6208.  
  6209.    #include <iostream.h> 
  6210.    #include <iomanip.h> 
  6211.  
  6212.    void main() 
  6213.    { 
  6214.      cout << "Hello world" << endl; 
  6215.    } 
  6216.  
  6217. The goal of this program is to display the message "Hello world" on the screen. 
  6218. The C version uses the C library printf routine to accomplish this task.  The 
  6219. C++ version uses the "iostream" library to accomplish this task.  We will take 
  6220. you through the steps necessary to produce this result. 
  6221.  
  6222.  
  6223. ΓòÉΓòÉΓòÉ 16.3. 16-bit Windows:  Building and Running the Non-GUI Windows 3.x Application ΓòÉΓòÉΓòÉ
  6224.  
  6225.  
  6226. Very little effort is required to port an existing C/C++ application to Windows 
  6227. 3.x. 
  6228.  
  6229. You must compile and link the file HELLO.C specifying the "bw" option. 
  6230.  
  6231.  
  6232.    C>wcl /l=windows/bw/bt=windows  hello.c 
  6233.  
  6234. The typical messages that appear on the screen are shown in the following 
  6235. illustration. 
  6236.  
  6237.  
  6238.    C>wcl /l=windows /bw/bt=windows hello.c 
  6239.    WATCOM C/C++16 Compile and Link Utility 
  6240.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6241.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6242.        wcc hello.c  /bw/bt=windows 
  6243.    WATCOM C16 Optimizing Compiler 
  6244.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6245.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6246.    hello.c: 6 lines, included 155, 0 warnings, 0 errors 
  6247.    Code size: 17 
  6248.  
  6249.    WATCOM Linker 
  6250.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6251.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6252.    loading object files 
  6253.    searching libraries 
  6254.    creating a Windows 16-bit executable 
  6255.  
  6256. If you examine the current directory, you will find that two files have been 
  6257. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  6258. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  6259.  
  6260. The resultant 16-bit Windows 3.x application HELLO.EXE can now be run under 
  6261. Windows 3.x as a Windows GUI application. 
  6262.  
  6263.  
  6264. ΓòÉΓòÉΓòÉ 16.4. 16-bit Windows:  Debugging the Non-GUI Windows 3.x Application ΓòÉΓòÉΓòÉ
  6265.  
  6266.  
  6267. Let us assume that you wish to debug your application in order to locate an 
  6268. error in programming.  In the previous section, the "hello" program was 
  6269. compiled with default compile and link options.  When debugging an application, 
  6270. it is useful to refer to the symbolic names of routines and variables.  It is 
  6271. also convenient to debug at the source line level rather than the machine 
  6272. language level.  To do this, we must direct both the compiler and linker to 
  6273. include additional debugging information in the object and executable files. 
  6274. Using the WCL command, this is fairly straightforward.  WCL recognizes the 
  6275. Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  6276. directives for the Watcom Linker. 
  6277.  
  6278. For example, to compile and link the "hello" program with debugging 
  6279. information, the following command may be issued. 
  6280.  
  6281.  
  6282.    C>wcl /l=windows/bw/bt=windows  /d2 hello.c 
  6283.  
  6284. The typical messages that appear on the screen are shown in the following 
  6285. illustration. 
  6286.  
  6287.  
  6288.    C>wcl /l=windows /bw/bt=windows /d2 hello.c 
  6289.    WATCOM C/C++16 Compile and Link Utility 
  6290.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6291.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6292.        wcc hello.c  /bw/bt=windows /d2 
  6293.    WATCOM C16 Optimizing Compiler 
  6294.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6295.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6296.    hello.c: 6 lines, included 155, 0 warnings, 0 errors 
  6297.    Code size: 23 
  6298.  
  6299.    WATCOM Linker 
  6300.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6301.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6302.    loading object files 
  6303.    searching libraries 
  6304.    creating a Windows 16-bit executable 
  6305.  
  6306. The "d2" option requests the maximum amount of debugging information that can 
  6307. be provided by the Watcom C/C++ compiler.  WCL will make sure that this 
  6308. debugging information is included in the executable file that is produced by 
  6309. the linker. 
  6310.  
  6311. The "Code size" value is larger than in the previous example since selection of 
  6312. the "d2" option results in fewer code optimizations by default.  You can 
  6313. request more optimization by specifying the appropriate options.  However, you 
  6314. do so at the risk of making it more difficult for yourself to determine the 
  6315. relationship between the object code and the original source language code. 
  6316.  
  6317. To request the Watcom Debugger to assist in debugging the application, select 
  6318. the Watcom Debugger icon.  It would be too ambitious to describe the debugger 
  6319. in this introductory chapter so we refer you to the book entitled Watcom 
  6320. Debugger User's Guide. 
  6321.  
  6322.  
  6323. ΓòÉΓòÉΓòÉ 16.5. 16-bit Windows:  Default Windowing Library Functions ΓòÉΓòÉΓòÉ
  6324.  
  6325.  
  6326. A few library functions have been written to enable some simple customization 
  6327. of the default windowing system's behaviour.  The following functions are 
  6328. supplied: 
  6329.  
  6330.  _dwDeleteOnClose 
  6331.  
  6332.  
  6333.  
  6334.          int _dwDeleteOnClose( int handle ); 
  6335.  
  6336.       This function tells the console window that it should close itself when 
  6337.       the file is closed.  You must pass to it the handle associated with the 
  6338.       opened console. 
  6339.  
  6340.  _dwSetAboutDlg 
  6341.  
  6342.  
  6343.  
  6344.          int _dwSetAboutDlg( const char *title, const char *text ); 
  6345.  
  6346.       This function sets the about dialog box of the default windowing system. 
  6347.       The "title" points to the string that will replace the current title.  If 
  6348.       title is NULL then the title will not be replaced.  The "text" points to 
  6349.       a string which will be placed in the about box.  To get multiple lines, 
  6350.       embed a new line after each logical line in the string.  If "text" is 
  6351.       NULL, then the current text in the about box will not be replaced. 
  6352.  
  6353.  _dwSetAppTitle 
  6354.  
  6355.  
  6356.  
  6357.          int _dwSetAppTitle( const char *title ); 
  6358.  
  6359.       This function sets the main window's title. 
  6360.  
  6361.  _dwSetConTitle 
  6362.  
  6363.  
  6364.  
  6365.          int _dwSetConTitle( int handle, const char *title ); 
  6366.  
  6367.       This function sets the console window's title which corresponds to the 
  6368.       handle passed to it. 
  6369.  
  6370.  _dwShutDown 
  6371.  
  6372.  
  6373.  
  6374.          int _dwShutDown( void ); 
  6375.  
  6376.       This function shuts down the default windowing I/O system.  The 
  6377.       application will continue to execute but no windows will be available for 
  6378.       output. 
  6379.  
  6380.  _dwYield 
  6381.  
  6382.  
  6383.  
  6384.          int _dwYield( void ); 
  6385.  
  6386.       This function yields control back to the operating system, thereby giving 
  6387.       other processes a chance to run. 
  6388.  
  6389.  These functions are described more fully in the WATCOM C Library Reference. 
  6390.  
  6391.  
  6392. ΓòÉΓòÉΓòÉ 17. 32-bit Windows:  Creating 32-bit Windows 3.x Applications ΓòÉΓòÉΓòÉ
  6393.  
  6394.  
  6395. This chapter describes how to compile and link 32-bit Windows 3.x applications 
  6396. simply and quickly.  In this chapter, we look at applications written to 
  6397. exploit the Windows 3.x Application Programming Interface (API). 
  6398.  
  6399. We will illustrate the steps to creating 32-bit Windows 3.x applications by 
  6400. taking a small sample application and showing you how to compile, link, run and 
  6401. debug it. 
  6402.  
  6403.  
  6404. ΓòÉΓòÉΓòÉ 17.1. 32-bit Windows:  The Sample Application ΓòÉΓòÉΓòÉ
  6405.  
  6406.  
  6407. To demonstrate the creation of 32-bit Windows 3.x applications, we introduce a 
  6408. simple sample program.  The following example is the "hello" program adapted 
  6409. for Windows. 
  6410.  
  6411.  
  6412.    #include <windows.h> 
  6413.  
  6414.    int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInst, 
  6415.              LPSTR lpCmdLine, int nCmdShow ) 
  6416.     { 
  6417.      MessageBox( NULL, "Hello world", 
  6418.            "Watcom C/C++ for Windows", 
  6419.            MB_OK | MB_TASKMODAL ); 
  6420.      return( 0 ); 
  6421.     } 
  6422.  
  6423. The goal of this program is to display the message "Hello world" on the screen. 
  6424. The MessageBox Windows API function is used to accomplish this task.  We will 
  6425. take you through the steps necessary to produce this result. 
  6426.  
  6427.  
  6428. ΓòÉΓòÉΓòÉ 17.2. 32-bit Windows:  Building and Running the Sample Windows 3.x Application ΓòÉΓòÉΓòÉ
  6429.  
  6430.  
  6431. To compile and link our example program which is stored in the file HELLO.C, 
  6432. enter the following command: 
  6433.  
  6434.  
  6435.    C>wcl386 /l=win386/bt=windows  hello.c 
  6436.  
  6437. The typical messages that appear on the screen are shown in the following 
  6438. illustration. 
  6439.  
  6440.  
  6441.    C>wcl386 /l=win386 /bt=windows hello.c 
  6442.    WATCOM C/C++32 Compile and Link Utility 
  6443.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6444.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6445.        wcc386 hello.c  /bt=windows 
  6446.    WATCOM C32 Optimizing Compiler 
  6447.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6448.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6449.    hello.c: 10 lines, included 6500, 0 warnings, 0 errors 
  6450.    Code size: 41 
  6451.  
  6452.    WATCOM Linker 
  6453.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6454.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6455.    loading object files 
  6456.    searching libraries 
  6457.    creating a Windows 32-bit executable 
  6458.  
  6459. If you examine the current directory, you will find that two files have been 
  6460. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.REX 
  6461. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  6462. The ".rex" file must now be combined with WATCOM's 32-bit Windows supervisor 
  6463. WIN386.EXT using the WATCOM Bind utility.  WBIND.EXE combines your 32-bit 
  6464. application code and data (".rex" file) with the 32-bit Windows supervisor. 
  6465. The process involves the following steps: 
  6466.  
  6467.    1. WBIND copies WIN386.EXT into the current directory. 
  6468.  
  6469.    2. WBIND.EXE optionally runs the resource compiler on the 32-bit Windows 
  6470.       supervisor so that the 32-bit executable can have access to the 
  6471.       applications resources. 
  6472.  
  6473.    3. WBIND.EXE concatenates WIN386.EXT and the ".rex" file, and creates a 
  6474.       ".exe" file with the same name as the ".rex" file. 
  6475.  
  6476.  The following describes the syntax of the WBIND command. 
  6477.  
  6478.  
  6479.     WBIND file_spec [-d] [-n] [-q] [-s supervisor] [-R rc_options] 
  6480.  
  6481.  The square brackets [ ] denote items which are optional. 
  6482.  
  6483.  WBIND 
  6484.       is the name of the WATCOM Bind utility. 
  6485.  
  6486.  file_spec 
  6487.       is the name of the 32-bit Windows EXE to bind. 
  6488.  
  6489.  -d 
  6490.       requests that a 32-bit DLL be built. 
  6491.  
  6492.  -n 
  6493.       indicates that the resource compiler is NOT to be invoked. 
  6494.  
  6495.  -q 
  6496.       requests that WBIND run in quiet mode (no informational messages are 
  6497.       displayed). 
  6498.  
  6499.  -s supervisor 
  6500.       specifies the path and name of the Windows supervisor to be bound with 
  6501.       the application.  If not specified, a search of the paths listed in the 
  6502.       PATH environment variable is performed.  If this search is not successful 
  6503.       and the WATCOM environment variable is defined, the %WATCOM%\BINW 
  6504.       directory is searched. 
  6505.  
  6506.  -R rc_options 
  6507.       all options after -R are passed to the resource compiler. 
  6508.  
  6509.  To bind our example program, the following command may be issued: 
  6510.  
  6511.  
  6512.     C>wbind hello -n 
  6513.  
  6514.  If the "s" option is specified, it must identify the location of the 
  6515.  WIN386.EXT file or the W386DLL.EXT file (if you are building a DLL). 
  6516.  
  6517.  Example: 
  6518.  
  6519.     C>wbind hello -n -s c:\watcom\binw\win386.ext 
  6520.  
  6521.  If the "s" option is not specified, then the WATCOM environment variable must 
  6522.  be defined or the "BINW" directory must be listed in your PATH environment 
  6523.  variable. 
  6524.  
  6525.  Example: 
  6526.  
  6527.     C>set watcom=c:\watcom 
  6528.      or 
  6529.     C>path c:\watcom\binw;c:\dos;c:\windows 
  6530.  
  6531.  The resultant 32-bit Windows 3.x application HELLO.EXE can now be run under 
  6532.  Windows 3.x. 
  6533.  
  6534.  
  6535. ΓòÉΓòÉΓòÉ 17.3. 32-bit Windows:  Debugging the Sample Windows 3.x Application ΓòÉΓòÉΓòÉ
  6536.  
  6537.  
  6538. Let us assume that you wish to debug your application in order to locate an 
  6539. error in programming.  In the previous section, the "hello" program was 
  6540. compiled with default compile and link options.  When debugging an application, 
  6541. it is useful to refer to the symbolic names of routines and variables.  It is 
  6542. also convenient to debug at the source line level rather than the machine 
  6543. language level.  To do this, we must direct both the compiler and linker to 
  6544. include additional debugging information in the object and executable files. 
  6545. Using the WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  6546. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  6547. directives for the Watcom Linker. 
  6548.  
  6549. For example, to compile and link the "hello" program with debugging 
  6550. information, the following command may be issued. 
  6551.  
  6552.  
  6553.    C>wcl386 /l=win386/bt=windows  /d2 hello.c 
  6554.  
  6555. The typical messages that appear on the screen are shown in the following 
  6556. illustration. 
  6557.  
  6558.  
  6559.    C>wcl386 /l=win386 /bt=windows /d2 hello.c 
  6560.    WATCOM C/C++32 Compile and Link Utility 
  6561.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6562.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6563.        wcc386 hello.c  /bt=windows /d2 
  6564.    WATCOM C32 Optimizing Compiler 
  6565.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6566.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6567.    hello.c: 10 lines, included 6500, 0 warnings, 0 errors 
  6568.    Code size: 66 
  6569.  
  6570.    WATCOM Linker 
  6571.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6572.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6573.    loading object files 
  6574.    searching libraries 
  6575.    creating a Windows 32-bit executable 
  6576.  
  6577. The "d2" option requests the maximum amount of debugging information that can 
  6578. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  6579. debugging information is included in the executable file that is produced by 
  6580. the linker. 
  6581.  
  6582. The "Code size" value is larger than in the previous example since selection of 
  6583. the "d2" option results in fewer code optimizations by default.  You can 
  6584. request more optimization by specifying the appropriate options.  However, you 
  6585. do so at the risk of making it more difficult for yourself to determine the 
  6586. relationship between the object code and the original source language code. 
  6587.  
  6588. Once again, the ".rex" file must be combined with WATCOM's 32-bit Windows 
  6589. supervisor WIN386.EXT using the WATCOM Bind utility.  This step is described in 
  6590. the previous section. 
  6591.  
  6592. To request the Watcom Debugger to assist in debugging the application, select 
  6593. the Watcom Debugger icon.  It would be too ambitious to describe the debugger 
  6594. in this introductory chapter so we refer you to the book entitled Watcom 
  6595. Debugger User's Guide. 
  6596.  
  6597.  
  6598. ΓòÉΓòÉΓòÉ 18. 32-bit Windows:  Porting Non-GUI Applications to 32-bit Windows 3.x ΓòÉΓòÉΓòÉ
  6599.  
  6600.  
  6601. Generally, an application that is to run in a windowed environment must be 
  6602. written in such a way as to exploit the Windows Application Programming 
  6603. Interface (API).  To take an existing character-based (i.e., non-graphical) 
  6604. application that ran under a system such as DOS and adapt it to run under 
  6605. Windows can require some considerable effort.  There is a steep learning curve 
  6606. associated with the API function libraries. 
  6607.  
  6608. This chapter describes how to create a Windows application quickly and simply 
  6609. from an application that does not use the Windows API.  The application will 
  6610. make use of WATCOM's default windowing support. 
  6611.  
  6612. Suppose you have a set of C/C++ applications that previously ran under a system 
  6613. like DOS and you now wish to run them under Windows 3.x.  To achieve this, you 
  6614. can simply recompile your application with the appropriate options and link 
  6615. with the appropriate libraries.  We provide a default windowing system that 
  6616. turns your character-mode application into a simple Windows 3.x Graphical User 
  6617. Interface (GUI) application. 
  6618.  
  6619. Normally, a Windows 3.x GUI application makes use of user-interface tools such 
  6620. as menus, icons, scroll bars, etc.  However, an application that was not 
  6621. designed as a windowed application (such as a DOS application) can run as a GUI 
  6622. application.  This is achieved by our default windowing system.  The following 
  6623. sections describe the default windowing system. 
  6624.  
  6625.  
  6626. ΓòÉΓòÉΓòÉ 18.1. 32-bit Windows:  Console Device in a Windowed Environment ΓòÉΓòÉΓòÉ
  6627.  
  6628.  
  6629. In a C/C++ application that runs under DOS, stdin (C++ cin) and stdout (C++ 
  6630. cout) are connected to the standard input and standard output devices 
  6631. respectively.  It is not a recommended practice to read directly from the 
  6632. standard input device or write to the standard output device when running in a 
  6633. windowed environment.  For this reason, a default windowing environment is 
  6634. created for C/C++ applications that read from stdin (C++ cin) or write to 
  6635. stdout (C++ cout).  When your application is started, a window is created in 
  6636. which output to stdout (C++ cout) is displayed and input from stdin (C++ cin) 
  6637. is requested. 
  6638.  
  6639. In addition to the standard I/O device, it is also possible to perform I/O to 
  6640. the console by explicitly opening a file whose name is "CON".  When this 
  6641. occurs, another window is created and displayed.  This window is different from 
  6642. the one created for standard input and standard output.  In fact, every time 
  6643. you open the console device a different window is created.  This provides a 
  6644. simple multi-windowing system for multiple streams of data to and from the 
  6645. console device. 
  6646.  
  6647.  
  6648. ΓòÉΓòÉΓòÉ 18.2. 32-bit Windows:  The Sample Non-GUI Application ΓòÉΓòÉΓòÉ
  6649.  
  6650.  
  6651. To demonstrate the creation of 32-bit Windows 3.x applications, we introduce a 
  6652. simple sample program.  For our example, we are going to use the famous "hello" 
  6653. program. 
  6654.  
  6655.  
  6656.    #include <stdio.h> 
  6657.  
  6658.    void main() 
  6659.     { 
  6660.      printf( "Hello world\n" ); 
  6661.     } 
  6662.  
  6663. The C++ version of this program follows: 
  6664.  
  6665.  
  6666.    #include <iostream.h> 
  6667.    #include <iomanip.h> 
  6668.  
  6669.    void main() 
  6670.    { 
  6671.      cout << "Hello world" << endl; 
  6672.    } 
  6673.  
  6674. The goal of this program is to display the message "Hello world" on the screen. 
  6675. The C version uses the C library printf routine to accomplish this task.  The 
  6676. C++ version uses the "iostream" library to accomplish this task.  We will take 
  6677. you through the steps necessary to produce this result. 
  6678.  
  6679.  
  6680. ΓòÉΓòÉΓòÉ 18.3. 32-bit Windows:  Building and Running the Non-GUI Windows 3.x Application ΓòÉΓòÉΓòÉ
  6681.  
  6682.  
  6683. Very little effort is required to port an existing C/C++ application to Windows 
  6684. 3.x. 
  6685.  
  6686. You must compile and link the file HELLO.C specifying the "bw" option. 
  6687.  
  6688.  
  6689.    C>wcl386 /l=win386/bw/bt=windows  hello.c 
  6690.  
  6691. The typical messages that appear on the screen are shown in the following 
  6692. illustration. 
  6693.  
  6694.  
  6695.    C>wcl386 /l=win386 /bw/bt=windows hello.c 
  6696.    WATCOM C/C++32 Compile and Link Utility 
  6697.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6698.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6699.        wcc386 hello.c  /bw/bt=windows 
  6700.    WATCOM C32 Optimizing Compiler 
  6701.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6702.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6703.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  6704.    Code size: 24 
  6705.  
  6706.    WATCOM Linker 
  6707.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6708.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6709.    loading object files 
  6710.    searching libraries 
  6711.    creating a Windows 32-bit executable 
  6712.  
  6713. If you examine the current directory, you will find that two files have been 
  6714. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.REX 
  6715. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  6716. The ".rex" file must now be combined with WATCOM's 32-bit Windows supervisor 
  6717. WIN386.EXT using the WATCOM Bind utility.  WBIND.EXE combines your 32-bit 
  6718. application code and data (".rex" file) with the 32-bit Windows supervisor. 
  6719. The process involves the following steps: 
  6720.  
  6721.    1. WBIND copies WIN386.EXT into the current directory. 
  6722.  
  6723.    2. WBIND.EXE optionally runs the resource compiler on the 32-bit Windows 
  6724.       supervisor so that the 32-bit executable can have access to the 
  6725.       applications resources. 
  6726.  
  6727.    3. WBIND.EXE concatenates WIN386.EXT and the ".rex" file, and creates a 
  6728.       ".exe" file with the same name as the ".rex" file. 
  6729.  
  6730.  The following describes the syntax of the WBIND command. 
  6731.  
  6732.  
  6733.     WBIND file_spec [-d] [-n] [-q] [-s supervisor] [-R rc_options] 
  6734.  
  6735.  The square brackets [ ] denote items which are optional. 
  6736.  
  6737.  WBIND 
  6738.       is the name of the WATCOM Bind utility. 
  6739.  
  6740.  file_spec 
  6741.       is the name of the 32-bit Windows EXE to bind. 
  6742.  
  6743.  -d 
  6744.       requests that a 32-bit DLL be built. 
  6745.  
  6746.  -n 
  6747.       indicates that the resource compiler is NOT to be invoked. 
  6748.  
  6749.  -q 
  6750.       requests that WBIND run in quiet mode (no informational messages are 
  6751.       displayed). 
  6752.  
  6753.  -s supervisor 
  6754.       specifies the path and name of the Windows supervisor to be bound with 
  6755.       the application.  If not specified, a search of the paths listed in the 
  6756.       PATH environment variable is performed.  If this search is not successful 
  6757.       and the WATCOM environment variable is defined, the %WATCOM%\BINW 
  6758.       directory is searched. 
  6759.  
  6760.  -R rc_options 
  6761.       all options after -R are passed to the resource compiler. 
  6762.  
  6763.  To bind our example program, the following command may be issued: 
  6764.  
  6765.  
  6766.     C>wbind hello -n 
  6767.  
  6768.  If the "s" option is specified, it must identify the location of the 
  6769.  WIN386.EXT file or the W386DLL.EXT file (if you are building a DLL). 
  6770.  
  6771.  Example: 
  6772.  
  6773.     C>wbind hello -n -s c:\watcom\binw\win386.ext 
  6774.  
  6775.  If the "s" option is not specified, then the WATCOM environment variable must 
  6776.  be defined or the "BINW" directory must be listed in your PATH environment 
  6777.  variable. 
  6778.  
  6779.  Example: 
  6780.  
  6781.     C>set watcom=c:\watcom 
  6782.      or 
  6783.     C>path c:\watcom\binw;c:\dos;c:\windows 
  6784.  
  6785.  The resultant 32-bit Windows 3.x application HELLO.EXE can now be run under 
  6786.  Windows 3.x as a Windows GUI application. 
  6787.  
  6788.  
  6789. ΓòÉΓòÉΓòÉ 18.4. 32-bit Windows:  Debugging the Non-GUI Windows 3.x Application ΓòÉΓòÉΓòÉ
  6790.  
  6791.  
  6792. Let us assume that you wish to debug your application in order to locate an 
  6793. error in programming.  In the previous section, the "hello" program was 
  6794. compiled with default compile and link options.  When debugging an application, 
  6795. it is useful to refer to the symbolic names of routines and variables.  It is 
  6796. also convenient to debug at the source line level rather than the machine 
  6797. language level.  To do this, we must direct both the compiler and linker to 
  6798. include additional debugging information in the object and executable files. 
  6799. Using the WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  6800. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  6801. directives for the Watcom Linker. 
  6802.  
  6803. For example, to compile and link the "hello" program with debugging 
  6804. information, the following command may be issued. 
  6805.  
  6806.  
  6807.    C>wcl386 /l=win386/bw/bt=windows  /d2 hello.c 
  6808.  
  6809. The typical messages that appear on the screen are shown in the following 
  6810. illustration. 
  6811.  
  6812.  
  6813.    C>wcl386 /l=win386 /bw/bt=windows /d2 hello.c 
  6814.    WATCOM C/C++32 Compile and Link Utility 
  6815.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  6816.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6817.        wcc386 hello.c  /bw/bt=windows /d2 
  6818.    WATCOM C32 Optimizing Compiler 
  6819.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  6820.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6821.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  6822.    Code size: 45 
  6823.  
  6824.    WATCOM Linker 
  6825.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  6826.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  6827.    loading object files 
  6828.    searching libraries 
  6829.    creating a Windows 32-bit executable 
  6830.  
  6831. The "d2" option requests the maximum amount of debugging information that can 
  6832. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  6833. debugging information is included in the executable file that is produced by 
  6834. the linker. 
  6835.  
  6836. The "Code size" value is larger than in the previous example since selection of 
  6837. the "d2" option results in fewer code optimizations by default.  You can 
  6838. request more optimization by specifying the appropriate options.  However, you 
  6839. do so at the risk of making it more difficult for yourself to determine the 
  6840. relationship between the object code and the original source language code. 
  6841.  
  6842. Once again, the ".rex" file must be combined with WATCOM's 32-bit Windows 
  6843. supervisor WIN386.EXT using the WATCOM Bind utility.  This step is described in 
  6844. the previous section. 
  6845.  
  6846. To request the Watcom Debugger to assist in debugging the application, select 
  6847. the Watcom Debugger icon.  It would be too ambitious to describe the debugger 
  6848. in this introductory chapter so we refer you to the book entitled Watcom 
  6849. Debugger User's Guide. 
  6850.  
  6851.  
  6852. ΓòÉΓòÉΓòÉ 18.5. 32-bit Windows:  Default Windowing Library Functions ΓòÉΓòÉΓòÉ
  6853.  
  6854.  
  6855. A few library functions have been written to enable some simple customization 
  6856. of the default windowing system's behaviour.  The following functions are 
  6857. supplied: 
  6858.  
  6859.  _dwDeleteOnClose 
  6860.  
  6861.  
  6862.  
  6863.          int _dwDeleteOnClose( int handle ); 
  6864.  
  6865.       This function tells the console window that it should close itself when 
  6866.       the file is closed.  You must pass to it the handle associated with the 
  6867.       opened console. 
  6868.  
  6869.  _dwSetAboutDlg 
  6870.  
  6871.  
  6872.  
  6873.          int _dwSetAboutDlg( const char *title, const char *text ); 
  6874.  
  6875.       This function sets the about dialog box of the default windowing system. 
  6876.       The "title" points to the string that will replace the current title.  If 
  6877.       title is NULL then the title will not be replaced.  The "text" points to 
  6878.       a string which will be placed in the about box.  To get multiple lines, 
  6879.       embed a new line after each logical line in the string.  If "text" is 
  6880.       NULL, then the current text in the about box will not be replaced. 
  6881.  
  6882.  _dwSetAppTitle 
  6883.  
  6884.  
  6885.  
  6886.          int _dwSetAppTitle( const char *title ); 
  6887.  
  6888.       This function sets the main window's title. 
  6889.  
  6890.  _dwSetConTitle 
  6891.  
  6892.  
  6893.  
  6894.          int _dwSetConTitle( int handle, const char *title ); 
  6895.  
  6896.       This function sets the console window's title which corresponds to the 
  6897.       handle passed to it. 
  6898.  
  6899.  _dwShutDown 
  6900.  
  6901.  
  6902.  
  6903.          int _dwShutDown( void ); 
  6904.  
  6905.       This function shuts down the default windowing I/O system.  The 
  6906.       application will continue to execute but no windows will be available for 
  6907.       output. 
  6908.  
  6909.  _dwYield 
  6910.  
  6911.  
  6912.  
  6913.          int _dwYield( void ); 
  6914.  
  6915.       This function yields control back to the operating system, thereby giving 
  6916.       other processes a chance to run. 
  6917.  
  6918.  These functions are described more fully in the WATCOM C Library Reference. 
  6919.  
  6920.  
  6921. ΓòÉΓòÉΓòÉ 19. Windows:  The Watcom 32-bit Windows 3.x Extender ΓòÉΓòÉΓòÉ
  6922.  
  6923.  
  6924. Watcom C/C++ contains the necessary tools and libraries to create 32-bit 
  6925. applications for Windows 3.x.  Using Watcom C/C++ gives the programmer the 
  6926. benefits of a 32-bit flat memory model and access to the full Windows API 
  6927. (along with the usual C/C++ library functions). 
  6928.  
  6929. The general model of the environment is as follows:  The 32-bit flat memory 
  6930. model program is linked against a special 32-bit Windows library.  This library 
  6931. contains the necessary information to invoke special 16-bit functions, which 
  6932. lie in the supervisor (WIN386.EXT).  The 32-bit program is then bound (using 
  6933. WBIND.EXE) with the supervisor to create a Windows executable.  At the same 
  6934. time as the 32-bit program is being bound, the resource compiler is run on the 
  6935. supervisor, and all the resources for the application are placed there.  When 
  6936. the application is started, the supervisor obtains the 32-bit memory, relocates 
  6937. the 32-bit application into the memory, and invokes the 32-bit application. 
  6938.  
  6939. All Windows functions are invoked from the supervisor, and all callback 
  6940. routines lie within the supervisor. The local heap resides within the 
  6941. supervisor as well. 
  6942.  
  6943. If you are starting from a 16-bit Windows application, most of the code will 
  6944. not change when you port it to the 32-bit Windows environment.  However, 
  6945. because of the nature of the Windows API and its implicit dependencies on a 
  6946. 16-bit environment, some source changes are necessary.  These source changes 
  6947. are minimal, and are backwards compatible with the 16-bit environment. 
  6948.  
  6949.  
  6950. ΓòÉΓòÉΓòÉ 19.1. Windows:  Pointers ΓòÉΓòÉΓòÉ
  6951.  
  6952.  
  6953. Throughout this document, there will be references to both near and far, and 
  6954. 16-bit and 32-bit pointers.  Since this can rapidly become confusing, some 
  6955. initial explanations will be given here. 
  6956.  
  6957. A far pointer is a pointer that is composed of both a selector and an offset. 
  6958. A selector determines a specific region of memory, and the offset is relative 
  6959. to the start of this region.  A near pointer is a pointer that has an offset 
  6960. only, the selector is automatically assumed by the CPU. 
  6961.  
  6962. The problem with far pointers is the selector overhead.  Using a far pointer is 
  6963. much more expensive than using a near pointer.  This is the advantage of the 
  6964. 32-bit flat memory model - all pointers within the program are near, and yet 
  6965. you can address up to 4 gigabytes of memory. 
  6966.  
  6967. A 16-bit near pointer occupies 2 bytes of memory (i.e., the offset is 16 bits 
  6968. long).  This pointer can reference up to 64K of data. 
  6969.  
  6970. A 16-bit far pointer occupies 4 bytes of memory.  There is a 16-bit selector 
  6971. and a 16-bit offset.  This pointer can reference up to 64K of data. 
  6972.  
  6973. A 32-bit near pointer occupies 4 bytes of memory (i.e., the offset is 32 bits 
  6974. long).  This pointer can reference up to 4 gigabytes of data. 
  6975.  
  6976. A 32-bit far pointer occupies 6 bytes of memory.  There is a 16-bit selector 
  6977. and a 32-bit offset.  This pointer can reference up to 4 gigabytes of data. 
  6978.  
  6979. Windows, in general, uses 16-bit far pointers to pass information around. 
  6980. These 16-bit far pointers can also be used by a 32-bit Windows application. 
  6981. Using a special macro, MK_FP32, the offset of the 16-bit far pointer is 
  6982. extended from 16 bits to 32 bits, and the pointer becomes a 32-bit far pointer. 
  6983. The 32-bit far pointer is then used by the application to access the data (note 
  6984. that offsets still must be less than 64K, since the selector is still for a 64K 
  6985. data area). 
  6986.  
  6987.  
  6988. ΓòÉΓòÉΓòÉ 19.2. Windows:  Implementation Overview ΓòÉΓòÉΓòÉ
  6989.  
  6990.  
  6991. This section provides an overview of the issues that require consideration when 
  6992. creating a 32-bit Windows application for a 16-bit Windows environment. 
  6993.  
  6994. First, all modules have to be recompiled for the 32-bit flat memory model with 
  6995. a compiler capable of generating 32-bit instructions.  Many Windows API 
  6996. functions take int as a parameter.  This int is from the 16-bit world, and is 2 
  6997. bytes long.  In the 32-bit world, this int becomes 4 bytes long.  Since Windows 
  6998. is only expecting two bytes of data, all occurrences of int have to be changed 
  6999. to short in WINDOWS.H. 
  7000.  
  7001. Pointers to data passed to Windows are all far pointers.  We will be passing 
  7002. pointers to data in our 32-bit flat address space, and these pointers are near 
  7003. pointers.  By simply getting rid of all far keywords in WINDOWS.H, all pointers 
  7004. will now be passed as 32-bit near pointers.  As well, notice that these 32-bit 
  7005. near pointers are the same size as as their 16-bit far pointer counterparts (4 
  7006. bytes).  This is good, since all data structures containing pointers will 
  7007. remain the same size. 
  7008.  
  7009. Windows cannot be called from 32-bit code on a 32-bit stack.  This means that 
  7010. in order to call the API functions, it is necessary to write a set of cover 
  7011. functions that will accept the parameters, switch into a 16-bit environment, 
  7012. and then call Windows.  There is another issue, though.  Windows only 
  7013. understands 16-bit pointers, so before calling Windows, all pointers being 
  7014. passed to Windows must be converted to 16-bit far pointers. 
  7015.  
  7016. It turns out that Windows can also call back to your application.  Windows can 
  7017. only call 16-bit code, though, so there is a need for a bridge from the 16-bit 
  7018. side to the 32-bit side.  It is necessary to allocate 16-bit call back routines 
  7019. that can be passed to Windows.  These call back routines will then switch into 
  7020. the 32-bit environment and call whatever 32-bit function is required.  The 
  7021. 32-bit call back has to be declared as a far function, since it is necessary to 
  7022. issue a far call to enter it from the 16-bit side.  If it is a far function, 
  7023. then the compiler will generate the appropriate code for it to return from the 
  7024. far call. 
  7025.  
  7026. Once Windows calls you back, it can hand you 16-bit far pointers in a long (4 
  7027. byte) parameter.  This pointer can only be used in the 32-bit environment if it 
  7028. is a 32-bit far pointer, not a 16-bit far pointer.  The conversion is simple: 
  7029. the 16-bit offset is extended to a 32-bit offset (the high word is zeroed out). 
  7030. Any far pointer that Windows hands to you must be converted in this way. 
  7031.  
  7032. Sometimes, a Windows application wants to call a procedure in a DLL.  The 
  7033. procedure address is a 16-bit far pointer.  It is not possible to issue an 
  7034. indirect call to this address from the 32-bit environment, so some sort of 
  7035. interface is needed.  This interface would switch into the 16-bit environment, 
  7036. and then call the 16-bit function. 
  7037.  
  7038. These issues, along with other minor items, are handled by Watcom C/C++, and 
  7039. are discussed in more technical detail in later sections. 
  7040.  
  7041.  
  7042. ΓòÉΓòÉΓòÉ 19.3. Windows:  System Structure ΓòÉΓòÉΓòÉ
  7043.  
  7044.  
  7045.  
  7046. Figure 5. WIN386 Structure 
  7047.  
  7048.  
  7049. Figure 6. 32-bit Application Structure 
  7050.  
  7051.  
  7052. ΓòÉΓòÉΓòÉ 19.4. Windows:  System Overview ΓòÉΓòÉΓòÉ
  7053.  
  7054.      WIN386.EXT is the key component of a 32-bit Windows application.  It is a 
  7055.       16-bit Windows application which contains: 
  7056.         -  All application resources. 
  7057.         -  A 16-bit local heap. 
  7058.         -  A 16-bit stack. 
  7059.      W386DLL.EXT is similar to WIN386.EXT, only it provides a DLL interface. 
  7060.  
  7061.       WIN386.EXT is bound to your 32-bit application to create a 32-bit 
  7062.       application that will run under Windows 3.x.  WIN386.EXT provides the 
  7063.       following functionality: 
  7064.         -  supervisor to bring the 32-bit application into memory and start it 
  7065.            running. 
  7066.         -  "glue" functions to connect to Windows for both API and DOS 
  7067.            functionality.  This interface is designed to transparently set up 
  7068.            the calling functions' pointers and parameters to their 16-bit 
  7069.            counterparts. 
  7070.         -  "glue-back" functions to allow Windows to call back 32-bit routines. 
  7071.         -  special code to allow debugging of 32-bit applications. 
  7072.      WINDOWS.H has been specially modified for use in the 32-bit Windows 
  7073.       environment.  As well, it contains all special definitions for 32-bit 
  7074.       applications. 
  7075.      WIN386.LIB contains all the necessary library functions to connect to the 
  7076.       32-bit supervisor WIN386.EXT.  All Windows API calls and Watcom C/C++ 
  7077.       library DOS calls are found here. 
  7078.      The standard C/C++ library functions, specially modified to run in the 
  7079.       32-bit environment, are located in the \WATCOM\LIB386\WIN directory. 
  7080.      WBIND.EXE merges your 32-bit executable and the appropriate Supervisor 
  7081.       into a single executable. 
  7082.  
  7083.  
  7084. ΓòÉΓòÉΓòÉ 19.5. Windows:  Steps to Obtaining a 32-bit Application ΓòÉΓòÉΓòÉ
  7085.  
  7086.  
  7087. The following is an overview of the procedure for creating a 32-bit Windows 
  7088. Application: 
  7089.  
  7090.    1. If you are starting with a 16-bit Windows application, you must adapt 
  7091.       your source code to the 32-bit environment. 
  7092.  
  7093.    2. You must compile the application using a 32-bit compiler. 
  7094.  
  7095.    3. You must link the application with the 32-bit libraries. 
  7096.  
  7097.    4. You must bind the 32-bit application with the 32-bit supervisor. 
  7098.  
  7099.    5. You can then run and/or debug the application. 
  7100.  
  7101.  
  7102. ΓòÉΓòÉΓòÉ 20. Windows:  Windows 3.x 32-bit Programming Overview ΓòÉΓòÉΓòÉ
  7103.  
  7104.  
  7105. This chapter includes the following topics: 
  7106.  
  7107.      WINDOWS.H 
  7108.      Environment Notes 
  7109.      Floating-point Emulation 
  7110.      Multiple Instances 
  7111.      Pointer Handling 
  7112.      When To Convert Incoming Pointers 
  7113.      When To Convert Outgoing Pointers 
  7114.      SendMessage and SendDlgItemMessage 
  7115.      GlobalAlloc and LocalAlloc 
  7116.      Callback Function Pointers 
  7117.      Window Sub-classing 
  7118.      Calling 16-bit DLLs 
  7119.      Making DLL Calls Transparent 
  7120.      Far Pointer Manipulation 
  7121.      _16 Functions 
  7122.  
  7123.  
  7124. ΓòÉΓòÉΓòÉ 20.1. Windows:  WINDOWS.H ΓòÉΓòÉΓòÉ
  7125.  
  7126.  
  7127. When developing programs, make sure WINDOWS.H is included as the first include 
  7128. file in all source files.  This header file contains only the following lines: 
  7129.  
  7130.  
  7131.    #ifdef _WINDOWS_16_ 
  7132.    #include <win16.h> 
  7133.    #else 
  7134.    #include <_win386.h> 
  7135.    #endif 
  7136.  
  7137. The file WIN16.H is the regular 16-bit Windows header file, and is only 
  7138. conditionally included for 16-bit Windows applications.  The file _WIN386.H 
  7139. contains all the prototypes and macros for the 32-bit environment, as well as 
  7140. including and modifying WIN16.H.  These modifications are changing int to 
  7141. short, and changing the far keyword to nothing.  These changes (that ONLY apply 
  7142. to things defined in WIN16.H) cause all integers to be 16-bit integers, and all 
  7143. LP...  pointer types to be near pointers. 
  7144.  
  7145. Other include files for Windows must be specifically requested by defining 
  7146. macros before including WINDOWS.H.  This is required so that the same changes 
  7147. made to the primary Windows header file will apply to routines declared in the 
  7148. other header files. 
  7149.  
  7150.  #define INCLUDE_COMMDLG_H 
  7151.        COMMDLG.H 
  7152.  
  7153.  #define INCLUDE_CUSTCNTL_H 
  7154.        CUSTCNTL.H 
  7155.  
  7156.  #define INCLUDE_DDE_H 
  7157.        DDE.H 
  7158.  
  7159.  #define INCLUDE_DDEML_H 
  7160.        DDEML.H 
  7161.  
  7162.  #define INCLUDE_DRIVINIT_H 
  7163.        DRIVINIT.H 
  7164.  
  7165.  #define INCLUDE_LZEXPAND_H 
  7166.        LZEXPAND.H 
  7167.  
  7168.  #define INCLUDE_MMSYSTEM_H 
  7169.        MMSYSTEM.H 
  7170.  
  7171.  #define INCLUDE_OLE_H 
  7172.        OLE.H 
  7173.  
  7174.  #define INCLUDE_PENWIN_H 
  7175.        PENWIN.H 
  7176.  
  7177.  #define INCLUDE_PENWOEM_H 
  7178.        PENWOEM.H 
  7179.  
  7180.  #define INCLUDE_PRINT_H 
  7181.        PRINT.H 
  7182.  
  7183.  #define INCLUDE_SHELLAPI_H 
  7184.        SHELLAPI.H 
  7185.  
  7186.  #define INCLUDE_STRESS_H 
  7187.        STRESS.H 
  7188.  
  7189.  #define INCLUDE_TOOLHELP_H 
  7190.        TOOLHELP.H 
  7191.  
  7192.  #define INCLUDE_VER_H 
  7193.        VER.H 
  7194.  
  7195.  
  7196. ΓòÉΓòÉΓòÉ 20.2. Windows:  Environment Notes ΓòÉΓòÉΓòÉ
  7197.  
  7198.      The Windows functions Catch and Throw save only the 16-bit state. 
  7199.       Instead of these functions, use the setjmp and longjmp functions. 
  7200.      The 32-bit Windows Supervisor uses the first 256 bytes of the 32-bit 
  7201.       application's stack to save state information.  If this is corrupted, 
  7202.       your application will abnormally terminate. 
  7203.      The 32-bit Windows Supervisor provides resources for up to 512 callback 
  7204.       routines.  Note that this restriction is only on the maximum number of 
  7205.       active callbacks. 
  7206.  
  7207.  
  7208. ΓòÉΓòÉΓòÉ 20.3. Windows:  Floating-point Emulation ΓòÉΓòÉΓòÉ
  7209.  
  7210.  
  7211. The file WEMU387.386 is included to support floating-point emulation for 32-bit 
  7212. applications running under Windows.  This file is installed in the [386Enh] 
  7213. section of your SYSTEM.INI file.  By using the floating-point emulator, your 
  7214. application can be compiled with the "fpi87" option to use inline 
  7215. floating-point instructions, and it will run on a machine without a numeric 
  7216. coprocessor. 
  7217.  
  7218. Only one of WEMU387.386 and WDEBUG.386 may be installed in your [386Enh] 
  7219. section.  WEMU387.386 may be distributed with your application. 
  7220.  
  7221.  
  7222. ΓòÉΓòÉΓòÉ 20.4. Windows:  Multiple Instances ΓòÉΓòÉΓòÉ
  7223.  
  7224.  
  7225. Since the 32-bit application resides in a flat memory space, it is NOT possible 
  7226. to share code with other instances.  This means that you must register new 
  7227. window classes with callbacks into the new instance's code space.  A simple way 
  7228. of accomplishing this is as follows: 
  7229.  
  7230.  
  7231.    int PASCAL WinMain( HANDLE hInstance, 
  7232.              HANDLE hPrevInstance; 
  7233.              LPSTR lpCmdLine, 
  7234.              int nCmdShow ); 
  7235.    { 
  7236.      WNDCLASS  wc; 
  7237.      HWND    hWnd 
  7238.      char    class[32]; 
  7239.  
  7240.      wc.style = NULL; 
  7241.      wc.lpfnWndProc = (LPVOID) MainWndProc; 
  7242.      wc.cbClsExtra = 0; 
  7243.      wc.cbWndExtra = 0; 
  7244.      wc.hInstance = hInstance; 
  7245.      wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); 
  7246.      wc.hCursor = LoadCursor( NULL, IDC_ARROW ); 
  7247.      wc.hbrBackground = GetStockObject( WHITE_BRUSH ); 
  7248.      wc.lpszMenuName = "Menu"; 
  7249.      sprintf( class,"Class%d",hInstance ); 
  7250.      wc.lpszClassName = class; 
  7251.      RegisterClass( &wc ); 
  7252.  
  7253.      hWnd = CreateWindow( 
  7254.        class, 
  7255.        "Application", 
  7256.        WS_OVERLAPPEDWINDOW, 
  7257.        CW_USEDEFAULT, 
  7258.        CW_USEDEFAULT, 
  7259.        CW_USEDEFAULT, 
  7260.        CW_USEDEFAULT, 
  7261.        NULL, 
  7262.        NULL, 
  7263.        hInstance, 
  7264.        NULL 
  7265.      ); 
  7266.  
  7267. The variable class contains a unique name based on the instance of the 
  7268. application. 
  7269.  
  7270.  
  7271. ΓòÉΓòÉΓòÉ 20.5. Windows:  Pointer Handling ΓòÉΓòÉΓòÉ
  7272.  
  7273.  
  7274. Windows 3.x is a 16-bit operating system.  Function pointers that Windows deals 
  7275. with are 16-bit far pointers, and any data you communicate to Windows with are 
  7276. 16-bit far pointers.  16-bit far pointers occupy 4 bytes of data, and are 
  7277. capable of addressing up to 64K.  For data objects larger than 64K, huge 
  7278. pointers are used (a sequence of far pointers that map out consecutive 64K 
  7279. segments for the data object).  16-bit far pointers are expensive to use due to 
  7280. the overhead of selector loads (each time you use the pointer, a segment 
  7281. register must have a value put in it).  16-bit huge pointers are even more 
  7282. expensive:  not only is there the overhead of selector loads, but a run-time 
  7283. call is necessary to perform any pointer arithmetic. 
  7284.  
  7285. In a 32-bit flat memory model, such as that of the Watcom C/C++ for Windows 
  7286. environment, all pointers are 32-bit near pointers (occupying 4 bytes of data 
  7287. as well).  However, these pointers may access objects of up to 4 gigabytes in 
  7288. size, and there is no selector load overhead. 
  7289.  
  7290. All Windows defined pointer types (e.g., LPSTR) are by default near pointers, 
  7291. not far pointers.  To obtain a far pointer, the far keyword must be explicitly 
  7292. coded, i.e., char far *foo, rather than LPSTR foo.  A 32-bit near pointer is 
  7293. the same size as a 16-bit far pointer, so that all Windows pointers are the 
  7294. same size in the 32-bit flat memory model as they are in the original 16-bit 
  7295. segmented model. 
  7296.  
  7297. For a 32-bit environment to communicate with Windows 3.x, there are some 
  7298. considerations.  All pointers sent to Windows must be converted from 32-bit 
  7299. near pointers to 16-bit far pointers.  These conversions are handled by the 
  7300. Supervisor. 
  7301.  
  7302. It is important to remember that all API functions which accept pointers (with 
  7303. the exception of functions that accept function pointers) accept 32-bit near 
  7304. pointers in this 32-bit model.  If you attempt to pass a 32-bit far pointer, 
  7305. the conversion will not take place correctly. 
  7306.  
  7307. 16-bit far pointers to data may be passed into the API functions, and the 
  7308. Supervisor will not do any conversion. 
  7309.  
  7310. Incoming pointers must be converted from 16-bit far pointers to 32-bit far 
  7311. pointers.  This conversion is a trivial one:  the offset portion of the 16-bit 
  7312. far pointer is extended to 32-bits.  Pointers from Windows are by their nature 
  7313. far (that is, the data is pointed to by its own selector), and must be used as 
  7314. far in the 32-bit environment.  Of course, conversions are only required if you 
  7315. actually need to reference the pointer. 
  7316.  
  7317. Function pointers (i.e., pointers to callback routines) used by Windows are not 
  7318. converted from 32-bit to 16-bit.  Rather, a 16-bit thunking layer that 
  7319. transfers control from the 16-bit environment to the 32-bit environment must be 
  7320. used.  This thunking layer is provided by the Supervisor. 
  7321.  
  7322.  
  7323. ΓòÉΓòÉΓòÉ 20.5.1. Windows:  When To Convert Incoming Pointers ΓòÉΓòÉΓòÉ
  7324.  
  7325.  
  7326. Whenever you wish to use a pointer passed to you by Windows, you must convert 
  7327. it to a 32-bit far pointer.  If you are passed a 16-bit far pointer, the macro 
  7328. MK_FP32 can be used to convert it to a 32-bit far pointer.  If you are passed a 
  7329. 16-bit near pointer (e.g., from LocalLock ), then the macro MK_LOCAL32 can be 
  7330. used to convert it to a 32-bit far pointer. 
  7331.  
  7332. Some places where pointer conversion may be required are: 
  7333.  
  7334.      LocalLock 
  7335.      GlobalLock 
  7336.      the lParam in a window callback routine (if it is a pointer) 
  7337.  
  7338.  
  7339. ΓòÉΓòÉΓòÉ 20.5.2. Windows:  When To Convert Outgoing Pointers ΓòÉΓòÉΓòÉ
  7340.  
  7341.  
  7342. Typically, there is no need to do any kind of conversions on your pointers when 
  7343. passing them to Windows.  The Supervisor handles all 32-bit to 16-bit 
  7344. translations for you, in the case of the regular Windows API functions. 
  7345. However, if you are passing a 32-bit pointer to some other 16-bit application 
  7346. in the Windows environment, then pointer conversions must by done.  There are 
  7347. two types of "outgoing" pointers:  data pointers and function pointers. 
  7348.  
  7349. Function pointers (to callback routines) must have a thunking layer provided, 
  7350. using the GetProc16 function (this is explained in detail in a later section). 
  7351.  
  7352. Data pointers can be translated from 32-bit to 16-bit using the AllocAlias16 
  7353. and AllocHugeAlias16 functions.  These functions create 16-bit far pointers 
  7354. that have the same linear address as the 32-bit near pointer that was 
  7355. converted. 
  7356.  
  7357. It is important to remember that when passing a pointer to a data structure in 
  7358. this fashion, any pointers in the data structure must also be converted. 
  7359.  
  7360. The Supervisor will convert any pointers that it knows about; but there are 
  7361. some complications created by the fact that Windows allows you to pass pointers 
  7362. in functions that are prototyped to take a long integer. 
  7363.  
  7364. The Windows API functions SendMessage and SendDlgItemMessage rely on other 
  7365. fields determining the nature of the long data item that they accept; this is 
  7366. discussed in detail in the next section. 
  7367.  
  7368.  
  7369. ΓòÉΓòÉΓòÉ 20.5.2.1. Windows:  SendMessage and SendDlgItemMessage ΓòÉΓòÉΓòÉ
  7370.  
  7371.  
  7372. SendMessage and SendDlgItemMessage have special cover functions that determine 
  7373. when the long integer is really a pointer and needs to be converted.  These 
  7374. cover functions are used automatically, unless the macro NOCOVERSENDS is 
  7375. defined before including  WINDOWS.H as in the following example. 
  7376.  
  7377.  
  7378.    #define NOCOVERSENDS 
  7379.    #include <windows.h> 
  7380.  
  7381. SendMessage and SendDlgItemMessage will do pointer conversions automatically 
  7382. using AllocAlias16 and FreeAlias16 (unless NOCOVERSENDS is defined) for the 
  7383. following message types: 
  7384.  
  7385.      combo boxes (CB_ messages) 
  7386.      edit controls (EM_ messages) 
  7387.      list boxes (LB_ messages) 
  7388.      certain windows messages (WM_ messages); 
  7389.  
  7390.  The messages that are intercepted by the cover functions for SendMessage and 
  7391.  SendDlgItemMessage are: 
  7392.  
  7393.  
  7394.     CB_ADDSTRING   CB_DIR      CB_FINDSTRING 
  7395.     CB_GETLBTEXT   CB_INSERTSTRING  CB_SELECTSTRING 
  7396.  
  7397.     EM_GETLINE    EM_GETRECT    EM_REPLACESEL 
  7398.     EM_SETRECT    EM_SETRECTNP   EM_SETTABSTOPS 
  7399.  
  7400.     LB_ADDSTRING   LB_DIR      LB_FINDSTRING 
  7401.     LB_GETITEMRECT  LB_GETSELITEMS  LB_GETTEXT 
  7402.     LB_INSERTSTRING  LB_SELECTSTRING  LB_SETTABSTOPS 
  7403.  
  7404.     WM_MDICREATE   WM_NCCALCSIZE 
  7405.  
  7406.  Note that for SendMessage and SendDlgItemMessage, some of the messages may NOT 
  7407.  require pointer conversion: 
  7408.  
  7409.      CB_ADDSTRING, CB_FINDSTRING, CB_INSERTSTRING will not need a conversion 
  7410.       if the combo box was created as owner-draw style without CBS_HASSTRINGS 
  7411.       style. 
  7412.      LB_ADDSTRING, LB_FINDSTRING, LB_INSERTSTRING will not need a conversion 
  7413.       if the list box was created as owner-draw style without LBS_HASSTRINGS 
  7414.       style. 
  7415.  
  7416.  The macro NOCOVERSENDS should be defined in modules where messages like these 
  7417.  are being sent.  With these messages, the lParam data item does not contain a 
  7418.  pointer, and the automatic pointer conversion would be incorrect. By doing 
  7419.  
  7420.  
  7421.     #define NOCOVERSENDS 
  7422.     #include "windows.h" 
  7423.  
  7424.  modules that send messages like the above will not have the pointer conversion 
  7425.  performed. 
  7426.  
  7427.  
  7428. ΓòÉΓòÉΓòÉ 20.5.3. Windows:  GlobalAlloc and LocalAlloc ΓòÉΓòÉΓòÉ
  7429.  
  7430.  
  7431. The functions GlobalAlloc and LocalAlloc are the typical way of allocating 
  7432. memory in the 16-bit Windows environment.  In the 32-bit environment, there is 
  7433. no need to use these functions.  The only time GlobalAlloc is needed is when 
  7434. allocating shared memory, i.e., GMEM_DDESHARE. 
  7435.  
  7436. The C runtime functions malloc and free manipulate your 32-bit near heap for 
  7437. you.  By using these functions to allocate memory, you may create data objects 
  7438. as large as the enhanced mode Windows memory manager will permit. 
  7439.  
  7440.  
  7441. ΓòÉΓòÉΓòÉ 20.5.4. Windows:  Callback Function Pointers ΓòÉΓòÉΓòÉ
  7442.  
  7443.  
  7444. To access a callback function, an instance of it must be created using 
  7445. MakeProcInstance.  This creates a "thunk" (a special piece of code) that 
  7446. automatically puts the application's data segment into the AX register, and 
  7447. then calls the specified callback function. 
  7448.  
  7449. In Windows 3.x, it is not possible to do a MakeProcInstance directly on a 
  7450. 32-bit callback routine, since Windows 3.x does not understand 32-bit 
  7451. applications.  Therefore, it is necessary to use a 16-bit callback routine that 
  7452. passes control to the 32-bit callback routine.  This 16-bit callback routine is 
  7453. automatically created by the Supervisor when using any of the standard Windows 
  7454. API functions that accept a callback routine. 
  7455.  
  7456. The 16-bit callback routine for a 32-bit application is a special layer that 
  7457. transfers the parameters from a 16-bit stack to the 32-bit stack, and then 
  7458. passes control to 32-bit code.  These 16-bit callback routines are found in the 
  7459. Supervisor.  The function GetProc16 provides pointers to these 16-bit callback 
  7460. routines. 
  7461.  
  7462. However, it is not often necessary to use the GetProc16 function to obtain a 
  7463. 16-bit/32-bit callback interface function. 
  7464.  
  7465. In the general case, one would have to write code as follows: 
  7466.  
  7467.  
  7468.    #define NOAUTOPROCS 
  7469.    #include <windows.h> 
  7470.  
  7471.    CALLBACKPTR   pCb; 
  7472.    FARPROC     fpProc; 
  7473.  
  7474.    pCb = GetProc16( A_Function, GETPROC_callbacktype ); 
  7475.    fpProc = MakeProcInstance( pCb, hInstance ); 
  7476.  
  7477.    /* do stuff */ 
  7478.  
  7479.    Do_it( ..., fpProc, ... ); 
  7480.  
  7481.    /* do more stuff */ 
  7482.  
  7483.    FreeProcInstance( fpProc ); 
  7484.    ReleaseProc16( pCb ); 
  7485.  
  7486. It is not necessary to use this general code in the case of the regular Windows 
  7487. API functions.  The following functions will automatically allocate the correct 
  7488. 16-bit/32-bit callback interface functions: 
  7489.  
  7490.      ChooseColor 
  7491.      ChooseFont 
  7492.      CorrectWriting 
  7493.      CreateDialog 
  7494.      CreateDialogIndirect 
  7495.      CreateDialogIndirectParam 
  7496.      CreateDialogParam 
  7497.      DdeInitialize 
  7498.      DialogBox 
  7499.      DialogBoxIndirect 
  7500.      DialogBoxIndirectParam 
  7501.      DialogBoxParam 
  7502.      DictionarySearch 
  7503.      EnumChildWindows 
  7504.      EnumFontFamilies 
  7505.      EnumFonts 
  7506.      EnumMetaFile 
  7507.      EnumObjects 
  7508.      EnumProps 
  7509.      EnumSymbols 
  7510.      EnumTaskWindows 
  7511.      EnumWindows 
  7512.      Escape (SETABORTPROC option) 
  7513.      FindText 
  7514.      GetOpenFileName 
  7515.      GetSaveFileName 
  7516.      GlobalNotify 
  7517.      GrayString 
  7518.      LineDDA 
  7519.      mciSetYieldProc 
  7520.      mmioInstallIOProc 
  7521.      NotifyRegister 
  7522.      PrintDlg 
  7523.      ProcessWriting 
  7524.      Recognize 
  7525.      RecognizeData 
  7526.      RegisterClass 
  7527.      ReplaceText 
  7528.      SetClassLong (GCL_WNDPROC option) 
  7529.      SetPenHook 
  7530.      SetResourceHandler 
  7531.      SetTimer 
  7532.      SetWindowLong (GWL_WNDPROC option) 
  7533.      SetWindowsHook 
  7534.      SetWindowsHookEx 
  7535.      TrainInk 
  7536.  
  7537.  As well, the following functions are covered to provide support for automatic 
  7538.  creation of 16-bit callback routines: 
  7539.  
  7540.      FreeProcInstance 
  7541.      MakeProcInstance 
  7542.      UnhookWindowsHook 
  7543.  
  7544.  If you need to get a callback that is not used by one of the above functions, 
  7545.  then you must code the general case.  Typically, this is required when a DLL 
  7546.  needs a callback routine.  In modules where this is necessary, you define the 
  7547.  macro NOAUTOPROCS before you include WINDOWS.H as in the following example. 
  7548.  
  7549.  
  7550.     #define NOAUTOPROCS 
  7551.     #include <windows.h> 
  7552.  
  7553.  Be careful of the following when using NOAUTOPROCS. 
  7554.  
  7555.    1. The call to MakeProcInstance and FreeProcInstance for the callback 
  7556.       function occurs in a module with NOAUTOPROCS defined. 
  7557.  
  7558.    2. No Windows API functions (listed above) are used in the module with 
  7559.       NOAUTOPROCS defined.  If they are, you must code the general case to use 
  7560.       them. 
  7561.  
  7562.  Note that NOAUTOPROCS is in effect on a module-to-module basis only. 
  7563.  
  7564.  You can avoid using NOAUTOPROCS on a call-by-call basis, if you do the 
  7565.  following: 
  7566.  
  7567.  
  7568.     #undef <function> 
  7569.     <function> 
  7570.     Note: re-defining is only needed if you want to 
  7571.        use a covered version of the function later on. 
  7572.     #define <function> _Cover_<function> 
  7573.  
  7574.  For example: 
  7575.  
  7576.  
  7577.     { 
  7578.     #undef SetWindowsHook 
  7579.     #undef MakeProcInstance 
  7580.  
  7581.       FARPROC fp,oldfp; 
  7582.       CALLBACKPTR cbp; 
  7583.  
  7584.       cbp = GetProc16( CallbackHook, GETPROC_CALLBACK ); 
  7585.       fp = MakeProcInstance( cbp, hInstance ); 
  7586.       oldfp = SetWindowsHook( WH_CALLWNDPROC, fp ); 
  7587.  
  7588.     } 
  7589.  
  7590.  This allows you to add general case code in the same module, without having to 
  7591.  break the module into two parts. 
  7592.  
  7593.  RegisterClass automatically does a GetProc16 for the callback function, unless 
  7594.  the macro NOCOVERRC is specified before including WINDOWS.H as in the 
  7595.  following example. 
  7596.  
  7597.  
  7598.     #define NOCOVERRC 
  7599.     #include <windows.h> 
  7600.  
  7601.  
  7602. ΓòÉΓòÉΓòÉ 20.5.4.1. Windows:  Window Sub-classing ΓòÉΓòÉΓòÉ
  7603.  
  7604.  
  7605. Sub-classing a Windows control in the 32-bit environment is straightforward. 
  7606. In fact, the code is identical to the code used in the 16-bit environment.  A 
  7607. simple example is: 
  7608.  
  7609.  
  7610.    FARPROC fpOldProc; 
  7611.  
  7612.    long FAR PASCAL SubClassProc( HWND hWnd, 
  7613.                   unsigned message, 
  7614.                   WORD wParam, 
  7615.                   LONG lParam ) 
  7616.    { 
  7617.      /* 
  7618.      * code for sub-classing here 
  7619.      */ 
  7620.      return( CallWindowProc( fpOldProc, hWnd, message, 
  7621.                  wParam, lParam ) ); 
  7622.    } 
  7623.  
  7624.  
  7625.    void SubClassDemo( void ) 
  7626.    { 
  7627.      HWND         hControl; 
  7628.      FARPROC       fp; 
  7629.      extern HANDLE    ProgramInstance; 
  7630.  
  7631.      /* assume hControl gets created in here */ 
  7632.  
  7633.      fpOldProc = (FARPROC) GetWindowLong( hControl, GWL_WNDPROC ); 
  7634.      fp = MakeProcInstance( SubClassProc, ProgramInstance ); 
  7635.      SetWindowLong( hControl, GWL_WNDPROC, (LONG) fp ); 
  7636.  
  7637.      /* set it back */ 
  7638.      SetWindowLong( hControl, GWL_WNDPROC, (LONG) fpOldProc ); 
  7639.      FreeProcInstance( fp ); 
  7640.    } 
  7641.  
  7642. Note that SetWindowLong is covered to recognize GWL_WNDPROC and automatically 
  7643. creates a 16-bit callback for the 32-bit callback.  When replacing the callback 
  7644. routine with the original 16-bit routine, the covered version of SetWindowLong 
  7645. recognizes that the function is not a 32-bit callback, and so passes the 
  7646. pointer right through to Windows unchanged. 
  7647.  
  7648.  
  7649. ΓòÉΓòÉΓòÉ 20.6. Windows:  Calling 16-bit DLLs ΓòÉΓòÉΓòÉ
  7650.  
  7651.  
  7652. A 16-bit function in a DLL can be called using the _Call16 function.  The first 
  7653. argument to _Call16 is the address of the 16-bit function.  This address is 
  7654. usually obtained by calling GetProcAddress with the name of the desired 
  7655. function.  The second argument to _Call16 is a string identifying the types of 
  7656. the parameters to be passed to the 16-bit function. 
  7657.  
  7658.  c 
  7659.       call a 'cdecl' function as opposed to a 'pascal' function (if specified, 
  7660.       it must be listed first) 
  7661.  
  7662.  b 
  7663.       unsigned BYTE 
  7664.  
  7665.  w 
  7666.       16-bit WORD 
  7667.  
  7668.  d 
  7669.       32-bit DWORD 
  7670.  
  7671.  f 
  7672.       double precision floating-point 
  7673.  
  7674.  p 
  7675.       32-bit flat pointer (converted to 16:16 far pointer) 
  7676.  
  7677.  The 16-bit function must use either the PASCAL or CDECL calling convention. 
  7678.  PASCAL calling convention is the default.  If the function uses the CDECL 
  7679.  calling convention, then you must specify the letter "c" as the first 
  7680.  character of the argument type string. 
  7681.  
  7682.  Pointer types will automatically be converted from 32-bit near pointers to 
  7683.  16-bit far pointers before the function is invoked.  Note that this pointer is 
  7684.  only valid over the period of the call; after control returns to the 32-bit 
  7685.  application, the 16-bit pointer created by the Supervisor is no longer valid. 
  7686.  
  7687.  The return value from _Call16 is a DWORD. 
  7688.  
  7689.  
  7690.     #include <windows.h> 
  7691.     HANDLE hDrv; 
  7692.     FARPROC lpfn; 
  7693.     int cb; 
  7694.  
  7695.       if( (hDrv = LoadLibrary ("foo.dll")) < 32 ) 
  7696.         return FALSE; 
  7697.       if( !(lpfn = GetProcAddress (hDrv, "ExtDeviceMode")) ) 
  7698.         return FALSE; 
  7699.  
  7700.       /* 
  7701.       * now, invoke the function 
  7702.       */ 
  7703.       cb = (WORD) _Call16( 
  7704.          lpfn,         // address of function 
  7705.          "wwdppddw",      // parameter type info 
  7706.          hwnd,         // parameters ... 
  7707.          hDrv, 
  7708.          NULL, 
  7709.          "POSTSCRIPT PRINTER", 
  7710.          "LPT1", 
  7711.          NULL, 
  7712.          NULL, 
  7713.          0 
  7714.           ); 
  7715.  
  7716.  
  7717. ΓòÉΓòÉΓòÉ 20.6.1. Windows:  Making DLL Calls Transparent ΓòÉΓòÉΓòÉ
  7718.  
  7719.  
  7720. This section gives an example of how to make your source code look as if you 
  7721. are calling the 16-bit DLL directly. 
  7722.  
  7723. Assume there are 3 functions that you want to call in the 16-bit DLL, with 
  7724. prototypes as follows: 
  7725.  
  7726.  
  7727.    HWND FAR PASCAL Initialize( WORD start_code ); 
  7728.    BOOL FAR PASCAL DoStuff( HWND win_hld, HDC win_dc ); 
  7729.    void FAR PASCAL Finish( void ); 
  7730.  
  7731. A fragment from the header file that you would include in your 32-bit 
  7732. application would be as follows: 
  7733.  
  7734.  
  7735.    extern FARPROC InitializeAddr; 
  7736.    extern FARPROC DoStuffAddr; 
  7737.    extern FARPROC FinishAddr; 
  7738.    #define Initialize( start_code ) \ 
  7739.     _Call16( InitializeAddr, "w", (WORD)start_code ) 
  7740.    #define DoStuff( win_hld, data ) \ 
  7741.     _Call16( DoStuffAddr, "wp", (HWND)win_hld, (LPVOID)data ) 
  7742.    #define Finish( void )  _Call16( FinishAddr, "" ) 
  7743.  
  7744. The header file fragment gives external references for the function addresses 
  7745. for each function, and sets up macros do a _Call16 for each of the functions. 
  7746.  
  7747. At start up, you would call the following function: 
  7748.  
  7749.  
  7750.    /* 
  7751.    * LoadDLL - get DLL ready for 32-bit use 
  7752.    */ 
  7753.    BOOL LoadDLL( void ) 
  7754.    { 
  7755.      HANDLE  dll; 
  7756.  
  7757.      dll = LoadLibrary( "chart.dll" ); 
  7758.      if( dll < 32 ) return( FALSE); 
  7759.  
  7760.      InitializeAddr = GetProcAddress( dll, "Initialize" ); 
  7761.      DoStuffAddr = GetProcAddress( dll, "DoStuff" ); 
  7762.      FinishAddr = GetProcAddress( dll, "Finish" ); 
  7763.      return( TRUE ); 
  7764.    } 
  7765.  
  7766. This function loads the 16-bit DLL and gets the addresses for all of the entry 
  7767. points in the DLL.  By including the header file with all the macros in it, you 
  7768. can code calls to the DLL functions as if you were calling the functions 
  7769. directly.  For example: 
  7770.  
  7771.  
  7772.    #include <windows.h> 
  7773.    #include "fragment.h" 
  7774.    char *data = "the data"; 
  7775.  
  7776.    void TestDLL( void ) 
  7777.    { 
  7778.      HWND res; 
  7779.  
  7780.      if( !LoadDLL() ) { 
  7781.        MessageBox( NULL, "Could not load DLL", 
  7782.              "Error", MB_OK ); 
  7783.        return; 
  7784.      } 
  7785.  
  7786.      res = Initialize( 1 ); 
  7787.      DoStuff( res, data ); 
  7788.      Finish(); 
  7789.    } 
  7790.  
  7791.  
  7792. ΓòÉΓòÉΓòÉ 20.7. Windows:  Far Pointer Manipulation ΓòÉΓòÉΓòÉ
  7793.  
  7794.  
  7795. The following C library functions are available for manipulating far data. 
  7796. These are useful when using pointers obtained by MK_FP32 and MK_LOCAL32. 
  7797.  
  7798. Memory manipulation: 
  7799.  
  7800.      _fmemccpy 
  7801.      _fmemchr 
  7802.      _fmemcmp 
  7803.      _fmemcpy 
  7804.      _fmemicmp 
  7805.      _fmemmove 
  7806.      _fmemset 
  7807.  
  7808.  String manipulation: 
  7809.  
  7810.      _fstrcat 
  7811.      _fstrchr 
  7812.      _fstrcmp 
  7813.      _fstrcpy 
  7814.      _fstrcspn 
  7815.      _fstricmp 
  7816.      _fstrlen 
  7817.      _fstrlwr 
  7818.      _fstrncat 
  7819.      _fstrncmp 
  7820.      _fstrncpy 
  7821.      _fstrnicmp 
  7822.      _fstrnset 
  7823.      _fstrpbrk 
  7824.      _fstrrchr 
  7825.      _fstrrev 
  7826.      _fstrset 
  7827.      _fstrspn 
  7828.      _fstrtok 
  7829.      _fstrupr 
  7830.  
  7831.  
  7832. ΓòÉΓòÉΓòÉ 20.8. Windows:  _16 Functions ΓòÉΓòÉΓòÉ
  7833.  
  7834.  
  7835. Every Windows API function that accepts a pointer has a corresponding _16 
  7836. function.  The _16 version of the function will not convert any of the pointers 
  7837. that it accepts; it will assume that all pointers are 16-bit far pointers 
  7838. already.  This applies to both data and function pointers. 
  7839.  
  7840. Some sample code demonstrating the use for this is: 
  7841.  
  7842.  
  7843.    void ReadEditBuffer( char *fname, HWND hwndEdit ) 
  7844.    { 
  7845.      int    file; 
  7846.      HANDLE   hText; 
  7847.      char far *flpData; 
  7848.      LPSTR   lpData; 
  7849.      WORD    filelen; 
  7850.  
  7851.      /* 
  7852.      * no error checking is performed; we just 
  7853.      * assume everything works for this example. 
  7854.      */ 
  7855.      file = _lopen( fname, 0); 
  7856.      filelen = _llseek( file, 0L, 2 ); 
  7857.  
  7858.      hText = (HANDLE) SendMessage( hwndEdit, EM_GETHANDLE, 
  7859.                     0, 0L ); 
  7860.      LocalReAlloc( hText, filelen+1, LHND ); 
  7861.      flpData = MK_LOCAL32( LocalLock( hText ) ); 
  7862.      lpData = (LPSTR) MK_FP16( flpB ); 
  7863.      _16_lread( file, lpData, filelen ); 
  7864.      _lclose( file ); 
  7865.  
  7866.    } 
  7867.  
  7868. This example reads the contents of a file into the buffer of an edit window. 
  7869. Because the edit window's memory is located in the local heap, which is the 
  7870. Supervisor's heap, the MK_LOCAL32 function is needed to access the data.  The 
  7871. MK_FP16 macro compresses the 32-bit far pointer into a 16-bit far pointer, 
  7872. which can then be used by the _16_lread function. 
  7873.  
  7874.  
  7875. ΓòÉΓòÉΓòÉ 21. Windows:  Windows 32-Bit Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  7876.  
  7877.  
  7878. Watcom C/C++ allows the creation of 32-bit Dynamic Link Libraries (DLL).  In 
  7879. fact, 32-bit DLLs are simpler to write than 16-bit DLLs.  A 16-bit DLL runs on 
  7880. the caller's stack, and thus DS != SS.  This creates difficulties in the small 
  7881. and medium memory models because near pointers to local variables are different 
  7882. from near pointers to global variables.  The 32-bit DLL runs on its own stack, 
  7883. in the usual flat memory space, which eliminates these concerns. 
  7884.  
  7885. There is a special version of the supervisor, W386DLL.EXT that performs a 
  7886. similar job to WIN386.EXT.  However, the 32-bit DLL supervisor is a 16-bit 
  7887. Windows DLL, rather than a 16-bit Windows application.  On the first use of the 
  7888. 32-bit DLL, the DLL supervisor loads the 32-bit DLL and invokes the 32-bit 
  7889. initialization routine (the DLL's WinMain routine).  The initialization routine 
  7890. declares all entry points (via DefineDLLEntry) and performs any other necessary 
  7891. initialization.  An index number in the range 1 to 128 is used to identify all 
  7892. external 32-bit DLL routines.  DefineDLLEntry is used to assign an index number 
  7893. to each routine, as well as to identify the arguments. 
  7894.  
  7895. The DLL supervisor contains a general entry point for Windows applications to 
  7896. call into called Win386LibEntry.  It also contains 128 specific entry points 
  7897. called DLL1 to DLL128 which correspond to the entry points established via 
  7898. DefineDLLEntry (the first argument to DefineDLLEntry is an index number in the 
  7899. range 1 to 128).  These entry points are FAR PASCAL functions.  All 
  7900. applications call into the 32-bit DLL via these entry points.  They build the 
  7901. necessary stack frame and switch to the 32-bit DLL's data space. 
  7902.  
  7903. If you call via Win386LibEntry then you pass the DLL entry point number or 
  7904. index (1 to 128) as the last argument.  Win386LibEntry uses this index number 
  7905. to call the appropriate 32-bit DLL routine.  From a pseudo-code point of view, 
  7906. the 16-bit supervisor might look like the following: 
  7907.  
  7908.  
  7909.    DLL1::  set index=1 
  7910.        invoke 32bitDLLindirect 
  7911.  
  7912.    DLL2::  set index=2 
  7913.        invoke 32bitDLLindirect 
  7914.          . 
  7915.          . 
  7916.          . 
  7917.    DLL128:: set index=128 
  7918.        invoke 32bitDLLindirect 
  7919.  
  7920.    Win386LibEntry:: 
  7921.        set index from index_argument 
  7922.        invoke 32bitDLLindirect 
  7923.  
  7924.    32bitDLLindirect: 
  7925.        set up stack frame 
  7926.        switch to 32-bit data space 
  7927.        call indirect registration_list[ index ] 
  7928.          . 
  7929.          . 
  7930.          . 
  7931.  
  7932. When you are creating a 32-bit DLL, keep in mind that the entry points you 
  7933. define may be invoked by a 16-bit application as well as a 32-bit application. 
  7934. It is for this reason that all far pointers passed to a 32-bit DLL are 16-bit 
  7935. far pointers.  Hence, whenever a pointer is passed as an argument to a 32-bit 
  7936. DLL entry point and you wish to access the data it points to, you must convert 
  7937. the pointer appropriately. 
  7938.  
  7939.  
  7940. ΓòÉΓòÉΓòÉ 21.1. Windows:  A Sample 32-bit DLL ΓòÉΓòÉΓòÉ
  7941.  
  7942.  
  7943. Let us begin our discussion of DLLs by showing the code for a simple DLL.  The 
  7944. source code for these examples is provided in the \WATCOM\SAMPLES\DLL 
  7945. directory.  We describe how to compile and link the examples in the section 
  7946. entitled Windows:  Creating and Debugging Dynamic Link Libraries.  The code for 
  7947. this DLL can be compiled with the 16-bit compiler to produce a 16-bit DLL and 
  7948. it can can be compiled with the 32-bit compiler to produce a 32-bit DLL.  The 
  7949. example illustrates the fundamental differences between the two types of DLLs. 
  7950. The 32-bit DLL has a WinMain routine and the 16-bit DLL has a LibMain routine. 
  7951.  
  7952. Example: 
  7953.  
  7954.    /* 
  7955.    *  DLL.C 
  7956.    */ 
  7957.    #include <stdio.h> 
  7958.    #include <windows.h> 
  7959.  
  7960.    #if defined(__386__)/* if we are doing a 32-bit DLL */ 
  7961.     #define DLL_ID "DLL32" 
  7962.    #else        /* else we are doing a 16-bit DLL */ 
  7963.     #define DLL_ID "DLL16" 
  7964.    #endif 
  7965.  
  7966.  
  7967.    long FAR PASCAL __export FooMe1(WORD w1, DWORD w2, WORD w3) 
  7968.    { 
  7969.     char buff[128]; 
  7970.  
  7971.     sprintf( buff, "FooMe1: w1=%hx, w2=%lx, w3=%hx", 
  7972.         w1, w2, w3 ); 
  7973.     MessageBox( NULL, buff, DLL_ID, MB_OK ); 
  7974.     return( w1 + w2 ); 
  7975.    } 
  7976.  
  7977.  
  7978.    long FAR PASCAL __export FooMe2( DWORD w1, WORD w2 ) 
  7979.    { 
  7980.     char buff[128]; 
  7981.  
  7982.     sprintf( buff, "FooMe2: w1=%lx, w2=%hx", w1, w2 ); 
  7983.     MessageBox( NULL, buff, DLL_ID, MB_OK ); 
  7984.     return( w1 + 1 ); 
  7985.    } 
  7986.  
  7987.  
  7988.    #if defined(__386__)/* if we are doing a 32-bit DLL */ 
  7989.    long PASCAL WinMain( HANDLE hInstance, 
  7990.              HANDLE hPrevInstance, 
  7991.              LPSTR  lpszCmdLine, 
  7992.              int   nCmdShow ) 
  7993.    { 
  7994.     if( DefineDLLEntry( 1, (void *) FooMe1, DLL_WORD, 
  7995.           DLL_DWORD, DLL_WORD, DLL_ENDLIST )) { 
  7996.       return( 0 ); 
  7997.     } 
  7998.     if( DefineDLLEntry( 2, (void *) FooMe2, DLL_DWORD, 
  7999.           DLL_WORD, DLL_ENDLIST ) ) { 
  8000.       return( 0 ); 
  8001.     } 
  8002.     MessageBox( NULL, "32-bit DLL Started", DLL_ID, MB_OK ); 
  8003.     return( 1 ); 
  8004.    } 
  8005.    #else        /* else we are doing a 16-bit DLL */ 
  8006.    BOOL FAR PASCAL LibMain( HANDLE hInstance, 
  8007.                WORD wDataSegment, 
  8008.                WORD wHeapSize, 
  8009.                LPSTR lpszCmdLine ) 
  8010.    { 
  8011.     #if 0 
  8012.     /* 
  8013.      We can't use MessageBox here since static binding is 
  8014.      used and a message queue has not been created by the 
  8015.      time DLL16 is loaded. 
  8016.     */ 
  8017.     MessageBox( NULL, "16-bit DLL Started", DLL_ID, MB_OK ); 
  8018.     #endif 
  8019.     return( TRUE ); 
  8020.    } 
  8021.    #endif 
  8022.  
  8023. To create a 16-bit DLL from this code, the following steps must be performed. 
  8024.  
  8025. Example: 
  8026.  
  8027.    C>wcc dll /mc /bt=windows /zu /fo=dll16 
  8028.    C>wlink system windows_dll file dll16 
  8029.    C>wlib -n dll16 +dll16.dll 
  8030.  
  8031. To create a 32-bit DLL from this code, the following steps must be performed. 
  8032.  
  8033. Example: 
  8034.  
  8035.    C>wcc386 dll /bt=windows /fo=dll32 
  8036.    C>wlink system win386 file dll32 
  8037.    C>wbind -n -d dll32 
  8038.  
  8039. There are two entry points defined, FooMe1 (index number 1) and FooMe2 (index 
  8040. number 2).  FooMe1 accepts three arguments:  a WORD, a DWORD, and a WORD. 
  8041. FooMe2 accepts two arguments:  a DWORD and a WORD. 
  8042.  
  8043. WinMain returns zero to notify Windows that the DLL initialization failed, and 
  8044. returns a one if initialization succeeds. 
  8045.  
  8046. WinMain accepts the same arguments as the WinMain procedure of a regular 
  8047. Windows program, however, only two arguments are used.  hInstance is the DLL 
  8048. handle and lpszCmdLine is the command line passed to the DLL. 
  8049.  
  8050.  
  8051. ΓòÉΓòÉΓòÉ 21.2. Windows:  Calling Functions in a 32-bit DLL from a 16-bit Application ΓòÉΓòÉΓòÉ
  8052.  
  8053.  
  8054. The following is a 16-bit Windows program that demonstrates how to call the two 
  8055. routines defined in our DLL example. 
  8056.  
  8057. Example: 
  8058.  
  8059.    /* 
  8060.    *  EXE16.C 
  8061.    */ 
  8062.    #include <stdio.h> 
  8063.    #include <windows.h> 
  8064.  
  8065.    #define Add3 1 
  8066.    #define Add2 2 
  8067.  
  8068.  
  8069.    typedef long (FAR PASCAL *FPROC)(); 
  8070.    typedef long (FAR PASCAL *FARPROC1)(WORD, DWORD, WORD, int); 
  8071.    typedef long (FAR PASCAL *FARPROC2)(DWORD, WORD, int); 
  8072.  
  8073.    long FAR PASCAL FooMe1( WORD, DWORD, WORD ); 
  8074.    long FAR PASCAL FooMe2( DWORD, WORD ); 
  8075.  
  8076.  
  8077.    int PASCAL WinMain( HANDLE hInstance, 
  8078.              HANDLE hPrevInstance, 
  8079.              LPSTR  lpszCmdLine, 
  8080.              int   nCmdShow ) 
  8081.    { 
  8082.     FPROC fp; 
  8083.     HANDLE hlib; 
  8084.     long cb; 
  8085.     char buff[128]; 
  8086.  
  8087.  
  8088.     MessageBox( NULL, "16-bit EXE Started", "EXE16", MB_OK ); 
  8089.  
  8090.  
  8091.     /* Do the 16-bit demo using static binding */ 
  8092.     cb = FooMe1( 0x666, 0x77777111, 0x6969 ); 
  8093.     sprintf( buff, "RC1 = %lx", cb ); 
  8094.     MessageBox( NULL, buff, "EXE16", MB_OK ); 
  8095.  
  8096.  
  8097.     cb = FooMe2( 0x12345678, 0x8888 ); 
  8098.     sprintf( buff, "RC2 = %lx", cb ); 
  8099.     MessageBox( NULL, buff, "EXE16", MB_OK ); 
  8100.  
  8101.  
  8102.     /* Do the 32-bit demo */ 
  8103.     hlib = LoadLibrary( "dll32.dll" ); 
  8104.     fp = (FPROC) GetProcAddress( hlib, "Win386LibEntry" ); 
  8105.  
  8106.  
  8107.     cb = (*(FARPROC1)fp)( 0x666, 0x77777111, 0x6969, Add3 ); 
  8108.     sprintf( buff, "RC1 = %lx", cb ); 
  8109.     MessageBox( NULL, buff, "EXE16", MB_OK ); 
  8110.  
  8111.  
  8112.     cb = (*(FARPROC2)fp)( 0x12345678, 0x8888, Add2 ); 
  8113.     sprintf( buff, "RC2 = %lx", cb ); 
  8114.     MessageBox( NULL, buff, "EXE16", MB_OK ); 
  8115.  
  8116.  
  8117.     return( 0 ); 
  8118.    } 
  8119.  
  8120. Note that the last argument of a call to the 32-bit DLL routine is the index 
  8121. number of the 32-bit DLL routine to use.  To create the 16-bit sample Windows 
  8122. executable from this code, the following steps must be performed. 
  8123.  
  8124. Example: 
  8125.  
  8126.    C>wcc exe16 /bt=windows 
  8127.    C>wlink system windows file exe16 library dll16 
  8128.  
  8129.  
  8130. ΓòÉΓòÉΓòÉ 21.3. Windows:  Writing a 16-bit Cover for the 32-bit DLL ΓòÉΓòÉΓòÉ
  8131.  
  8132.  
  8133. The following is a suggested way to make a 32-bit DLL behave just like a 16-bit 
  8134. DLL from the point of view of the person trying to use the DLL. 
  8135.  
  8136. Create a library of cover functions for each of the entry points.  Each library 
  8137. entry would call the 32-bit DLL using the appropriate index number. 
  8138.  
  8139. For example, assume we have 3 functions in our DLL, Initialize, DoStuff, and 
  8140. Finish.  Assume Initialize takes an integer, DoStuff takes an integer and a 
  8141. pointer, and Finish takes nothing.  We could build a 16-bit library as follows: 
  8142.  
  8143. Example: 
  8144.  
  8145.    #include <windows.h> 
  8146.    typedef long (FAR PASCAL *FPROC)(); 
  8147.    extern long FAR PASCAL Win386LibEntry(); 
  8148.    FPROC LibEntry = Win386LibEntry; 
  8149.  
  8150.  
  8151.    BOOL Initialize( int parm ) 
  8152.    { 
  8153.      return( LibEntry( parm, 1 ) ); 
  8154.    } 
  8155.  
  8156.  
  8157.    int DoStuff( int parm1, LPVOID parm2 ) 
  8158.    { 
  8159.      return( LibEntry( parm1, parm2, 2 ) ); 
  8160.    } 
  8161.  
  8162.  
  8163.    void Finish( void ) 
  8164.    { 
  8165.      LibEntry( 3 ); 
  8166.    } 
  8167.  
  8168.  
  8169. ΓòÉΓòÉΓòÉ 21.4. Windows:  Creating and Debugging Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  8170.  
  8171.  
  8172. In the following sections, we will take you through the steps of compiling, 
  8173. linking, and debugging both 16-bit and 32-bit Dynamic Link Libraries (DLLs). 
  8174.  
  8175. We will use example programs that are provided in source-code form in the 
  8176. Watcom C/C++ package.  The files described in this chapter are located in the 
  8177. directory \WATCOM\SAMPLES\DLL.  The following files are provided: 
  8178.  
  8179.  GEN16.C 
  8180.       is the source code for a generic 16-bit Windows application that calls 
  8181.       functions in a 32-bit Windows DLL. 
  8182.  
  8183.  GEN16.LNK 
  8184.       is the linker directive file for linking the 16-bit Windows application. 
  8185.  
  8186.  GEN32.C 
  8187.       is the source code for a generic 32-bit Windows application that calls 
  8188.       functions in both 16-bit and 32-bit Windows DLLs. 
  8189.  
  8190.  GEN32.LNK 
  8191.       is the linker directive file for linking the 32-bit Windows application. 
  8192.  
  8193.  DLL16.C 
  8194.       is the source code for a simple 16-bit DLL containing one library 
  8195.       routine. 
  8196.  
  8197.  DLL16.LNK 
  8198.       is the linker directive file for linking the 16-bit Windows DLL. 
  8199.  
  8200.  DLL32.C 
  8201.       is the source code for a more complex 32-bit DLL containing three library 
  8202.       routines. 
  8203.  
  8204.  DLL32.LNK 
  8205.       is the linker directive file for linking the 32-bit Windows DLL. 
  8206.  
  8207.  EXE16.C 
  8208.       is the source code for a generic 16-bit Windows application that calls 
  8209.       functions in both 16-bit and 32-bit Windows DLLs. 
  8210.  
  8211.  DLL.C 
  8212.       is the source code for a DLL containing three library routines.  The 
  8213.       source code for this DLL can be used to create both 16-bit and 32-bit 
  8214.       DLLs. 
  8215.  
  8216.  MAKEFILE 
  8217.       is a makefile for compiling and linking the programs described above. 
  8218.  
  8219.  
  8220. ΓòÉΓòÉΓòÉ 21.4.1. Windows:  Building the Applications ΓòÉΓòÉΓòÉ
  8221.  
  8222.  
  8223. To create the DLLs and test applications, we will use the WATCOM Watcom Make 
  8224. utility and the supplied makefile. 
  8225.  
  8226. Example: 
  8227.  
  8228.    C>wmake -f makefile 
  8229.  
  8230.  
  8231. ΓòÉΓòÉΓòÉ 21.4.2. Windows:  Installing the Examples under Windows ΓòÉΓòÉΓòÉ
  8232.  
  8233.  
  8234. Start up Microsoft Windows 3.x if you have not already done so.  Add the 
  8235. EXE16.EXE file to one of your Window groups using the Microsoft Program 
  8236. Manager. 
  8237.  
  8238.    1. Select the "New..." entry from the "File" menu of the Microsoft Windows 
  8239.       Program Manager. 
  8240.  
  8241.    2. Select "Program Item" from the "New Program Object" window and press the 
  8242.       "OK" button. 
  8243.  
  8244.    3. Enter "DLL Test" as a description for the EXE16 program.  Enter the full 
  8245.       path to the EXE16 program as a command line. 
  8246.  
  8247.       Example: 
  8248.  
  8249.          Description:   Test 
  8250.          Command Line:  c:\work\dll\exe16.exe 
  8251.  
  8252.  
  8253. ΓòÉΓòÉΓòÉ 21.4.3. Windows:  Running the Examples ΓòÉΓòÉΓòÉ
  8254.  
  8255.  
  8256. Start the 16-bit application by double clicking on its icon.  A number of 
  8257. message boxes are presented.  You may wish to compare the output in each 
  8258. message box with the source code of the program to determine if the correct 
  8259. results are being obtained.  Click on the "OK" button as each of them are 
  8260. displayed. 
  8261.  
  8262.  
  8263. ΓòÉΓòÉΓòÉ 21.4.4. Windows:  Debugging a 32-bit DLL ΓòÉΓòÉΓòÉ
  8264.  
  8265.  
  8266. The Watcom Debugger can be used to debug a DLL.  To debug a 32-bit DLL, a 
  8267. "breakpoint" instruction must be inserted into the source code for the DLL at 
  8268. the "WinMain" entry point.  This is done using the "pragma" compiler directive. 
  8269. We have already added the breakpoint to the source code for the 32-bit DLL. 
  8270.  
  8271. Example: 
  8272.  
  8273.    extern void BreakPoint( void ); 
  8274.    #pragma aux BreakPoint = 0xcc; 
  8275.  
  8276.    int PASCAL WinMain( HANDLE hInstance, 
  8277.              HANDLE x1, 
  8278.              LPSTR lpCmdLine, 
  8279.              int x2 ) 
  8280.    { 
  8281.  
  8282.  
  8283.     BreakPoint(); 
  8284.     DefineDLLEntry( 1, (void *) Lib1, 
  8285.                DLL_WORD, 
  8286.                DLL_DWORD, 
  8287.                DLL_WORD, 
  8288.            . 
  8289.            . 
  8290.            . 
  8291.  
  8292. Start up Microsoft Windows 3.x if you have not already done so.  Start the 
  8293. debugger by double-clicking on the Watcom Debugger icon.  At the prompt, enter 
  8294. the path specification for the application.  When the debugger has successfully 
  8295. loaded EXE16, start execution of the program.  When the breakpoint is 
  8296. encountered in the 32-bit DLL, the debugger is re-entered.  The debugger will 
  8297. automatically skip past the breakpoint. 
  8298.  
  8299. From this point on, you can symbolically debug the 32-bit DLL.  You might, for 
  8300. example, set breakpoints at the start of each DLL routine to debug each of them 
  8301. as they are called. 
  8302.  
  8303.  
  8304. ΓòÉΓòÉΓòÉ 21.4.5. Windows:  Summary ΓòÉΓòÉΓòÉ
  8305.  
  8306.  
  8307. Note that the "WinMain" entry point is only called once, at the start of any 
  8308. application requesting it.  After this, the "WinMain" entry point is no longer 
  8309. called.  You may have to restart Windows to debug this section of code a second 
  8310. or third time. 
  8311.  
  8312.  
  8313. ΓòÉΓòÉΓòÉ 22. Windows:  Interfacing Visual Basic and Watcom C/C++ DLLs ΓòÉΓòÉΓòÉ
  8314.  
  8315.  
  8316. This chapter describes how to interface Microsoft Visual Basic 3.0 applications 
  8317. and 32-bit Dynamic Link Libraries (DLLs) created by Watcom C/C++.  It describes 
  8318. how to write functions for a 32-bit DLL, how to compile and link them, and how 
  8319. to call these functions from Visual Basic.  One of the proposed techniques 
  8320. involves the use of a set of cover functions in a 16-bit DLL so, indirectly, 
  8321. this chapter also describes interfacing to 16-bit DLLs. 
  8322.  
  8323. It is possible to invoke the Win386LibEntry function (Watcom's 32-bit function 
  8324. entry point, described below) directly from Visual Basic.  However, this 
  8325. technique limits the arguments that can be passed to a 32-bit DLL.  The 
  8326. procedure and problems are explained below. 
  8327.  
  8328. To work around the problem, a 16-bit DLL can be created, that covers the 32-bit 
  8329. DLL.  Within the 16-bit DLL, we will place cover functions that will call the 
  8330. corresponding 32-bit function in the 32-bit DLL.  We illustrate the creation of 
  8331. the 16-bit DLL using the 16-bit C compiler in Watcom C/C++. 
  8332.  
  8333. Before we begin our example, there are some important technical issues to 
  8334. consider. 
  8335.  
  8336. The discussion in this chapter assumes that you, the developer, have a working 
  8337. knowledge of Visual Basic, including how to bring up the general declarations 
  8338. screen, how to create command buttons, and how to associate code with command 
  8339. buttons.  You must use Visual Basic 3.0 or later.  Visual Basic Version 2.x 
  8340. will not work because of a deficiency in this product regarding the calling of 
  8341. functions in DLLs. 
  8342.  
  8343. For the purposes of the following discussion, you should have installed both 
  8344. the 16-bit and 32-bit versions of Watcom C/C++, as well as version 3.0 or later 
  8345. of Visual Basic.  Ensure that the PATH,  INCLUDE and WINDOWS_INCLUDE 
  8346. environment variables are defined to include at least the directories 
  8347. indicated.  We have assumed that Watcom C/C++ is installed in the C:\WATCOM 
  8348. directory, and Visual Basic is in the C:\VB directory: 
  8349.  
  8350.  
  8351.    set path=c:\watcom\binw;c:\vb;c:\dos;c:\windows 
  8352.    set include=c:\watcom\h 
  8353.    set windows_include=c:\watcom\h\win 
  8354.  
  8355. Watcom's 32-bit DLL supervisor contains a general entry point for Windows 
  8356. applications to call into called Win386LibEntry.  It also contains 128 specific 
  8357. entry points called DLL1 to DLL128 which correspond to the entry points 
  8358. established via DefineDLLEntry (the first argument to DefineDLLEntry is an 
  8359. index number in the range 1 to 128).  All applications call into the 32-bit DLL 
  8360. via these entry points.  They build the necessary stack frame and switch to the 
  8361. 32-bit DLL's data space. 
  8362.  
  8363. If you call via Win386LibEntry then you pass the DLL entry point number or 
  8364. index (1 to 128) as the last argument.  Win386LibEntry uses this index number 
  8365. to call the appropriate 32-bit DLL routine. 
  8366.  
  8367. In many languages and programs (such as C and Microsoft Excel), function calls 
  8368. are very flexible.  In other words, a function can be called with different 
  8369. argument types each time.  This is generally necessary for calling 
  8370. Win386LibEntry in a 32-bit extended DLL function.  The reason is that this 
  8371. function takes the same arguments as the function being called, as well as the 
  8372. index number of the called function.  After the 32-bit flat model has been set 
  8373. up, Win386LibEntry then calls this function.  In Visual Basic, once a function 
  8374. is declared as having certain arguments, it cannot be redeclared.  For example, 
  8375. suppose we have a declaration as follows: 
  8376.  
  8377. Example: 
  8378.  
  8379.    Declare Function Win386LibEntry Lib "c:\path\vbdll32.dll" 
  8380.    => (ByVal v1 As Integer, ByVal v2 As Long, ByVal 
  8381.    => v3 As Integer, ByVal I As Integer) As Long 
  8382.  
  8383. (Note:  the => means to continue the statement on the same line.) In this 
  8384. example, we could only call a function in any 32-bit extended DLL with a 16-bit 
  8385. integer as the first and third argument, and a 32-bit integer as the second 
  8386. argument.  There are three ways to work around this deficiency in Visual Basic: 
  8387.  
  8388.    1. Use the Visual Basic "Alias" attribute to declare Win386LibEntry 
  8389.       differently for each DLL routine.  Reference the different DLL routines 
  8390.       using these aliases. 
  8391.  
  8392.    2. Use the specific entry point, one of DLL1 through DLL128, corresponding 
  8393.       to the DLL routine that you want to call.  Each entry point can be 
  8394.       described to take different arguments.  We can still use the "Alias" 
  8395.       attribute to make the link between the name we use in the Visual Basic 
  8396.       function and the name in the 32-bit extended DLL.  This is the method 
  8397.       that we will use in the "Direct Call" technique discussed below.  It is 
  8398.       simpler to use since it requires one less argument (you don't require the 
  8399.       index number). 
  8400.  
  8401.    3. Use a method which involves calling functions in a 16-bit "cover" DLL 
  8402.       written in a flexible-argument language, which then calls the functions 
  8403.       in the 32-bit DLL.  This is the "Indirect Call" method discussed below. 
  8404.  
  8405.  
  8406. ΓòÉΓòÉΓòÉ 22.1. Windows:  A Working Example ΓòÉΓòÉΓòÉ
  8407.  
  8408.  
  8409. The best way to demonstrate these techniques is through an example.  This 
  8410. example consists of a Visual Basic application with 3 push buttons.  The first 
  8411. push button invokes a direct call to a 32-bit DLL which will display a message 
  8412. window with its arguments, the second push button invokes an indirect call to 
  8413. the same function through a 16-bit DLL, and the third button exits the Visual 
  8414. Basic application. 
  8415.  
  8416.  To create a Visual Basic application: 
  8417.  
  8418.  (1) 
  8419.        Start up a new project folder from the "File" menu. 
  8420.  
  8421.  (2) 
  8422.        Select "View Form" from the "Project" window. 
  8423.  
  8424.  (3) 
  8425.        Draw three command buttons on the form by selecting command buttons from 
  8426.       the "Toolbox" window. 
  8427.  
  8428.  (4) 
  8429.        Change the caption on each button.  To do this, highlight the first 
  8430.       button.  Then, open the "Properties" window.  Double click on the 
  8431.       "Caption window", and change the caption to "Direct call".  Highlight the 
  8432.       second button, and change its caption to "Indirect call".  Highlight the 
  8433.       third, changing the caption to "Exit". 
  8434.  
  8435.       Now, your Visual Basic application should have three push buttons, 
  8436.       "Direct call", "Indirect call", and "Exit". 
  8437.  
  8438.  (5) 
  8439.        Double click on the "Direct Call" button. 
  8440.  
  8441.       An edit window will pop up.  Enter the following code: 
  8442.  
  8443.  
  8444.          Sub Command1_Click () 
  8445.            Dim var1, var2 As Integer 
  8446.            Dim varlong, worked As Long 
  8447.  
  8448.            var1 = 230 
  8449.            varlong = 215 
  8450.            var2 = 32 
  8451.            worked = Add3(var1, varlong, var2) 
  8452.            Print worked 
  8453.            worked = Add2(varlong, var2) 
  8454.            Print worked 
  8455.          End Sub 
  8456.  
  8457.  (6) 
  8458.        Double click on the "Indirect Call" button. 
  8459.  
  8460.       Another edit window will pop up.  Enter the following code: 
  8461.  
  8462.  
  8463.          Sub Command2_Click () 
  8464.            Dim var1, var2 As Integer 
  8465.            Dim varlong, worked As Long 
  8466.  
  8467.            var1 = 230 
  8468.            varlong = 215 
  8469.            var2 = 32 
  8470.            worked = Function1( var1, varlong, var2 ) 
  8471.            Print worked 
  8472.            worked = Function2( varlong, var2 ) 
  8473.            Print worked 
  8474.          End Sub 
  8475.  
  8476.  (7) 
  8477.        Double click on the "Exit" command button and enter the following code 
  8478.       in the pop-up window: 
  8479.  
  8480.  
  8481.          Sub Command3_Click () 
  8482.            End 
  8483.          End Sub 
  8484.  
  8485.  (8) 
  8486.        Select "View Code" from the "Project" window.  To interface these Visual 
  8487.       Basic functions to the DLLs, the following code is needed in the 
  8488.  
  8489.  
  8490.          Object: [general] Proc: [declarations] 
  8491.  
  8492.       section of the code.  This code assumes that VBDLL32.DLL and COVER16.DLL 
  8493.       are in the C:\PATH directory.  Modify the pathnames appropriately if this 
  8494.       is not the case.  (Note:  the => means to continue the statement on the 
  8495.       same line.) 
  8496.  
  8497.  
  8498.          Declare Function Function1 Lib "c:\path\cover16.dll" 
  8499.          => (ByVal v1 As Integer, ByVal v2 As Long, 
  8500.          => ByVal v3 As Integer) As Long 
  8501.  
  8502.          Declare Function Function2 Lib "c:\path\cover16.dll" 
  8503.          => (ByVal v1 As Long, ByVal v2 As Integer) As Long 
  8504.  
  8505.          Declare Function Add3 Lib "c:\path\vbdll32.dll" 
  8506.          => Alias "DLL1" 
  8507.          => (ByVal v1 As Integer, ByVal v2 As Long, 
  8508.          => ByVal v3 As Integer) As Long 
  8509.  
  8510.          Declare Function Add2 Lib "c:\path\vbdll32.dll" 
  8511.          => Alias "DLL2" 
  8512.          => (ByVal v1 As Long, ByVal v2 As Integer) As Long 
  8513.  
  8514.  Now, when all of the code below is compiled correctly, and the Visual Basic 
  8515.  program is run, the "Direct call" button will call the DLL1 and DLL2 functions 
  8516.  directly, aliased as the functions Add3 and Add2 respectively.  The "Indirect 
  8517.  call" button will call the 16-bit DLL, which will then call the 32-bit DLL, 
  8518.  for both Function1 and Function2.  To run the Visual Basic program, select 
  8519.  "Start" from the "Run" menu. 
  8520.  
  8521.  
  8522. ΓòÉΓòÉΓòÉ 22.2. Windows:  Sample Visual Basic DLL Programs ΓòÉΓòÉΓòÉ
  8523.  
  8524.  
  8525. The sample programs provided below are for a 32-bit DLL, and a 16-bit cover 
  8526. DLL, which will call the two functions contained in the 32-bit DLL. 
  8527.  
  8528.  
  8529. ΓòÉΓòÉΓòÉ 22.2.1. Windows:  Source Code for VBDLL32.DLL ΓòÉΓòÉΓòÉ
  8530.  
  8531.  
  8532.  
  8533.    /* 
  8534.    *  VBDLL32.C 
  8535.    */ 
  8536.    #include <stdio.h> 
  8537.    #include <windows.h>   /* required for all Windows applications */ 
  8538.  
  8539.    long FAR PASCAL Add3( short var1, long varlong, short var2 ) 
  8540.    { 
  8541.     char buf[128]; 
  8542.  
  8543.     sprintf( buf, "Add3: var1=%d, varlong=%ld, var2=%d", 
  8544.            var1, varlong, var2 ); 
  8545.     MessageBox( NULL, buf, "VBDLL32", MB_OK | MB_TASKMODAL ); 
  8546.     return( var1 + varlong + var2 ); 
  8547.    } 
  8548.  
  8549.    long FAR PASCAL Add2( long varlong, short var2 ) 
  8550.    { 
  8551.     char buf[128]; 
  8552.  
  8553.     sprintf( buf, "Add2: varlong=%ld, var2=%d", varlong, var2 ); 
  8554.     MessageBox( NULL, buf, "VBDLL32", MB_OK | MB_TASKMODAL ); 
  8555.     return( varlong + var2 ); 
  8556.    } 
  8557.  
  8558.    #pragma off (unreferenced); 
  8559.    int PASCAL WinMain(HANDLE hInstance, HANDLE x1, LPSTR lpCmdLine, int x2) 
  8560.    #pragma on (unreferenced); 
  8561.    { 
  8562.     DefineDLLEntry( 1, (void *) Add3, DLL_WORD, DLL_DWORD, DLL_WORD, 
  8563.               DLL_ENDLIST ); 
  8564.     DefineDLLEntry( 2, (void *) Add2, DLL_DWORD, DLL_WORD, DLL_ENDLIST ); 
  8565.     return( 1 ); 
  8566.    } 
  8567.  
  8568.  
  8569. ΓòÉΓòÉΓòÉ 22.2.2. Windows:  Source code for COVER16.DLL ΓòÉΓòÉΓòÉ
  8570.  
  8571.  
  8572. The functions in this 16-bit DLL will call the functions in the 32-bit DLL, 
  8573. VBDLL32.DLL, shown above, with the appropriate Win386LibEntry call for each 
  8574. function. 
  8575.  
  8576.  
  8577.    /* 
  8578.    *  COVER16.C 
  8579.    */ 
  8580.  
  8581.    #include <stdio.h> 
  8582.    #include <windows.h>   /* required for all Windows applications */ 
  8583.  
  8584.    typedef long (FAR PASCAL *FPROC)(); 
  8585.  
  8586.    FPROC DLL_1; 
  8587.    FPROC DLL_2; 
  8588.  
  8589.    long FAR PASCAL __export Function1( short var1, 
  8590.                      long var2, 
  8591.                      short var3 ) 
  8592.    { 
  8593.      return( (long) DLL_1( var1, var2, var3 ) ); 
  8594.    } 
  8595.  
  8596.    long FAR PASCAL __export Function2( long var1, short var2 ) 
  8597.    { 
  8598.      return( (long) DLL_2( var1, var2 ) ); 
  8599.    } 
  8600.  
  8601.    #pragma off (unreferenced); 
  8602.    BOOL FAR PASCAL LibMain( HANDLE hInstance, WORD wDataSegment, 
  8603.                WORD wHeapSize, LPSTR lpszCmdLine ) 
  8604.    #pragma on (unreferenced); 
  8605.    { 
  8606.      HANDLE hlib; 
  8607.  
  8608.      /* Do our DLL initialization */ 
  8609.      hlib = LoadLibrary( "vbdll32.dll" ); 
  8610.      if( hlib < 32 ) { 
  8611.        MessageBox( NULL, 
  8612.              "Make sure your PATH contains VBDLL32.DLL", 
  8613.              "COVER16", MB_OK | MB_ICONEXCLAMATION ); 
  8614.        return( FALSE ); 
  8615.      } 
  8616.      DLL_1 = (FPROC) GetProcAddress( hlib, "DLL1" ); 
  8617.      DLL_2 = (FPROC) GetProcAddress( hlib, "DLL2" ); 
  8618.      return( TRUE ); 
  8619.    } 
  8620.  
  8621.  
  8622. ΓòÉΓòÉΓòÉ 22.3. Windows:  Compiling and Linking the Examples ΓòÉΓòÉΓòÉ
  8623.  
  8624.  
  8625. To create the 32-bit DLL VBDLL32.DLL, type the following at the command line 
  8626. (make sure that VBDLL32.C is in your current directory): 
  8627.  
  8628.  
  8629.    wcl386 vbdll32 -bt=windows -bd -d2 -l=win386 
  8630.    wbind vbdll32 -d -n 
  8631.  
  8632. To create the 16-bit DLL COVER16.DLL, type the following at the command line 
  8633. (make sure that COVER16.C are in your current directory): 
  8634.  
  8635.  
  8636.    wcl cover16 -mc -bt=windows -bd -zu -d2 -l=windows_dll 
  8637.  
  8638. Notes: 
  8639.  
  8640.    1. The "mc" option selects the compact memory model (small code, big data). 
  8641.       The code for 16-bit DLLs must be compiled with one of the big data 
  8642.       models. 
  8643.  
  8644.    2. The "bd" option indicates that a DLL will be created from the object 
  8645.       files. 
  8646.  
  8647.    3. The "bt" option selects the "windows" target.  This option causes the C 
  8648.       or C++ compiler to generate Windows prologue/epilogue code sequences 
  8649.       which are required for Microsoft Windows applications.  It also causes 
  8650.       the compiler to use the WINDOWS_INCLUDE environment variable for header 
  8651.       file searches.  It also causes the compiler to define the macro 
  8652.       __WINDOWS__ and, for the 32-bit C or C++ compiler only, the macro 
  8653.       __WINDOWS_386__. 
  8654.  
  8655.    4. The "zu" option is used when compiling 16-bit code that is to be placed 
  8656.       in a Dynamic Link Library (DLL) since the SS register points to the stack 
  8657.       segment of the calling application upon entry to the function. 
  8658.  
  8659.    5. The "d2" option is used to disable optimizations and include debugging 
  8660.       information in the object file and DLL.  The techniques for debugging 
  8661.       DLLs are described in the chapter entitled Windows:  Windows 32-Bit 
  8662.       Dynamic Link Libraries. 
  8663.  
  8664.  You are now ready to run the Visual Basic application. 
  8665.  
  8666.  
  8667. ΓòÉΓòÉΓòÉ 23. Windows:  WIN386 Library Functions and Macros ΓòÉΓòÉΓòÉ
  8668.  
  8669.  
  8670. Each special Windows function or macro in the Watcom C/C++ library is described 
  8671. in this chapter.  Each description consists of a number of subsections: 
  8672.  
  8673.  Synopsis: 
  8674.       This subsection gives the header files that should be included within a 
  8675.       source file that references the function or macro.  It also shows an 
  8676.       appropriate declaration for the function or for a function that could be 
  8677.       substituted for a macro. This declaration is not included in your 
  8678.       program; only the header file(s) should be included. 
  8679.  
  8680.       When a pointer argument is passed to a function and that function does 
  8681.       not modify the item indicated by that pointer, the argument is shown with 
  8682.       const before the argument.  For example, 
  8683.  
  8684.  
  8685.          const char *string 
  8686.  
  8687.       indicates that the array pointed at by string is not changed. 
  8688.  
  8689.  Description: 
  8690.       This subsection is a description of the function or macro. 
  8691.  
  8692.  Returns: 
  8693.       This subsection describes the return value (if any) for the function or 
  8694.       macro. 
  8695.  
  8696.  Errors: 
  8697.       This subsection describes the possible  errno values. 
  8698.  
  8699.  See Also: 
  8700.       This optional subsection provides a list of related functions or macros. 
  8701.  
  8702.  Example: 
  8703.       This optional subsection consists of one or more examples of the use of 
  8704.       the function.  The examples are often just fragments of code (not 
  8705.       complete programs) for illustration purposes. 
  8706.  
  8707.  Classification: 
  8708.       This subsection provides an indication of where the function or macro is 
  8709.       commonly found.  The functions or macros in this section are all 
  8710.       classified as "WIN386" (i.e., they pertain to 32-bit Windows 
  8711.       programming). 
  8712.  
  8713.  
  8714. ΓòÉΓòÉΓòÉ 23.1. Windows:  AllocAlias16 ΓòÉΓòÉΓòÉ
  8715.  
  8716.  Synopsis: 
  8717.  
  8718.       #include <windows.h> 
  8719.       DWORD AllocAlias16( void *ptr ); 
  8720.  
  8721.  Description: 
  8722.       The AllocAlias16 function obtains a 16-bit far pointer equivalent of a 
  8723.       32-bit near pointer.  These pointers are used when passing data pointers 
  8724.       to Windows through functions that have DWORD arguments, and for any 
  8725.       pointers within data structures passed this way. 
  8726.  
  8727.  Returns: 
  8728.       The AllocAlias16 function returns a 16-bit far pointer usable by Windows, 
  8729.       or returns 0 if the alias cannot be allocated. 
  8730.  
  8731.  See Also: 
  8732.        FreeAlias16 
  8733.  
  8734.  Example: 
  8735.  
  8736.       #include <windows.h> 
  8737.  
  8738.        DWORD mcs_16; 
  8739.        /* 
  8740.         * Send a message to a MDI client to create a window. 
  8741.         * _16SendMessage is used for this example, since it will 
  8742.         * not do any pointer conversions automatically. 
  8743.         */ 
  8744.        MDICREATESTRUCT mcs; 
  8745.        mcs.szTitle = (LPSTR) AllocAlias16( "c:\\foo.bar" ); 
  8746.        mcs.szClass = (LPSTR) AllocAlias16( "mdichild" ); 
  8747.        mcs.hOwner  = hInst; 
  8748.        mcs.x = mcs.cx = (int) CW_USEDEFAULT; 
  8749.        mcs.y = mcs.cy = (int) CW_USEDEFAULT; 
  8750.        mcs.style = 0; 
  8751.  
  8752.        /* tell the MDI Client to create the child */ 
  8753.        mcs_16 = AllocAlias16( &mcs ); 
  8754.        hwnd = (WORD) _16SendMessage( hwndMDIClient, 
  8755.                      WM_MDICREATE, 
  8756.                      0, 
  8757.                      (LONG) mcs_16 ); 
  8758.        FreeAlias16( mcs_16 ); 
  8759.        FreeAlias16( (DWORD) mcs.szClass ); 
  8760.        FreeAlias16( (DWORD) mcs.szTitle ); 
  8761.  
  8762.  Classification: 
  8763.       WIN386 
  8764.  
  8765.  
  8766. ΓòÉΓòÉΓòÉ 23.2. Windows:  AllocHugeAlias16 ΓòÉΓòÉΓòÉ
  8767.  
  8768.  Synopsis: 
  8769.  
  8770.       #include <windows.h> 
  8771.       DWORD AllocHugeAlias16( void *ptr, DWORD size ); 
  8772.  
  8773.  Description: 
  8774.       The AllocHugeAlias16 function obtains a 16-bit far pointer to a 32-bit 
  8775.       memory object that is size bytes in size.  This is similar to the 
  8776.       function  AllocAlias16, except that  AllocAlias16 will only give 16-bit 
  8777.       far pointers to 32-bit memory objects of up to 64K in size.  To get 
  8778.       16-bit far pointers to 32-bit memory objects larger than 64K, 
  8779.       AllocHugeAlias16 should be used. 
  8780.  
  8781.  Returns: 
  8782.       The AllocHugeAlias16 function returns a 16-bit far pointer usable by 
  8783.       Windows, or returns 0 if the alias cannot be allocated. 
  8784.  
  8785.  See Also: 
  8786.        AllocAlias16,  FreeAlias16,  FreeHugeAlias16 
  8787.  
  8788.  Example: 
  8789.  
  8790.       #include <windows.h> 
  8791.       #include <malloc.h> 
  8792.       #define SIZE 300000 
  8793.  
  8794.        DWORD alias; 
  8795.        void *tmp; 
  8796.  
  8797.        tmp = malloc( SIZE ); 
  8798.        alias = AllocHugeAlias16( tmp, SIZE ); 
  8799.  
  8800.        /* Windows calls using the alias ... */ 
  8801.  
  8802.        FreeHugeAlias16( alias, SIZE ); 
  8803.  
  8804.  Classification: 
  8805.       WIN386 
  8806.  
  8807.  
  8808. ΓòÉΓòÉΓòÉ 23.3. Windows:  _Call16 ΓòÉΓòÉΓòÉ
  8809.  
  8810.  Synopsis: 
  8811.  
  8812.       #include <windows.h> 
  8813.       DWORD _Call16( FARPROC lpFunc, char *fmt, ... ); 
  8814.  
  8815.  Description: 
  8816.       The _Call16 function performs the same function as 
  8817.       GetIndirectFunctionHandle,  InvokeIndirectFunctionHandle, and 
  8818.       FreeIndirectFunctionHandle but is much easier to use.  The first argument 
  8819.       lpFunc is the address of the 16-bit function to be called.  This address 
  8820.       is usually obtained by calling  GetProcAddress with the name of the 
  8821.       desired function.  The second argument fmt is a string identifying the 
  8822.       types of the parameters to be passed to the 16-bit function. 
  8823.  
  8824.       c 
  8825.                 call a 'cdecl' function as opposed to a 'pascal' function (if 
  8826.                 specified, it must be listed first) 
  8827.  
  8828.       b 
  8829.                 unsigned BYTE 
  8830.  
  8831.       w 
  8832.                 16-bit WORD 
  8833.  
  8834.       d 
  8835.                 32-bit DWORD 
  8836.  
  8837.       f 
  8838.                 double precision floating-point 
  8839.  
  8840.       p 
  8841.                 32-bit flat pointer (converted to 16:16 far pointer) 
  8842.       The 16-bit function must use either the  PASCAL or  CDECL calling 
  8843.       convention.  PASCAL calling convention is the default.  If the function 
  8844.       uses the  CDECL calling convention, then you must specify the letter "c" 
  8845.       as the first character of the argument type string. 
  8846.  
  8847.       Pointer types will automatically be converted from 32-bit near pointers 
  8848.       to 16-bit far pointers before the function is invoked.  Note that this 
  8849.       pointer is only valid over the period of the call; after control returns 
  8850.       to the 32-bit application, the 16-bit pointer created by the Supervisor 
  8851.       is no longer valid. 
  8852.  
  8853.  Returns: 
  8854.       The _Call16 function returns a 32-bit DWORD which represents the return 
  8855.       value from the 16-bit function that was called. 
  8856.  
  8857.  See Also: 
  8858.        GetIndirectFunctionHandle,  InvokeIndirectFunctionHandle, 
  8859.       FreeIndirectFunctionHandle 
  8860.  
  8861.  Example: 
  8862.  
  8863.       #include <windows.h> 
  8864.       HANDLE hDrv; 
  8865.       FARPROC lpfn; 
  8866.       int cb; 
  8867.  
  8868.         if( (hDrv = LoadLibrary ("foo.dll")) < 32 ) 
  8869.           return FALSE; 
  8870.         if( !(lpfn = GetProcAddress (hDrv, "ExtDeviceMode")) ) 
  8871.           return FALSE; 
  8872.  
  8873.         /* 
  8874.          * now, invoke the function 
  8875.          */ 
  8876.         cb = (WORD) _Call16( 
  8877.             lpfn,         // address of function 
  8878.             "wwdppddw",      // parameter type info 
  8879.             hwnd,         // parameters ... 
  8880.             hDrv, 
  8881.             NULL, 
  8882.             "POSTSCRIPT PRINTER", 
  8883.             "LPT1", 
  8884.             NULL, 
  8885.             NULL, 
  8886.             0 
  8887.             ); 
  8888.  
  8889.  Classification: 
  8890.       WIN386 
  8891.  
  8892.  
  8893. ΓòÉΓòÉΓòÉ 23.4. Windows:  DefineDLLEntry ΓòÉΓòÉΓòÉ
  8894.  
  8895.  Synopsis: 
  8896.  
  8897.       #include <windows.h> 
  8898.       int DefineDLLEntry( int index, void * routine, ... ); 
  8899.  
  8900.  Description: 
  8901.       The DefineDLLEntry function defines an index number for the 32-bit DLL 
  8902.       procedure routine.  The parameter index defines the index number that 
  8903.       must be used in order to invoke the 32-bit FAR procedure routine.  The 
  8904.       variable argument list defines the types of parameters that will be 
  8905.       received by the 32-bit DLL routine.  Valid parameter types are: 
  8906.  
  8907.       DLL_PTR 
  8908.                 16-bit far pointer 
  8909.  
  8910.       DLL_DWORD 
  8911.                 32-bits 
  8912.  
  8913.       DLL_WORD 
  8914.                 16-bits 
  8915.  
  8916.       DLL_CHAR 
  8917.                 8-bits 
  8918.  
  8919.       DLL_ENDLIST 
  8920.                 Marks the end of the variable argument list. 
  8921.       Note that all pointers are received as 16-bit far pointers.  To access 
  8922.       the data from the 32-bit DLL, the  MK_FP32 macro must be applied.  The 
  8923.       data can then be accessed with the resulting 32-bit far pointer. 
  8924.  
  8925.  Returns: 
  8926.       The DefineDLLEntry function returns zero if successful, and a non-zero 
  8927.       value otherwise. 
  8928.  
  8929.  Example: 
  8930.  
  8931.       #include <windows.h> 
  8932.       int FAR PASCAL FooMe( WORD w1, DWORD w2, WORD w3 ) 
  8933.       { 
  8934.        char str[128]; 
  8935.  
  8936.        sprintf( str, "w1=%hx, w2=%lx, w3=%hx", w1, w2, w3 ); 
  8937.        MessageBox( NULL, str, "DLL Test", MB_OK ); 
  8938.        return( w1 + w2 ); 
  8939.       } 
  8940.  
  8941.       int PASCAL WinMain( HANDLE hInstance, HANDLE x1, 
  8942.           LPSTR lpCmdLine, int x2 ) 
  8943.       { 
  8944.        DefineDLLEntry( 1, (PROCPTR) FooMe, DLL_WORD, 
  8945.                DLL_DWORD, DLL_WORD, DLL_ENDLIST ); 
  8946.        MessageBox( NULL, "32-bit DLL Started", "Test", MB_OK ); 
  8947.        return( 1 ); 
  8948.       } 
  8949.  
  8950.  Classification: 
  8951.       WIN386 
  8952.  
  8953.  
  8954. ΓòÉΓòÉΓòÉ 23.5. Windows:  DefineUserProc16 ΓòÉΓòÉΓòÉ
  8955.  
  8956.  Synopsis: 
  8957.  
  8958.       #include <windows.h> 
  8959.       int DefineUserProc16( int typ, PROCPTR routine, ... ); 
  8960.  
  8961.  Description: 
  8962.       The DefineUserProc16 function defines the arguments accepted by the user 
  8963.       defined callback procedure routine.  There may be up to 32 user defined 
  8964.       callbacks.  The parameter typ indicates which one of 
  8965.       GETPROC_USERDEFINED_1 through  GETPROC_USERDEFINED_32 is being defined 
  8966.       (see  GetProc16).  The callback routine must be declared as FAR PASCAL, 
  8967.       or as FAR cdecl.  The variable argument list defines the types of 
  8968.       parameters that will be received by the user defined callback procedure 
  8969.       routine.  Valid parameter types are: 
  8970.  
  8971.       UDP16_PTR 
  8972.                 16-bit far pointer 
  8973.  
  8974.       UDP16_DWORD 
  8975.                 32-bits 
  8976.  
  8977.       UDP16_WORD 
  8978.                 16-bits 
  8979.  
  8980.       UDP16_CHAR 
  8981.                 8-bits 
  8982.  
  8983.       UDP16_CDECL 
  8984.                 callback routine will be declared as type  cdecl rather than as 
  8985.                 type  PASCAL.  This keyword may be placed anywhere before the 
  8986.                 UDP16_ENDLIST keyword. 
  8987.  
  8988.       UDP16_ENDLIST 
  8989.                 Marks the end of the variable argument list. 
  8990.       Once the DefineUserProc16 function has been used to declare the user 
  8991.       callback routine, then  GetProc16 may be used to get a 16-bit function 
  8992.       pointer that may be used by Windows. 
  8993.  
  8994.  Returns: 
  8995.       The DefineUserProc16 function returns zero if it succeeds and non-zero if 
  8996.       it fails. 
  8997.  
  8998.  See Also: 
  8999.        GetProc16 
  9000.  
  9001.  Example: 
  9002.  
  9003.       #include <windows.h> 
  9004.  
  9005.       WORD FAR PASCAL Test( DWORD a, WORD b ) 
  9006.       { 
  9007.        char foo[128]; 
  9008.  
  9009.        sprintf( foo, "a=%lx, b=%hx", a, b ); 
  9010.        MessageBox( NULL, foo, "TEST", MB_OK ); 
  9011.        return( 0x123 ); 
  9012.       } 
  9013.  
  9014.       int DefineTest( void ) 
  9015.       { 
  9016.        FARPROC cb; 
  9017.  
  9018.        DefineUserProc16( GETPROC_USERDEFINED_1, 
  9019.                 (PROCPTR) Test, 
  9020.                 UDP16_DWORD, 
  9021.                 UDP16_WORD, 
  9022.                 UDP16_ENDLIST ); 
  9023.  
  9024.        cb = GetProc16( (PROCPTR) Test, GETPROC_USERDEFINED_1 ); 
  9025.  
  9026.        /* 
  9027.         * cb may then be used whenever a pointer to the 
  9028.         * callback is required by 16-bit Windows 
  9029.         */ 
  9030.       } 
  9031.  
  9032.  Classification: 
  9033.       WIN386 
  9034.  
  9035.  
  9036. ΓòÉΓòÉΓòÉ 23.6. Windows:  FreeAlias16 ΓòÉΓòÉΓòÉ
  9037.  
  9038.  Synopsis: 
  9039.  
  9040.       #include <windows.h> 
  9041.       void FreeAlias16( DWORD fp16 ); 
  9042.  
  9043.  Description: 
  9044.        FreeAlias16 frees a 16-bit far pointer alias for a 32-bit near pointer 
  9045.       that was allocated with  AllocAlias16.  This is important to do when 
  9046.       there is no further use for the pointer since there are a limited number 
  9047.       of 16-bit aliases available (due to limited space in the local descriptor 
  9048.       table). 
  9049.  
  9050.  Returns: 
  9051.       The FreeAlias16 function returns nothing. 
  9052.  
  9053.  See Also: 
  9054.        AllocAlias16 
  9055.  
  9056.  Example: 
  9057.  
  9058.       #include <windows.h> 
  9059.  
  9060.        DWORD mcs_16; 
  9061.        /* 
  9062.         * Send a message to a MDI client to create a window. 
  9063.         * _16SendMessage is used for this example, since it will 
  9064.         * not do any pointer conversions automatically. 
  9065.         */ 
  9066.        MDICREATESTRUCT mcs; 
  9067.        mcs.szTitle = (LPSTR) AllocAlias16( "c:\\foo.bar" ); 
  9068.        mcs.szClass = (LPSTR) AllocAlias16( "mdichild" ); 
  9069.        mcs.hOwner  = hInst; 
  9070.        mcs.x = mcs.cx = (int) CW_USEDEFAULT; 
  9071.        mcs.y = mcs.cy = (int) CW_USEDEFAULT; 
  9072.        mcs.style = 0; 
  9073.  
  9074.        /* tell the MDI Client to create the child */ 
  9075.        mcs_16 = AllocAlias16( &mcs ); 
  9076.        hwnd = (WORD) _16SendMessage( hwndMDIClient, 
  9077.                      WM_MDICREATE, 
  9078.                      0, 
  9079.                      (LONG) mcs_16 ); 
  9080.        FreeAlias16( mcs_16 ); 
  9081.        FreeAlias16( (DWORD) mcs.szClass ); 
  9082.        FreeAlias16( (DWORD) mcs.szTitle ); 
  9083.  
  9084.  Classification: 
  9085.       WIN386 
  9086.  
  9087.  
  9088. ΓòÉΓòÉΓòÉ 23.7. Windows:  FreeHugeAlias16 ΓòÉΓòÉΓòÉ
  9089.  
  9090.  Synopsis: 
  9091.  
  9092.       #include <windows.h> 
  9093.       void FreeHugeAlias16( DWORD fp16, DWORD size ); 
  9094.  
  9095.  Description: 
  9096.        FreeHugeAlias16 frees a 16-bit far pointer alias that was allocated with 
  9097.       AllocHugeAlias16.  The size of the original 32-bit memory object must be 
  9098.       specified.  It is important to use  FreeHugeAlias16 when there is no 
  9099.       further use for the pointer, since there are a limited number of 16-bit 
  9100.       aliases available (due to limited space in the local descriptor table). 
  9101.  
  9102.  Returns: 
  9103.       The FreeHugeAlias16 function returns nothing. 
  9104.  
  9105.  See Also: 
  9106.        AllocHugeAlias16,  AllocAlias16,  FreeAlias16 
  9107.  
  9108.  Example: 
  9109.  
  9110.       #include <windows.h> 
  9111.       #include <malloc.h> 
  9112.       #define SIZE 300000 
  9113.  
  9114.        DWORD alias; 
  9115.        void *tmp; 
  9116.  
  9117.        tmp = malloc( SIZE ); 
  9118.        alias = AllocHugeAlias16( tmp, SIZE ); 
  9119.  
  9120.        /* windows calls using the alias ... */ 
  9121.  
  9122.        FreeHugeAlias16( alias, SIZE ); 
  9123.  
  9124.  Classification: 
  9125.       WIN386 
  9126.  
  9127.  
  9128. ΓòÉΓòÉΓòÉ 23.8. Windows:  FreeIndirectFunctionHandle ΓòÉΓòÉΓòÉ
  9129.  
  9130.  Synopsis: 
  9131.  
  9132.       #include <windows.h> 
  9133.       void FreeIndirectFunctionHandle( HINDIR handle ); 
  9134.  
  9135.  Description: 
  9136.        FreeIndirectFunctionHandle frees a handle that was obtained using 
  9137.       GetIndirectFunctionHandle.  This is important to do when there is no 
  9138.       further use for the pointer since there are a limited number of 16-bit 
  9139.       aliases available (due to limited space in the local descriptor table). 
  9140.  
  9141.  Returns: 
  9142.       The FreeIndirectFunctionHandle function returns nothing. 
  9143.  
  9144.  See Also: 
  9145.        _Call16,  GetIndirectFunctionHandle,  InvokeIndirectFunction 
  9146.  
  9147.  Example: 
  9148.  
  9149.       #include <windows.h> 
  9150.  
  9151.        HANDLE hDrv; 
  9152.        FARPROC lpfn; 
  9153.  
  9154.        if( (hDrv = LoadLibrary( "foo.lib" )) < 32 ) 
  9155.          return FALSE; 
  9156.        if( !(lpfn = GetProcAddress( hDrv, "ExtDeviceMode" )) ) 
  9157.          return FALSE; 
  9158.  
  9159.       #ifdef __WINDOWS_386__ 
  9160.        hIndir = GetIndirectFunctionHandle( 
  9161.              lpfn, 
  9162.              INDIR_WORD, 
  9163.              INDIR_WORD, 
  9164.              INDIR_DWORD, 
  9165.              INDIR_PTR, 
  9166.              INDIR_PTR, 
  9167.              INDIR_DWORD, 
  9168.              INDIR_DWORD, 
  9169.              INDIR_WORD, 
  9170.              INDIR_ENDLIST ); 
  9171.  
  9172.        cb = (WORD) InvokeIndirectFunction( 
  9173.               hIndir, 
  9174.               hwnd, 
  9175.               hDrv, 
  9176.               NULL, 
  9177.               "POSTSCRIPT PRINTER", 
  9178.               "LPT1", 
  9179.               NULL, 
  9180.               NULL, 
  9181.               0 ); 
  9182.        FreeIndirectFunctionHandle( hIndir ); 
  9183.  
  9184.       #else 
  9185.        cb = lpfn( hwnd, 
  9186.              hDrv, 
  9187.              NULL, 
  9188.              "POSTSCRIPT PRINTER", 
  9189.              "LPT1", 
  9190.              NULL, 
  9191.              NULL, 
  9192.              0 ); 
  9193.       #endif 
  9194.  
  9195.  Classification: 
  9196.       WIN386 
  9197.  
  9198.  
  9199. ΓòÉΓòÉΓòÉ 23.9. Windows:  GetIndirectFunctionHandle ΓòÉΓòÉΓòÉ
  9200.  
  9201.  Synopsis: 
  9202.  
  9203.       #include <windows.h> 
  9204.       HINDIR GetIndirectFunctionHandle( FARPROC prc, ... ); 
  9205.  
  9206.  Description: 
  9207.       The GetIndirectFunctionHandle function gets a handle for a 16-bit 
  9208.       procedure that is to be invoked indirectly.  The procedure is assumed to 
  9209.       have PASCAL calling convention, unless the  INDIR_CDECL parameter is 
  9210.       used, to indicate that Microsoft C calling convention is to be used.  The 
  9211.       16-bit far pointer prc is supplied to GetIndirectFunctionHandle, and a 
  9212.       list of the type of each parameter (in the order that they will be passed 
  9213.       to the 16-bit function).  The parameter types are: 
  9214.  
  9215.       INDIR_DWORD 
  9216.                 A DWORD will be passed. 
  9217.  
  9218.       INDIR_WORD 
  9219.                 A WORD will be passed. 
  9220.  
  9221.       INDIR_CHAR 
  9222.                 A char will be passed. 
  9223.  
  9224.       INDIR_PTR 
  9225.                 A pointer will be passed.  This is only used if pointer 
  9226.                 conversion from 32-bit to 16-bit is required, otherwise; 
  9227.                 INDIR_DWORD is specified. 
  9228.  
  9229.       INDIR_CDECL 
  9230.                 This option may be included anywhere in the list before the 
  9231.                 INDIR_ENDLIST keyword.  When this is used, the calling 
  9232.                 convention used to invoke the 16-bit function will be the 
  9233.                 Microsoft C calling convention. 
  9234.  
  9235.       INDIR_ENDLIST 
  9236.                 Marks the end of the parameter list. 
  9237.       There is no substitute for this function when compiling for 16-bit 
  9238.       Windows.  In order to make the code 16-bit Windows compatible, 
  9239.       conditional code (based on the __WINDOWS_386__ macro) should be placed 
  9240.       around the GetIndirectFunctionHandle usage (see the example). 
  9241.  
  9242.       This handle is a data structure that was created using the  malloc 
  9243.       function.  To free the handle, just use one of the 
  9244.       FreeIndirectFunctionHandle or  free functions. 
  9245.  
  9246.       You may find it easier to use  _Call16 rather than 
  9247.       GetIndirectFunctionHandle followed by a call to  InvokeIndirectFunction. 
  9248.  
  9249.  Returns: 
  9250.       The GetIndirectFunctionHandle function returns a handle to the indirect 
  9251.       function, or NULL if a handle could not be allocated.  This handle is 
  9252.       used in conjunction with  InvokeIndirectFunction to call the 16-bit 
  9253.       procedure. 
  9254.  
  9255.  See Also: 
  9256.        _Call16,  FreeIndirectFunctionHandle,  InvokeIndirectFunction 
  9257.  
  9258.  Example: 
  9259.  
  9260.       #include <windows.h> 
  9261.  
  9262.        HANDLE hDrv; 
  9263.        FARPROC lpfn; 
  9264.  
  9265.        if( (hDrv = LoadLibrary( "foo.lib" )) < 32 ) 
  9266.          return FALSE; 
  9267.        if( !(lpfn = GetProcAddress( hDrv, "ExtDeviceMode" )) ) 
  9268.          return FALSE; 
  9269.  
  9270.       #ifdef __WINDOWS_386__ 
  9271.        hIndir = GetIndirectFunctionHandle( 
  9272.              lpfn, 
  9273.              INDIR_WORD, 
  9274.              INDIR_WORD, 
  9275.              INDIR_DWORD, 
  9276.              INDIR_PTR, 
  9277.              INDIR_PTR, 
  9278.              INDIR_DWORD, 
  9279.              INDIR_DWORD, 
  9280.              INDIR_WORD, 
  9281.              INDIR_ENDLIST ); 
  9282.  
  9283.        cb = (WORD) InvokeIndirectFunction( 
  9284.               hIndir, 
  9285.               hwnd, 
  9286.               hDrv, 
  9287.               NULL, 
  9288.               "POSTSCRIPT PRINTER", 
  9289.               "LPT1", 
  9290.               NULL, 
  9291.               NULL, 
  9292.               0 ); 
  9293.        FreeIndirectFunctionHandle( hIndir ); 
  9294.  
  9295.       #else 
  9296.        cb = lpfn( hwnd, 
  9297.              hDrv, 
  9298.              NULL, 
  9299.              "POSTSCRIPT PRINTER", 
  9300.              "LPT1", 
  9301.              NULL, 
  9302.              NULL, 
  9303.              0 ); 
  9304.       #endif 
  9305.  
  9306.  Classification: 
  9307.       WIN386 
  9308.  
  9309.  
  9310. ΓòÉΓòÉΓòÉ 23.10. Windows:  GetProc16 ΓòÉΓòÉΓòÉ
  9311.  
  9312.  Synopsis: 
  9313.  
  9314.       #include <windows.h> 
  9315.       CALLBACKPTR GetProc16( PROCPTR fcn, long type ); 
  9316.  
  9317.  Description: 
  9318.       The GetProc16 function returns a 16-bit far function pointer suitable for 
  9319.       use as a Windows callback function.  This callback function will invoke 
  9320.       the 32-bit far procedure specified by fcn.  The types of callback 
  9321.       functions that may be allocated are: 
  9322.  
  9323.       GETPROC_CALLBACK 
  9324.                 This is the most common form of callback; suitable as the 
  9325.                 callback routine for a window.  The callback has the form: 
  9326.  
  9327.  
  9328.                    long FAR PASCAL WProc( HWND, unsigned, 
  9329.                          WORD, LONG ); 
  9330.  
  9331.       GETPROC_ABORTPROC 
  9332.                 This is the callback type used for trapping abort requests when 
  9333.                 printing.  The callback has the form: 
  9334.  
  9335.  
  9336.                    int FAR PASCAL AbortProc( HDC, WORD ); 
  9337.  
  9338.       GETPROC_ENUMCHILDWINDOWS 
  9339.                 This callback is used with the  EnumChildWindows Windows 
  9340.                 function.  The callback function has the form 
  9341.  
  9342.  
  9343.                    BOOL FAR PASCAL EnumChildWindowsFunc( 
  9344.                          HWND, DWORD ); 
  9345.  
  9346.       GETPROC_ENUMFONTS 
  9347.                 This callback type is used with the  EnumFonts Windows 
  9348.                 function.  The callback has the form: 
  9349.  
  9350.  
  9351.                    int FAR PASCAL EnumFontsFunc( LPLOGFONT, 
  9352.                          LPTEXTMETRICS, short, LPSTR ); 
  9353.  
  9354.       GETPROC_ENUMMETAFILE 
  9355.                 This callback is used with the  EnumMetaFile Windows function. 
  9356.                 The callback function has the form: 
  9357.  
  9358.  
  9359.                    int FAR PASCAL EnumMetaFileFunc( HDC, 
  9360.                          LPHANDLETABLE, LPMETARECORD, 
  9361.                          short, LPSTR ); 
  9362.  
  9363.       GETPROC_ENUMOBJECTS 
  9364.                 This callback is used with the  EnumObjects Windows function. 
  9365.                 The callback function has the form: 
  9366.  
  9367.  
  9368.                    int FAR PASCAL EnumObjectsFunc( LPSTR, LPSTR ); 
  9369.  
  9370.       GETPROC_ENUMPROPS_FIXED_DS 
  9371.                 This callback is used with the  EnumProps Windows function, 
  9372.                 when the fixed data segments callback is needed.  The callback 
  9373.                 function has the form: 
  9374.  
  9375.  
  9376.                    int FAR PASCAL EnumPropsFunc( 
  9377.                          HWND, LPSTR, HANDLE ); 
  9378.  
  9379.       GETPROC_ENUMPROPS_MOVEABLE_DS 
  9380.                 This callback is used with the  EnumProps Windows function, 
  9381.                 when the moveable data segments callback is needed.  The 
  9382.                 callback function has the form: 
  9383.  
  9384.  
  9385.                    int FAR PASCAL EnumPropsFunc( 
  9386.                          HWND, WORD, PSTR, HANDLE ); 
  9387.  
  9388.       GETPROC_ENUMTASKWINDOWS 
  9389.                 This callback is used with the  EnumTaskWindows Windows 
  9390.                 function.  The callback function has the form: 
  9391.  
  9392.  
  9393.                    int FAR PASCAL EnumTaskWindowsFunc( 
  9394.                          HWND, DWORD ); 
  9395.  
  9396.       GETPROC_ENUMWINDOWS 
  9397.                 This callback is used with the  EnumWindows Windows function. 
  9398.                 The callback function has the form: 
  9399.  
  9400.  
  9401.                    int FAR PASCAL EnumWindowsFunc( HWND, DWORD ); 
  9402.  
  9403.       GETPROC_GLOBALNOTIFY 
  9404.                 This callback is used with the  GlobalNotify Windows function. 
  9405.                 The callback function has the form: 
  9406.  
  9407.  
  9408.                    int FAR PASCAL GlobalNotifyFunc( HANDLE ); 
  9409.  
  9410.       GETPROC_GRAYSTRING 
  9411.                 This callback is used with the  GrayString Windows function. 
  9412.                 The callback function has the form: 
  9413.  
  9414.  
  9415.                    int FAR PASCAL GrayStringFunc( 
  9416.                          HDC, DWORD, short ); 
  9417.  
  9418.       GETPROC_LINEDDA 
  9419.                 This callback is used with the  LineDDA Windows function.  The 
  9420.                 callback function has the form: 
  9421.  
  9422.  
  9423.                    void FAR PASCAL LineDDAFunc( 
  9424.                          short, short, LPSTR ); 
  9425.  
  9426.       GETPROC_SETRESOURCEHANDLER 
  9427.                 This callback is used with the  SetResourceHandler Windows 
  9428.                 function.  The callback function has the form: 
  9429.  
  9430.  
  9431.                    int FAR PASCAL SetResourceHandlerFunc( 
  9432.                          HANDLE, HANDLE, HANDLE ); 
  9433.  
  9434.       GETPROC_SETTIMER 
  9435.                 This callback is used with the  SetTimer Windows function.  The 
  9436.                 callback function has the form: 
  9437.  
  9438.  
  9439.                    int FAR PASCAL SetTimerFunc( 
  9440.                          HWND, WORD, short, DWORD ); 
  9441.  
  9442.       GETPROC_SETWINDOWSHOOK 
  9443.                 This callback is used with the  SetWindowsHook Windows 
  9444.                 function.  The callback function has the form: 
  9445.  
  9446.  
  9447.                    int FAR PASCAL SetWindowsHookFunc( 
  9448.                          short, WORD, DWORD ); 
  9449.  
  9450.       GETPROC_USERDEFINED_x 
  9451.                 This callback is used in conjunction with  DefineUserProc16 
  9452.                 function to create a callback routine with an arbitrary set of 
  9453.                 parameters.  Up to 32 user defined callbacks are allowed, they 
  9454.                 are identified by using GETPROC_USERDEFINED_1 through 
  9455.                 GETPROC_USERDEFINED_32.  The user defined callback must be 
  9456.                 declared as a FAR PASCAL function, or as a FAR cdecl function. 
  9457.  
  9458.  Returns: 
  9459.       The GetProc16 function returns a 16-bit far pointer to a callback 
  9460.       procedure.  This pointer may then be fed to any Windows function that 
  9461.       requires a pointer to a function within the 32-bit program.  Note that 
  9462.       the callback function within the 32-bit program must be declared as  FAR. 
  9463.  
  9464.  See Also: 
  9465.        ReleaseProc16 
  9466.  
  9467.  Example: 
  9468.  
  9469.       #include <windows.h> 
  9470.  
  9471.        CALLBACKPTR cbp; 
  9472.        FARPROC lpProcAbout; 
  9473.        /* 
  9474.         * Get a 16-bit callback routine to point at 
  9475.         * our About dialogue procedure, then create 
  9476.         * the dialogue.  We use _16 versions of 
  9477.         * MakeProcInstance, DialogBox, and 
  9478.         * FreeProcInstance because they do not do 
  9479.         * any magic work on the callback routines. 
  9480.         */ 
  9481.        cbp = GetProc16( (PROCPTR) About, 
  9482.                 GETPROC_CALLBACK ); 
  9483.  
  9484.        lpProcAbout = _16MakeProcInstance( cbp, hInst ); 
  9485.  
  9486.        _16DialogBox( hInst, 
  9487.              "AboutBox", 
  9488.              hWnd, 
  9489.              lpProcAbout ); 
  9490.  
  9491.        _16FreeProcInstance( lpProcAbout ); 
  9492.        ReleaseProc16( cbp ); 
  9493.  
  9494.  Classification: 
  9495.       WIN386 
  9496.  
  9497.  
  9498. ΓòÉΓòÉΓòÉ 23.11. Windows:  InvokeIndirectFunction ΓòÉΓòÉΓòÉ
  9499.  
  9500.  Synopsis: 
  9501.  
  9502.       #include <windows.h> 
  9503.       long InvokeIndirectFunction( HINDIR handle, ... ); 
  9504.  
  9505.  Description: 
  9506.       The InvokeIndirectFunction function invokes the 16-bit function pointed 
  9507.       to by the specified handle.  The handle must have been previously 
  9508.       allocated using the  GetIndirectFunctionHandle function.  The handle is 
  9509.       followed by the list of parameters to be passed to the 16-bit function. 
  9510.  
  9511.       If you specified  INDIR_PTR as a parameter when allocating the handle, 
  9512.       then a 16-bit pointer is allocated for a 32-bit pointer that you pass. 
  9513.       However, this pointer is freed when the 16-bit function being invoked 
  9514.       returns. 
  9515.  
  9516.       There is no substitute for this function when compiling for 16-bit 
  9517.       Windows.  In order to make the code 16-bit Windows compatible, 
  9518.       conditional code (based on the __WINDOWS_386__ macro) should be placed 
  9519.       around the InvokeIndirectFunction usage (see the example). 
  9520.  
  9521.  Returns: 
  9522.       The InvokeIndirectFunction function returns the value which the 16-bit 
  9523.       function returned.  If the 16-bit function returns a short rather than a 
  9524.       long, the result must be typecast. 
  9525.  
  9526.  See Also: 
  9527.        _Call16,  FreeIndirectFunctionHandle,  GetIndirectFunctionHandle 
  9528.  
  9529.  Example: 
  9530.  
  9531.       #include <windows.h> 
  9532.  
  9533.        HANDLE hDrv; 
  9534.        FARPROC lpfn; 
  9535.        HINDIR hIndir; 
  9536.        int cb; 
  9537.  
  9538.        if( (hDrv = LoadLibrary( "foo.lib" )) < 32 ) 
  9539.          return FALSE; 
  9540.        if( !(lpfn = GetProcAddress( hDrv, "ExtDeviceMode" )) ) 
  9541.          return FALSE; 
  9542.       #ifdef __WINDOWS_386__ 
  9543.  
  9544.        hIndir = GetIndirectFunctionHandle( 
  9545.              lpfn, 
  9546.              INDIR_WORD, 
  9547.              INDIR_WORD, 
  9548.              INDIR_DWORD, 
  9549.              INDIR_PTR, 
  9550.              INDIR_PTR, 
  9551.              INDIR_DWORD, 
  9552.              INDIR_DWORD, 
  9553.              INDIR_WORD, 
  9554.              INDIR_ENDLIST ); 
  9555.  
  9556.        cb = (WORD) InvokeIndirectFunction( 
  9557.               hIndir, 
  9558.               hwnd, 
  9559.               hDrv, 
  9560.               NULL, 
  9561.               "POSTSCRIPT PRINTER", 
  9562.               "LPT1", 
  9563.               NULL, 
  9564.               NULL, 
  9565.               0 ); 
  9566.        FreeIndirectFunctionHandle( hIndir ); 
  9567.       #else 
  9568.  
  9569.        cb = lpfn( hwnd, 
  9570.              hDrv, 
  9571.              NULL, 
  9572.              "POSTSCRIPT PRINTER", 
  9573.              "LPT1", 
  9574.              NULL, 
  9575.              NULL, 
  9576.              0 ); 
  9577.       #endif 
  9578.  
  9579.  Classification: 
  9580.       WIN386 
  9581.  
  9582.  
  9583. ΓòÉΓòÉΓòÉ 23.12. Windows:  MapAliasToFlat ΓòÉΓòÉΓòÉ
  9584.  
  9585.  Synopsis: 
  9586.  
  9587.       #include <windows.h> 
  9588.       void *MapAliasToFlat( DWORD alias ); 
  9589.  
  9590.  Description: 
  9591.       The MapAliasToFlat function returns a 32-bit near pointer equivalent of a 
  9592.       pointer allocated previously with  AllocAlias16 or  AllocHugeAlias16. 
  9593.       This is useful if you are communicating with a 16-bit application that is 
  9594.       returning pointers that you previously gave it. 
  9595.  
  9596.  Returns: 
  9597.       The MapAliasToFlat function returns a 32-bit near pointer usable by the 
  9598.       32-bit application. 
  9599.  
  9600.  See Also: 
  9601.        AllocAlias16,  AllocHugeAlias16 
  9602.  
  9603.  Example: 
  9604.  
  9605.       #include <windows.h> 
  9606.  
  9607.        DWORD alias; 
  9608.        void  *ptr; 
  9609.  
  9610.        alias = (DWORD) AllocAlias16( &alias ); 
  9611.        alias += 5; 
  9612.        ptr = MapAliasToFlat( alias ); 
  9613.        if( ptr == ((char *)&alias + 5) ) { 
  9614.          MessageBox( NULL,"It Worked","",MB_OK ); 
  9615.        } else { 
  9616.          MessageBox( NULL,"It Failed","",MB_OK ); 
  9617.        } 
  9618.  
  9619.  Classification: 
  9620.       WIN386 
  9621.  
  9622.  
  9623. ΓòÉΓòÉΓòÉ 23.13. Windows:  MK_FP16 ΓòÉΓòÉΓòÉ
  9624.  
  9625.  Synopsis: 
  9626.  
  9627.       #include <windows.h> 
  9628.       DWORD MK_FP16( void far * fp32 ); 
  9629.  
  9630.  Description: 
  9631.       The MK_FP16 function converts a 32-bit far pointer to a 16-bit far 
  9632.       pointer.  The 16-bit pointer is created by simply removing the high word 
  9633.       of the offset of the 32-bit pointer. 
  9634.  
  9635.       The 32-bit far pointer must be one that was obtained by using  MK_FP32 to 
  9636.       extend a 16-bit pointer. 
  9637.  
  9638.       This is useful whenever it is necessary to pass a 16-bit far pointer a 
  9639.       parameter to a Windows function though an _16 function. 
  9640.  
  9641.  Returns: 
  9642.       The MK_FP16 returns a 16-bit far pointer. 
  9643.  
  9644.  See Also: 
  9645.        MK_LOCAL32,  MK_FP32 
  9646.  
  9647.  Example: 
  9648.  
  9649.       #include <windows.h> 
  9650.  
  9651.        DRAWITEMSTRUCT   FAR *lpdis; 
  9652.        RECT  rc; 
  9653.        DWORD alias; 
  9654.        /* 
  9655.         * The drawitem struct was passed as a long, so we 
  9656.         * have to convert it to a 32 bit far pointer. 
  9657.         * Then, we want the 16 bit far pointer of the rcItem 
  9658.         * element so we can pass it to CopyRect (_16CopyRect 
  9659.         * is a version of CopyRect that does not convert 
  9660.         * the pointers it was given). 
  9661.         */ 
  9662.        case WM_DRAWITEM: 
  9663.         lpdis = MK_FP32( (void *) lParam ); 
  9664.         alias = AllocAlias16( > ); 
  9665.         _16CopyRect( (LPRECT) alias, 
  9666.                (LPRECT) MK_FP16( &lpdis->rcItem ) ); 
  9667.         FreeAlias16( alias ); 
  9668.  
  9669.  Classification: 
  9670.       WIN386 
  9671.  
  9672.  
  9673. ΓòÉΓòÉΓòÉ 23.14. Windows:  MK_FP32 ΓòÉΓòÉΓòÉ
  9674.  
  9675.  Synopsis: 
  9676.  
  9677.       #include <windows.h> 
  9678.       void far *MK_FP32( void * fp16 ); 
  9679.  
  9680.  Description: 
  9681.       The MK_FP32 function converts a 16-bit far pointer to a 32-bit far 
  9682.       pointer.  This is needed whenever Windows returns a 16-bit far pointer, 
  9683.       and access to the data is needed by the 32-bit program. 
  9684.  
  9685.  Returns: 
  9686.       The MK_FP32 returns a 32-bit far pointer. 
  9687.  
  9688.  See Also: 
  9689.        MK_LOCAL32,  MK_FP16 
  9690.  
  9691.  Example: 
  9692.  
  9693.       #include <windows.h> 
  9694.  
  9695.        MEASUREITEMSTRUCT far *mis; 
  9696.  
  9697.        case WM_MEASUREITEM: 
  9698.         /* 
  9699.          * Windows has passed us a 16 bit far pointer 
  9700.          * to the measure item data structure.  We 
  9701.          * use MK_FP32 to make that pointer a 32-bit far 
  9702.          * pointer, which enables us to access the data. 
  9703.          */ 
  9704.         mis = MK_FP32( (void *) lParam ); 
  9705.         mis->itemHeight = MEASUREITEMHEIGHT; 
  9706.         mis->itemWidth  = MEASUREITEMWIDTH; 
  9707.         return TRUE; 
  9708.  
  9709.  Classification: 
  9710.       WIN386 
  9711.  
  9712.  
  9713. ΓòÉΓòÉΓòÉ 23.15. Windows:  MK_LOCAL32 ΓòÉΓòÉΓòÉ
  9714.  
  9715.  Synopsis: 
  9716.  
  9717.       #include <windows.h> 
  9718.       void far *MK_LOCAL32( void * fp16 ); 
  9719.  
  9720.  Description: 
  9721.       The MK_LOCAL32 function converts a 16-bit near pointer to a 32-bit far 
  9722.       pointer.  This is needed whenever Windows returns a 16-bit near pointer 
  9723.       that is to be accessed by the 32-bit program. 
  9724.  
  9725.  Returns: 
  9726.       The MK_LOCAL32 returns a 32-bit far pointer. 
  9727.  
  9728.  See Also: 
  9729.        MK_FP32,  MK_FP16 
  9730.  
  9731.  Example: 
  9732.  
  9733.       #include <windows.h> 
  9734.  
  9735.        WORD ich,cch; 
  9736.        char *pch; 
  9737.        char far *fpch; 
  9738.        HANDLE hT; 
  9739.  
  9740.        /* 
  9741.         * Request the data from an edit window; copy it 
  9742.         * into a local buffer so that it can be passed 
  9743.         * to TextOut 
  9744.         */ 
  9745.        ich = (WORD) SendMessage( hwndEdit, 
  9746.                     EM_LINEINDEX, 
  9747.                     iLine, 
  9748.                     0L ); 
  9749.        cch = (WORD) SendMessage( hwndEdit, 
  9750.                     EM_LINELENGTH, 
  9751.                     ich, 
  9752.                     0L ); 
  9753.        fpch = MK_LOCAL32( LocalLock( hT ) ) ; 
  9754.        pch = alloca( cch ); 
  9755.        _fmemcpy( pch, fpch + ich, cch ); 
  9756.  
  9757.        TextOut( hdc, 0, yExtSoFar, (LPSTR) pch, cch ); 
  9758.        LocalUnlock( hT ); 
  9759.  
  9760.  Classification: 
  9761.       WIN386 
  9762.  
  9763.  
  9764. ΓòÉΓòÉΓòÉ 23.16. Windows:  PASS_WORD_AS_POINTER ΓòÉΓòÉΓòÉ
  9765.  
  9766.  Synopsis: 
  9767.  
  9768.       #include <windows.h> 
  9769.       void *PASS_WORD_AS_POINTER( DWORD dw ); 
  9770.  
  9771.  Description: 
  9772.       Some Windows API functions have pointer parameters that do not always 
  9773.       take pointers.  Sometimes these parameters are pure data.  In order to 
  9774.       stop the supervisor from trying to convert the data into a 16-bit far 
  9775.       pointer, the PASS_WORD_AS_POINTER function is used. 
  9776.  
  9777.  Returns: 
  9778.       The PASS_WORD_AS_POINTER returns a 32-bit "near" pointer, that is really 
  9779.       the parameter dw. 
  9780.  
  9781.  Example: 
  9782.  
  9783.       #include <windows.h> 
  9784.  
  9785.        Func( PASS_WORD_AS_POINTER( 1 ) ); 
  9786.  
  9787.  Classification: 
  9788.       WIN386 
  9789.  
  9790.  
  9791. ΓòÉΓòÉΓòÉ 23.17. Windows:  ReleaseProc16 ΓòÉΓòÉΓòÉ
  9792.  
  9793.  Synopsis: 
  9794.  
  9795.       #include <windows.h> 
  9796.       void ReleaseProc16( CALLBACKPTR cbp ); 
  9797.  
  9798.  Description: 
  9799.        ReleaseProc16 releases the callback function allocated by  GetProc16. 
  9800.       Since the callback routines are a limited resource, it is important to 
  9801.       release the routines when they are no longer required. 
  9802.  
  9803.  Returns: 
  9804.       The ReleaseProc16 function returns nothing. 
  9805.  
  9806.  See Also: 
  9807.        GetProc16 
  9808.  
  9809.  Example: 
  9810.  
  9811.       #include <windows.h> 
  9812.  
  9813.        CALLBACKPTR cbp; 
  9814.        FARPROC lpProcAbout; 
  9815.        /* 
  9816.         * Get a 16-bit callback routine to point at 
  9817.         * our About dialogue procedure, then create 
  9818.         * the dialogue.  We use _16 versions of 
  9819.         * MakeProcInstance, DialogBox, and 
  9820.         * FreeProcInstance because they do not do 
  9821.         * any magic work on the callback routines. 
  9822.         */ 
  9823.         cbp = GetProc16( (PROCPTR) About, 
  9824.                 GETPROC_CALLBACK ); 
  9825.  
  9826.         lpProcAbout = _16MakeProcInstance( cbp, hInst ); 
  9827.  
  9828.         _16DialogBox( hInst, 
  9829.              "AboutBox", 
  9830.              hWnd, 
  9831.              lpProcAbout ); 
  9832.  
  9833.         _16FreeProcInstance( lpProcAbout ); 
  9834.         ReleaseProc16( cbp ); 
  9835.  
  9836.  Classification: 
  9837.       WIN386 
  9838.  
  9839.  
  9840. ΓòÉΓòÉΓòÉ 24. Windows:  32-bit Extended Windows Application Development ΓòÉΓòÉΓòÉ
  9841.  
  9842.  
  9843. The purpose of this chapter is to anticipate some common questions about 32-bit 
  9844. Windows application development. 
  9845.  
  9846. The following topics are discussed in this chapter: 
  9847.  
  9848.      Can you call 16-bit code from a 32-bit Windows application? 
  9849.      Can I WinExec another Windows application? 
  9850.      How do I add my Windows resources? 
  9851.      All function pointers passed to Windows must be 16-bit far pointers, 
  9852.       correct? 
  9853.      Why are 32-bit callback routines FAR? 
  9854.      Why use the _16 API functions? 
  9855.      What about pointers in structures? 
  9856.      When do I use MK_FP32? 
  9857.      What is the difference between AllocAlias16 and MK_FP16? 
  9858.  
  9859.  
  9860. ΓòÉΓòÉΓòÉ 24.1. Windows:  Can you call 16-bit code from a 32-bit Windows application? ΓòÉΓòÉΓòÉ
  9861.  
  9862.  
  9863. A 32-bit Windows application can make a call to 16-bit code through the use of 
  9864. the Watcom  _Call16 or  InvokeIndirectFunction procedures.  These functions 
  9865. ensure that the Watcom Windows Supervisor prepares the stack for the 16-bit 
  9866. call and return to the 32-bit code.  The 32-bit application uses  LoadLibrary 
  9867. function to bring the 16-bit DLL into memory and then calls the 16-bit 
  9868. procedures.  To invoke 16-bit procedures, use  GetProcAddress to get the 16-bit 
  9869. far pointer to the function.  Use the  _Call16 procedure to call the 16-bit 
  9870. function since it is simpler to use than the  GetIndirectFunctionHandle, 
  9871. InvokeIndirectFunction, and  FreeIndirectFunctionHandle sequence.  An example 
  9872. of this process is provided under the  _Call16 Windows library function 
  9873. description. 
  9874.  
  9875. This method can be used to call any 16-bit Dynamic Link Library (DLL) procedure 
  9876. or any 32-bit extended DLL procedure from within a 32-bit application, 
  9877. including DLLs that are available as products through Independent Software 
  9878. Vendors (ISVs). 
  9879.  
  9880.  
  9881. ΓòÉΓòÉΓòÉ 24.2. Windows:  Can I WinExec another Windows application? ΓòÉΓòÉΓòÉ
  9882.  
  9883.  
  9884. As far as Windows is concerned, the WinExec was made by a 16-bit application, 
  9885. and the application specified will be started.  This new application can be a 
  9886. 16-bit application or another 32-bit application that was implemented with 
  9887. Watcom C/C++ 
  9888.  
  9889.  
  9890. ΓòÉΓòÉΓòÉ 24.3. Windows:  How do I add my Windows resources? ΓòÉΓòÉΓòÉ
  9891.  
  9892.  
  9893. The  WBIND utility automatically runs the resource compiler to add the 
  9894. resources to the 32-bit Windows supervisor (since the supervisor is a 16-bit 
  9895. Windows application).  Note that resource compiler options may be specified by 
  9896. using the "R" option of  WBIND. 
  9897.  
  9898.  
  9899. ΓòÉΓòÉΓòÉ 24.4. Windows:  All function pointers passed to Windows must be 16-bit far pointers, correct? ΓòÉΓòÉΓòÉ
  9900.  
  9901.  
  9902. All function pointers passed to Windows must be 16-bit far pointers since no 
  9903. translation is applied to any function pointers passed to Windows.  Translation 
  9904. is often not possible, since any functions that Windows is to call back must be 
  9905. exported, and only 16-bit functions can be exported. 
  9906.  
  9907. A 16-bit far pointer to a function is obtained in one of two ways:  either 
  9908. Windows gives it to you (via  GetProcAddr, for example), or you obtain a 
  9909. pointer from the supervisor, via  GetProc16. 
  9910.  
  9911. Function pointers obtained from Windows may either be fed into other Windows 
  9912. functions requiring function pointers, or called indirectly by using  _Call16 
  9913. or by using the  GetIndirectFunctionHandle,  InvokeIndirectFunction, and 
  9914. FreeIndirectFunctionHandle sequence. 
  9915.  
  9916. The function  GetProc16 returns a 16-bit far pointer to a callback function 
  9917. that Windows can use.  This callback function will direct control into the 
  9918. desired 32-bit routine. 
  9919.  
  9920.  
  9921. ΓòÉΓòÉΓòÉ 24.5. Windows:  Why are 32-bit callback routines FAR? ΓòÉΓòÉΓòÉ
  9922.  
  9923.  
  9924. The callback routines are declared as FAR so that the compiler will generate a 
  9925. far return from the procedure.  This is necessary since the 32-bit callback 
  9926. routine is "far" called from the supervisor. 
  9927.  
  9928. The callback routine is still "near" in the sense that it lies within the 
  9929. 32-bit flat address space of the application.  This means that  GetProc16 only 
  9930. needs the offset of the 32-bit callback function in order to set up the 16-bit 
  9931. procedure to call back correctly.  Thus,  GetProc16 accepts type  PROCPTR which 
  9932. is in fact only 4 bytes long.  The compiler will provide the offset only, which 
  9933. is, as already stated, all that is needed. 
  9934.  
  9935.  
  9936. ΓòÉΓòÉΓòÉ 24.6. Windows:  Why use the _16 API functions? ΓòÉΓòÉΓòÉ
  9937.  
  9938.  
  9939. The regular Windows API functions used in Watcom C/C++ automatically convert 
  9940. any pointers to 16-bit far pointers for use by Windows.  Sometimes, you may 
  9941. have a set of pointers that are 16-bit far pointers already (e.g., obtained 
  9942. from  GlobalLock), and do not need any conversion.  The "_16..." API functions 
  9943. do not convert pointers, they simply pass them on directly to Windows.  See the 
  9944. appendix entitled Special Windows API Functions for a list of the "_16..." API 
  9945. functions. 
  9946.  
  9947.  
  9948. ΓòÉΓòÉΓòÉ 24.7. Windows:  What about pointers in structures? ΓòÉΓòÉΓòÉ
  9949.  
  9950.  
  9951. Pointers in structures will be converted if the Windows API function actually 
  9952. takes a pointer to that structure (i.e., if it is possible for the supervisor 
  9953. to identify that structure).  There are few functions that accept pointers to 
  9954. structures containing pointers.  One such function is RegisterClass which 
  9955. accepts a pointer to a WNDCLASS structure. 
  9956.  
  9957. If Windows has you passing a pointer to a structure through a 32-bit integer 
  9958. argument, then it is not possible for the supervisor to identify that as a 
  9959. pointer that needs conversion.  It is also not possible for the supervisor to 
  9960. convert any pointers contained in the structure, since it is not aware that it 
  9961. is a structure (as far as the supervisor is concerned, that data is what 
  9962. Windows said it was - a 32-bit integer).  In this case, it is necessary to get 
  9963. 16-bit far pointer equivalents to the 32-bit near pointers that you want to 
  9964. pass.  Use  AllocAlias16 for this. 
  9965.  
  9966.  
  9967. ΓòÉΓòÉΓòÉ 24.8. Windows:  When do I use MK_FP32? ΓòÉΓòÉΓòÉ
  9968.  
  9969.  
  9970.  MK_FP32 is used to convert all 16-bit far pointers to 32-bit far pointers that 
  9971. can be used by your 32-bit application.  For example, to access the memory 
  9972. returned by  GlobalLock requires the use of  MK_FP32.  To access any pointer 
  9973. passed to you (in a callback routine) requires the use of  MK_FP32 if you want 
  9974. access to that data in your 32-bit application. 
  9975.  
  9976.  
  9977. ΓòÉΓòÉΓòÉ 24.9. Windows:  What is the difference between AllocAlias16 and MK_FP16? ΓòÉΓòÉΓòÉ
  9978.  
  9979.  
  9980.  AllocAlias16 actually gets a new selector that points at the same memory as 
  9981. the 32-bit near pointer, whereas  MK_FP16 squishes a 32-bit far pointer back 
  9982. into a 16-bit far pointer (i.e., it reverses  MK_FP32). 
  9983.  
  9984.  
  9985. ΓòÉΓòÉΓòÉ 24.10. Windows:  Tell Me More About Thunking and Aliases ΓòÉΓòÉΓòÉ
  9986.  
  9987.  
  9988. Consider the following example. 
  9989.  
  9990.  
  9991.    dwAlias = AllocAlias16( pszSomething ); 
  9992.    hwnd = CreateWindowEx( 
  9993.          0L,           // extendedStyle 
  9994.          "classname",       // class name 
  9995.          "", 
  9996.          WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_HSCROLL| 
  9997.          WS_BORDER|WS_CAPTION|WS_SYSMENU, 
  9998.          x, y, 0, 0,       // x, y, cx, cy 
  9999.          hwndParent,       // hwndParent 
  10000.          NULL,          // control ID 
  10001.          g_app.hinst,       // hInstance 
  10002.          (void FAR*)dwAlias);   // lpCreateParams 
  10003.  
  10004.    FreeAlias16( dwAlias ); 
  10005.  
  10006. When I get the lpCreateParams parameter in WM_CREATE, I don't get the original 
  10007. dwAlias but something else which looks like another alias to me.  So the 
  10008. question is:  Must the CreateWindowEx parameter lpCreateParams be "thunked" or 
  10009. is this done automatically by the supervisor? 
  10010.  
  10011. Thunks are always created for function pointers.  Aliases are always created 
  10012. for data pointers.  There are 3 data pointer parameters in the CreateWindowEx 
  10013. function call.  Aliases are created for all three pointers.  The lpCreateParams 
  10014. argument is a pointer to a struct which contains 3 pointers.  Aliases are not 
  10015. created for the 3 pointers inside the struct.  If you need to have this done, 
  10016. then you will have to create the aliases yourself.  If you create aliases for 
  10017. the parameters to CreateWindowEx, then you must call the _16CreateWindowEx 
  10018. function which will not create any aliases. 
  10019.  
  10020. Here is some further information on thunks (which are created for function 
  10021. pointers).  There is code in the supervisor that trys (note the word trys) to 
  10022. determine if the user has already created a thunk and, if so, avoids creating a 
  10023. double thunk which will always generate a GPF.  The best policy is to let the 
  10024. supervisor automatically create all thunks for you unless you have a very 
  10025. specific reason not to, in which case you should call the _16 version of the 
  10026. function. 
  10027.  
  10028. Here is some further information on aliases (which are created for data 
  10029. pointers).  There is no way for the supervisor to determine if a value is a 
  10030. 32-bit flat pointer or an alias for the pointer.  So if you pass in an alias to 
  10031. the non _16 version of the function, the supervisor will create an alias for 
  10032. the alias which will end up pointing to the wrong memory location.  If you are 
  10033. going to create the alias, then you must call the _16 version of the function. 
  10034.  
  10035.  
  10036. ΓòÉΓòÉΓòÉ 25. Special Variables for Windows Programming ΓòÉΓòÉΓòÉ
  10037.  
  10038.  __A000 
  10039.       A selector for addressing the real-mode segment 0xA000. 
  10040.  
  10041.  __B000 
  10042.       A selector for addressing the real-mode segment 0xB000. 
  10043.  
  10044.  __B800 
  10045.       A selector for addressing the real-mode segment 0xB800. 
  10046.  
  10047.  __C000 
  10048.       A selector for addressing the real-mode segment 0xC000. 
  10049.  
  10050.  __D000 
  10051.       A selector for addressing the real-mode segment 0xD000. 
  10052.  
  10053.  __E000 
  10054.       A selector for addressing the real-mode segment 0xE000. 
  10055.  
  10056.  __F000 
  10057.       A selector for addressing the real-mode segment 0xF000. 
  10058.  
  10059.  LocalPtr 
  10060.       The selector for the supervisor's data area. 
  10061.  
  10062.  
  10063. ΓòÉΓòÉΓòÉ 26. Definitions of Windows Terms ΓòÉΓòÉΓòÉ
  10064.  
  10065.  CALLBACKPTR 
  10066.       Pointer to a 16-bit callback routine; used to call into 32-bit functions. 
  10067.  
  10068.  DWORD 
  10069.       An unsigned long. 
  10070.  
  10071.  HINDIR 
  10072.       A handle to 16-bit function that needs to be called indirectly. 
  10073.  
  10074.  PROCPTR 
  10075.       A pointer to a 32-bit callback routine.  Although the callback routine is 
  10076.       declared as far, only the 32-bit offset is used. 
  10077.  
  10078.  WORD 
  10079.       An unsigned short. 
  10080.  
  10081.  
  10082. ΓòÉΓòÉΓòÉ 27. Special Windows API Functions ΓòÉΓòÉΓòÉ
  10083.  
  10084.  
  10085. On rare occasions, you want to use 16-bit far pointers directly in a Windows 
  10086. function.  Since all Windows functions in the 32-bit environment are expecting 
  10087. 32-bit near pointers, you cannot simply use the 16-bit far pointer directly in 
  10088. the function. 
  10089.  
  10090. The following functions are special versions of Windows API functions that do 
  10091. NOT convert any of the pointers from 32-bit to 16-bit.  There are _16 versions 
  10092. of all Windows API functions that accept data pointers. 
  10093.  
  10094.       _16AddAtom 
  10095.       _16AddFontResource 
  10096.       _16AdjustWindowRect 
  10097.       _16AdjustWindowRectEx 
  10098.       _16AnimatePalette 
  10099.       _16AnsiLower 
  10100.       _16AnsiLowerBuff 
  10101.       _16AnsiToOem 
  10102.       _16AnsiToOemBuff 
  10103.       _16AnsiUpper 
  10104.       _16AnsiUpperBuff 
  10105.       _16BuildCommDCB 
  10106.       _16CallMsgFilter 
  10107.       _16ChangeMenu 
  10108.       _16ClientToScreen 
  10109.       _16ClipCursor 
  10110.       _16CopyMetaFile 
  10111.       _16CopyRect 
  10112.       _16CreateBitmap 
  10113.       _16CreateBitmapIndirect 
  10114.       _16CreateBrushIndirect 
  10115.       _16CreateCursor 
  10116.       _16CreateDC 
  10117.       _16CreateDialog 
  10118.       _16CreateDialogIndirect 
  10119.       _16CreateDialogIndirectParam 
  10120.       _16CreateDialogParam 
  10121.       _16CreateDIBitmap 
  10122.       _16CreateEllipticRgnIndirect 
  10123.       _16CreateFont 
  10124.       _16CreateFontIndirect 
  10125.       _16CreateIC 
  10126.       _16CreateIcon 
  10127.       _16CreateMetaFile 
  10128.       _16CreatePalette 
  10129.       _16CreatePenIndirect 
  10130.       _16CreatePolygonRgn 
  10131.       _16CreatePolyPolygonRgn 
  10132.       _16CreateRectRgnIndirect 
  10133.       _16CreateWindow 
  10134.       _16CreateWindowEx 
  10135.       _16DialogBox 
  10136.       _16DialogBoxIndirect 
  10137.       _16DialogBoxIndirectParam 
  10138.       _16DialogBoxParam 
  10139.       _16DispatchMessage 
  10140.       _16DlgDirList 
  10141.       _16DlgDirListComboBox 
  10142.       _16DlgDirSelect 
  10143.       _16DlgDirSelectComboBox 
  10144.       _16DPtoLP 
  10145.       _16DrawFocusRect 
  10146.       _16DrawText 
  10147.       _16EndPaint 
  10148.       _16EnumChildWindows 
  10149.       _16EnumFonts 
  10150.       _16EnumMetaFile 
  10151.       _16EnumObjects 
  10152.       _16EnumProps 
  10153.       _16EnumTaskWindows 
  10154.       _16EnumWindows 
  10155.       _16EqualRect 
  10156.       _16Escape 
  10157.       _16ExtTextOut 
  10158.       _16FillRect 
  10159.       _16FindAtom 
  10160.       _16FindResource 
  10161.       _16FindWindow 
  10162.       _16FrameRect 
  10163.       _16FreeProcInstance 
  10164.       _16GetAtomName 
  10165.       _16GetBitmapBits 
  10166.       _16GetCaretPos 
  10167.       _16GetCharWidth 
  10168.       _16GetClassInfo 
  10169.       _16GetClassName 
  10170.       _16GetClientRect 
  10171.       _16GetClipboardFormatName 
  10172.       _16GetClipBox 
  10173.       _16GetCodeInfo 
  10174.       _16GetCommError 
  10175.       _16GetCommState 
  10176.       _16GetCursorPos 
  10177.       _16GetDIBits 
  10178.       _16GetDlgItemInt 
  10179.       _16GetDlgItemText 
  10180.       _16GetEnvironment 
  10181.       _16GetKeyboardState 
  10182.       _16GetKeyNameText 
  10183.       _16GetMenuString 
  10184.       _16GetMetaFile 
  10185.       _16GetModuleFileName 
  10186.       _16GetModuleHandle 
  10187.       _16GetObject 
  10188.       _16GetPaletteEntries 
  10189.       _16GetPriorityClipboardFormat 
  10190.       _16GetPrivateProfileInt 
  10191.       _16GetPrivateProfileString 
  10192.       _16GetProcAddress 
  10193.       _16GetProfileInt 
  10194.       _16GetProfileString 
  10195.       _16GetProp 
  10196.       _16GetRgnBox 
  10197.       _16GetScrollRange 
  10198.       _16GetSystemDirectory 
  10199.       _16GetSystemPaletteEntries 
  10200.       _16GetTabbedTextExtent 
  10201.       _16GetTempFileName 
  10202.       _16GetTextExtent 
  10203.       _16GetTextFace 
  10204.       _16GetTextMetrics 
  10205.       _16GetUpdateRect 
  10206.       _16GetWindowRect 
  10207.       _16GetWindowsDirectory 
  10208.       _16GetWindowText 
  10209.       _16GlobalAddAtom 
  10210.       _16GlobalFindAtom 
  10211.       _16GlobalGetAtomName 
  10212.       _16GlobalNotify 
  10213.       _16GrayString 
  10214.       _16InflateRect 
  10215.       _16IntersectRect 
  10216.       _16InvalidateRect 
  10217.       _16InvertRect 
  10218.       _16IsDialogMessage 
  10219.       _16IsRectEmpty 
  10220.       _16LineDDA 
  10221.       _16LoadAccelerators 
  10222.       _16LoadBitmap 
  10223.       _16LoadCursor 
  10224.       _16LoadIcon 
  10225.       _16LoadLibrary 
  10226.       _16LoadMenu 
  10227.       _16LoadMenuIndirect 
  10228.       _16LoadModule 
  10229.       _16LoadString 
  10230.       _16LPtoDP 
  10231.       _16MakeProcInstance 
  10232.       _16MapDialogRect 
  10233.       _16MessageBox 
  10234.       _16OemToAnsi 
  10235.       _16OemToAnsiBuff 
  10236.       _16OffsetRect 
  10237.       _16OpenComm 
  10238.       _16OpenFile 
  10239.       _16OutputDebugString 
  10240.       _16PlayMetaFileRecord 
  10241.       _16Polygon 
  10242.       _16Polyline 
  10243.       _16PolyPolygon 
  10244.       _16PtInRect 
  10245.       _16ReadComm 
  10246.       _16RectInRegion 
  10247.       _16RectVisible 
  10248.       _16RegisterClipboardFormat 
  10249.       _16RegisterWindowMessage 
  10250.       _16RemoveFontResource 
  10251.       _16RemoveProp 
  10252.       _16ScreenToClient 
  10253.       _16ScrollDC 
  10254.       _16ScrollWindow 
  10255.       _16SetBitmapBits 
  10256.       _16SetCommState 
  10257.       _16SetDIBits 
  10258.       _16SetDIBitsToDevice 
  10259.       _16SetDlgItemText 
  10260.       _16SetEnvironment 
  10261.       _16SetKeyboardState 
  10262.       _16SetPaletteEntries 
  10263.       _16SetProp 
  10264.       _16SetRect 
  10265.       _16SetRectEmpty 
  10266.       _16SetResourceHandler 
  10267.       _16SetSysColors 
  10268.       _16SetTimer 
  10269.       _16SetWindowsHook 
  10270.       _16SetWindowText 
  10271.       _16StretchDIBits 
  10272.       _16TabbedTextOut 
  10273.       _16TextOut 
  10274.       _16ToAscii 
  10275.       _16TrackPopupMenu 
  10276.       _16TranslateAccelerator 
  10277.       _16TranslateMDISysAccel 
  10278.       _16TranslateMessage 
  10279.       _16UnhookWindowsHook 
  10280.       _16UnionRect 
  10281.       _16UnregisterClass 
  10282.       _16ValidateRect 
  10283.       _16WinExec 
  10284.       _16WinHelp 
  10285.       _16WriteComm 
  10286.       _16WritePrivateProfileString 
  10287.       _16WriteProfileString 
  10288.       _16_lread 
  10289.       _16_lwrite 
  10290.  
  10291.  
  10292. ΓòÉΓòÉΓòÉ 28. NT:  Windows NT Programming Overview ΓòÉΓòÉΓòÉ
  10293.  
  10294.  
  10295. Windows NT supports both non-windowed character-mode applications and windowed 
  10296. Graphical User Interface (GUI) applications.  In addition, Windows NT supports 
  10297. Dynamic Link Libraries and applications with multiple threads of execution. 
  10298.  
  10299. We have supplied all the necessary tools for native development on Windows NT. 
  10300. You can also cross develop for Windows NT using either the DOS-hosted compilers 
  10301. and tools, the Windows 95-hosted compilers and tools, or the OS/2-hosted 
  10302. compilers and tools.  Testing and debugging of your Windows NT application must 
  10303. be done on Windows NT or Windows 95. 
  10304.  
  10305. If you are creating a character-mode application, you may also be interested in 
  10306. a special DOS extender from Phar Lap (TNT) that can run your Windows NT 
  10307. character-mode application under DOS. 
  10308.  
  10309.  
  10310. ΓòÉΓòÉΓòÉ 28.1. NT:  Windows NT Programming Note ΓòÉΓòÉΓòÉ
  10311.  
  10312.  
  10313. When doing Win32 programming, you should use the /ei and /zp4 options to 
  10314. compile C and C++ code with the Watcom compilers since this adjusts the 
  10315. compilers to match the default Microsoft compiler behaviour.  Some Microsoft 
  10316. software relies on the default behaviour of their own compiler regarding the 
  10317. treatment of enums and structure packing alignment. 
  10318.  
  10319.  
  10320. ΓòÉΓòÉΓòÉ 28.2. NT:  Windows NT Character-mode Versus GUI ΓòÉΓòÉΓòÉ
  10321.  
  10322.  
  10323. Basically, there are two classes of C/C++ applications that can run in a 
  10324. windowed environment like Windows NT. 
  10325.  
  10326. The first are those C/C++ applications that do not use any of the Win32 API 
  10327. functions; they are strictly C/C++ applications that do not rely on the 
  10328. features of a particular operating system.  Watcom gives you two choices when 
  10329. porting these kinds of applications to Windows NT.  You may choose to create a 
  10330. character-mode application that makes no use of the windowing capabilities of 
  10331. the system (the remainder of this chapter will deal with these kinds of 
  10332. applications).  Or, you may choose to make use of Watcom's default windowing 
  10333. system in which application output will be directed to one or more windows. 
  10334. The latter can give somewhat of a GUI look-and-feel to an application what 
  10335. wasn't designed for the GUI environment.  A subsequent chapter deals with the 
  10336. creation of applications that make use of the default windowing system. 
  10337.  
  10338. The second class of C/C++ applications are those that actually call Win32 API 
  10339. functions directly.  These are applications that have been tailored for the 
  10340. Win32 operating environment.  A subsequent chapter deals with the creation of 
  10341. applications that make use of the Win32 API. 
  10342.  
  10343.  
  10344. ΓòÉΓòÉΓòÉ 28.3. NT:  Windows NT Character-mode Applications ΓòÉΓòÉΓòÉ
  10345.  
  10346.  
  10347. Suppose you have a set of C/C++ applications that previously ran under DOS and 
  10348. you now wish to run them under Windows NT.  To achieve this, simply recompile 
  10349. your application and link with the appropriate libraries.  Depending on the 
  10350. method with which you linked your application, it can run in a Windows NT 
  10351. character-mode environment, or as a Windows NT GUI application.  A Windows NT 
  10352. GUI application has full access to the complete set of user-interface tools 
  10353. such as menus, icons, scroll bars, etc.  An application that was not designed 
  10354. as a windowed application (such as a DOS application) can run as a GUI 
  10355. application.  This is achieved by a default windowing system that is optionally 
  10356. linked with your application.  The creation of default windowing applications 
  10357. is described in a later chapter. 
  10358.  
  10359. Very little effort is required to port an existing C/C++ application to Windows 
  10360. NT.  Let us try to run the following sample program (contained in the file 
  10361. HELLO.C). 
  10362.  
  10363.  
  10364.    #include <stdio.h> 
  10365.  
  10366.    int main( void ) 
  10367.    { 
  10368.      printf( "Hello world\n" ); 
  10369.      return( 0 ); 
  10370.    } 
  10371.  
  10372. An equivalent C++ program follows: 
  10373.  
  10374.  
  10375.    #include <iostream.h> 
  10376.    #include <iomanip.h> 
  10377.  
  10378.    int main( void ) 
  10379.    { 
  10380.      cout << "Hello world" << endl; 
  10381.      return( 0 ); 
  10382.    } 
  10383.  
  10384. First we must compile the file HELLO.C by issuing the following command. 
  10385.  
  10386.  
  10387.    C:\>wcc386 hello 
  10388.  
  10389. Once we have successfully compiled the file, we can link it by issuing the 
  10390. following command. 
  10391.  
  10392.  
  10393.    C:\>wlink system nt file hello 
  10394.  
  10395. This will create a character-mode application. 
  10396.  
  10397.  
  10398. ΓòÉΓòÉΓòÉ 29. NT:  Creating Windows NT GUI Applications ΓòÉΓòÉΓòÉ
  10399.  
  10400.  
  10401. This chapter describes how to compile and link Windows NT GUI applications 
  10402. simply and quickly.  In this chapter, we look at applications written to 
  10403. exploit the Windows NT Application Programming Interface (API). 
  10404.  
  10405. We will illustrate the steps to creating Windows NT GUI applications by taking 
  10406. a small sample application and showing you how to compile, link, run and debug 
  10407. it. 
  10408.  
  10409.  
  10410. ΓòÉΓòÉΓòÉ 29.1. NT:  The Sample Application ΓòÉΓòÉΓòÉ
  10411.  
  10412.  
  10413. To demonstrate the creation of Windows NT GUI applications, we introduce a 
  10414. simple sample program.  The following example is the "hello" program adapted 
  10415. for Windows. 
  10416.  
  10417.  
  10418.    #include <windows.h> 
  10419.  
  10420.    int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInst, 
  10421.              LPSTR lpCmdLine, int nCmdShow ) 
  10422.     { 
  10423.      MessageBox( NULL, "Hello world", 
  10424.            "Watcom C/C++ for Windows", 
  10425.            MB_OK | MB_TASKMODAL ); 
  10426.      return( 0 ); 
  10427.     } 
  10428.  
  10429. The goal of this program is to display the message "Hello world" on the screen. 
  10430. The MessageBox Windows API function is used to accomplish this task.  We will 
  10431. take you through the steps necessary to produce this result. 
  10432.  
  10433.  
  10434. ΓòÉΓòÉΓòÉ 29.2. NT:  Building and Running the Sample Windows NT Application ΓòÉΓòÉΓòÉ
  10435.  
  10436.  
  10437. To compile and link our example program which is stored in the file HELLO.C, 
  10438. enter the following command: 
  10439.  
  10440.  
  10441.    C>wcl386 /l=nt_win/bt=nt  hello.c 
  10442.  
  10443. The typical messages that appear on the screen are shown in the following 
  10444. illustration. 
  10445.  
  10446.  
  10447.    C>wcl386 /l=nt_win /bt=nt hello.c 
  10448.    WATCOM C/C++32 Compile and Link Utility 
  10449.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  10450.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10451.        wcc386 hello.c  /bt=nt 
  10452.    WATCOM C32 Optimizing Compiler 
  10453.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  10454.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10455.    hello.c: 10 lines, included 6500, 0 warnings, 0 errors 
  10456.    Code size: 41 
  10457.  
  10458.    WATCOM Linker 
  10459.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  10460.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10461.    loading object files 
  10462.    searching libraries 
  10463.    creating a Windows NT windowed executable 
  10464.  
  10465. If you examine the current directory, you will find that two files have been 
  10466. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  10467. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  10468.  
  10469. The resultant Windows NT GUI application HELLO.EXE can now be run under Windows 
  10470. NT. 
  10471.  
  10472.  
  10473. ΓòÉΓòÉΓòÉ 29.3. NT:  Debugging the Sample Windows NT Application ΓòÉΓòÉΓòÉ
  10474.  
  10475.  
  10476. Let us assume that you wish to debug your application in order to locate an 
  10477. error in programming.  In the previous section, the "hello" program was 
  10478. compiled with default compile and link options.  When debugging an application, 
  10479. it is useful to refer to the symbolic names of routines and variables.  It is 
  10480. also convenient to debug at the source line level rather than the machine 
  10481. language level.  To do this, we must direct both the compiler and linker to 
  10482. include additional debugging information in the object and executable files. 
  10483. Using the  WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  10484. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  10485. directives for the Watcom Linker. 
  10486.  
  10487. For example, to compile and link the "hello" program with debugging 
  10488. information, the following command may be issued. 
  10489.  
  10490.  
  10491.    C>wcl386 /l=nt_win/bt=nt  /d2 hello.c 
  10492.  
  10493. The typical messages that appear on the screen are shown in the following 
  10494. illustration. 
  10495.  
  10496.  
  10497.    C>wcl386 /l=nt_win /bt=nt /d2 hello.c 
  10498.    WATCOM C/C++32 Compile and Link Utility 
  10499.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  10500.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10501.        wcc386 hello.c  /bt=nt /d2 
  10502.    WATCOM C32 Optimizing Compiler 
  10503.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  10504.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10505.    hello.c: 10 lines, included 6500, 0 warnings, 0 errors 
  10506.    Code size: 66 
  10507.  
  10508.    WATCOM Linker 
  10509.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  10510.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10511.    loading object files 
  10512.    searching libraries 
  10513.    creating a Windows NT windowed executable 
  10514.  
  10515. The "d2" option requests the maximum amount of debugging information that can 
  10516. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  10517. debugging information is included in the executable file that is produced by 
  10518. the linker. 
  10519.  
  10520. The "Code size" value is larger than in the previous example since selection of 
  10521. the "d2" option results in fewer code optimizations by default.  You can 
  10522. request more optimization by specifying the appropriate options.  However, you 
  10523. do so at the risk of making it more difficult for yourself to determine the 
  10524. relationship between the object code and the original source language code. 
  10525.  
  10526. To request the Watcom Debugger to assist in debugging the application, select 
  10527. the Watcom Debugger icon.  It would be too ambitious to describe the debugger 
  10528. in this introductory chapter so we refer you to the book entitled Watcom 
  10529. Debugger User's Guide. 
  10530.  
  10531.  
  10532. ΓòÉΓòÉΓòÉ 30. NT:  Porting Non-GUI Applications to Windows NT GUI ΓòÉΓòÉΓòÉ
  10533.  
  10534.  
  10535. Generally, an application that is to run in a windowed environment must be 
  10536. written in such a way as to exploit the Windows Application Programming 
  10537. Interface (API).  To take an existing character-based (i.e., non-graphical) 
  10538. application that ran under a system such as DOS and adapt it to run under 
  10539. Windows can require some considerable effort.  There is a steep learning curve 
  10540. associated with the API function libraries. 
  10541.  
  10542. This chapter describes how to create a Windows application quickly and simply 
  10543. from an application that does not use the Windows API.  The application will 
  10544. make use of WATCOM's default windowing support. 
  10545.  
  10546. Suppose you have a set of C/C++ applications that previously ran under a system 
  10547. like DOS and you now wish to run them under Windows NT.  To achieve this, you 
  10548. can simply recompile your application with the appropriate options and link 
  10549. with the appropriate libraries.  We provide a default windowing system that 
  10550. turns your character-mode application into a simple Windows NT Graphical User 
  10551. Interface (GUI) application. 
  10552.  
  10553. Normally, a Windows NT GUI application makes use of user-interface tools such 
  10554. as menus, icons, scroll bars, etc.  However, an application that was not 
  10555. designed as a windowed application (such as a DOS application) can run as a GUI 
  10556. application.  This is achieved by our default windowing system.  The following 
  10557. sections describe the default windowing system. 
  10558.  
  10559.  
  10560. ΓòÉΓòÉΓòÉ 30.1. NT:  Console Device in a Windowed Environment ΓòÉΓòÉΓòÉ
  10561.  
  10562.  
  10563. In a C/C++ application that runs under DOS, stdin (C++ cin) and stdout (C++ 
  10564. cout) are connected to the standard input and standard output devices 
  10565. respectively.  It is not a recommended practice to read directly from the 
  10566. standard input device or write to the standard output device when running in a 
  10567. windowed environment.  For this reason, a default windowing environment is 
  10568. created for C/C++ applications that read from stdin (C++ cin) or write to 
  10569. stdout (C++ cout).  When your application is started, a window is created in 
  10570. which output to stdout (C++ cout) is displayed and input from stdin (C++ cin) 
  10571. is requested. 
  10572.  
  10573. In addition to the standard I/O device, it is also possible to perform I/O to 
  10574. the console by explicitly opening a file whose name is "CON".  When this 
  10575. occurs, another window is created and displayed.  This window is different from 
  10576. the one created for standard input and standard output.  In fact, every time 
  10577. you open the console device a different window is created.  This provides a 
  10578. simple multi-windowing system for multiple streams of data to and from the 
  10579. console device. 
  10580.  
  10581.  
  10582. ΓòÉΓòÉΓòÉ 30.2. NT:  The Sample Non-GUI Application ΓòÉΓòÉΓòÉ
  10583.  
  10584.  
  10585. To demonstrate the creation of Windows NT GUI applications, we introduce a 
  10586. simple sample program.  For our example, we are going to use the famous "hello" 
  10587. program. 
  10588.  
  10589.  
  10590.    #include <stdio.h> 
  10591.  
  10592.    void main() 
  10593.     { 
  10594.      printf( "Hello world\n" ); 
  10595.     } 
  10596.  
  10597. The C++ version of this program follows: 
  10598.  
  10599.  
  10600.    #include <iostream.h> 
  10601.    #include <iomanip.h> 
  10602.  
  10603.    void main() 
  10604.    { 
  10605.      cout << "Hello world" << endl; 
  10606.    } 
  10607.  
  10608. The goal of this program is to display the message "Hello world" on the screen. 
  10609. The C version uses the C library printf routine to accomplish this task.  The 
  10610. C++ version uses the "iostream" library to accomplish this task.  We will take 
  10611. you through the steps necessary to produce this result. 
  10612.  
  10613.  
  10614. ΓòÉΓòÉΓòÉ 30.3. NT:  Building and Running the Non-GUI Windows NT Application ΓòÉΓòÉΓòÉ
  10615.  
  10616.  
  10617. Very little effort is required to port an existing C/C++ application to Windows 
  10618. NT. 
  10619.  
  10620. You must compile and link the file HELLO.C specifying the "bw" option. 
  10621.  
  10622.  
  10623.    C>wcl386 /l=nt_win/bw/bt=windows  hello.c 
  10624.  
  10625. The typical messages that appear on the screen are shown in the following 
  10626. illustration. 
  10627.  
  10628.  
  10629.    C>wcl386 /l=nt_win /bw/bt=windows hello.c 
  10630.    WATCOM C/C++32 Compile and Link Utility 
  10631.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  10632.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10633.        wcc386 hello.c  /bw/bt=windows 
  10634.    WATCOM C32 Optimizing Compiler 
  10635.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  10636.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10637.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  10638.    Code size: 24 
  10639.  
  10640.    WATCOM Linker 
  10641.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  10642.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10643.    loading object files 
  10644.    searching libraries 
  10645.    creating a Windows NT windowed executable 
  10646.  
  10647. If you examine the current directory, you will find that two files have been 
  10648. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  10649. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  10650.  
  10651. The resultant Windows NT GUI application HELLO.EXE can now be run under Windows 
  10652. NT as a Windows GUI application. 
  10653.  
  10654.  
  10655. ΓòÉΓòÉΓòÉ 30.4. NT:  Debugging the Non-GUI Windows NT Application ΓòÉΓòÉΓòÉ
  10656.  
  10657.  
  10658. Let us assume that you wish to debug your application in order to locate an 
  10659. error in programming.  In the previous section, the "hello" program was 
  10660. compiled with default compile and link options.  When debugging an application, 
  10661. it is useful to refer to the symbolic names of routines and variables.  It is 
  10662. also convenient to debug at the source line level rather than the machine 
  10663. language level.  To do this, we must direct both the compiler and linker to 
  10664. include additional debugging information in the object and executable files. 
  10665. Using the  WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  10666. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  10667. directives for the Watcom Linker. 
  10668.  
  10669. For example, to compile and link the "hello" program with debugging 
  10670. information, the following command may be issued. 
  10671.  
  10672.  
  10673.    C>wcl386 /l=nt_win/bw/bt=windows  /d2 hello.c 
  10674.  
  10675. The typical messages that appear on the screen are shown in the following 
  10676. illustration. 
  10677.  
  10678.  
  10679.    C>wcl386 /l=nt_win /bw/bt=windows /d2 hello.c 
  10680.    WATCOM C/C++32 Compile and Link Utility 
  10681.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  10682.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10683.        wcc386 hello.c  /bw/bt=windows /d2 
  10684.    WATCOM C32 Optimizing Compiler 
  10685.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  10686.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10687.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  10688.    Code size: 45 
  10689.  
  10690.    WATCOM Linker 
  10691.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  10692.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  10693.    loading object files 
  10694.    searching libraries 
  10695.    creating a Windows NT windowed executable 
  10696.  
  10697. The "d2" option requests the maximum amount of debugging information that can 
  10698. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  10699. debugging information is included in the executable file that is produced by 
  10700. the linker. 
  10701.  
  10702. The "Code size" value is larger than in the previous example since selection of 
  10703. the "d2" option results in fewer code optimizations by default.  You can 
  10704. request more optimization by specifying the appropriate options.  However, you 
  10705. do so at the risk of making it more difficult for yourself to determine the 
  10706. relationship between the object code and the original source language code. 
  10707.  
  10708. To request the Watcom Debugger to assist in debugging the application, select 
  10709. the Watcom Debugger icon.  It would be too ambitious to describe the debugger 
  10710. in this introductory chapter so we refer you to the book entitled Watcom 
  10711. Debugger User's Guide. 
  10712.  
  10713.  
  10714. ΓòÉΓòÉΓòÉ 30.5. NT:  Default Windowing Library Functions ΓòÉΓòÉΓòÉ
  10715.  
  10716.  
  10717. A few library functions have been written to enable some simple customization 
  10718. of the default windowing system's behaviour.  The following functions are 
  10719. supplied: 
  10720.  
  10721.  _dwDeleteOnClose 
  10722.  
  10723.  
  10724.  
  10725.          int _dwDeleteOnClose( int handle ); 
  10726.  
  10727.       This function tells the console window that it should close itself when 
  10728.       the file is closed.  You must pass to it the handle associated with the 
  10729.       opened console. 
  10730.  
  10731.  _dwSetAboutDlg 
  10732.  
  10733.  
  10734.  
  10735.          int _dwSetAboutDlg( const char *title, const char *text ); 
  10736.  
  10737.       This function sets the about dialog box of the default windowing system. 
  10738.       The "title" points to the string that will replace the current title.  If 
  10739.       title is NULL then the title will not be replaced.  The "text" points to 
  10740.       a string which will be placed in the about box.  To get multiple lines, 
  10741.       embed a new line after each logical line in the string.  If "text" is 
  10742.       NULL, then the current text in the about box will not be replaced. 
  10743.  
  10744.  _dwSetAppTitle 
  10745.  
  10746.  
  10747.  
  10748.          int _dwSetAppTitle( const char *title ); 
  10749.  
  10750.       This function sets the main window's title. 
  10751.  
  10752.  _dwSetConTitle 
  10753.  
  10754.  
  10755.  
  10756.          int _dwSetConTitle( int handle, const char *title ); 
  10757.  
  10758.       This function sets the console window's title which corresponds to the 
  10759.       handle passed to it. 
  10760.  
  10761.  _dwShutDown 
  10762.  
  10763.  
  10764.  
  10765.          int _dwShutDown( void ); 
  10766.  
  10767.       This function shuts down the default windowing I/O system.  The 
  10768.       application will continue to execute but no windows will be available for 
  10769.       output. 
  10770.  
  10771.  _dwYield 
  10772.  
  10773.  
  10774.  
  10775.          int _dwYield( void ); 
  10776.  
  10777.       This function yields control back to the operating system, thereby giving 
  10778.       other processes a chance to run. 
  10779.  
  10780.  These functions are described more fully in the WATCOM C Library Reference. 
  10781.  
  10782.  
  10783. ΓòÉΓòÉΓòÉ 31. NT:  Windows NT Multi-threaded Applications ΓòÉΓòÉΓòÉ
  10784.  
  10785.  
  10786. This chapter describes how to create multi-threaded applications.  A 
  10787. multi-threaded application is one whose tasks are divided among several threads 
  10788. of execution.  A process is an executing application and the resources it uses. 
  10789. A thread is the smallest unit of execution within a process.  Each thread has 
  10790. its own stack and a set of machine registers and shares all resources with its 
  10791. parent process.  The path of execution of one thread does not affect that of 
  10792. another; each thread is an independent entity. 
  10793.  
  10794. Typically, an application has a single thread of execution.  In this type of 
  10795. application, all tasks, once initiated, are completed before the next task 
  10796. begins.  In contrast, tasks in a multi-threaded application can be performed 
  10797. concurrently since more than one thread is executing at once.  For example, 
  10798. each thread may be designed to perform a separate task. 
  10799.  
  10800.  
  10801. ΓòÉΓòÉΓòÉ 31.1. NT:  Programming Considerations ΓòÉΓòÉΓòÉ
  10802.  
  10803.  
  10804. Since a multi-threaded application consists of many threads of execution, there 
  10805. are a number of issues that you must consider. 
  10806.  
  10807. Since threads share the resources of its parent, it may be necessary to 
  10808. serialize access to these resources.  For example, if your application has a 
  10809. function that displays information on the console and is used by all threads, 
  10810. it is necessary to allow only one thread to use that function at any time. 
  10811. That is, once a thread calls that function, the function should ensure that no 
  10812. other thread displays information until all information for the initial thread 
  10813. has been displayed.  An example of such a function is the printf library 
  10814. function. 
  10815.  
  10816. Another issue that must be considered when creating multi-threaded applications 
  10817. is global variables.  If you have global variables that contain thread-specific 
  10818. information, there must be an instance of each global variable for each thread. 
  10819. An example of such a variable is the errno global variable defined in the 
  10820. run-time libraries.  If an error condition was created by a thread, you would 
  10821. not want it to affect the execution of other threads.  Therefore, each thread 
  10822. should contain its own instance of this variable. 
  10823.  
  10824.  
  10825. ΓòÉΓòÉΓòÉ 31.2. NT:  Creating Threads ΓòÉΓòÉΓòÉ
  10826.  
  10827.  
  10828. Each application initially contains a single thread.  The run-time libraries 
  10829. contain two functions that create and terminate threads of execution.  The 
  10830. function _beginthread creates a thread of execution and the function _endthread 
  10831. ends a thread of execution.  The macro _threadid can be used to determine the 
  10832. current thread identifier. 
  10833.  
  10834. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  10835.  
  10836.  WARNING!  If any thread calls a library function, you must use the 
  10837. _beginthread function to create the thread.  Do not use the CreateThread API 
  10838. function. 
  10839.  
  10840. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  10841.  
  10842.  
  10843. ΓòÉΓòÉΓòÉ 31.2.1. NT:  Creating a New Thread ΓòÉΓòÉΓòÉ
  10844.  
  10845.  
  10846. The _beginthread function creates a new thread.  It is defined as follows. 
  10847.  
  10848.  
  10849.    unsigned long _beginthread( void (*start_address)(void *), 
  10850.                  unsigned stack_size, 
  10851.                  void *arglist); 
  10852.  
  10853.  where 
  10854.       description 
  10855.  
  10856.  start_address 
  10857.       is the address of the function that will be called when the newly created 
  10858.       thread is executed.  When the thread returns from that function, the 
  10859.       thread will be terminated.  Note that a call to the _endthread function 
  10860.       will also terminate the thread. 
  10861.  
  10862.  stack_size 
  10863.       specifies the size of the stack to be allocated by the operating system 
  10864.       for the new thread.  The stack size should be a multiple of 4K. 
  10865.  
  10866.  arglist 
  10867.       is passed as an argument to the function specified by start_address.  If 
  10868.       no argument is required, a value of NULL can be specified. 
  10869.  
  10870.  If a new thread is successfully created, the thread identifier of the new 
  10871.  thread is returned.  Otherwise, a value of -1 is returned. 
  10872.  
  10873.  The header file PROCESS.H contains the definition of the _beginthread 
  10874.  function. 
  10875.  
  10876.  Another thread related function for Windows NT is _beginthreadex.  See the 
  10877.  Watcom C Library Reference for more information. 
  10878.  
  10879.  
  10880. ΓòÉΓòÉΓòÉ 31.2.2. NT:  Terminating the Current Thread ΓòÉΓòÉΓòÉ
  10881.  
  10882.  
  10883. The _endthread function terminates the current thread.  It is defined as 
  10884. follows. 
  10885.  
  10886.  
  10887.    void _endthread( void ) 
  10888.  
  10889. The header file PROCESS.H contains the definition of the _endthread function. 
  10890.  
  10891.  
  10892. ΓòÉΓòÉΓòÉ 31.2.3. NT:  Getting the Current Thread Identifier ΓòÉΓòÉΓòÉ
  10893.  
  10894.  
  10895. The _threadid macro can be used to determine the current thread identifier.  It 
  10896. is defined as follows. 
  10897.  
  10898.  
  10899.    int *__threadid(void); 
  10900.    #define _threadid (__threadid()) 
  10901.  
  10902. The header file STDDEF.H contains the definition of the _threadid macro. 
  10903.  
  10904.  
  10905. ΓòÉΓòÉΓòÉ 31.3. NT:  A Multi-threaded Example ΓòÉΓòÉΓòÉ
  10906.  
  10907.  
  10908. Let us create a simple multi-threaded application. 
  10909.  
  10910.  
  10911.    #include <process.h> 
  10912.    #include <stdio.h> 
  10913.    #include <stddef.h> 
  10914.    #include <windows.h> 
  10915.  
  10916.    static  volatile int   NumThreads; 
  10917.    static  volatile int   HoldThreads; 
  10918.  
  10919.    CRITICAL_SECTION CriticalSection; 
  10920.  
  10921.    #define NUM_THREADS   5 
  10922.    #define STACK_SIZE    8192 
  10923.  
  10924.    static void a_thread( void *arglist ) 
  10925.    /***********************************/ 
  10926.    { 
  10927.      while( HoldThreads ) { 
  10928.        Sleep( 1 ); 
  10929.      } 
  10930.      printf( "Hi from thread %d\n", *_threadid ); 
  10931.      EnterCriticalSection( &CriticalSection ); 
  10932.      --NumThreads; 
  10933.      LeaveCriticalSection( &CriticalSection ); 
  10934.      _endthread(); 
  10935.    } 
  10936.  
  10937.    int main( void ) 
  10938.    /**************/ 
  10939.    { 
  10940.      int     i; 
  10941.  
  10942.      printf( "Initial thread id = %d\n", *_threadid ); 
  10943.      NumThreads = 0; 
  10944.      HoldThreads = 1; 
  10945.      InitializeCriticalSection( &CriticalSection ); 
  10946.      /* initial thread counts as 1 */ 
  10947.      for( i = 2; i <= NUM_THREADS; ++i ) { 
  10948.        if( _beginthread( a_thread, STACK_SIZE, NULL ) == -1 ) { 
  10949.          printf( "creation of thread %d failed\n", i ); 
  10950.        } else { 
  10951.          ++NumThreads; 
  10952.        } 
  10953.      } 
  10954.  
  10955.      HoldThreads = 0; 
  10956.      while( NumThreads != 0 ) { 
  10957.        Sleep( 1 ); 
  10958.      } 
  10959.      DeleteCriticalSection( &CriticalSection ); 
  10960.      return( 0 ); 
  10961.    } 
  10962.  
  10963. Note: 
  10964.  
  10965.    1. In the function a_thread, EnterCriticalSection and LeaveCriticalSection 
  10966.       are called when we modify the variable NumThreads.  This ensures that the 
  10967.       action of extracting the value of NumThreads from memory, incrementing 
  10968.       the value, and storing the new result into memory, occurs without 
  10969.       interruption.  If these functions were not called, it would be possible 
  10970.       for two threads to extract the value of NumThreads from memory before an 
  10971.       update occurred. 
  10972.  
  10973.  Let us assume that the file MTHREAD.C contains the above example.  Before 
  10974.  compiling the file, make sure that the WATCOM environment variable is set to 
  10975.  the directory in which you installed Watcom C/C++.  Also, the INCLUDE 
  10976.  environment variable must include the \WATCOM\H\NT and \WATCOM\H directories 
  10977.  ("\WATCOM" is the directory in which Watcom C/C++ was installed). 
  10978.  
  10979.  We can now compile and link the application by issuing the following command. 
  10980.  
  10981.  
  10982.     C:\>wcl386 /bt=nt /bm /l=nt mthread 
  10983.  
  10984.  The "bm" option must be specified since we are creating a multi-threaded 
  10985.  application.  If your multi-threaded application contains more than one 
  10986.  module, each module must be compiled using the "bm" switch. 
  10987.  
  10988.  The "l" option specifies the target system for which the application is to be 
  10989.  linked.  The system name nt is defined in the file WLSYSTEM.LNK which is 
  10990.  located in the "BINW" directory of the directory in which you installed Watcom 
  10991.  C/C++. 
  10992.  
  10993.  The multi-threaded application is now ready to be run. 
  10994.  
  10995.  
  10996. ΓòÉΓòÉΓòÉ 32. NT:  Windows NT Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  10997.  
  10998.  
  10999. A dynamic link library, like a standard library, is a library of functions. 
  11000. When an application uses functions from a standard library, the library 
  11001. functions referenced by the application become part of the executable module. 
  11002. This form of linking is called static linking.  When an application uses 
  11003. functions from a dynamic link library, the library functions referenced by the 
  11004. application are not included in the executable module.  Instead, the executable 
  11005. module contains references to these functions which are resolved when the 
  11006. application is loaded.  This form of linking is called dynamic linking. 
  11007.  
  11008. Let us consider some of the advantages of using dynamic link libraries over 
  11009. standard libraries. 
  11010.  
  11011.    1. Functions in dynamic link libraries are not linked into your program. 
  11012.       Only references to the functions in dynamic link libraries are placed in 
  11013.       the program module.  These references are called import definitions.  As 
  11014.       a result, the linking time is reduced and disk space is saved.  If many 
  11015.       applications reference the same dynamic link library, the saving in disk 
  11016.       space can be significant. 
  11017.  
  11018.    2. Since program modules only reference dynamic link libraries and do not 
  11019.       contain the actual executable code, a dynamic link library can be updated 
  11020.       without re-linking your application.  When your application is executed, 
  11021.       it will use the updated version of the dynamic link library. 
  11022.  
  11023.    3. Dynamic link libraries also allow sharing of code and data between the 
  11024.       applications that use them.  If many applications that use the same 
  11025.       dynamic link library are executing concurrently, the sharing of code and 
  11026.       data segments improves memory utilization. 
  11027.  
  11028.  
  11029. ΓòÉΓòÉΓòÉ 32.1. NT:  Creating Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  11030.  
  11031.  
  11032. Once you have developed the source for a library of functions, a number of 
  11033. steps are required to create a dynamic link library containing those functions. 
  11034.  
  11035. First, you must compile your source using the "bd" compiler option.  This 
  11036. option tells the compiler that the module you are compiling is part of a 
  11037. dynamic link library.  Once you have successfully compiled your source, you 
  11038. must create a linker directive file that describes the attributes of your 
  11039. dynamic link library.  The following lists the most common linker directives 
  11040. required to create a dynamic link library. 
  11041.  
  11042.    1. The "SYSTEM" directive is used to specify that a dynamic link library is 
  11043.       to be created. 
  11044.  
  11045.    2. The "EXPORT" directive is used to to specify which functions in the 
  11046.       dynamic link library are to be exported. 
  11047.  
  11048.    3. The "OPTION" directive is used to specify attributes such as the name of 
  11049.       the dynamic link library and how to allocate the automatic data segment 
  11050.       when the dynamic link library is referenced. 
  11051.  
  11052.    4. The "SEGMENT" directive is used to specify attributes of segments.  For 
  11053.       example, a segment may be read-only or read-write. 
  11054.  
  11055.  Once the dynamic link library is created, you must allow access to the dynamic 
  11056.  link library to applications that wish to use it.  This can be done by 
  11057.  creating an import library for the dynamic link library or creating a linker 
  11058.  directive file that contains "IMPORT" directives for each of the entry points 
  11059.  in the dynamic link library. 
  11060.  
  11061.  
  11062. ΓòÉΓòÉΓòÉ 32.2. NT:  Creating a Sample Dynamic Link Library ΓòÉΓòÉΓòÉ
  11063.  
  11064.  
  11065. Let us now create a dynamic link library using the following example. 
  11066.  
  11067.  
  11068.    #include <stdio.h> 
  11069.    #include <windows.h> 
  11070.  
  11071.    #if defined(__cplusplus) 
  11072.    #define EXTERNC extern "C" 
  11073.    #else 
  11074.    #define EXTERNC 
  11075.    #endif 
  11076.  
  11077.    DWORD TlsIndex; /* Global Thread Local Storage index */ 
  11078.  
  11079.    /* Error checking should be performed in following code */ 
  11080.  
  11081.    BOOL APIENTRY LibMain( HANDLE hinstDLL, 
  11082.               DWORD  fdwReason, 
  11083.               LPVOID lpvReserved ) 
  11084.    { 
  11085.      switch( fdwReason ) { 
  11086.      case DLL_PROCESS_ATTACH: 
  11087.        /* do process initialization */ 
  11088.  
  11089.        /* create TLS index */ 
  11090.        TlsIndex = TlsAlloc(); 
  11091.        break; 
  11092.  
  11093.      case DLL_THREAD_ATTACH: 
  11094.        /* do thread initialization */ 
  11095.  
  11096.        /* allocate private storage for thread */ 
  11097.        /* and save pointer to it */ 
  11098.        TlsSetValue( TlsIndex, malloc(200) ); 
  11099.        break; 
  11100.  
  11101.      case DLL_THREAD_DETACH: 
  11102.        /* do thread cleanup */ 
  11103.  
  11104.        /* get the TLS value and free associated memory */ 
  11105.        free( TlsGetValue( TlsIndex ) ); 
  11106.        break; 
  11107.  
  11108.      case DLL_PROCESS_DETACH: 
  11109.        /* do process cleanup */ 
  11110.  
  11111.        /* free TLS index */ 
  11112.        TlsFree( TlsIndex ); 
  11113.        break; 
  11114.      } 
  11115.      return( 1 );     /* indicate success */ 
  11116.      /* returning 0 indicates initialization failure */ 
  11117.    } 
  11118.    EXTERNC void dll_entry_1( void ) 
  11119.    { 
  11120.      printf( "Hi from dll entry #1\n" ); 
  11121.    } 
  11122.  
  11123.    EXTERNC void dll_entry_2( void ) 
  11124.    { 
  11125.      printf( "Hi from dll entry #2\n" ); 
  11126.    } 
  11127.  
  11128.  Arguments: 
  11129.  
  11130.  hinstDLL 
  11131.       This is a handle for the DLL.  It can be used as a argument to other 
  11132.       functions such as  GetModuleFileName. 
  11133.  
  11134.  fdwReason 
  11135.       This argument indicates why  LibMain is being called.  It can have one of 
  11136.       the following values: 
  11137.  
  11138.       Value 
  11139.                 Meaning 
  11140.  
  11141.       DLL_PROCESS_ATTACH 
  11142.                 This value indicates that the DLL is attaching to the address 
  11143.                 space of the current process as a result of the process 
  11144.                 starting up or as a result of a call to  LoadLibrary.  A DLL 
  11145.                 can use this opportunity to initialize any instance data or to 
  11146.                 use the  TlsAlloc function to allocate a Thread Local Storage 
  11147.                 (TLS) index. 
  11148.  
  11149.                 During initial process startup or after a call to  LoadLibrary, 
  11150.                 the operating system scans the list of loaded DLLs for the 
  11151.                 process.  For each DLL that has not already been called with 
  11152.                 the DLL_PROCESS_ATTACH value, the system calls the DLL's 
  11153.                 LibMain entry-point.  This call is made in the context of the 
  11154.                 thread that caused the process address space to change, such as 
  11155.                 the primary thread of the process or the thread that called 
  11156.                 LoadLibrary. 
  11157.  
  11158.       DLL_THREAD_ATTACH 
  11159.                 This value indicates that the current process is creating a new 
  11160.                 thread.  When this occurs, the system calls the  LibMain 
  11161.                 entry-point of all DLLs currently attached to the process.  The 
  11162.                 call is made in the context of the new thread.  DLLs can use 
  11163.                 this opportunity to initialize a Thread Local Storage (TLS) 
  11164.                 slot for the thread.  A thread calling the DLL's LibMain with 
  11165.                 the DLL_PROCESS_ATTACH value does not call  LibMain with the 
  11166.                 DLL_THREAD_ATTACH value.  Note that  LibMain is called with 
  11167.                 this value only by threads created after the DLL is attached to 
  11168.                 the process.  When a DLL is attached by  LoadLibrary, existing 
  11169.                 threads do not call the  LibMain entry-point of the newly 
  11170.                 loaded DLL. 
  11171.  
  11172.       DLL_THREAD_DETACH 
  11173.                 This value indicates that a thread is exiting normally.  If the 
  11174.                 DLL has stored a pointer to allocated memory in a TLS slot, it 
  11175.                 uses this opportunity to free the memory.  The operating system 
  11176.                 calls the  LibMain entry-point of all currently loaded DLLs 
  11177.                 with this value.  The call is made in the context of the 
  11178.                 exiting thread.  There are cases in which  LibMain is called 
  11179.                 for a terminating thread even if the DLL never attached to the 
  11180.                 thread.  For example,  LibMain is never called with the 
  11181.                 DLL_THREAD_ATTACH value in the context of the thread in either 
  11182.                 of these two situations: 
  11183.  
  11184.                     The thread was the initial thread in the process, so the 
  11185.                      system called  LibMain with the DLL_PROCESS_ATTACH value. 
  11186.                     The thread was already running when a call to the 
  11187.                      LoadLibrary function was made, so the system never called 
  11188.                      LibMain for it. 
  11189.  
  11190.       DLL_PROCESS_DETACH 
  11191.                 This value indicates that the DLL is detaching from the address 
  11192.                 space of the calling process as a result of either a normal 
  11193.                 termination or of a call to  FreeLibrary.  The DLL can use this 
  11194.                 opportunity to call the  TlsFree function to free any TLS 
  11195.                 indices allocated by using  TlsAlloc and to free any thread 
  11196.                 local data.  When a DLL detaches from a process as a result of 
  11197.                 process termination or as a result of a call to  FreeLibrary, 
  11198.                 the operating system does not call the DLL's  LibMain with the 
  11199.                 DLL_THREAD_DETACH value for the individual threads of the 
  11200.                 process.  The DLL is only given DLL_PROCESS_DETACH 
  11201.                 notification.  DLLs can take this opportunity to clean up all 
  11202.                 resources for all threads attached and known to the DLL. 
  11203.  
  11204.  lpvReserved 
  11205.       This argument specifies further aspects of DLL initialization and 
  11206.       cleanup.  If fdwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for 
  11207.       dynamic loads and non-NULL for static loads.  If fdwReason is 
  11208.       DLL_PROCESS_DETACH, lpvReserved is NULL if  LibMain has been called by 
  11209.       using  FreeLibrary and non-NULL if  LibMain has been called during 
  11210.       process termination. 
  11211.  
  11212.  Return Value 
  11213.       When the system calls the LibMain function with the DLL_PROCESS_ATTACH 
  11214.       value, the function returns TRUE (1) if initialization succeeds or FALSE 
  11215.       (0) if initialization fails. 
  11216.  
  11217.       If the return value is FALSE (0) when  LibMain is called because the 
  11218.       process uses the  LoadLibrary function,  LoadLibrary returns NULL. 
  11219.  
  11220.       If the return value is FALSE (0) when  LibMain is called during process 
  11221.       initialization, the process terminates with an error.  To get extended 
  11222.       error information, call  GetLastError. 
  11223.  
  11224.       When the system calls  LibMain with any value other than 
  11225.       DLL_PROCESS_ATTACH, the return value is ignored. 
  11226.  
  11227.  Assume the above example is contained in the file DLLSAMP.C.  We can compile 
  11228.  the file using the following command.  Note that we must specify the "bd" 
  11229.  compiler option. 
  11230.  
  11231.  
  11232.     C:\>wcc386 /bd dllsamp 
  11233.  
  11234.  Before we can link our example, we must create a linker directive file that 
  11235.  describes the attributes and entry points of our dynamic link library.  The 
  11236.  following is a linker directive file, called DLLSAMP.LNK, that can be used to 
  11237.  create the dynamic link library. 
  11238.  
  11239.  
  11240.     system nt_dll initinstance terminstance 
  11241.     export dll_entry_1_ 
  11242.     export dll_entry_2_ 
  11243.     file dllsamp 
  11244.  
  11245.  Notes: 
  11246.  
  11247.    1. The "SYSTEM" directive specifies that we are creating a Windows NT 
  11248.       dynamic link library. 
  11249.  
  11250.    2. When a dynamic link library uses the Watcom C/C++ run-time libraries, an 
  11251.       automatic data segment is created each time a new process accesses the 
  11252.       dynamic link library.  For this reason, initialization code must be 
  11253.       executed when a process accesses the dynamic link library for the first 
  11254.       time.  To achieve this, "INITINSTANCE" must be specified in the "SYSTEM" 
  11255.       directive.  Similarly, "TERMINSTANCE" must be specified so that the 
  11256.       termination code is executed when a process has completed its access to 
  11257.       the dynamic link library.  If the Watcom C/C++ run-time libraries are not 
  11258.       used, these options are not required. 
  11259.  
  11260.    3. The "EXPORT" directive specifies the entry points into the dynamic link 
  11261.       library.  Note that the names specified in the "EXPORT" directive are 
  11262.       appended with an underscore.  This is the default naming convention used 
  11263.       when compiling using the register-based calling convention.  No 
  11264.       underscore is required when compiling using the stack-based calling 
  11265.       convention. 
  11266.  
  11267.  We can now create our dynamic link library by issuing the following command. 
  11268.  
  11269.  
  11270.     C:\>wlink @dllsamp 
  11271.  
  11272.  A file called DLLSAMP.DLL will be created. 
  11273.  
  11274.  
  11275. ΓòÉΓòÉΓòÉ 32.3. NT:  Using Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  11276.  
  11277.  
  11278. Once we have created a dynamic link library, we must allow other applications 
  11279. to access the functions available in the dynamic link library.  There are two 
  11280. ways to achieve this. 
  11281.  
  11282. The first method is to create a linker directive file which contains an 
  11283. "IMPORT" directive for all entry points in the dynamic link library.  The 
  11284. "IMPORT" directive provides the name of the entry point and the name of the 
  11285. dynamic link library.  When creating an application that references a function 
  11286. in the dynamic link library, this linker directive file would be included as 
  11287. part of the linking process that created the application. 
  11288.  
  11289. The second method is to use import libraries.  An import library is a standard 
  11290. library that is created from a dynamic link library by using the Watcom Library 
  11291. Manager.  It contains object modules that describe the entry points in a 
  11292. dynamic link library.  The resulting import library can then be specified in a 
  11293. "LIBRARY" directive in the same way one would specify a standard library. 
  11294.  
  11295. Using an import library is the preferred method of providing references to 
  11296. functions in dynamic link libraries.  When a dynamic link library is modified, 
  11297. typically the import library corresponding to the modified dynamic link library 
  11298. is updated to reflect the changes.  Hence, any directive file that specifies 
  11299. the import library in a "LIBRARY" directive need not be modified.  However, if 
  11300. you are using "IMPORT" directives, you may have to modify the "IMPORT" 
  11301. directives to reflect the changes in the dynamic link library. 
  11302.  
  11303. Let us create an import library for our sample dynamic link library we created 
  11304. in the previous section.  We do this by issuing the following command. 
  11305.  
  11306.  
  11307.    C:\>wlib dllsamp +dllsamp.dll 
  11308.  
  11309. A standard library called DLLSAMP.LIB will be created. 
  11310.  
  11311. Suppose the following sample program, contained in the file DLLTEST.C, calls 
  11312. the functions from our sample dynamic link library. 
  11313.  
  11314.  
  11315.    #include <stdio.h> 
  11316.    #include <process.h> 
  11317.    #if defined(__cplusplus) 
  11318.    #define EXTERNC extern "C" 
  11319.    #else 
  11320.    #define EXTERNC 
  11321.    #endif 
  11322.  
  11323.    EXTERNC void dll_entry_1( void ); 
  11324.    EXTERNC void dll_entry_2( void ); 
  11325.  
  11326.    #define STACK_SIZE    8192 
  11327.  
  11328.    static void thread( void *arglist ) 
  11329.    { 
  11330.      printf( "Hi from thread\n" ); 
  11331.      _endthread(); 
  11332.    } 
  11333.  
  11334.    int main( void ) 
  11335.    { 
  11336.      unsigned long  tid; 
  11337.  
  11338.      dll_entry_1(); 
  11339.      tid = _beginthread( thread, STACK_SIZE, NULL ); 
  11340.      dll_entry_2(); 
  11341.      return( 0 ); 
  11342.    } 
  11343.  
  11344. We can compile and link our sample application by issuing the following 
  11345. command. 
  11346.  
  11347.  
  11348.    C:\>wcl386 /bm /l=nt dlltest dllsamp.lib 
  11349.  
  11350. If we had created a linker directive file of "IMPORT" directives instead of an 
  11351. import library for the dynamic link library, the linker directive file, say 
  11352. DLLIMPS.LNK, would be as follows. 
  11353.  
  11354.  
  11355.    import dll_entry_1_ dllsamp 
  11356.    import dll_entry_2_ dllsamp 
  11357.  
  11358. Note that the names specified in the "IMPORT" directive are appended with an 
  11359. underscore.  This is the default naming convention used when compiling using 
  11360. the register-based calling convention.  No underscore is required when 
  11361. compiling using the stack-based calling convention. 
  11362.  
  11363. To compile and link our sample application, we would issue the following 
  11364. command. 
  11365.  
  11366.  
  11367.    C:\>wcl386 /bm /l=nt dlltest /"@dllimps" 
  11368.  
  11369.  
  11370. ΓòÉΓòÉΓòÉ 32.4. NT:  The Dynamic Link Library Data Area ΓòÉΓòÉΓòÉ
  11371.  
  11372.  
  11373. The Watcom C/C++ 32-bit run-time library does not support the general case 
  11374. operation of DLLs in an execution environment where there is only one instance 
  11375. of the DATA segment (DGROUP) for that DLL. 
  11376.  
  11377. There are two cases that can lead to a DLL executing with only one instance of 
  11378. the DGROUP. 
  11379.  
  11380.    1. DLLs linked for 32-bit OS/2 without the MANYAUTODATA option. 
  11381.  
  11382.    2. DLLs linked for the Win32 API and executing under Win32s. 
  11383.  
  11384.  In these cases the run-time library startup code detects that there is only 
  11385.  one instance of the DGROUP when a second process attempts to attach to the 
  11386.  DLL.  At that point, it issues a diagnostic for the user and then notifies the 
  11387.  operating system that the second process cannot attach to the DLL. 
  11388.  
  11389.  Developers who require DLLs to operate when there is only one instance of the 
  11390.  DGROUP can suppress the function which issues the diagnostic and notifies the 
  11391.  operating system that the second process cannot attach to the DLL. 
  11392.  
  11393.  Doing so requires good behaviour on the part of processes attaching to the 
  11394.  DLL.  This good behaviour consists primarily of ensuring that the first 
  11395.  process to attach to the DLL is also the last process to detach from the DLL 
  11396.  thereby ensuring that the DATA segment is not released back to the free memory 
  11397.  pool. 
  11398.  
  11399.  To suppress the function which issues the diagnostic and notifies the 
  11400.  operating system that the second process cannot attach to the DLL, the 
  11401.  developer must provide a replacement entry point with the following prototype: 
  11402.  
  11403.  
  11404.     int __disallow_single_dgroup( int ); 
  11405.  
  11406.  This function should return zero to indicate that the detected single copy of 
  11407.  the DATA segment is allowed. 
  11408.  
  11409.  
  11410. ΓòÉΓòÉΓòÉ 33. NT:  Creating Windows NT POSIX Applications ΓòÉΓòÉΓòÉ
  11411.  
  11412.  
  11413. This chapter describes how to compile and link POSIX applications for Windows 
  11414. NT.  There are a number of issues to consider. 
  11415.  
  11416.    1. Watcom does not provide its own POSIX libraries.  You must use those 
  11417.       included with the Microsoft Win32 SDK. They are LIBCPSX.LIB, PSXDLL.LIB 
  11418.       and PSXRTL.LIB.  If you installed the Win32 SDK component when you 
  11419.       installed the Watcom software, you will find these libraries in the 
  11420.       %WATCOM%\LIB386\NT directory. 
  11421.  
  11422.    2. Since you will be using Microsoft POSIX libraries compiled by the 
  11423.       Microsoft compiler, you must follow the calling conventions used by 
  11424.       Microsoft (i.e., the __cdecl convention).  The Watcom compiler can 
  11425.       generate these calling conventions provided that the POSIX library 
  11426.       routines are all properly prototyped. 
  11427.  
  11428.    3. Watcom does not provide its own header files for use with the Microsoft 
  11429.       POSIX libraries.  The Microsoft Win32 SDK includes only a subset of the 
  11430.       headers required for calling the POSIX library routines.  If you 
  11431.       installed the Win32 SDK component when you installed the Watcom software, 
  11432.       you will find these headers in the %WATCOM%\SDK\POSIX\H and 
  11433.       %WATCOM%\SDK\POSIX\H\SYS directories.  Take a look at these directories 
  11434.       to see what is and what is not included. 
  11435.  
  11436.    4. If you have the Microsoft compiler, then you will likely have access to 
  11437.       the missing header files.  If you do not have the Microsoft compiler, 
  11438.       then you will have to define prototypes for any of the POSIX library 
  11439.       routines that you use for which no prototypes are defined in any of the 
  11440.       POSIX header files. 
  11441.  
  11442.    5. There is one exception to the generation of the __cdecl calling 
  11443.       convention for appropriately prototyped functions.  This is the main 
  11444.       function.  Since many Microsoft sample programs inappropriately declare 
  11445.       the main function as __cdecl, it was necessary to make a special case in 
  11446.       the Watcom compilers to ignore the __cdecl attribute when used for this 
  11447.       entry point.  To work around this problem, a special pragma is used. 
  11448.       This is shown in the following example. 
  11449.  
  11450.    6. Since we are going to use the Microsoft POSIX libraries rather than the 
  11451.       Watcom libraries, we will use the "zl" compile option to instruct the 
  11452.       Watcom compiler not to include references to Watcom libraries in the 
  11453.       object files. 
  11454.  
  11455.  To illustrate the creation of a POSIX application, we will use a simple 
  11456.  example.  This program displays an identifying banner and then displays its 
  11457.  arguments one at a time. 
  11458.  
  11459.  Example: 
  11460.  
  11461.     [POSIXSMP.C] 
  11462.     #include <unistd.h> 
  11463.  
  11464.     // The Win32 SDK doesn't provide a complete set of 
  11465.     // headers for the libraries (e.g., no stdio.h). 
  11466.  
  11467.     extern int __cdecl printf( char *, ... ); 
  11468.  
  11469.     // Note: the "__cdecl" attribute is ignored for main(). 
  11470.  
  11471.     int __cdecl main( int argc, char **argv ) 
  11472.     { 
  11473.       int i; 
  11474.       printf( "POSIX sample program\n" ); 
  11475.       for( i = 0 ; i < argc ; i++ ) { 
  11476.         printf( "%d: %s\n", i, argv[i] ); 
  11477.       } 
  11478.       return 0; 
  11479.     } 
  11480.  
  11481.     // Since the "__cdecl" attribute is ignored, 
  11482.     // make sure that parms go on the stack for main 
  11483.     // and that main gets the _ in the right place by 
  11484.     // using a pragma to do so. 
  11485.  
  11486.     #pragma aux main "_*" parm []; 
  11487.  
  11488.     // The compiler emits references to these symbols, 
  11489.     // so make sure they get defined here to prevent 
  11490.     // unresolved references. 
  11491.  
  11492.     int _cstart_; 
  11493.     #pragma aux _cstart_ "*"; 
  11494.     int __argc; 
  11495.     #pragma aux __argc "*"; 
  11496.  
  11497.  The example program illustrates some of the special considerations required 
  11498.  for using the Microsoft POSIX libraries rather than the Watcom libraries. 
  11499.  There are also some special link time issues and these are addressed in the 
  11500.  following sample "makefile". 
  11501.  
  11502.  Example: 
  11503.  
  11504.     [MAKEFILE] 
  11505.     posixsmp.exe : posixsmp.c posix.add makefile. 
  11506.      set nt_include= 
  11507.      set include=$(%watcom)\sdk\posix\h;$(%watcom)\sdk\posix\h\sys 
  11508.      wcc386 -bt=nt -oaxt -zl posixsmp.c 
  11509.      wlink @posix.add file posixsmp sys nt_posix option map 
  11510.  
  11511.     posix.add : 
  11512.      %create posix.add 
  11513.      %append posix.add system begin nt_posix 
  11514.      %append posix.add  option osname='Windows NT character-mode posix' 
  11515.      %append posix.add  libpath %WATCOM%\lib386\nt 
  11516.      %append posix.add  option nodefaultlib 
  11517.      %append posix.add  option start=___PosixProcessStartup 
  11518.      %append posix.add  lib { libcpsx.lib psxrtl.lib psxdll.lib } 
  11519.      %append posix.add  format windows nt ^ 
  11520.      %append posix.add  runtime posix 
  11521.      %append posix.add end 
  11522.  
  11523.  A new "nt_posix" system is defined in the POSIX.ADD file.  This file is 
  11524.  generated automatically by the makefile. 
  11525.  
  11526.  That is about all there is to creating a Windows NT POSIX application.  One 
  11527.  final note - make sure when using the Microsoft headers that all the library 
  11528.  routines that you use are declared as __cdecl otherwise your application will 
  11529.  not run correctly. 
  11530.  
  11531.  
  11532. ΓòÉΓòÉΓòÉ 34. 16-bit OS/2:  Creating 16-bit OS/2 1.x Applications ΓòÉΓòÉΓòÉ
  11533.  
  11534.  
  11535.  
  11536. An OS/2 application can be one of the following; a fullscreen application, a 
  11537. PM-compatible application, or a Presentation Manager application.  A fullscreen 
  11538. application runs in its own screen group.  A PM-compatible application will run 
  11539. in an OS/2 fullscreen environment or in a window in the Presentation Manager 
  11540. screen group but does not take direct advantage of menus, mouse or other 
  11541. features available in the Presentation Manager.  A Presentation Manager 
  11542. application has full access to the complete set of user-interface tools such as 
  11543. menus, icons, scroll bars, etc. 
  11544.  
  11545. This chapter deals with the creation of OS/2 fullscreen applications.  For 
  11546. information on creating Presentation Manager applications, refer to the section 
  11547. entitled OS/2:  Programming for OS/2 Presentation Manager. 
  11548.  
  11549. We will illustrate the steps to creating 16-bit OS/2 1.x applications by taking 
  11550. a small sample application and showing you how to compile, link, run and debug 
  11551. it. 
  11552.  
  11553.  
  11554. ΓòÉΓòÉΓòÉ 34.1. 16-bit OS/2:  The Sample Application ΓòÉΓòÉΓòÉ
  11555.  
  11556.  
  11557. To demonstrate the creation of 16-bit OS/2 1.x applications using command-line 
  11558. oriented tools, we introduce a simple sample program.  For our example, we are 
  11559. going to use the famous "hello" program. 
  11560.  
  11561.  
  11562.    #include <stdio.h> 
  11563.  
  11564.    void main() 
  11565.     { 
  11566.      printf( "Hello world\n" ); 
  11567.     } 
  11568.  
  11569. The C++ version of this program follows: 
  11570.  
  11571.  
  11572.    #include <iostream.h> 
  11573.    #include <iomanip.h> 
  11574.  
  11575.    void main() 
  11576.    { 
  11577.      cout << "Hello world" << endl; 
  11578.    } 
  11579.  
  11580. The goal of this program is to display the message "Hello world" on the screen. 
  11581. The C version uses the C library printf routine to accomplish this task.  The 
  11582. C++ version uses the "iostream" library to accomplish this task.  We will take 
  11583. you through the steps necessary to produce this result. 
  11584.  
  11585.  
  11586. ΓòÉΓòÉΓòÉ 34.2. 16-bit OS/2:  Building and Running the Sample OS/2 1.x Application ΓòÉΓòÉΓòÉ
  11587.  
  11588.  
  11589. To compile and link our example program which is stored in the file HELLO.C, 
  11590. enter the following command: 
  11591.  
  11592.  
  11593.    [C:\]wcl /l=os2 hello.c 
  11594.  
  11595. The typical messages that appear on the screen are shown in the following 
  11596. illustration. 
  11597.  
  11598.  
  11599.    [C:\]wcl /l=os2 hello.c 
  11600.    WATCOM C/C++16 Compile and Link Utility 
  11601.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  11602.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11603.        wcc hello.c 
  11604.    WATCOM C16 Optimizing Compiler 
  11605.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  11606.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11607.    hello.c: 6 lines, included 155, 0 warnings, 0 errors 
  11608.    Code size: 17 
  11609.  
  11610.    WATCOM Linker 
  11611.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  11612.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11613.    loading object files 
  11614.    searching libraries 
  11615.    creating an OS/2 16-bit executable 
  11616.  
  11617. Provided that no errors were encountered during the compile or link phases, the 
  11618. "hello" program may now be run. 
  11619.  
  11620.  
  11621.    [C:\]hello 
  11622.    Hello world 
  11623.  
  11624. If you examine the current directory, you will find that two files have been 
  11625. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  11626. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  11627. It is HELLO.EXE that is run by OS/2 when you enter the "hello" command. 
  11628.  
  11629.  
  11630. ΓòÉΓòÉΓòÉ 34.3. 16-bit OS/2:  Debugging the Sample OS/2 1.x Application ΓòÉΓòÉΓòÉ
  11631.  
  11632.  
  11633. Let us assume that you wish to debug your application in order to locate an 
  11634. error in programming.  In the previous section, the "hello" program was 
  11635. compiled with default compile and link options.  When debugging an application, 
  11636. it is useful to refer to the symbolic names of routines and variables.  It is 
  11637. also convenient to debug at the source line level rather than the machine 
  11638. language level.  To do this, we must direct both the compiler and linker to 
  11639. include additional debugging information in the object and executable files. 
  11640. Using the  WCL command, this is fairly straightforward.  WCL recognizes the 
  11641. Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  11642. directives for the Watcom Linker. 
  11643.  
  11644. For example, to compile and link the "hello" program with debugging 
  11645. information, the following command may be issued. 
  11646.  
  11647.  
  11648.    [C:\]wcl /l=os2 /d2 hello.c 
  11649.  
  11650. The typical messages that appear on the screen are shown in the following 
  11651. illustration. 
  11652.  
  11653.  
  11654.    [C:\]wcl /l=os2 /d2 hello.c 
  11655.    WATCOM C/C++16 Compile and Link Utility 
  11656.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  11657.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11658.        wcc hello.c  /d2 
  11659.    WATCOM C16 Optimizing Compiler 
  11660.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  11661.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11662.    hello.c: 6 lines, included 155, 0 warnings, 0 errors 
  11663.    Code size: 23 
  11664.  
  11665.    WATCOM Linker 
  11666.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  11667.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11668.    loading object files 
  11669.    searching libraries 
  11670.    creating an OS/2 16-bit executable 
  11671.  
  11672. The "d2" option requests the maximum amount of debugging information that can 
  11673. be provided by the Watcom C/C++ compiler.  WCL will make sure that this 
  11674. debugging information is included in the executable file that is produced by 
  11675. the linker. 
  11676.  
  11677. The "Code size" value is larger than in the previous example since selection of 
  11678. the "d2" option results in fewer code optimizations by default.  You can 
  11679. request more optimization by specifying the appropriate options.  However, you 
  11680. do so at the risk of making it more difficult for yourself to determine the 
  11681. relationship between the object code and the original source language code. 
  11682.  
  11683. For OS/2, you should also include the BINP\DLL directory in the "LIBPATH" 
  11684. directive of the system configuration file CONFIG.SYS.  It contains the Watcom 
  11685. Debugger Dynamic Link Libraries (DLLs). 
  11686.  
  11687. Example: 
  11688.  
  11689.    libpath=c:\watcom\binp\dll 
  11690.  
  11691. To request the Watcom Debugger to assist in debugging the application, the 
  11692. following command may be issued. 
  11693.  
  11694.  
  11695.    [C:\]wd hello 
  11696.  
  11697. It would be too ambitious to describe the debugger in this introductory chapter 
  11698. so we refer you to the book entitled Watcom Debugger User's Guide. 
  11699.  
  11700.  
  11701. ΓòÉΓòÉΓòÉ 35. 32-bit OS/2:  Creating 32-bit OS/2 Applications ΓòÉΓòÉΓòÉ
  11702.  
  11703.  
  11704. An OS/2 application can be one of the following; a fullscreen application, a 
  11705. PM-compatible application, or a Presentation Manager application.  A fullscreen 
  11706. application runs in its own screen group.  A PM-compatible application will run 
  11707. in an OS/2 fullscreen environment or in a window in the Presentation Manager 
  11708. screen group but does not take direct advantage of menus, mouse or other 
  11709. features available in the Presentation Manager.  A Presentation Manager 
  11710. application has full access to the complete set of user-interface tools such as 
  11711. menus, icons, scroll bars, etc. 
  11712.  
  11713. This chapter deals with the creation of OS/2 fullscreen applications.  For 
  11714. information on creating Presentation Manager applications, refer to the section 
  11715. entitled OS/2:  Programming for OS/2 Presentation Manager. 
  11716.  
  11717. We will illustrate the steps to creating 32-bit OS/2 applications by taking a 
  11718. small sample application and showing you how to compile, link, run and debug 
  11719. it. 
  11720.  
  11721.  
  11722. ΓòÉΓòÉΓòÉ 35.1. 32-bit OS/2:  The Sample Application ΓòÉΓòÉΓòÉ
  11723.  
  11724.  
  11725. To demonstrate the creation of 32-bit OS/2 applications using command-line 
  11726. oriented tools, we introduce a simple sample program.  For our example, we are 
  11727. going to use the famous "hello" program. 
  11728.  
  11729.  
  11730.    #include <stdio.h> 
  11731.  
  11732.    void main() 
  11733.     { 
  11734.      printf( "Hello world\n" ); 
  11735.     } 
  11736.  
  11737. The C++ version of this program follows: 
  11738.  
  11739.  
  11740.    #include <iostream.h> 
  11741.    #include <iomanip.h> 
  11742.  
  11743.    void main() 
  11744.    { 
  11745.      cout << "Hello world" << endl; 
  11746.    } 
  11747.  
  11748. The goal of this program is to display the message "Hello world" on the screen. 
  11749. The C version uses the C library printf routine to accomplish this task.  The 
  11750. C++ version uses the "iostream" library to accomplish this task.  We will take 
  11751. you through the steps necessary to produce this result. 
  11752.  
  11753.  
  11754. ΓòÉΓòÉΓòÉ 35.2. 32-bit OS/2:  Building and Running the Sample OS/2 Application ΓòÉΓòÉΓòÉ
  11755.  
  11756.  
  11757. To compile and link our example program which is stored in the file HELLO.C, 
  11758. enter the following command: 
  11759.  
  11760.  
  11761.    [C:\]wcl386 /l=os2v2 hello.c 
  11762.  
  11763. The typical messages that appear on the screen are shown in the following 
  11764. illustration. 
  11765.  
  11766.  
  11767.    [C:\]wcl386 /l=os2v2 hello.c 
  11768.    WATCOM C/C++32 Compile and Link Utility 
  11769.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  11770.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11771.        wcc386 hello.c 
  11772.    WATCOM C32 Optimizing Compiler 
  11773.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  11774.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11775.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  11776.    Code size: 24 
  11777.  
  11778.    WATCOM Linker 
  11779.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  11780.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11781.    loading object files 
  11782.    searching libraries 
  11783.    creating an OS/2 32-bit executable 
  11784.  
  11785. Provided that no errors were encountered during the compile or link phases, the 
  11786. "hello" program may now be run. 
  11787.  
  11788.  
  11789.    [C:\]hello 
  11790.    Hello world 
  11791.  
  11792. If you examine the current directory, you will find that two files have been 
  11793. created.  These are HELLO.OBJ (the result of compiling HELLO.C) and HELLO.EXE 
  11794. (the result of linking HELLO.OBJ with the appropriate Watcom C/C++ libraries). 
  11795. It is HELLO.EXE that is run by OS/2 when you enter the "hello" command. 
  11796.  
  11797.  
  11798. ΓòÉΓòÉΓòÉ 35.3. 32-bit OS/2:  Debugging the Sample OS/2 Application ΓòÉΓòÉΓòÉ
  11799.  
  11800.  
  11801. Let us assume that you wish to debug your application in order to locate an 
  11802. error in programming.  In the previous section, the "hello" program was 
  11803. compiled with default compile and link options.  When debugging an application, 
  11804. it is useful to refer to the symbolic names of routines and variables.  It is 
  11805. also convenient to debug at the source line level rather than the machine 
  11806. language level.  To do this, we must direct both the compiler and linker to 
  11807. include additional debugging information in the object and executable files. 
  11808. Using the  WCL386 command, this is fairly straightforward.  WCL386 recognizes 
  11809. the Watcom C/C++ compiler "debug" options and will create the appropriate debug 
  11810. directives for the Watcom Linker. 
  11811.  
  11812. For example, to compile and link the "hello" program with debugging 
  11813. information, the following command may be issued. 
  11814.  
  11815.  
  11816.    [C:\]wcl386 /l=os2v2 /d2 hello.c 
  11817.  
  11818. The typical messages that appear on the screen are shown in the following 
  11819. illustration. 
  11820.  
  11821.  
  11822.    [C:\]wcl386 /l=os2v2 /d2 hello.c 
  11823.    WATCOM C/C++32 Compile and Link Utility 
  11824.    Copyright by WATCOM International Corp. 1988, 1997. All rights reserved. 
  11825.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11826.        wcc386 hello.c  /d2 
  11827.    WATCOM C32 Optimizing Compiler 
  11828.    Copyright by WATCOM International Corp. 1984, 1997. All rights reserved. 
  11829.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11830.    hello.c: 6 lines, included 174, 0 warnings, 0 errors 
  11831.    Code size: 45 
  11832.  
  11833.    WATCOM Linker 
  11834.    Copyright by WATCOM International Corp. 1985, 1997. All rights reserved. 
  11835.    WATCOM is a trademark of Sybase, Inc. and its subsidiaries. 
  11836.    loading object files 
  11837.    searching libraries 
  11838.    creating an OS/2 32-bit executable 
  11839.  
  11840. The "d2" option requests the maximum amount of debugging information that can 
  11841. be provided by the Watcom C/C++ compiler.  WCL386 will make sure that this 
  11842. debugging information is included in the executable file that is produced by 
  11843. the linker. 
  11844.  
  11845. The "Code size" value is larger than in the previous example since selection of 
  11846. the "d2" option results in fewer code optimizations by default.  You can 
  11847. request more optimization by specifying the appropriate options.  However, you 
  11848. do so at the risk of making it more difficult for yourself to determine the 
  11849. relationship between the object code and the original source language code. 
  11850.  
  11851. To request the Watcom Debugger to assist in debugging the application, the 
  11852. following command may be issued. 
  11853.  
  11854.  
  11855.    [C:\]wd hello 
  11856.  
  11857. It would be too ambitious to describe the debugger in this introductory chapter 
  11858. so we refer you to the book entitled Watcom Debugger User's Guide. 
  11859.  
  11860.  
  11861. ΓòÉΓòÉΓòÉ 36. OS/2:  OS/2 2.x Multi-threaded Applications ΓòÉΓòÉΓòÉ
  11862.  
  11863.  
  11864. This chapter describes how to create multi-threaded applications.  A 
  11865. multi-threaded application is one whose tasks are divided among several threads 
  11866. of execution.  A process is an executing application and the resources it uses. 
  11867. A thread is the smallest unit of execution within a process.  Each thread has 
  11868. its own stack and a set of machine registers and shares all resources with its 
  11869. parent process.  The path of execution of one thread does not affect that of 
  11870. another; each thread is an independent entity. 
  11871.  
  11872. Typically, an application has a single thread of execution.  In this type of 
  11873. application, all tasks, once initiated, are completed before the next task 
  11874. begins.  In contrast, tasks in a multi-threaded application can be performed 
  11875. concurrently since more than one thread is executing at once.  For example, 
  11876. each thread may be designed to perform a separate task. 
  11877.  
  11878.  
  11879. ΓòÉΓòÉΓòÉ 36.1. OS/2:  Programming Considerations ΓòÉΓòÉΓòÉ
  11880.  
  11881.  
  11882. Since a multi-threaded application consists of many threads of execution, there 
  11883. are a number of issues that you must consider. 
  11884.  
  11885. Since threads share the resources of its parent, it may be necessary to 
  11886. serialize access to these resources.  For example, if your application has a 
  11887. function that displays information on the console and is used by all threads, 
  11888. it is necessary to allow only one thread to use that function at any time. 
  11889. That is, once a thread calls that function, the function should ensure that no 
  11890. other thread displays information until all information for the initial thread 
  11891. has been displayed.  An example of such a function is the printf library 
  11892. function. 
  11893.  
  11894. Another issue that must be considered when creating multi-threaded applications 
  11895. is global variables.  If you have global variables that contain thread-specific 
  11896. information, there must be an instance of each global variable for each thread. 
  11897. An example of such a variable is the errno global variable defined in the 
  11898. run-time libraries.  If an error condition was created by a thread, you would 
  11899. not want it to affect the execution of other threads.  Therefore, each thread 
  11900. should contain its own instance of this variable. 
  11901.  
  11902.  
  11903. ΓòÉΓòÉΓòÉ 36.2. OS/2:  Creating Threads ΓòÉΓòÉΓòÉ
  11904.  
  11905.  
  11906. Each application initially contains a single thread.  The run-time libraries 
  11907. contain two functions that create and terminate threads of execution.  The 
  11908. function _beginthread creates a thread of execution and the function _endthread 
  11909. ends a thread of execution.  The macro _threadid can be used to determine the 
  11910. current thread identifier. 
  11911.  
  11912. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  11913.  
  11914.  WARNING!  If any thread calls a library function, you must use the 
  11915. _beginthread function to create the thread.  Do not use the DosCreateThread API 
  11916. function. 
  11917.  
  11918. ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
  11919.  
  11920.  
  11921. ΓòÉΓòÉΓòÉ 36.2.1. OS/2:  Creating a New Thread ΓòÉΓòÉΓòÉ
  11922.  
  11923.  
  11924. The _beginthread function creates a new thread.  It is defined as follows. 
  11925.  
  11926.  
  11927.    int _beginthread( void (*start_address)(void *), 
  11928.             void *stack_bottom, 
  11929.             unsigned stack_size, 
  11930.             void *arglist ); 
  11931.  
  11932.  where 
  11933.       description 
  11934.  
  11935.  start_address 
  11936.       is the address of the function that will be called when the newly created 
  11937.       thread is executed.  When the thread returns from that function, the 
  11938.       thread will be terminated.  Note that a call to the _endthread function 
  11939.       will also terminate the thread. 
  11940.  
  11941.  stack_bottom 
  11942.       specifies the bottom of the stack to be used by the thread.  Note that 
  11943.       this argument is ignored as it is only needed to simplify the port of 
  11944.       OS/2 1.x multi-threaded applications to OS/2 2.x.  Under OS/2 2.x, the 
  11945.       operating system allocates the stack for the new thread.  A value of NULL 
  11946.       may be specified. 
  11947.  
  11948.  stack_size 
  11949.       specifies the size of the stack to be allocated by the operating system 
  11950.       for the new thread.  The stack size should be a multiple of 4K. 
  11951.  
  11952.  arglist 
  11953.       is passed as an argument to the function specified by start_address.  If 
  11954.       no argument is required, a value of NULL can be specified. 
  11955.  
  11956.  If a new thread is successfully created, the thread identifier of the new 
  11957.  thread is returned.  Otherwise, a value of -1 is returned. 
  11958.  
  11959.  The header file PROCESS.H contains the definition of the _beginthread 
  11960.  function. 
  11961.  
  11962.  
  11963. ΓòÉΓòÉΓòÉ 36.2.2. OS/2:  Terminating the Current Thread ΓòÉΓòÉΓòÉ
  11964.  
  11965.  
  11966. The _endthread function terminates the current thread.  It is defined as 
  11967. follows. 
  11968.  
  11969.  
  11970.    void _endthread( void ) 
  11971.  
  11972. The header file PROCESS.H contains the definition of the _endthread function. 
  11973.  
  11974.  
  11975. ΓòÉΓòÉΓòÉ 36.2.3. OS/2:  Getting the Current Thread Identifier ΓòÉΓòÉΓòÉ
  11976.  
  11977.  
  11978. The _threadid macro can be used to determine the current thread identifier.  It 
  11979. is defined as follows. 
  11980.  
  11981.  
  11982.    int *__threadid(void); 
  11983.    #define _threadid (__threadid()) 
  11984.  
  11985. The header file STDDEF.H contains the definition of the _threadid macro. 
  11986.  
  11987.  
  11988. ΓòÉΓòÉΓòÉ 36.3. OS/2:  A Multi-threaded Example ΓòÉΓòÉΓòÉ
  11989.  
  11990.  
  11991. Let us create a simple multi-threaded application. 
  11992.  
  11993.  
  11994.    #include <process.h> 
  11995.    #include <stdio.h> 
  11996.    #include <stddef.h> 
  11997.    #define INCL_DOS 
  11998.    #include <os2.h> 
  11999.  
  12000.    static  volatile int   NumThreads; 
  12001.    static  volatile int   HoldThreads; 
  12002.  
  12003.    #define NUM_THREADS   5 
  12004.    #define STACK_SIZE    8192 
  12005.  
  12006.    static void a_thread( void *arglist ) 
  12007.    /***********************************/ 
  12008.    { 
  12009.      while( HoldThreads ) { 
  12010.        DosSleep( 1 ); 
  12011.      } 
  12012.      printf( "Hi from thread %d\n", *_threadid ); 
  12013.      DosEnterCritSec(); 
  12014.      --NumThreads; 
  12015.      DosExitCritSec(); 
  12016.      _endthread(); 
  12017.    } 
  12018.  
  12019.    int main( void ) 
  12020.    /**************/ 
  12021.    { 
  12022.      int     i; 
  12023.  
  12024.      printf( "Initial thread id = %d\n", *_threadid ); 
  12025.      NumThreads = 0; 
  12026.      HoldThreads = 1; 
  12027.      /* initial thread counts as 1 */ 
  12028.      for( i = 2; i <= NUM_THREADS; ++i ) { 
  12029.        if( _beginthread( a_thread, NULL, STACK_SIZE, NULL ) == -1 ) { 
  12030.          printf( "creation of thread %d failed\n", i ); 
  12031.        } else { 
  12032.          ++NumThreads; 
  12033.        } 
  12034.      } 
  12035.  
  12036.      HoldThreads = 0; 
  12037.      while( NumThreads != 0 ) { 
  12038.        DosSleep( 1 ); 
  12039.      } 
  12040.      return( 0 ); 
  12041.    } 
  12042.  
  12043. Note: 
  12044.  
  12045.    1. In the function a_thread, DosEnterCritSec and DosExitCritSec are called 
  12046.       when we modify the variable NumThreads.  This ensures that the action of 
  12047.       extracting the value of NumThreads from memory, incrementing the value, 
  12048.       and storing the new result into memory, occurs without interruption.  If 
  12049.       these functions were not called, it would be possible for two threads to 
  12050.       extract the value of NumThreads from memory before an update occurred. 
  12051.  
  12052.  Let us assume that the file MTHREAD.C contains the above example.  Before 
  12053.  compiling the file, make sure that the WATCOM environment variable is set to 
  12054.  the directory in which you installed Watcom C/C++.  Also, the INCLUDE 
  12055.  environment variable must include the \WATCOM\H\OS2 and \WATCOM\H directories 
  12056.  ("\WATCOM" is the directory in which Watcom C/C++ was installed). 
  12057.  
  12058.  We can now compile and link the application by issuing the following command. 
  12059.  
  12060.  
  12061.     [C:\]wcl386 /bt=os2 /bm /l=os2v2 mthread 
  12062.  
  12063.  The "bm" option must be specified since we are creating a multi-threaded 
  12064.  application.  If your multi-threaded application contains more than one 
  12065.  module, each module must be compiled using the "bm" switch. 
  12066.  
  12067.  The "l" option specifies the target system for which the application is to be 
  12068.  linked.  The system name os2v2 is defined in the file WLSYSTEM.LNK which is 
  12069.  located in the "BINW" directory of the directory in which you installed Watcom 
  12070.  C/C++. 
  12071.  
  12072.  The multi-threaded application is now ready to be run. 
  12073.  
  12074.  
  12075. ΓòÉΓòÉΓòÉ 36.4. OS/2:  Thread Limits ΓòÉΓòÉΓòÉ
  12076.  
  12077.  
  12078. There is a limit to the number of threads an application can create under 
  12079. 16-bit OS/2.  The default limit is 32.  This limit can be adjusted by 
  12080. statically initializing the unsigned global variable __MaxThreads. 
  12081.  
  12082. Under 32-bit OS/2, there is no limit to the number of threads an application 
  12083. can create.  However, due to the way in which multiple threads are supported in 
  12084. the WATCOM libraries, there is a small performance penalty once the number of 
  12085. threads exceeds the default limit of 32 (this number includes the initial 
  12086. thread).  If you are creating more than 32 threads and wish to avoid this 
  12087. performance penalty, you can redefine the threshold value of 32.  You can 
  12088. statically initialize the global variable __MaxThreads. 
  12089.  
  12090. By adding the following line to your multi-threaded application, the new 
  12091. threshold value will be set to 48. 
  12092.  
  12093.  
  12094.    unsigned __MaxThreads = { 48 }; 
  12095.  
  12096.  
  12097. ΓòÉΓòÉΓòÉ 37. OS/2:  OS/2 2.x Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  12098.  
  12099.  
  12100. A dynamic link library, like a standard library, is a library of functions. 
  12101. When an application uses functions from a standard library, the library 
  12102. functions referenced by the application become part of the executable module. 
  12103. This form of linking is called static linking.  When an application uses 
  12104. functions from a dynamic link library, the library functions referenced by the 
  12105. application are not included in the executable module.  Instead, the executable 
  12106. module contains references to these functions which are resolved when the 
  12107. application is loaded.  This form of linking is called dynamic linking. 
  12108.  
  12109. Let us consider some of the advantages of using dynamic link libraries over 
  12110. standard libraries. 
  12111.  
  12112.    1. Functions in dynamic link libraries are not linked into your program. 
  12113.       Only references to the functions in dynamic link libraries are placed in 
  12114.       the program module.  These references are called import definitions.  As 
  12115.       a result, the linking time is reduced and disk space is saved.  If many 
  12116.       applications reference the same dynamic link library, the saving in disk 
  12117.       space can be significant. 
  12118.  
  12119.    2. Since program modules only reference dynamic link libraries and do not 
  12120.       contain the actual executable code, a dynamic link library can be updated 
  12121.       without re-linking your application.  When your application is executed, 
  12122.       it will use the updated version of the dynamic link library. 
  12123.  
  12124.    3. Dynamic link libraries also allow sharing of code and data between the 
  12125.       applications that use them.  If many applications that use the same 
  12126.       dynamic link library are executing concurrently, the sharing of code and 
  12127.       data segments improves memory utilization. 
  12128.  
  12129.  
  12130. ΓòÉΓòÉΓòÉ 37.1. OS/2:  Creating Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  12131.  
  12132.  
  12133. Once you have developed the source for a library of functions, a number of 
  12134. steps are required to create a dynamic link library containing those functions. 
  12135.  
  12136. First, you must compile your source using the "bd" compiler option.  This 
  12137. option tells the compiler that the module you are compiling is part of a 
  12138. dynamic link library.  Once you have successfully compiled your source, you 
  12139. must create a linker directive file that describes the attributes of your 
  12140. dynamic link library.  The following lists the most common linker directives 
  12141. required to create a dynamic link library. 
  12142.  
  12143.    1. The "SYSTEM" directive is used to specify that a dynamic link library is 
  12144.       to be created. 
  12145.  
  12146.    2. The "EXPORT" directive is used to to specify which functions in the 
  12147.       dynamic link library are to be exported. 
  12148.  
  12149.    3. The "OPTION" directive is used to specify attributes such as the name of 
  12150.       the dynamic link library and how to allocate the automatic data segment 
  12151.       when the dynamic link library is referenced. 
  12152.  
  12153.    4. The "SEGMENT" directive is used to specify attributes of segments.  For 
  12154.       example, a segment may be read-only or read-write. 
  12155.  
  12156.  Once the dynamic link library is created, you must allow access to the dynamic 
  12157.  link library to applications that wish to use it.  This can be done by 
  12158.  creating an import library for the dynamic link library or creating a linker 
  12159.  directive file that contains "IMPORT" directives for each of the entry points 
  12160.  in the dynamic link library. 
  12161.  
  12162.  
  12163. ΓòÉΓòÉΓòÉ 37.2. OS/2:  Creating a Sample Dynamic Link Library ΓòÉΓòÉΓòÉ
  12164.  
  12165.  
  12166. Let us now create a dynamic link library using the following example. 
  12167.  
  12168.  
  12169.    #include <stdio.h> 
  12170.    #if defined(__cplusplus) 
  12171.    #define EXTERNC extern "C" 
  12172.    #else 
  12173.    #define EXTERNC 
  12174.    #endif 
  12175.  
  12176.    unsigned LibMain( unsigned hmod, unsigned termination ) 
  12177.    { 
  12178.      if( termination ) { 
  12179.        /* DLL is detaching from process */ 
  12180.      } else { 
  12181.        /* DLL is attaching to process */ 
  12182.      } 
  12183.      return( 1 ); 
  12184.    } 
  12185.    EXTERNC void dll_entry_1( void ) 
  12186.    { 
  12187.      printf( "Hi from dll entry #1\n" ); 
  12188.    } 
  12189.  
  12190.    EXTERNC void dll_entry_2( void ) 
  12191.    { 
  12192.      printf( "Hi from dll entry #2\n" ); 
  12193.    } 
  12194.  
  12195. Starting with version 11, 32-bit OS/2 DLLs can include a  LibMain entry point 
  12196. when you are using the Watcom C/C++ run-time libraries. 
  12197.  
  12198.  Arguments: 
  12199.  
  12200.  hmod 
  12201.       This is a handle for the DLL. 
  12202.  
  12203.  termination 
  12204.       A 0 value indicates that the DLL is attaching to the address space of the 
  12205.       current process as a result of the process starting up or as a result of 
  12206.       a call to  LoadLibrary.  A DLL can use this opportunity to initialize any 
  12207.       instance data. 
  12208.  
  12209.       A non-zero value indicates that the DLL is detaching from the address 
  12210.       space of the calling process as a result of either a normal termination 
  12211.       or of a call to  FreeLibrary. 
  12212.  
  12213.  Return Value 
  12214.       The LibMain function returns 1 if initialization succeeds or 0 if 
  12215.       initialization fails. 
  12216.  
  12217.       If the return value is 0 when  LibMain is called because the process uses 
  12218.       the  LoadLibrary function,  LoadLibrary returns NULL. 
  12219.  
  12220.       If the return value is 0 when  LibMain is called during process 
  12221.       initialization, the process terminates with an error. 
  12222.  
  12223.  Assume the above example is contained in the file DLLSAMP.C.  We can compile 
  12224.  the file using the following command.  Note that we must specify the "bd" 
  12225.  compiler option. 
  12226.  
  12227.  
  12228.     [C:\]wcc386 /bd dllsamp 
  12229.  
  12230.  Before we can link our example, we must create a linker directive file that 
  12231.  describes the attributes and entry points of our dynamic link library.  The 
  12232.  following is a linker directive file, called DLLSAMP.LNK, that can be used to 
  12233.  create the dynamic link library. 
  12234.  
  12235.  
  12236.     system os2v2 dll initinstance terminstance 
  12237.     option manyautodata 
  12238.     export dll_entry_1_ 
  12239.     export dll_entry_2_ 
  12240.     file dllsamp 
  12241.  
  12242.  Notes: 
  12243.  
  12244.    1. The "SYSTEM" directive specifies that we are creating a 32-bit OS/2 
  12245.       dynamic link library. 
  12246.  
  12247.    2. The "MANYAUTODATA" option specifies that the automatic data segment is 
  12248.       allocated for every instance of the dynamic link library.  This option 
  12249.       must be specified only for a dynamic link library that uses the Watcom 
  12250.       C/C++ run-time libraries.  If the Watcom C/C++ run-time libraries are not 
  12251.       used, this option is not required.  Our example does use the Watcom C/C++ 
  12252.       run-time libraries so we must specify the "MANYAUTODATA" option. 
  12253.  
  12254.       As was just mentioned, when a dynamic link library uses the Watcom C/C++ 
  12255.       run-time libraries, an automatic data segment is created each time a 
  12256.       process accesses the dynamic link library.  For this reason, 
  12257.       initialization code must be executed when a process accesses the dynamic 
  12258.       link library for the first time.  To achieve this, "INITINSTANCE" must be 
  12259.       specified in the "SYSTEM" directive.  Similarly, "TERMINSTANCE" must be 
  12260.       specified so that the termination code is executed when a process has 
  12261.       completed its access to the dynamic link library.  If the Watcom C/C++ 
  12262.       run-time libraries are not used, these options are not required. 
  12263.  
  12264.    3. The "EXPORT" directive specifies the entry points into the dynamic link 
  12265.       library.  Note that the names specified in the "EXPORT" directive are 
  12266.       appended with an underscore.  This is the default naming convention used 
  12267.       when compiling using the register-based calling convention.  No 
  12268.       underscore is required when compiling using the stack-based calling 
  12269.       convention. 
  12270.  
  12271.  We can now create our dynamic link library by issuing the following command. 
  12272.  
  12273.  
  12274.     [C:\]wlink @dllsamp 
  12275.  
  12276.  A file called DLLSAMP.DLL will be created. 
  12277.  
  12278.  
  12279. ΓòÉΓòÉΓòÉ 37.3. OS/2:  Using Dynamic Link Libraries ΓòÉΓòÉΓòÉ
  12280.  
  12281.  
  12282. Once we have created a dynamic link library, we must allow other applications 
  12283. to access the functions available in the dynamic link library.  There are two 
  12284. ways to achieve this. 
  12285.  
  12286. The first method is to create a linker directive file which contains an 
  12287. "IMPORT" directive for all entry points in the dynamic link library.  The 
  12288. "IMPORT" directive provides the name of the entry point and the name of the 
  12289. dynamic link library.  When creating an application that references a function 
  12290. in the dynamic link library, this linker directive file would be included as 
  12291. part of the linking process that created the application. 
  12292.  
  12293. The second method is to use import libraries.  An import library is a standard 
  12294. library that is created from a dynamic link library by using the Watcom Library 
  12295. Manager.  It contains object modules that describe the entry points in a 
  12296. dynamic link library.  The resulting import library can then be specified in a 
  12297. "LIBRARY" directive in the same way one would specify a standard library. 
  12298.  
  12299. Using an import library is the preferred method of providing references to 
  12300. functions in dynamic link libraries.  When a dynamic link library is modified, 
  12301. typically the import library corresponding to the modified dynamic link library 
  12302. is updated to reflect the changes.  Hence, any directive file that specifies 
  12303. the import library in a "LIBRARY" directive need not be modified.  However, if 
  12304. you are using "IMPORT" directives, you may have to modify the "IMPORT" 
  12305. directives to reflect the changes in the dynamic link library. 
  12306.  
  12307. Let us create an import library for our sample dynamic link library we created 
  12308. in the previous section.  We do this by issuing the following command. 
  12309.  
  12310.  
  12311.    [C:\]wlib dllsamp +dllsamp.dll 
  12312.  
  12313. A standard library called DLLSAMP.LIB will be created. 
  12314.  
  12315. Suppose the following sample program, contained in the file DLLTEST.C, calls 
  12316. the functions from our sample dynamic link library. 
  12317.  
  12318.  
  12319.    #include <stdio.h> 
  12320.    #if defined(__cplusplus) 
  12321.    #define EXTERNC extern "C" 
  12322.    #else 
  12323.    #define EXTERNC 
  12324.    #endif 
  12325.  
  12326.    EXTERNC void dll_entry_1( void ); 
  12327.    EXTERNC void dll_entry_2( void ); 
  12328.  
  12329.    int main( void ) 
  12330.    { 
  12331.      dll_entry_1(); 
  12332.      dll_entry_2(); 
  12333.      return( 0 ); 
  12334.    } 
  12335.  
  12336. We can compile and link our sample application by issuing the following 
  12337. command. 
  12338.  
  12339.  
  12340.    [C:\]wcl386 /l=os2v2 dlltest dllsamp.lib 
  12341.  
  12342. If we had created a linker directive file of "IMPORT" directives instead of an 
  12343. import library for the dynamic link library, the linker directive file, say 
  12344. DLLIMPS.LNK, would be as follows. 
  12345.  
  12346.  
  12347.    import dll_entry_1_ dllsamp 
  12348.    import dll_entry_2_ dllsamp 
  12349.  
  12350. Note that the names specified in the "IMPORT" directive are appended with an 
  12351. underscore.  This is the default naming convention used when compiling using 
  12352. the register-based calling convention.  No underscore is required when 
  12353. compiling using the stack-based calling convention. 
  12354.  
  12355. To compile and link our sample application, we would issue the following 
  12356. command. 
  12357.  
  12358.  
  12359.    [C:\]wcl386 /l=os2v2 dlltest /"@dllimps" 
  12360.  
  12361.  
  12362. ΓòÉΓòÉΓòÉ 37.4. OS/2:  The Dynamic Link Library Data Area ΓòÉΓòÉΓòÉ
  12363.  
  12364.  
  12365. The Watcom C/C++ 32-bit run-time library does not support the general case 
  12366. operation of DLLs in an execution environment where there is only one instance 
  12367. of the DATA segment (DGROUP) for that DLL. 
  12368.  
  12369. There are two cases that can lead to a DLL executing with only one instance of 
  12370. the DGROUP. 
  12371.  
  12372.    1. DLLs linked for 32-bit OS/2 without the MANYAUTODATA option. 
  12373.  
  12374.    2. DLLs linked for the Win32 API and executing under Win32s. 
  12375.  
  12376.  In these cases the run-time library startup code detects that there is only 
  12377.  one instance of the DGROUP when a second process attempts to attach to the 
  12378.  DLL.  At that point, it issues a diagnostic for the user and then notifies the 
  12379.  operating system that the second process cannot attach to the DLL. 
  12380.  
  12381.  Developers who require DLLs to operate when there is only one instance of the 
  12382.  DGROUP can suppress the function which issues the diagnostic and notifies the 
  12383.  operating system that the second process cannot attach to the DLL. 
  12384.  
  12385.  Doing so requires good behaviour on the part of processes attaching to the 
  12386.  DLL.  This good behaviour consists primarily of ensuring that the first 
  12387.  process to attach to the DLL is also the last process to detach from the DLL 
  12388.  thereby ensuring that the DATA segment is not released back to the free memory 
  12389.  pool. 
  12390.  
  12391.  To suppress the function which issues the diagnostic and notifies the 
  12392.  operating system that the second process cannot attach to the DLL, the 
  12393.  developer must provide a replacement entry point with the following prototype: 
  12394.  
  12395.  
  12396.     int __disallow_single_dgroup( int ); 
  12397.  
  12398.  This function should return zero to indicate that the detected single copy of 
  12399.  the DATA segment is allowed. 
  12400.  
  12401.  
  12402. ΓòÉΓòÉΓòÉ 37.5. OS/2:  Dynamic Link Library Initialization/Termination ΓòÉΓòÉΓòÉ
  12403.  
  12404.  
  12405. Each dynamic link library (DLL) has an initialization and termination routine 
  12406. associated with it.  The initialization routine can either be called the first 
  12407. time any process accesses the DLL ("INITGLOBAL" is specified at link time) or 
  12408. each time a process accesses the DLL ("INITINSTANCE" is specified at link 
  12409. time).  Similarly, the termination routine can either be called when all 
  12410. processes have completed their access of the DLL ("TERMGLOBAL" is specified at 
  12411. link time) or each time a process completes its access of the DLL 
  12412. ("TERMINSTANCE" is specified at link time). 
  12413.  
  12414. For a DLL that uses the C/C++ run-time libraries, initialization and 
  12415. termination of the C/C++ run-time environment is performed automatically.  It 
  12416. is also possible for a DLL to do its own special initialization and termination 
  12417. process. 
  12418.  
  12419. The C/C++ run-time environment provides two methods for calling user-written 
  12420. DLL initialization and termination code. 
  12421.  
  12422.    1. If you provide your own version of LibMain then it will be called for 
  12423.       initialization and termination.  The use of LibMain is described earlier 
  12424.       in this chapter. 
  12425.  
  12426.    2. If you do not provide your own version of LibMain then a default version 
  12427.       is linked in from the library.  This version will call  __dll_initialize 
  12428.       for DLL initialization and  __dll_terminate for DLL termination.  Default 
  12429.       stub versions of these two routines are included in the run-time library. 
  12430.       If you wish to perform additional initialization/termination that is 
  12431.       specific to your dynamic link library, you may write your own versions of 
  12432.       these routines. 
  12433.  
  12434.  Once the C/C++ run-time environment is initialized, the routine 
  12435.  __dll_initialize is called.  After the C/C++ run-time environment is 
  12436.  terminated, the routine __dll_terminate is called.  This last point is 
  12437.  important since it means that you cannot do any run-time calls in the 
  12438.  termination routine. 
  12439.  
  12440.  The initialization and termination routines return an integer.  A value of 0 
  12441.  indicates failure; a value of 1 indicates success.  The following example 
  12442.  illustrates sample initialization/termination routines. 
  12443.  
  12444.  
  12445.     #include <stdlib.h> 
  12446.  
  12447.     #define WORKING_SIZE (64 * 1024) 
  12448.  
  12449.     char *WorkingStorage; 
  12450.  
  12451.     #if defined(__cplusplus) 
  12452.     #define EXTERNC extern "C" 
  12453.     #else 
  12454.     #define EXTERNC 
  12455.     #endif 
  12456.  
  12457.     void __dll_finalize( void ); 
  12458.  
  12459.     EXTERNC int __dll_initialize( void ) 
  12460.     { 
  12461.       WorkingStorage = malloc( WORKING_SIZE ); 
  12462.       if( WorkingStorage == NULL ) return( 0 ); 
  12463.       atexit( __dll_finalize ); 
  12464.       return( 1 ); 
  12465.     } 
  12466.  
  12467.     void __dll_finalize( void ) 
  12468.     { 
  12469.       free( WorkingStorage ); 
  12470.     } 
  12471.  
  12472.     EXTERNC int __dll_terminate( void ) 
  12473.     { 
  12474.       /* no C run-time calls allowed under OS/2 Warp */ 
  12475.       return( 1 ); 
  12476.     } 
  12477.  
  12478.     EXTERNC void dll_entry( void ) 
  12479.     { 
  12480.       /* use array WorkingStorage */ 
  12481.     } 
  12482.  
  12483.  In the above example, the process initialization routine allocates storage 
  12484.  that the dynamic link library needs, the routine dll_entry uses the storage, 
  12485.  and the process termination routine frees the storage allocated in the 
  12486.  initialization routine. 
  12487.  
  12488.  
  12489. ΓòÉΓòÉΓòÉ 38. OS/2:  Programming for OS/2 Presentation Manager ΓòÉΓòÉΓòÉ
  12490.  
  12491.  
  12492. Basically, there are two classes of C/C++ applications that can run in a 
  12493. windowed environment. 
  12494.  
  12495. The first are those C/C++ applications that do not use any of the Presentation 
  12496. Manager API functions; they are strictly C/C++ applications that do not rely on 
  12497. the features of a particular operating system. 
  12498.  
  12499. The second class of C/C++ applications are those that actually call 
  12500. Presentation Manager API functions directly.  These are applications that have 
  12501. been tailored for the Presentation Manager operating environment. 
  12502.  
  12503. It is assumed that the reader is familiar with the concepts of Presentation 
  12504. Manager programming. 
  12505.  
  12506.  
  12507. ΓòÉΓòÉΓòÉ 38.1. OS/2:  Porting Existing C/C++ Applications ΓòÉΓòÉΓòÉ
  12508.  
  12509.  
  12510. Suppose you have a set of C/C++ applications that previously ran under DOS and 
  12511. you now wish to run them under OS/2.  To achieve this, simply recompile your 
  12512. application and link with the appropriate libraries.  Depending on the method 
  12513. with which you linked your application, it can run in an OS/2 fullscreen 
  12514. environment, a PM-compatible window, or as a Presentation Manager application. 
  12515. An OS/2 fullscreen application runs in its own screen group.  A PM-compatible 
  12516. application will run in an OS/2 fullscreen environment or in a window in the 
  12517. Presentation Manager screen group but does not take direct advantage of menus, 
  12518. mouse or other features available in the Presentation Manager.  A Presentation 
  12519. Manager application has full access to the complete set of user-interface tools 
  12520. such as menus, icons, scroll bars, etc.  An application that was not designed 
  12521. as a windowed application (such as a DOS application) can run as a Presentation 
  12522. Manager application.  This is achieved by a default windowing system that is 
  12523. optionally linked with your application.  The following sections describe the 
  12524. default windowing system. 
  12525.  
  12526.  
  12527. ΓòÉΓòÉΓòÉ 38.1.1. OS/2:  Console Device in a Windowed Environment ΓòÉΓòÉΓòÉ
  12528.  
  12529.  
  12530. In a C/C++ application that runs under DOS, stdin (C++ cin) and stdout (C++ 
  12531. cout) are connected to the standard input and standard output devices 
  12532. respectively.  It is not a recommended practice to read directly from the 
  12533. standard input device or write to the standard output device when running in a 
  12534. windowed environment.  For this reason, a default windowing environment is 
  12535. created for C/C++ applications that read from stdin (C++ cin) or write to 
  12536. stdout (C++ cout).  When your application is started, a window is created in 
  12537. which output to stdout (C++ cout) is displayed and input from stdin (C++ cin) 
  12538. is requested. 
  12539.  
  12540. In addition to the standard I/O device, it is also possible to perform I/O to 
  12541. the console by explicitly opening a file whose name is "CON".  When this 
  12542. occurs, another window is created and displayed.  This window is different from 
  12543. the one created for standard input and standard output.  In fact, every time 
  12544. you open the console device a different window is created.  This provides a 
  12545. simple multi-windowing system for multiple streams of data to and from the 
  12546. console device. 
  12547.  
  12548.  
  12549. ΓòÉΓòÉΓòÉ 38.1.2. OS/2:  An Example ΓòÉΓòÉΓòÉ
  12550.  
  12551.  
  12552. Very little effort is required to port an existing C/C++ application to OS/2. 
  12553. Let us try to run the following sample program (contained in the file HELLO.C). 
  12554.  
  12555.  
  12556.    #include <stdio.h> 
  12557.  
  12558.    int main( void ) 
  12559.    /**************/ 
  12560.    { 
  12561.      printf( "Hello world!\n" ); 
  12562.      return( 0 ); 
  12563.    } 
  12564.  
  12565. An equivalent C++ program follows: 
  12566.  
  12567.  
  12568.    #include <iostream.h> 
  12569.    #include <iomanip.h> 
  12570.  
  12571.    int main( void ) 
  12572.    { 
  12573.      cout << "Hello world" << endl; 
  12574.      return( 0 ); 
  12575.    } 
  12576.  
  12577. First we must compile the file HELLO.C by issuing the following command. 
  12578.  
  12579.  
  12580.    [C:\]wcc386 hello 
  12581.  
  12582. Once we have successfully compiled the file, we can link it by issuing the 
  12583. following command. 
  12584.  
  12585.  
  12586.    [C:\]wlink sys os2v2 file hello 
  12587.  
  12588. This will create a PM-compatible application.  If you wish to create a 
  12589. fullscreen application, link with the following command. 
  12590.  
  12591.  
  12592.    [C:\]wlink sys os2v2 fullscreen file hello 
  12593.  
  12594. If you wish to use the default windowing system, you must recompile your 
  12595. application and specify a special option, namely "bw". 
  12596.  
  12597.  
  12598.    [C:\]wcc386 /bw hello 
  12599.  
  12600. We now link our application with the following command. 
  12601.  
  12602.  
  12603.    [C:\]wlink sys os2v2_pm file hello 
  12604.  
  12605.  
  12606. ΓòÉΓòÉΓòÉ 38.2. OS/2:  Default Windowing Library Functions ΓòÉΓòÉΓòÉ
  12607.  
  12608.  
  12609. A few library functions have been written to enable some simple customization 
  12610. of the default windowing system's behaviour.  The following functions are 
  12611. supplied: 
  12612.  
  12613.  _dwDeleteOnClose 
  12614.  
  12615.  
  12616.  
  12617.          int _dwDeleteOnClose( int handle ); 
  12618.  
  12619.       This function tells the console window that it should close itself when 
  12620.       the file is closed.  You must pass to it the handle associated with the 
  12621.       opened console. 
  12622.  
  12623.  _dwSetAboutDlg 
  12624.  
  12625.  
  12626.  
  12627.          int _dwSetAboutDlg( const char *title, const char *text ); 
  12628.  
  12629.       This function sets the about dialog box of the default windowing system. 
  12630.       The "title" points to the string that will replace the current title.  If 
  12631.       title is NULL then the title will not be replaced.  The "text" points to 
  12632.       a string which will be placed in the about box.  To get multiple lines, 
  12633.       embed a new line after each logical line in the string.  If "text" is 
  12634.       NULL, then the current text in the about box will not be replaced. 
  12635.  
  12636.  _dwSetAppTitle 
  12637.  
  12638.  
  12639.  
  12640.          int _dwSetAppTitle( const char *title ); 
  12641.  
  12642.       This function sets the main window's title. 
  12643.  
  12644.  _dwSetConTitle 
  12645.  
  12646.  
  12647.  
  12648.          int _dwSetConTitle( int handle, const char *title ); 
  12649.  
  12650.       This function sets the console window's title which corresponds to the 
  12651.       handle passed to it. 
  12652.  
  12653.  _dwShutDown 
  12654.  
  12655.  
  12656.  
  12657.          int _dwShutDown( void ); 
  12658.  
  12659.       This function shuts down the default windowing I/O system.  The 
  12660.       application will continue to execute but no windows will be available for 
  12661.       output. 
  12662.  
  12663.  _dwYield 
  12664.  
  12665.  
  12666.  
  12667.          int _dwYield( void ); 
  12668.  
  12669.       This function yields control back to the operating system, thereby giving 
  12670.       other processes a chance to run. 
  12671.  
  12672.  These functions are described more fully in the WATCOM C Library Reference. 
  12673.  
  12674.  
  12675. ΓòÉΓòÉΓòÉ 38.3. OS/2:  Calling Presentation Manager API Functions ΓòÉΓòÉΓòÉ
  12676.  
  12677.  
  12678. It is also possible for a C/C++ application to create its own windowing 
  12679. environment.  This is achieved by calling PM API functions directly from your 
  12680. C/C++ program.  The techniques for developing these applications can be found 
  12681. in the OS/2 Technical Library.  To order the Technical Library, call one of the 
  12682. following numbers. 
  12683.  
  12684.  
  12685.    In Canada:       1-800-465-1234 
  12686.    In the United States: 1-800-426-7282 (OS/2 2.0, 2.1) 
  12687.               1-800-879-2755 (OS/2 Warp) 
  12688.  
  12689. You can also order copies of these books from an IBM authorized dealer or IBM 
  12690. representative. 
  12691.  
  12692.  
  12693. ΓòÉΓòÉΓòÉ 39. OS/2:  Developing an OS/2 Physical Device Driver ΓòÉΓòÉΓòÉ
  12694.  
  12695.  
  12696. In this chapter, we discuss the development of Physical Device Drivers (PDD) 
  12697. for OS/2.  The tools used in the creation of the sample PDD are: 
  12698.  
  12699.      the 16-bit Watcom C compiler 
  12700.      the Watcom Assembler 
  12701.      the Watcom Make utility 
  12702.  
  12703.  The sample Physical Device Driver that we are going to build, HRTIMER.SYS, 
  12704.  provides access to a high resolution timer.  Additional sources of information 
  12705.  on PDDs can be found in the following: 
  12706.  
  12707.    1. OS/2 2.0 Technical Library - Physical Device Driver Reference 
  12708.  
  12709.    2. Writing OS/2 2.1 Device Drivers in C by Steve J.  Mastrianni 
  12710.  
  12711.    3. An OS/2 High Resolution Software Timer by Derek Williams, an article 
  12712.       which appeared in the Fall 1991 issue of IBM Personal Systems Developer 
  12713.       magazine.  The source code for this device driver was adapted from the 
  12714.       magazine article.  For detailed information on the way this device driver 
  12715.       works, please read that article. 
  12716.  
  12717.  HRTIMER.SYS is a 16-bit device driver which runs under OS/2 1.x and 2.x/3.x. 
  12718.  It has a resolution of 840 nanoseconds (i.e., 1 tick of the Intel 8253/8254 
  12719.  timer = 840 nanoseconds). 
  12720.  
  12721.  Here are some notes on creating Physical Device Drivers using Watcom software 
  12722.  tools. 
  12723.  
  12724.    1. A Physical Device Driver is linked as a DLL. 
  12725.  
  12726.    2. The first segment must be a data segment, the next a code segment. 
  12727.  
  12728.    3. By default only the first two segments remain after initialization, extra 
  12729.       segments have to be marked IOPL. 
  12730.  
  12731.    4. The assembler file, DEVSEGS.ASM, defines the segment ordering. 
  12732.  
  12733.    5. #pragma dataseg and #pragma codeseg are used to get various pieces of 
  12734.       code and data into the correct segments. 
  12735.  
  12736.    6. The _HEADER segment contains the device header and must be at the 
  12737.       beginning of the data segment. 
  12738.  
  12739.    7. The _INITCODE and _INITDATA segments are used to place initialization 
  12740.       code and data at the end so it can be discarded by OS/2. 
  12741.  
  12742.  To compile the source code for the 16-bit Physical Device Drivers, we use the 
  12743.  following options: 
  12744.  
  12745.  /bt=os2 
  12746.       build target is OS/2 
  12747.  
  12748.  /ms 
  12749.       16-bit small code/small data model 
  12750.  
  12751.  /5 
  12752.       Pentium optimizations (this is optional) 
  12753.  
  12754.  /omi 
  12755.       inline math and intrinsic functions (this is optional) 
  12756.  
  12757.  /s 
  12758.       no stack checking 
  12759.  
  12760.  /zdp 
  12761.       DS is pegged to DGROUP 
  12762.  
  12763.  /zff 
  12764.       FS floats, i.e.  not fixed to a segment 
  12765.  
  12766.  /zgf 
  12767.       GS floats, i.e.  not fixed to a segment 
  12768.  
  12769.  /zu 
  12770.       SS != DGROUP 
  12771.  
  12772.  /zl 
  12773.       remove default library information 
  12774.  
  12775.  To link the object code for the 16-bit Physical Device Drivers, we use the 
  12776.  following options: 
  12777.  
  12778.  name hrtimer.sys 
  12779.       to name the executable file. 
  12780.  
  12781.  sys os2 dll initglobal 
  12782.       to link a 16-bit OS/2 DLL.  Specifying INITGLOBAL will cause the 
  12783.       initialization routine to be called the first time the dynamic link 
  12784.       library is loaded. 
  12785.  
  12786.  option map 
  12787.       to generate a map file. 
  12788.  
  12789.  option quiet 
  12790.       to minimize the number of linker informational messages. 
  12791.  
  12792.  lib os2 
  12793.       to include the 16-bit OS2.LIB library file. 
  12794.  
  12795.  file ... 
  12796.       to include the component object files of the device driver. 
  12797.  
  12798.  The sample files used to create the Physical Device Driver and the programs 
  12799.  that use it are located in the \WATCOM\SRC\OS2\PDD directory.  The Physical 
  12800.  Device Driver files are: 
  12801.  
  12802.  DEVSEGS.ASM 
  12803.       This small assembler file orders the segment definitions in the 
  12804.       executable file. 
  12805.  
  12806.  
  12807.          Data Segments  _HEADER 
  12808.                  CONST 
  12809.                  CONST2 
  12810.                  _DATA 
  12811.                  _BSS 
  12812.                  _INITDATA (discardable) 
  12813.          Code Segments  _TEXT 
  12814.                  _INITCODE (discardable) 
  12815.  
  12816.  HEADER.C 
  12817.       The first thing that must follow the EXE Header is the Device Driver 
  12818.       Header. 
  12819.  
  12820.  STRATEGY.C 
  12821.       This is the resident portion of the Strategy routine. 
  12822.  
  12823.  STRATINI.C 
  12824.       This is the discardable portion of the Strategy routine, the 
  12825.       initialization code and data. 
  12826.  
  12827.  HRTIMER.H 
  12828.       This file contains the definition of the timer "timestamp" structure. 
  12829.  
  12830.  HRDEV.H 
  12831.       This file contains definitions for the Intel 8253 hardware timer. 
  12832.  
  12833.  DEVHDR.H 
  12834.       This file contains definitions for the Device Driver Header structure 
  12835.       (see page 3-2, "Physical Device Driver Header" of PDD Reference). 
  12836.  
  12837.  DEVDEFS.H 
  12838.       This file provides type definitions. 
  12839.  
  12840.  DEVREQP.H 
  12841.       This file contains definitions for the Device Driver Request Packets. 
  12842.  
  12843.  DEVAUX.H 
  12844.       This file contains definitions for the Device Driver Help (DevHlp) 
  12845.       routines. 
  12846.  
  12847.  The demonstration program files are: 
  12848.  
  12849.  HRTEST.C 
  12850.       This file is a sample C program that shows how to use the device driver 
  12851.       to calculate elapsed times.  It demonstrates how to open the device 
  12852.       driver, read timestamps from it and close it.  It factors in the overhead 
  12853.       of the read and has a function that is used to calculate elapsed time 
  12854.       from a start and stop timestamp. 
  12855.  
  12856.  TIMER.C 
  12857.       This file is a sample C program that can be used to time other 
  12858.       applications.  It also uses the device driver. 
  12859.  
  12860.  To build the device driver and demonstration programs, set your current 
  12861.  directory to \WATCOM\SRC\OS2\PDD and type: 
  12862.  
  12863.  
  12864.     wmake 
  12865.  
  12866.  To install the device driver, put the following statement in your CONFIG.SYS 
  12867.  file. 
  12868.  
  12869.  
  12870.     DEVICE=\WATCOM\SRC\OS2\PDD\HRTIMER.SYS 
  12871.  
  12872.  You must then reboot OS/2. 
  12873.  
  12874.  To run the test program, use the following command-line: 
  12875.  
  12876.  
  12877.     HRTEST [milliseconds] 
  12878.  
  12879.  For [milliseconds], you can enter any number (e.g., 2000 which is 2 seconds). 
  12880.  
  12881.   HRTEST.EXE will issue a DosSleep for the amount of milliseconds specified or 
  12882.  will use a default if no command-line parameter is given.  It will get a 
  12883.  timestamp from the device driver before and after the DosSleep and will 
  12884.  calculate the elapsed time of that sleep and display the results.  It will do 
  12885.  this continuously until Ctrl/C or Ctrl/Break is pressed. 
  12886.  
  12887.  Keep in mind that DosSleep has a granularity of 32 milliseconds.  Any 
  12888.  discrepancy between the number of milliseconds used for the DosSleep and the 
  12889.  elapsed time results from the timer are the fault of this granularity, not a 
  12890.  problem with the timer.  DosSleep is used solely as a convenient method of 
  12891.  displaying the capabilities of the driver. 
  12892.  
  12893.  To run the timer program, use the following command-line: 
  12894.  
  12895.  
  12896.     TIMER program_name [program_args] 
  12897.  
  12898.  For example, to time an OS/2 Directory command, issue the following command. 
  12899.  
  12900.  Example: 
  12901.  
  12902.     timer cmd /c dir c: 
  12903.  
  12904.  
  12905. ΓòÉΓòÉΓòÉ 40. OS/2:  Using the IBM OS/2 WorkFrame/2 ΓòÉΓòÉΓòÉ
  12906.  
  12907.  
  12908. Watcom C/C++ has been integrated into the IBM Developer's WorkFrame/2 version 
  12909. 1.1.  The IBM Developer's WorkFrame/2 provides a complete development 
  12910. environment for editing, compiling, linking, and debugging your application. 
  12911. You must install the IBM Developer's WorkFrame/2 on your system before you can 
  12912. use it.  Also, you must have selected support for IBM Developer's WorkFrame/2 
  12913. when you installed Watcom C/C++. 
  12914.  
  12915. Note that Watcom C/C++ was tested with version 1.1 of WorkFrame/2.  We do not 
  12916. guarantee that Watcom C/C++ will work with later versions of WorkFrame/2. 
  12917.  
  12918. WorkFrame/2 provides a convenient, user-friendly and consistent method of 
  12919. accessing the compiler and tools. For example, setting compiler options is 
  12920. achieved through the use of pulldown menus and dialogs that list all the 
  12921. options and provide help information for each option.  You can also invoke the 
  12922. compiler from a pulldown menu. 
  12923.  
  12924. It is assumed that you are familiar with the operating procedures required to 
  12925. use the IBM Developer's WorkFrame/2. 
  12926.  
  12927.  
  12928. ΓòÉΓòÉΓòÉ 41. AutoCAD:  Creating AutoCAD Applications ΓòÉΓòÉΓòÉ
  12929.  
  12930.  
  12931.  
  12932. Watcom C/C++ supports the DOS version of the AutoCAD Development System (ADS) 
  12933. from Autodesk (release 13 and earlier versions).  ADS is a set of header files 
  12934. and a library.  The header files (files with extension ".h") are located in the 
  12935. \ACAD\ADS directory (assuming you installed AutoCAD in the "\ACAD" directory). 
  12936. Files in this directory with extension ".C" are sample ADS applications.  The 
  12937. ADS library is called WCADS.LIB and is located in the \ACAD\ADS directory. 
  12938.  
  12939. The ADS library WCADS.LIB is in a format that is specific to the Phar Lap 
  12940. development tools and must be converted to a standard form so that the Watcom 
  12941. Linker can read the library dictionary.  This is achieved by issuing the 
  12942. following two commands. 
  12943.  
  12944.    1. Protect the old ADS library by renaming it. 
  12945.  
  12946.       Example: 
  12947.  
  12948.          C>ren wcads.lib owcads.lib 
  12949.  
  12950.    2. Convert the library by issuing the following command. 
  12951.  
  12952.       Example: 
  12953.  
  12954.          C>wlib wcads +owcads.lib 
  12955.  
  12956.  
  12957. ΓòÉΓòÉΓòÉ 41.1. AutoCAD:  Compiling an ADS Application ΓòÉΓòÉΓòÉ
  12958.  
  12959.  
  12960. As an example, we will create the ADS application contained in the file FACT.C. 
  12961. In order to compile this file, we must set the INCLUDE environment variable to 
  12962. the paths that contain the necessary header files. 
  12963.  
  12964. Example: 
  12965.  
  12966.    C>set include=\watcom\h;\acad\ads 
  12967.  
  12968. We can now compile FACT.C by issuing the following command. 
  12969.  
  12970. Example: 
  12971.  
  12972.    C>wcc386 /fpi87 /3s fact 
  12973.  
  12974. The "fpi87" option tells the compiler to generate in-line 80x87 floating-point 
  12975. instructions.  The "3s" option selects 80387 instruction timings and the 
  12976. stack-based calling convention.  The stack-based calling convention is required 
  12977. for AutoCAD applications. 
  12978.  
  12979.  
  12980. ΓòÉΓòÉΓòÉ 41.2. AutoCAD:  Linking an ADS Application ΓòÉΓòÉΓòÉ
  12981.  
  12982.  
  12983. Each ADS application requires a special version of the startup module that is 
  12984. contained in the Watcom C/C++ run-time library CLIB3S.LIB.  This special 
  12985. version, ADSSTART.OBJ, is located in the \WATCOM\LIB386\DOS directory.  It is 
  12986. automatically included when you use the system ads directive shown below. 
  12987.  
  12988. For ease of use, create the following linker directive file and name it 
  12989. FACT.LNK. 
  12990.  
  12991.  
  12992.    system ads 
  12993.    file fact 
  12994.    library \acad\ads\wcads 
  12995.  
  12996. We can now link our ADS application by issuing the following command. 
  12997.  
  12998. Example: 
  12999.  
  13000.    C>wlink @fact 
  13001.  
  13002.  
  13003. ΓòÉΓòÉΓòÉ 41.3. AutoCAD:  One-Step Compiling and Linking ΓòÉΓòÉΓòÉ
  13004.  
  13005.  
  13006. For simple applications, the above steps can be combined into a single command 
  13007. as follows: 
  13008.  
  13009. Example: 
  13010.  
  13011.    C>wcl386 /l=ads /fpi87 /3s \acad\ads\wcads.lib fact 
  13012.  
  13013. The WCL386 utility will automatically generate the appropriate linker directive 
  13014. file. 
  13015.  
  13016.  
  13017. ΓòÉΓòÉΓòÉ 41.4. AutoCAD:  Debugging an ADS Application ΓòÉΓòÉΓòÉ
  13018.  
  13019.  
  13020. If you wish to debug your ADS application with the Watcom Debugger, you must 
  13021. specify the "d1" or "d2" option when compiling the source code.  The "d1" 
  13022. compiler option generates only line numbering information; the "d2" compiler 
  13023. option generates full debugging information that includes symbolic information 
  13024. for all variables. 
  13025.  
  13026. Example: 
  13027.  
  13028.    C>wcc386 /fpi87 /3s /d2 fact 
  13029.  
  13030. When we link our application we must inform the Watcom Linker to create an 
  13031. executable file that contains the debugging information generated by the 
  13032. compiler.  This is done by adding the "DEBUG ALL" directive to our directive 
  13033. file. 
  13034.  
  13035.  
  13036.    debug all 
  13037.    system ads 
  13038.    file fact 
  13039.    library \acad\ads\wcads 
  13040.  
  13041. We must link our application again. 
  13042.  
  13043. Example: 
  13044.  
  13045.    C>wlink @fact 
  13046.  
  13047. Before running the Watcom Debugger, add the following line to your ACAD.ADS 
  13048. file. 
  13049.  
  13050.  
  13051.    \watcom\binw\adshelp.exp 
  13052.  
  13053. The ACAD.ADS file contains a list of ADS applications that are loaded by 
  13054. AutoCAD when AutoCAD is loaded.  The ADSHELP.EXP file is an ADS application 
  13055. that is required by the Watcom Debugger for debugging ADS applications. 
  13056.  
  13057. An earlier version of the Watcom Debugger required that you set the DOSX 
  13058. environment variable to PRIVILEGED (DOSX=-priv) for AutoCAD Release 12 since 
  13059. AutoCAD was linked as UNPRIVILEGED.  Starting with version 10 of the debugger, 
  13060. this is no longer required and, in fact, will cause unpredictable results for 
  13061. release 13 if it is set. 
  13062.  
  13063. To invoke the Watcom Debugger, enter the following command. 
  13064.  
  13065. Example: 
  13066.  
  13067.    C>wd /tr=ads /swap 
  13068.  
  13069. If you have a two-monitor setup, you may omit the "swap" option. 
  13070.  
  13071. Note that we did not specify the AutoCAD executable file; the debugger trap 
  13072. file, ADS.TRP, will load AutoCAD automatically.  You should now be in the 
  13073. Watcom Debugger.  At this point, enter the following debugger command. 
  13074.  
  13075. Example: 
  13076.  
  13077.    ads fact.exp 
  13078.  
  13079. You should now be in AutoCAD.  When you load your ADS application from 
  13080. AutoLISP, the debugger will be entered and source for your program should be 
  13081. displayed in the source window.  The ADS.DBG file contains a sequence of 
  13082. debugger commands that starts AutoCAD, loads the debugging information from the 
  13083. executable file you specify, and relocates address information based on the 
  13084. code and data selector values for your application.  You are now ready to debug 
  13085. your ADS application. 
  13086.  
  13087. For large ADS applications, you may get an error when the "ADS" debugger 
  13088. command file is invoked indicating that the debugger was unable to load the 
  13089. debugging information from the executable file because of memory constraints. 
  13090. If the error message "no memory for debugging information" or "no memory for 
  13091. debugging information - increase dynamic memory" is issued, use the debugger 
  13092. "dynamic" option to increase the amount of dynamic memory (the default is 40k). 
  13093. The following example increases the amount of dynamic memory to 60k. 
  13094.  
  13095. Example: 
  13096.  
  13097.    C>wd /tr=ads /swap /dynamic=60k 
  13098.  
  13099.  
  13100. ΓòÉΓòÉΓòÉ 42. Creating NetWare 386 NLM Applications ΓòÉΓòÉΓòÉ
  13101.  
  13102.  
  13103. Watcom C/C++ supports version 4.0 of the Netware 386 API.  We include the 
  13104. following components: 
  13105.  
  13106.  header files 
  13107.       Header files for the Netware 4.0 API are located in the \WATCOM\NOVH 
  13108.       directory. 
  13109.  
  13110.  import libraries 
  13111.       Import libraries for the Netware 4.0 API are located in the \WATCOM\NOVI 
  13112.       directory. 
  13113.  
  13114.  libraries 
  13115.       The C/C++ libraries for Netware 4.0 is located in the \WATCOM\LIB386 and 
  13116.       \WATCOM\LIB386\NETWARE directories. 
  13117.  
  13118.  debug servers 
  13119.       Servers for remote debugging of Netware 4.0 NLMs are located in the 
  13120.       \WATCOM\NLM directory.  The same directory also contains the Watcom 
  13121.       Execution Sampler for NLMs. 
  13122.  
  13123.  Applications built for version 4.0 will run on 4.1.  We do not include support 
  13124.  for any API specific to version 4.1.  Netware developers must use the support 
  13125.  included with Watcom C/C++ version 10.0 or greater since the version supplied 
  13126.  by Novell only works with Watcom C/C++ version 9.5.  Netware 4.1 support 
  13127.  requires modification to the header files supplied by Novell.  Contact Novell 
  13128.  for more information. 
  13129.  
  13130.  The following special notes apply to developing applications for NetWare. 
  13131.  
  13132.    1. You must compile your source files with the "/bt=NETWARE" option.  This 
  13133.       will cause the compiler to: 
  13134.  
  13135.           use the small memory model instead of the flat memory model, 
  13136.           use stack-based calling conventions, 
  13137.           search the NETWARE_INCLUDE environment variable before searching the 
  13138.            INCLUDE environment variable, and 
  13139.           reference a special startup symbol,  __WATCOM_Prelude, in the 
  13140.            libraries. 
  13141.  
  13142.    2. You must compile your source files with the small memory model option 
  13143.       ("ms").  This is accomplished by specifying the "/bt=NETWARE" option. 
  13144.  
  13145.    3. You must compile your source files with one of the stack-based calling 
  13146.       convention options ("3s", "4s" or "5s"). This is accomplished by 
  13147.       specifying the "/bt=NETWARE" option. 
  13148.  
  13149.    4. You must set the NETWARE_INCLUDE environment variable to point to the 
  13150.       \WATCOM\NOVH directory.  This environment variable will be searched first 
  13151.       when you compile with the "/bt=NETWARE" option. Alternatively, you can 
  13152.       set the INCLUDE environment variable to include \WATCOM\NOVH before other 
  13153.       include directories. 
  13154.  
  13155.    5. If you are using the compile and link utility WCL386, you must use the 
  13156.       following options:  "/l=NETWARE /bt=NETWARE". 
  13157.  
  13158.    6. You must specify 
  13159.  
  13160.  
  13161.          system NETWARE 
  13162.  
  13163.       when linking an NLM.  This is automatic if you are using WCL386 and the 
  13164.       "/l=NETWARE" option. 
  13165.  
  13166.    7. If you are using other Netware APIs such as NWSNUT, then you must include 
  13167.       module and  import statements as input to the Watcom Linker. 
  13168.  
  13169.       Example: 
  13170.  
  13171.          module nwsnut 
  13172.          import @%WATCOM%\novi\nwsnut.imp 
  13173.  
  13174.       This is done automatically for the C Library (CLIB.IMP).  The following 
  13175.       import lists have been provided for Netware API libraries. 
  13176.  
  13177.  
  13178.          AIO.IMP 
  13179.          APPLETLK.IMP 
  13180.          BSD.IMP 
  13181.          CLIB.IMP 
  13182.          DSAPI.IMP 
  13183.          MATHLIB.IMP 
  13184.          NWSNUT.IMP 
  13185.          SOCKLIB.IMP 
  13186.          STREAMS.IMP 
  13187.          TLI.IMP 
  13188.  
  13189.  
  13190. ΓòÉΓòÉΓòÉ 43. Inter-Language calls:  C and FORTRAN ΓòÉΓòÉΓòÉ
  13191.  
  13192.  
  13193. The purpose of this chapter is to anticipate common questions about 
  13194. mixed-language development using Watcom C/C++ and Watcom FORTRAN 77. 
  13195.  
  13196. The following topics are discussed in this chapter: 
  13197.  
  13198.      Symbol Naming Convention 
  13199.      Argument Passing Convention 
  13200.      Memory Model Compatibility 
  13201.      Integer Type Compatibility 
  13202.      How do I pass integers from C to a FORTRAN function? 
  13203.      How do I pass integers from FORTRAN to a C function? 
  13204.      How do I pass a string from a C function to FORTRAN? 
  13205.      How do I pass a string from FORTRAN to a C function? 
  13206.      How do I access a FORTRAN common block from within C? 
  13207.      How do I call a C function that accepts a variable number of arguments? 
  13208.  
  13209.  
  13210. ΓòÉΓòÉΓòÉ 43.1. Symbol Naming Convention ΓòÉΓòÉΓòÉ
  13211.  
  13212.  
  13213. The symbol naming convention describes how a symbol in source form is mapped to 
  13214. its object form.  Because of this mapping, the name generated in the object 
  13215. file may differ from its original source form. 
  13216.  
  13217. Default symbol naming conventions vary between compilers.  Watcom C/C++ 
  13218. prefixes an underscore character to the beginning of variable names and appends 
  13219. an underscore to the end of function names during the compilation process. 
  13220. Watcom FORTRAN 77 converts symbols to upper case.  Auxiliary pragmas can be 
  13221. used to resolve this inconsistency. 
  13222.  
  13223. Pragmas are compiler directives which can provide several capabilities, one of 
  13224. which is to provide information used for code generation.  When calling a 
  13225. FORTRAN subprogram from C, we want to instruct the compiler NOT to append the 
  13226. underscore at the end of the function name and to convert the name to upper 
  13227. case.  This is achieved by using the following C auxiliary pragma: 
  13228.  
  13229.  
  13230.    #pragma aux ftnname "^"; 
  13231.  
  13232. The "^" character tells the compiler to convert the symbol name "ftnname" to 
  13233. upper case; no underscore character will be appended.  This solves potential 
  13234. linker problems with "ftnname" since (by C convention) the linker would attempt 
  13235. to resolve a reference to "ftnname_". 
  13236.  
  13237. When calling C functions from FORTRAN, we need to instruct the compiler to add 
  13238. the underscore at the end of the function name, and to convert the name to 
  13239. lower case.  Since the FORTRAN compiler automatically converts identifiers to 
  13240. uppercase, it is necessary to force the compiler to emit an equivalent 
  13241. lowercase name.  Both of these things can be done with the following FORTRAN 
  13242. auxiliary pragma: 
  13243.  
  13244.  
  13245.    *$pragma aux CNAME "!_" 
  13246.  
  13247. There is another less convenient way to do this as shown in the following: 
  13248.  
  13249.  
  13250.    *$pragma aux CNAME "cname_" 
  13251.  
  13252. In the latter example, the case of the name in quotation marks is preserved. 
  13253.  
  13254. Use of these pragmas resolves the naming differences, however, the issue of 
  13255. argument passing must still be resolved. 
  13256.  
  13257.  
  13258. ΓòÉΓòÉΓòÉ 43.2. Argument Passing Convention ΓòÉΓòÉΓòÉ
  13259.  
  13260.  
  13261. In general, C uses call-by-value (passes argument values) while FORTRAN uses 
  13262. call-by-reference (passes pointers to argument values).  This implies that to 
  13263. pass arguments to a FORTRAN subprogram we must pass the addresses of arguments 
  13264. rather than their values.  C uses the "&" character to signify "address of". 
  13265.  
  13266. Example: 
  13267.  
  13268.    result = ftnname( &arg ); 
  13269.  
  13270. When calling a C function from FORTRAN, the pragma used to correct the naming 
  13271. conventions must also instruct the compiler that the C function is expecting 
  13272. values, not addresses. 
  13273.  
  13274.  
  13275.    *$pragma aux CNAME "!_" parm (value) 
  13276.  
  13277. The "parm (value)" addition instructs the FORTRAN compiler to pass values, 
  13278. instead of addresses. 
  13279.  
  13280. Character data (strings) are an exception to the general case when used as 
  13281. arguments.  In C, strings are not thought of as a whole entity, but rather as 
  13282. an "array of characters".  Since strings are not considered scalar arguments, 
  13283. they are referenced differently in both C and FORTRAN.  This is described in 
  13284. more detail in a following section. 
  13285.  
  13286.  
  13287. ΓòÉΓòÉΓòÉ 43.3. Memory Model Compatibility ΓòÉΓòÉΓòÉ
  13288.  
  13289.  
  13290. While it is really not an issue with the 32-bit compilers (both use the default 
  13291. "flat" memory model), it is important to know that the default memory model 
  13292. used in Watcom FORTRAN 77 applications is the "large" memory model ("ml") with 
  13293. "medium" and "huge" memory models as options.  Since the 16-bit Watcom C/C++ 
  13294. default is the "small" memory model, you must specify the correct memory model 
  13295. when compiling your C/C++ code with the 16-bit C or C++ compiler. 
  13296.  
  13297.  
  13298. ΓòÉΓòÉΓòÉ 43.4. Linking Considerations ΓòÉΓòÉΓòÉ
  13299.  
  13300.  
  13301. When both C/C++ and FORTRAN object files are combined into an executable 
  13302. program or dynamic link library, it is important that you list a least one of 
  13303. the FORTRAN object files first in the Watcom Linker (WLINK) "FILES" directive 
  13304. to guarantee the proper search order of the FORTRAN and C run-time libraries. 
  13305. If you place a C/C++ object file first, you may inadvertently cause the wrong 
  13306. version of run-time initialization routines to be loaded by the linker. 
  13307.  
  13308.  
  13309. ΓòÉΓòÉΓòÉ 43.5. Integer Type Compatibility ΓòÉΓòÉΓòÉ
  13310.  
  13311.  
  13312. In general, the number of bytes used to store an integer type is implementation 
  13313. dependent.  In FORTRAN, the default size of an integer type is always 4 bytes, 
  13314. while in C/C++, the size is architecture dependent.  The size of an "int" is 2 
  13315. bytes for the 16-bit Watcom C/C++ compilers and 4 bytes for the 32-bit 
  13316. compilers while the size of a "long" is 4 bytes regardless of architecture.  It 
  13317. is safest to prototype the function in C, specifying exactly what size integers 
  13318. are being used.  The byte sizes are as follows: 
  13319.  
  13320.    1. LONG - 4 bytes 
  13321.  
  13322.    2. SHORT - 2 bytes 
  13323.  
  13324.  Since FORTRAN uses a default of 4 bytes, we should specify the "long" keyword 
  13325.  in C for integer types. 
  13326.  
  13327.  Example: 
  13328.  
  13329.     long int ftnname( long int *, long int *, long int * ); 
  13330.  
  13331.  In this case, "ftnname" takes three "pointers to long ints" as arguments, and 
  13332.  returns a "long int".  By specifying that the arguments are pointers, and not 
  13333.  values, and by specifying "long int" for the return type, this prototype has 
  13334.  solved the problems of argument passing and integer type compatibility. 
  13335.  
  13336.  
  13337. ΓòÉΓòÉΓòÉ 43.6. How do I pass integers from C to a FORTRAN function? ΓòÉΓòÉΓòÉ
  13338.  
  13339.  
  13340. The following Watcom C/C++ routine passes three integers to a FORTRAN function 
  13341. that returns an integer value. 
  13342.  
  13343.  
  13344.    /* MIX1C.C - This C program calls a FORTRAN function to 
  13345.    *      compute the max of three numbers. 
  13346.    * 
  13347.    * Compile/Link: wcl /ml mix1c mix1f.obj /fe=mix1 
  13348.    *        wcl386  mix1c mix1f.obj /fe=mix1 
  13349.    */ 
  13350.  
  13351.    #include <stdio.h> 
  13352.  
  13353.    #pragma aux tmax3 "^"; 
  13354.    long int tmax3( long int *, long int *, long int * ); 
  13355.  
  13356.    void main() 
  13357.    { 
  13358.      long int  result; 
  13359.      long int  i, j, k; 
  13360.  
  13361.      i = -1; 
  13362.      j = 12; 
  13363.      k = 5; 
  13364.      result = tmax3( &i, &j, &k ); 
  13365.      printf( "Maximum is %ld\n", result ); 
  13366.    } 
  13367.  
  13368. The FORTRAN function: 
  13369.  
  13370.  
  13371.    * MIX1F.FOR - This FORTRAN function accepts three integer 
  13372.    *       arguments and returns their maximum. 
  13373.  
  13374.    * Compile: wfc[386] mix1f.for 
  13375.  
  13376.        integer function tmax3( arga, argb, argc ) 
  13377.        integer arga, argb, argc 
  13378.  
  13379.        tmax3 = arga 
  13380.        if ( argb .gt. tmax3 ) tmax3 = argb 
  13381.        if ( argc .gt. tmax3 ) tmax3 = argc 
  13382.        end 
  13383.  
  13384.  
  13385. ΓòÉΓòÉΓòÉ 43.7. How do I pass integers from FORTRAN to a C function? ΓòÉΓòÉΓòÉ
  13386.  
  13387.  
  13388. The following Watcom FORTRAN 77 routine passes three integers to a Watcom C/C++ 
  13389. function that returns an integer value. 
  13390.  
  13391.  
  13392.    *  MIX2F.FOR - This FORTRAN program calls a C function to 
  13393.    *        compute the max of three numbers. 
  13394.    * 
  13395.    * Compile/Link: wfl[386] mix2f mix2c.obj /fe=mix2 
  13396.  
  13397.    *$pragma aux tmax3 "!_" parm (value) 
  13398.  
  13399.        program mix2f 
  13400.  
  13401.        integer*4  tmax3 
  13402.        integer*4  result 
  13403.        integer*4  i, j, k 
  13404.  
  13405.        i = -1 
  13406.        j = 12 
  13407.        k = 5 
  13408.        result = tmax3( i, j, k ) 
  13409.        print *, 'Maximum is ', result 
  13410.        end 
  13411.  
  13412. The C function "tmax3" is shown below. 
  13413.  
  13414.  
  13415.    /* MIX2C.C - This C function accepts 3 integer arguments 
  13416.    *      and returns their maximum. 
  13417.    * 
  13418.    * Compile: wcc /ml mix2c 
  13419.    *      wcc386  mix2c 
  13420.    */ 
  13421.  
  13422.    long int tmax3( long int arga, 
  13423.            long int argb, 
  13424.            long int argc ) 
  13425.  
  13426.    { 
  13427.      long int  result; 
  13428.      result = arga; 
  13429.      if( argb > result ) result = argb; 
  13430.      if( argc > result ) result = argc; 
  13431.      return( result ); 
  13432.    } 
  13433.  
  13434.  
  13435. ΓòÉΓòÉΓòÉ 43.8. How do I pass a string from a C function to FORTRAN? ΓòÉΓòÉΓòÉ
  13436.  
  13437.  
  13438. Character strings are referenced differently in C and FORTRAN.  The C language 
  13439. terminates its strings with a null character as an End-Of-String (EOS) marker. 
  13440. In this case, C need not store the length of the string in memory. FORTRAN, 
  13441. however, does not use any EOS marker; hence it must store each string's length 
  13442. in memory. 
  13443.  
  13444. The structure FORTRAN uses to keep track of character data is called a "string 
  13445. descriptor" which consists of a pointer to the character data (2, 4, or 6 
  13446. bytes, depending on the data model) followed by an unsigned integer length (2 
  13447. bytes or 4 bytes, depending on the data model). 
  13448.  
  13449.  
  13450.      system option  size of pointer   size of length 
  13451.      ------ ------  ---------------   -------------- 
  13452.      16-bit /MM    16 bits       16 bits 
  13453.      16-bit /ML    32 bits       16 bits 
  13454.      32-bit /MF    32 bits       32 bits 
  13455.      32-bit /ML    48 bits       32 bits 
  13456.  
  13457. In order to access character data, FORTRAN needs to have access to the data's 
  13458. string descriptor.  Hence, FORTRAN expects a pointer to a string descriptor to 
  13459. be passed as an argument for character data. 
  13460.  
  13461. Passing string arguments between C and FORTRAN is a simple task of describing a 
  13462. struct type in C containing the two fields described above.  The first field 
  13463. must contain the pointer to the character data, and the second field must 
  13464. contain the length of the string being passed.  A pointer to this structure can 
  13465. then be passed to FORTRAN. 
  13466.  
  13467.  
  13468.    * MIX3F.FOR - This FORTRAN program calls a function written 
  13469.    *       in C that passes back a string. 
  13470.    * 
  13471.    * Compile/Link: wfl[386] mix3f mix3c.obj /fe=mix3 
  13472.  
  13473.        program mix3f 
  13474.  
  13475.        character*80 sendstr 
  13476.        character*80 cstring 
  13477.  
  13478.        cstring = sendstr() 
  13479.        print *, cstring(1:lentrim(cstring)) 
  13480.        end 
  13481.  
  13482. The C function "sendstr" is shown below. 
  13483.  
  13484.  
  13485.    /* MIX3C.C - This C function passes a string back to its 
  13486.    *      calling FORTRAN program. 
  13487.    * 
  13488.    * Compile: wcc /ml mix3c 
  13489.    *      wcc386  mix3c 
  13490.    */ 
  13491.  
  13492.    #include <string.h> 
  13493.  
  13494.    #pragma aux sendstr "^"; 
  13495.  
  13496.    typedef struct descriptor { 
  13497.      char      *addr; 
  13498.      unsigned    len; 
  13499.    } descriptor; 
  13500.  
  13501.    void sendstr( descriptor *ftn_str_desc ) 
  13502.    { 
  13503.      ftn_str_desc->addr = "This is a C string"; 
  13504.      ftn_str_desc->len  = strlen( ftn_str_desc->addr ); 
  13505.    } 
  13506.  
  13507.  
  13508. ΓòÉΓòÉΓòÉ 43.9. How do I pass a string from FORTRAN to a C function? ΓòÉΓòÉΓòÉ
  13509.  
  13510.  
  13511. By default, FORTRAN passes the address of the string descriptor when passing 
  13512. strings.  If the C function knows it is being passed a string descriptor 
  13513. address, then it is very similar to the above example.  If the C function is 
  13514. expecting normal C-type strings, then a FORTRAN pragma can be used to pass the 
  13515. string correctly.  When the Watcom FORTRAN 77 compiler pragma to pass by value 
  13516. is used for strings, then just a pointer to the string is passed. 
  13517.  
  13518. Example: 
  13519.  
  13520.    *$pragma aux cname "!_" parm (value) 
  13521.  
  13522. The following example FORTRAN mainline defines a string, and passes it to a C 
  13523. function that prints it out. 
  13524.  
  13525.  
  13526.    * MIX4F.FOR - This FORTRAN program calls a function written 
  13527.    *       in C and passes it a string. 
  13528.    * 
  13529.    * Compile/Link: wfl[386] mix4f mix4c.obj /fe=mix4 
  13530.  
  13531.    *$pragma aux cstr "!_" parm (value) 
  13532.  
  13533.        program mix4f 
  13534.  
  13535.        character*80 forstring 
  13536.  
  13537.        forstring = 'This is a FORTRAN string'//char(0) 
  13538.        call cstr( forstring ) 
  13539.        end 
  13540.  
  13541. The C function: 
  13542.  
  13543.  
  13544.    /* MIX4C.C - This C function prints a string passed from 
  13545.    *      FORTRAN. 
  13546.    * 
  13547.    * Compile: wcc /ml mix4c 
  13548.    *      wcc386  mix4c 
  13549.    */ 
  13550.  
  13551.    #include <stdio.h> 
  13552.  
  13553.    void cstr( char *instring ) 
  13554.    { 
  13555.      printf( "%s\n", instring ); 
  13556.    } 
  13557.  
  13558.  
  13559. ΓòÉΓòÉΓòÉ 43.10. How do I access a FORTRAN common block from within C? ΓòÉΓòÉΓòÉ
  13560.  
  13561.  
  13562. The following code demonstrates a technique for accessing a FORTRAN common 
  13563. block in a C routine.  The C routine defines an extern struct to correspond to 
  13564. the FORTRAN common block. 
  13565.  
  13566.  
  13567.    * MIX5F.FOR - This program shows how a FORTRAN common 
  13568.    *       block can be accessed from C. 
  13569.    * 
  13570.    * Compile/Link: wfl[386] mix5f mix5c.obj /fe=mix5 
  13571.  
  13572.        program mix5f 
  13573.        external put 
  13574.        common/cblk/i,j 
  13575.  
  13576.        i=12 
  13577.        j=10 
  13578.        call put 
  13579.        print *, 'i = ', i 
  13580.        print *, 'j = ', j 
  13581.        end 
  13582.  
  13583. The C function: 
  13584.  
  13585.  
  13586.    /* MIX5C.C - This code shows how to access a FORTRAN 
  13587.    *      common block from C. 
  13588.    * 
  13589.    * Compile: wcc /ml mix5c 
  13590.    *      wcc386  mix5c 
  13591.    */ 
  13592.    #include <stdio.h> 
  13593.  
  13594.    #pragma aux put "^"; 
  13595.    #pragma aux cblk "^"; 
  13596.  
  13597.    #ifdef __386__ 
  13598.    #define FAR 
  13599.    #else 
  13600.    #define FAR far 
  13601.    #endif 
  13602.  
  13603.    extern struct cb { 
  13604.      long int i,j; 
  13605.    } FAR cblk; 
  13606.  
  13607.    void put( void ) 
  13608.    { 
  13609.      printf( "i = %ld\n", cblk.i ); 
  13610.      printf( "j = %ld\n", cblk.j ); 
  13611.      cblk.i++; 
  13612.      cblk.j++; 
  13613.    } 
  13614.  
  13615. For the 16-bit C compiler, the common block "cblk" is described as  far to 
  13616. force a load of the segment portion of the address.  Otherwise, since the 
  13617. object is smaller than 32K (the default data threshold), it is assumed to be 
  13618. located in the DGROUP group which is accessed through the SS segment register. 
  13619.  
  13620.  
  13621. ΓòÉΓòÉΓòÉ 43.11. How do I call a C function that accepts a variable number of arguments? ΓòÉΓòÉΓòÉ
  13622.  
  13623.  
  13624. One capability that C possesses is the ability to define functions that accept 
  13625. variable number of arguments.  This feature is not present, however, in the 
  13626. definition of the FORTRAN 77 language.  As a result, a special pragma is 
  13627. required to call these kinds of functions. 
  13628.  
  13629.  
  13630.    *$pragma aux printf "!_" parm (value) caller [] 
  13631.  
  13632. The "caller" specifies that the caller will pop the arguments from the stack. 
  13633. The "[]" indicates that there are no arguments passed in registers because the 
  13634. printf function takes a variable number of arguments passed on the stack.  The 
  13635. following example is a FORTRAN function that uses this pragma.  It calls the 
  13636. printf function to print the value 47 on the screen. 
  13637.  
  13638.  
  13639.    * MIX6.FOR - This FORTRAN program calls the C 
  13640.    *       printf function. 
  13641.  
  13642.    * Compile/Link: wfl[386] mix6 
  13643.  
  13644.    *$pragma aux printf "!_" parm (value) caller [] 
  13645.  
  13646.        program mix6 
  13647.  
  13648.        character cr/z0d/, nullchar/z00/ 
  13649.  
  13650.        call printf( 'Value is %ld.'//cr//nullchar, 47 ) 
  13651.        end 
  13652.  
  13653. For more information on the pragmas that are used extensively during 
  13654. inter-language programming, please refer to the chapter entitled "Pragmas" in 
  13655. both the Watcom C/C++ User's Guide and the Watcom FORTRAN 77 User's Guide. 
  13656.  
  13657.  
  13658. ΓòÉΓòÉΓòÉ 44. Commonly Asked Questions and Answers ΓòÉΓòÉΓòÉ
  13659.  
  13660.  
  13661. As with any sophisticated piece of software, there are topics that are not 
  13662. directly addressed by the descriptive portions of the manuals.  The purpose of 
  13663. this chapter is to anticipate common questions concerning Watcom C/C++.  It is 
  13664. difficult to predict what topics will prove to be useful but with that in mind, 
  13665. we hope that this chapter will help our customers make full use of Watcom 
  13666. C/C++. 
  13667.  
  13668. A number of example programs are presented throughout.  The source text for 
  13669. these files can be found in the \WATCOM\SAMPLES\GOODIES directory. 
  13670.  
  13671. The purpose of this chapter is to present some of the more commonly asked 
  13672. questions from our users and the answers to these questions.  The following 
  13673. topics are discussed: 
  13674.  
  13675.      How do I determine my current patch level? 
  13676.      How do I convert to Watcom C/C++? 
  13677.      What should I know about optimization? 
  13678.      Why can't the compiler find "stdio.h"? 
  13679.      How do I resolve an "Undefined Reference" linker error? 
  13680.      Why aren't my variables set to zero? 
  13681.      What does "size of DGROUP exceeds 64K" mean for 16-bit applications? 
  13682.      What does "NULL assignment detected" mean in 16-bit applications? 
  13683.      What does "Stack Overflow!" mean? 
  13684.      Why do I get redefinition errors from WLINK? 
  13685.      How can I open more than 20 files at a time? 
  13686.      How can I see my source files in the debugger? 
  13687.      What is the difference between the "d1" and "d2" compiler options? 
  13688.  
  13689.  
  13690. ΓòÉΓòÉΓòÉ 44.1. Determining my current patch level ΓòÉΓòÉΓòÉ
  13691.  
  13692.  
  13693. In an effort to immediately correct any problems discovered in the originally 
  13694. shipped product, Watcom provides patches as a continued service to its 
  13695. customers.  To determine the current patch level of your Watcom software, a 
  13696. TECHINFO utility program has been provided.  This program will display your 
  13697. current environment variables, the patch level of various Watcom software 
  13698. programs, and other pertinent information, such as your AUTOEXEC.BAT and 
  13699. CONFIG.SYS files.  This information proves to be very useful when reporting a 
  13700. problem to the Technical Support team. 
  13701.  
  13702. To run TECHINFO, you must ensure the Watcom environment variable has been set 
  13703. to the directory where your Watcom software has been installed.  TECHINFO will 
  13704. pause after each screenful of information.  The output is also placed in the 
  13705. file TECHINFO.OUT. 
  13706.  
  13707. Below is an example of some partial output produced by running the TECHINFO 
  13708. utility: 
  13709.  
  13710. Example: 
  13711.  
  13712.    WATCOM's Techinfo Utility, Version 1.4 
  13713.    Current Time: Thu Oct 27 15:58:34 1994 
  13714.  
  13715.    WATCOM              Phone: (519) 884-0702 
  13716.    415 Phillip St.         Fax: (519) 747-4971 
  13717.    Waterloo, Ontario 
  13718.    CANADA   N2L 3X2 
  13719.  
  13720.    -------------WATCOM C Environment Variables ------------- 
  13721.    WATCOM=<c:\watcom> 
  13722.    EDPATH=<c:\watcom\eddat> 
  13723.    INCLUDE=<c:\watcom\h;c:\watcom\h\os2> 
  13724.    FINCLUDE=<c:\watcom\src\fortran;c:\watcom\src\fortran\win> 
  13725.    LIBOS2=<c:\watcom\lib286\os2;c:\watcom\lib286> 
  13726.    PATH=<c:\dos;c:\windows;c:\watcom\binw> 
  13727.    TMP=<h:\temp> 
  13728.    File 'c:\watcom\binw\wcc386.exe' has been patched to level '.d' 
  13729.    ...etc... 
  13730.  
  13731. In this example, the software has been patched to level "d".  In most cases, 
  13732. all tools will share a common patch level.  However, there are instances where 
  13733. certain tools have been patched to one level while others are patched to a 
  13734. different level.  For example, the compiler may be patched to level "d" while 
  13735. the debugger is only patched to level "c".  Basically, this means that there 
  13736. were no debugger changes in the D-level patches. 
  13737.  
  13738. If you run the TECHINFO utility, and determine that you are not at the current 
  13739. patch level, it is recommended that you update your software.  Patches are 
  13740. available on Watcom's bulletin board, Watcom's FTP site and CompuServe.  They 
  13741. are available 24 hours a day.  Patches are also available on the current 
  13742. release CD-ROM.  Each patch will include a batch file that allows you to apply 
  13743. the patches to your existing software.  Note that patches must be applied in 
  13744. sequential order, as each patch depends on the previous one. 
  13745.  
  13746.  
  13747. ΓòÉΓòÉΓòÉ 44.2. Converting to Watcom C/C++ ΓòÉΓòÉΓòÉ
  13748.  
  13749.  
  13750. There are some common steps involved in converting C programs written for other 
  13751. compilers.  Conversion from UNIX and other IBM-compatible PC compilers will be 
  13752. covered in detail later.  There are six major problems with most programs that 
  13753. are ported to Watcom C/C++.  The assumptions that most foreign programs make 
  13754. that may be invalid when using Watcom C/C++ are: 
  13755.  
  13756.    1. sizeof( pointer ) == sizeof( int ) 
  13757.  
  13758.       (true for 16-bit systems except "far" pointers, true for 32-bit systems 
  13759.       except "far" pointers) 
  13760.  
  13761.    2. sizeof( long ) == sizeof( int ) 
  13762.  
  13763.       (not true for 16-bit systems) 
  13764.  
  13765.    3. sizeof( short ) == sizeof( int ) 
  13766.  
  13767.       (not true for 32-bit systems) 
  13768.  
  13769.    4. arguments are always passed on the stack 
  13770.  
  13771.    5. dereferencing the NULL pointer 
  13772.  
  13773.    6. "char" is either signed or unsigned 
  13774.  
  13775.  These assumptions are very easy to make when developing programs for only one 
  13776.  system.  The first point becomes important when you move a program to 80x86 
  13777.  systems.  Depending on the memory model, the size of an integer might not 
  13778.  equal the size of a pointer.  You might ask how this assumption is made in 
  13779.  programs.  The C language will assume that a function returns an integer 
  13780.  unless told otherwise.  If a programmer does not declare a function as 
  13781.  returning a pointer, the compiler will generate code which would convert an 
  13782.  integer to a pointer.  On other systems, where the size of an integer is equal 
  13783.  to the size of a pointer this would amount to nothing because no conversion 
  13784.  was necessary (to change size).  The older C compilers did not worry about 
  13785.  warning the programmer about this condition and as such this error is imbedded 
  13786.  in a lot of older C code.  As C was moved to other machines, it became 
  13787.  apparent that this assumption was no longer valid for all machines.  The 80x86 
  13788.  architecture can have 16-bit integers and 32-bit pointers (in the compact, 
  13789.  large, and huge memory models), which means that more care must be taken when 
  13790.  working with declarations (converting an int to a 32-bit pointer will result 
  13791.  in a segment value of 0x0000 or 0xffff).  Similarly, the 386 architecture can 
  13792.  have 32-bit integers and 48-bit pointers. 
  13793.  
  13794.  The Watcom C/C++ compiler will complain about incorrect pointer and integer 
  13795.  mixing thus making programs compiled with Watcom C/C++ much more portable. 
  13796.  For instance, if the Watcom C/C++ compiler complains about your usage of the 
  13797.  "malloc" memory allocation function then you probably forgot to include 
  13798.  "<stdlib.h>" which contains the prototype of the "malloc" function. 
  13799.  
  13800.  Example: 
  13801.  
  13802.     extern void *malloc( unsigned ); 
  13803.  
  13804.  The Watcom C/C++ compiler was complaining about you trying to assign an 
  13805.  integer (the value returned by "malloc") to a pointer.  By including the 
  13806.  header file with the correct prototype, the Watcom C/C++ compiler can validate 
  13807.  that you are in fact assigning a pointer value to a pointer. 
  13808.  
  13809.  Passing arguments on the stack has been the method used by most older 
  13810.  compilers because it allowed the C library function "printf" to work with a 
  13811.  variable number of arguments.  Older C compilers catered to a few functions by 
  13812.  forcing all the argument handling to be handled by the caller of the function. 
  13813.  With the advent of the ANSI standard, which forced all functions expecting a 
  13814.  variable number of arguments to be declared properly, compilers can generate 
  13815.  smaller code for routines that did not require a variable number of arguments. 
  13816.  
  13817.  Example: 
  13818.  
  13819.     /* function accepting two arguments */ 
  13820.     extern FILE *fopen( char *, char * ); 
  13821.     /* function accepting a variable number of arguments */ 
  13822.     extern int printf( char *, ... ); 
  13823.  
  13824.  The Watcom C/C++ compiler takes advantage of this part of the ANSI standard by 
  13825.  passing arguments in registers (for the first few arguments).  If there are 
  13826.  not enough registers for all of the arguments, the rest of the arguments are 
  13827.  passed on the stack but the routine being called is responsible for removing 
  13828.  them from the stack.  By default, the Watcom C/C++ compiler uses this calling 
  13829.  convention because it results in faster procedure calls and smaller code.  The 
  13830.  Watcom C/C++ calling convention carries with it a responsibility to ensure 
  13831.  that all functions are prototyped correctly before they are used.  For 
  13832.  instance, if a procedure is called with too few arguments, the assumptions 
  13833.  that the code generator made (while generating the code) will be invalidated. 
  13834.  The code generator assumes that AX (EAX for the 32-bit compiler) and any other 
  13835.  registers used to pass arguments will be modified by the called function.  The 
  13836.  code generator also assumes that the exact amount of arguments pushed on the 
  13837.  stack will be removed by the function that is called.  It is important to 
  13838.  recognize this aspect of the Watcom C/C++ compiler because the program will 
  13839.  simply not work unless the caller and the function being called strictly agree 
  13840.  on the number and types of the arguments being passed.  See the "Assembly 
  13841.  Language Considerations" chapter in the Watcom C/C++ User's Guide for more 
  13842.  details. 
  13843.  
  13844.  Some compilers allow the NULL pointer to be dereferenced and return NULL (we 
  13845.  have never understood the rationale behind this, nor why some compilers 
  13846.  continue to support this type of code).  Leaving the aesthetics of this type 
  13847.  of code behind, using the NULL dereferencing assumption in a program will 
  13848.  ensure that the program will not be portable.  Source code which contains the 
  13849.  NULL dereferencing assumption must be corrected before it will work with 
  13850.  Watcom C/C++. 
  13851.  
  13852.  Programs that assume that the "char" type is "signed" should use the Watcom 
  13853.  C/C++ compiler "j" option.  The "j" option will indicate to the Watcom C/C++ 
  13854.  compiler that the "char" type is "signed" rather than the default "unsigned". 
  13855.  
  13856.  
  13857. ΓòÉΓòÉΓòÉ 44.2.1. Conversion from UNIX compilers ΓòÉΓòÉΓòÉ
  13858.  
  13859.  
  13860. The ANSI standard for C (which Watcom C/C++ adheres to) is very similar to UNIX 
  13861. C.  Most of the effort in converting UNIX C programs will involve replacing 
  13862. references to library functions (such as the CURSES library).  There are many 
  13863. third-party libraries which are implementations of UNIX libraries on 
  13864. IBM-compatible Personal Computers.  There is a common problem which many older 
  13865. UNIX programs exhibit, namely, functions that accept a variable number of 
  13866. arguments are coded in many different ways.  Functions accepting a variable 
  13867. number of arguments must be coded according to the ANSI standard if they are to 
  13868. work with Watcom C/C++.  We will code an example of a function which will 
  13869. return the maximum of a list of positive integers. 
  13870.  
  13871.  
  13872.    /* 
  13873.     variable number of arguments example 
  13874.    */ 
  13875.    #include <stdarg.h> 
  13876.  
  13877.    int MaxList( int how_many, ... ) 
  13878.    { 
  13879.      va_list args; 
  13880.      int max; 
  13881.  
  13882.      max = 0; 
  13883.      va_start( args, how_many ); 
  13884.      while( how_many > 0 ) { 
  13885.        value = va_arg( args, int ); 
  13886.        if( value > max ) { 
  13887.          max = value; 
  13888.        } 
  13889.      } 
  13890.      va_end( args ); 
  13891.  
  13892.      return( max ); 
  13893.    } 
  13894.  
  13895. Notice that the standard header file STDARG.H must be included in any source 
  13896. file which defines a function that handles a variable number of arguments.  The 
  13897. function "MaxList" must be prototyped correctly in other source files external 
  13898. to the source file containing the definition of "MaxList". 
  13899.  
  13900.  
  13901.    extern int MaxList( int how_many, ... ); 
  13902.  
  13903. See the Watcom C Library Reference manual description of "va_arg" for a more 
  13904. complete description of variable number of arguments handling. 
  13905.  
  13906.  
  13907. ΓòÉΓòÉΓòÉ 44.2.2. Conversion from IBM-compatible PC compilers ΓòÉΓòÉΓòÉ
  13908.  
  13909.  
  13910. Most of the compilers available for IBM-compatible PCs have been following the 
  13911. ANSI standard and, as such, the majority of programs will not require extensive 
  13912. source changes.  There are problems with programs that use compiler-specific 
  13913. library functions.  The use of compiler-specific library functions can be dealt 
  13914. with in two different ways: 
  13915.  
  13916.    1. use equivalent Watcom C/C++ library functions 
  13917.  
  13918.    2. write your own library functions 
  13919.  
  13920.  If portability must be maintained with the other compiler, the predefined 
  13921.  macro "__WATCOMC__" can be used to conditionally compile the correct code for 
  13922.  the Watcom C/C++ compiler. 
  13923.  
  13924.  The default calling convention for the Watcom C/C++ compiler is different from 
  13925.  the calling convention used by other compilers for Intel-based personal 
  13926.  computers.  The Watcom C/C++ calling convention is different because it will 
  13927.  pass some arguments in registers (thus reducing the overhead of a function 
  13928.  call) rather than pushing all of the arguments on the stack.  The Watcom C/C++ 
  13929.  compiler is flexible enough to use different calling conventions on a per 
  13930.  function basis.  Converting code from other compilers usually involves 
  13931.  recompiling the C source files and setting up prototypes (to use the older 
  13932.  calling convention) for functions written in assembly language.  For instance, 
  13933.  if you have the functions "video_init", "video_put", and "video_get" written 
  13934.  in assembly language, you can use the following prototypes in any source file 
  13935.  which uses these functions. 
  13936.  
  13937.  
  13938.     #include <stddef.h> 
  13939.  
  13940.     extern int  cdecl video_init( void ); 
  13941.     extern void cdecl video_put( int row,int col,char ch,int attr ); 
  13942.     extern char cdecl video_get( int row,int col ); 
  13943.  
  13944.  The inclusion of the STDDEF.H header file defines the "cdecl" calling 
  13945.  convention.  The Watcom C/C++ compiler will ensure that any calls to these 
  13946.  three functions will adhere to the "cdecl" calling conventions.  The Watcom 
  13947.  C/C++ compiler will put a trailing underscore "_" character (as opposed to the 
  13948.  beginning of the name for the "cdecl" convention) on any function names to 
  13949.  ensure that the program will not link register calling convention calls to 
  13950.  "cdecl" convention functions (or vice versa).  If the linker indicates that 
  13951.  functions defined in assembler files cannot be resolved, it could be a result 
  13952.  of not prototyping the functions properly as "cdecl" functions. 
  13953.  
  13954.  Hint:  (16-bit applications only) Most 16-bit C compilers (including Watcom 
  13955.  C/C++) have a "large" memory model which means that four byte pointers are 
  13956.  used for both code and data references.  A subtle point to watch out for 
  13957.  involves differences between memory model definitions of different compilers. 
  13958.  The "cdecl" calling convention allows functions to assume that the DS segment 
  13959.  register points to the group "DGROUP".  The Watcom C/C++ large memory model 
  13960.  has what is called a "floating DS".  Any function used for the large memory 
  13961.  model cannot assume that the DS segment register points to the group "DGROUP". 
  13962.  There are a few possible recourses. 
  13963.  
  13964.    1. The assembly code could save and restore the DS segment register and set 
  13965.       DS to DGROUP in order to conform to the Watcom C/C++ convention.  If 
  13966.       there are only a few accesses to DGROUP data, it is advisable to use the 
  13967.       SS segment register which points to DGROUP in the large memory model. 
  13968.  
  13969.    2. The assembly function could be described using a pragma that states that 
  13970.       DS should point to "DGROUP" before calling the function. 
  13971.  
  13972.       #pragma aux _Setcolor parm loadds 
  13973.  
  13974.       In the above example, _Setcolor is the sample function being described. 
  13975.  
  13976.    3. The final alternative would be the use of the "zdp" compiler option.  The 
  13977.       "zdp" option informs the code generator that the DS register must always 
  13978.       point to "DGROUP".  This is the default in the small, medium and flat 
  13979.       memory models.  Note that "flat" is a 32-bit memory model only. 
  13980.  
  13981.  
  13982. ΓòÉΓòÉΓòÉ 44.3. What you should know about optimization ΓòÉΓòÉΓòÉ
  13983.  
  13984.  
  13985. The C/C++ language contains features which allow simpler compilers to generate 
  13986. code of reasonable quality.  Register declarations and imbedding assignments in 
  13987. expressions are two of the ways that C allows the programmer to "help" the 
  13988. compiler generate good quality code.  An important point about the Watcom C/C++ 
  13989. compiler is that it is not as important (as it is with other compilers) to 
  13990. "help" the compiler.  In order to make good decisions about code generation, 
  13991. the Watcom C/C++ compiler uses modern optimization techniques. 
  13992.  
  13993. Hint:  The definitive reference on compiler design is the "dragon" book 
  13994. "Compilers - Principles, Techniques, and Tools", Alfred V.  Aho, Ravi Sethi, 
  13995. and Jeffrey D.  Ullman, published by Addison-Wesley, Reading, Massachusetts, 
  13996. 1986.  The authors of the "dragon" book advocate a conservative approach to 
  13997. code generation where optimizations must preserve the semantics of the original 
  13998. program.  The conservative approach is used throughout the Watcom C/C++ 
  13999. compiler to ensure that programmers can use the compiler without worrying about 
  14000. the semantics of their program being changed.  The programmer can request that 
  14001. potentially unsafe optimizations be performed.  With regard to the "oa" (ignore 
  14002. aliasing) option provided by the Watcom C/C++ compiler, the compiler only 
  14003. ignores aliasing of global variables rather than ignore aliasing totally like 
  14004. other compilers. 
  14005.  
  14006. There are certain pieces of information which the compiler cannot derive from 
  14007. the source code.  The "#pragma" compiler directive is used to provide extra 
  14008. information to the compiler.  It is necessary to have a complete understanding 
  14009. of both C/C++ and the machine architecture (i.e., 80x86) before using the 
  14010. powerful pragma compiler directives.  See the "Pragmas" chapter in the Watcom 
  14011. C/C++ User's Guide for more details. 
  14012.  
  14013. Debugging optimized programs is difficult because variables can be assigned to 
  14014. different locations (i.e., memory or registers) in different parts of the 
  14015. function.  The "d2" compiler option will restrict the amount of optimization so 
  14016. that variables occupy one location and can be easily displayed.  It follows 
  14017. that the "d2" option is useful for initial development but production programs 
  14018. should be compiled with only the "d1" option for the best code quality.  Before 
  14019. you distribute your application to others, you may wish to use the Watcom Strip 
  14020. Utility (WSTRIP) to remove debugging information from the executable image on 
  14021. disk thereby reducing disk space requirements. 
  14022.  
  14023. Hint:  The "d2" compiler option will generate symbolic information (for every 
  14024. local variable) and line number information for the source file.  The "d1" 
  14025. compiler option will only generate line number information for the source file. 
  14026. The use of these options determines what kind of information will be available 
  14027. for the particular module during the debugging session. 
  14028.  
  14029. Incorrect programs can sometimes work when compiled with the "d2" option and 
  14030. not work when compiled with the "d1" option.  One way this sort of problem 
  14031. arises involves local arrays. 
  14032.  
  14033.  
  14034.    void example( void ) 
  14035.    { 
  14036.      int i; 
  14037.      int a[10]; 
  14038.  
  14039.      for( i = 0; i <= 10; ++i ) 
  14040.        a[i] = i; 
  14041.      do_something( a ); 
  14042.    } 
  14043.  
  14044. The "for" loop initializes one too many array elements but the version compiled 
  14045. with the "d2" option will overwrite the variable "i" without causing any 
  14046. problems.  The same function compiled with the "d1" option would have the 
  14047. variable "i" in a register.  The erroneous access of "a[10]" would modify a 
  14048. value that is used to restore a register when the function returns.  The 
  14049. register would be "restored" with an incorrect value and this would affect the 
  14050. execution of the function that called this function.  The above example shows 
  14051. how a program can work when compiled with the "d2" option and stop working when 
  14052. compiled with the "d1" option.  You should always test your program fully with 
  14053. all the modules compiled with the "d1" option to protect yourself from any 
  14054. surprises. 
  14055.  
  14056.  
  14057. ΓòÉΓòÉΓòÉ 44.4. The compiler cannot find "stdio.h" ΓòÉΓòÉΓòÉ
  14058.  
  14059.  
  14060. The standard header files are usually located in the sub-directory that the 
  14061. Watcom C/C++ compiler is installed in.  Suppose that the header files are 
  14062. located in the sub-directory C:\WATCOM\H.  If the compiler indicates (through 
  14063. an error message) that it is unable to locate the file STDIO.H, we have 
  14064. forgotten something.  There are two ways to indicate to the Watcom C/C++ 
  14065. compiler the location of the standard header files. 
  14066.  
  14067.    1. use the INCLUDE environment variable 
  14068.  
  14069.    2. use the "i" option (Watcom C/C++, Watcom Compile and Link) 
  14070.  
  14071.  The use of the environment variable is the simplest way to ensure that the 
  14072.  include files will be found.  For instance, if you include the following line 
  14073.  in your system initialization file, AUTOEXEC.BAT, 
  14074.  
  14075.  
  14076.     set include=c:\watcom\h 
  14077.  
  14078.  the Watcom C/C++ compiler will be able to find the standard include files. 
  14079.  The use of the "i" option is another way to give the directory name of the 
  14080.  standard include files. 
  14081.  
  14082.  Example: 
  14083.  
  14084.     C>wcc myfile.c -ic:\watcom\h 
  14085.       or 
  14086.     C>wcc386 myfile.c -ic:\watcom\h 
  14087.       or 
  14088.     C>wpp myfile.cpp -ic:\watcom\h 
  14089.       or 
  14090.     C>wpp386 myfile.cpp -ic:\watcom\h 
  14091.  
  14092.  The usual manner that these methods are combined is as follows.  The INCLUDE 
  14093.  environment variable is used to give the location of the standard C library 
  14094.  header files.  Any directories of header files local to a specific programming 
  14095.  project are often candidates for the "i" option method.  See the "Watcom C/C++ 
  14096.  #include File Processing" section of the chapter entitled "The Watcom C/C++ 
  14097.  Compilers" in the Watcom C/C++ User's Guide for more details. 
  14098.  
  14099.  
  14100. ΓòÉΓòÉΓòÉ 44.5. Resolving an "Undefined Reference" linker error ΓòÉΓòÉΓòÉ
  14101.  
  14102.  
  14103. The Watcom Linker builds an executable file by a process of resolving 
  14104. references to functions or data items that are declared in other source files. 
  14105. Certain conditions arise that cause the linker to generate an "Undefined 
  14106. Reference" error message.  An "Undefined Reference" error message will be 
  14107. displayed by the linker when it cannot find a function or data item that was 
  14108. referenced in the program.  Verify that you have included all the required 
  14109. object modules in the linker command and that you are linking with the correct 
  14110. libraries.  There are a couple of "undefined references" that require some 
  14111. explanation. 
  14112.  
  14113.  _cstart_ 
  14114.       The unresolved reference for  _cstart_ indicates that the linker cannot 
  14115.       find the C/C++ run-time libraries.  The 16-bit C run-time libraries for 
  14116.       the small memory model are CLIBS.LIB and, either MATHS.LIB, or 
  14117.       MATH87S.LIB.  The 32-bit C run-time libraries for the flat memory model 
  14118.       compiled for the register-based argument passing model are CLIB3R.LIB 
  14119.       and, either MATH3R.LIB, or MATH387R.LIB.  Ensure that the WATCOM 
  14120.       environment variable is set to the directory that Watcom C/C++ was 
  14121.       installed in. 
  14122.  
  14123.  _fltused_ 
  14124.       The _fltused_ undefined reference indicates that floating-point 
  14125.       arithmetic has been used in the modules that exhibit this error.  The 
  14126.       remedy is to ensure that the linker can find the appropriate math 
  14127.       library.  For the 16-bit small memory model, it is either MATHS.LIB, or 
  14128.       MATH87S.LIB For the 32-bit register-based argument passing model, it is 
  14129.       either MATH3R.LIB, or MATH387R.LIB depending on which floating-point 
  14130.       option is used.  Ensure that the WATCOM environment variable is set to 
  14131.       the directory that Watcom C/C++ was installed in. 
  14132.  
  14133.  _small_code_ 
  14134.       If this undefined reference occurs when you are trying to create a 16-bit 
  14135.       application, we have saved you many hours of debugging!  The reason for 
  14136.       this undefined reference is that the "main" entry point has been compiled 
  14137.       for a big code model (in any one of medium, large, or huge memory 
  14138.       models).  Any of the modules that have this undefined reference have been 
  14139.       compiled for a small code model (in any one of small or compact memory 
  14140.       models) and as such do not have the correct return instructions.  You 
  14141.       should recompile the modules so that all the modules are compiled for the 
  14142.       same memory model.  Combining source modules compiled for different 
  14143.       memory models is very difficult and often leads to strange bugs.  If your 
  14144.       program has special considerations and this reference causes you 
  14145.       problems, there is a "work-around".  You could resolve the reference with 
  14146.       a PUBLIC declaration in an assembler file or code the following in Watcom 
  14147.       C/C++. 
  14148.  
  14149.  
  14150.          /* rest of your module */ 
  14151.  
  14152.          void _small_code( void ) 
  14153.          {} 
  14154.  
  14155.       The code generator will generate a single RET instruction with the public 
  14156.       symbol _small_code_ attached to it.  The common epilogue optimizations 
  14157.       will probably combine this function with another function's RET 
  14158.       instruction and you will not even pay the small penalty of one byte of 
  14159.       extra code. 
  14160.  
  14161.       There may be another cause of this problem, the "main" function must be 
  14162.       entered in lower case letters ("Main" or "MAIN" are not identified as 
  14163.       being the same as "main" by the compiler).  The compiler will identify 
  14164.       the module that contains the definition of the function "main" by 
  14165.       creating the public definition of either _small_code_ or _big_code_ 
  14166.       depending on the memory model it was compiled in. 
  14167.  
  14168.  _big_code_ 
  14169.       Your module that contains the "main" entry point has been compiled with a 
  14170.       16-bit small code model (small or compact).  The modules that have this 
  14171.       undefined reference have been compiled in 16-bit big code models (medium, 
  14172.       large, or huge).  You should recompile the modules so that all the 
  14173.       modules are compiled in the same memory model.  See the explanation for 
  14174.       _small_code_ for more details. 
  14175.  
  14176.  main_ 
  14177.       All C programs, except applications developed specifically for Microsoft 
  14178.       Windows, must have a function called "main".  The name "main" must be in 
  14179.       lower case for the compiler to generate the appropriate information in 
  14180.       the "main" module. 
  14181.  
  14182.  WINMAIN 
  14183.       All Windows programs must have a function called "WinMain".  The function 
  14184.       "WinMain" must be declared "pascal" in order that the compiler generate 
  14185.       the appropriate name in the "WinMain" module. 
  14186.  
  14187.  
  14188. ΓòÉΓòÉΓòÉ 44.6. Why my variables are not set to zero ΓòÉΓòÉΓòÉ
  14189.  
  14190.  
  14191. The linker is the program that handles the organization of code and data and 
  14192. builds the executable file.  C guarantees that all global and static 
  14193. uninitialized data will contain zeros.  The "BSS" region contains all 
  14194. uninitialized global and static data for C programs (the name "BSS" is a 
  14195. remnant of the early UNIX C compilers).  Most C compilers take advantage of 
  14196. this situation by not explicitly storing all the zeros to achieve smaller 
  14197. executable file sizes.  In order for the program to work correctly, there must 
  14198. be some code (that will be executed before "main") that will clear the "BSS" 
  14199. region.  The code that is executed before "main" is called "startup" code.  The 
  14200. linker must indicate to the startup code where the "BSS" region is located.  In 
  14201. order to do this, the Watcom Linker (WLINK) treats the "BSS" segment (region) 
  14202. in a special manner.  The special variables '_edata' and '_end' are constructed 
  14203. by the Watcom Linker so that the startup code knows the beginning and end of 
  14204. the "BSS" region. 
  14205.  
  14206. Some users may prefer to use the linker provided by another compiler vendor for 
  14207. development.  In order to have the program execute correctly, some extra care 
  14208. must be taken with other linkers.  For instance, with the Microsoft linker 
  14209. (LINK) you must ensure that the '/DOSSEG' command line option is used.  With 
  14210. the Phar Lap Linker, you must use the "-DOSORDER" command line option.  In 
  14211. general, if you must use other linkers, extract the module that contains 
  14212. _cstart from CLIB?.LIB (?  will change depending on the memory model) and 
  14213. specify the object file containing _cstart as the first object file to be 
  14214. processed by the linker.  The object file will contain the information 
  14215. necessary for the linker to build the executable file correctly. 
  14216.  
  14217.  
  14218. ΓòÉΓòÉΓòÉ 44.7. What does "size of DGROUP exceeds 64K" mean for 16-bit applications? ΓòÉΓòÉΓòÉ
  14219.  
  14220.  
  14221. This question applies to 16-bit applications.  There are two types of segments 
  14222. in which data is stored.  The two types of segments are classified as "near" 
  14223. and "far".  There is only one "near" segment while there may be many "far" 
  14224. segments.  The single "near" segment is provided for quick access to data but 
  14225. is limited to less than 64K in size.  Conversely, the "far" segments can hold 
  14226. more than 64K of data but suffer from a slight execution time penalty for 
  14227. accessing the data.  The "near" segment is linked by arranging for the 
  14228. different parts of the "near" segment to fall into a group called DGROUP.  See 
  14229. the section entitled "Memory Layout" in the Watcom Linker User's Guide for more 
  14230. details. 
  14231.  
  14232. The 8086 architecture cannot support segments larger than 64K.  As a result, if 
  14233. the size of DGROUP exceeds 64K, the program cannot execute correctly.  The 
  14234. basic idea behind solving this problem is to move data out of the single "near" 
  14235. segment into one or more "far" segments.  Of course, this solution does not 
  14236. come without any penalties.  The penalty is paid in decreased execution speed 
  14237. as a result of accessing "far" data items.  The magnitude of this execution 
  14238. speed penalty depends on the behavior of the program and, as such, cannot be 
  14239. predicted (i.e., we cannot say that the program will take precisely 5% longer 
  14240. to execute).  The specific solution to this problem depends on the memory model 
  14241. being used in the compilation of the program. 
  14242.  
  14243. If you are compiling with the tiny, small, or medium memory models then there 
  14244. are two possible solutions.  The first solution involves changing the program 
  14245. source code so that any large data items are declared as "far" data items and 
  14246. accessed with "far" pointers.  The addition of the "far" keyword into the 
  14247. source code makes the source code non-portable but this might be an acceptable 
  14248. tradeoff.  See the "Advanced Types" chapter in the Watcom C Language Reference 
  14249. manual for details on the use of the "near" and "far" keywords.  The second 
  14250. solution is to change memory models and use the large or compact memory model. 
  14251. The use of the large or compact memory model allows the compiler to use "far" 
  14252. segments to store data items that are larger than 32K. 
  14253.  
  14254. The large and compact memory models will only allocate data items into "far" 
  14255. segments if the size of the data item exceeds 32K.  If the size of DGROUP 
  14256. exceeds 64K then a good solution is to reduce the size threshold so that 
  14257. smaller data items will be stored into "far" segments.  The relevant compiler 
  14258. option to accomplish this task is "zt<num>".  The "zt" option sets a data size 
  14259. threshold which, if exceeded, will allocate the data item in "far" segments. 
  14260. For instance, if the option "zt100" is used, any data item larger than 100 
  14261. bytes will be allocated in "far" segments.  A good starting value for the data 
  14262. threshold is 32 bytes (i.e., "zt32").  The number of compilations necessary to 
  14263. reduce the size of DGROUP for a successful link with WLINK depends on the 
  14264. program.  Minimally, any files which allocate a lot of data items should be 
  14265. recompiled.  The "zt<num>" option should be used for all subsequent compiles, 
  14266. but the recompilation of all the source files in the program is not necessary. 
  14267. If the "DGROUP exceeds 64K" WLINK error persists, the threshold used in the 
  14268. "zt<num>" option should be reduced and all of the source files should be 
  14269. recompiled. 
  14270.  
  14271.  
  14272. ΓòÉΓòÉΓòÉ 44.8. What does "NULL assignment detected" mean in 16-bit applications? ΓòÉΓòÉΓòÉ
  14273.  
  14274.  
  14275. This question applies to 16-bit applications.  The C language makes use of the 
  14276. concept of a NULL pointer.  The NULL pointer cannot be dereferenced according 
  14277. to the ANSI standard.  The Watcom C/C++ compiler cannot signal the programmer 
  14278. when the NULL address has been written to or read from because the Intel-based 
  14279. personal computers do not have the necessary hardware support.  The best that 
  14280. the run-time system can do is help programmers find these sorts of errors 
  14281. through indirect means.  The lower 32 bytes of "near" memory have been seeded 
  14282. with 32 bytes of the value 0x01.  The C run-time function "_exit" checks these 
  14283. 32 bytes to ensure that they have not been written over.  Any modification of 
  14284. these 32 bytes results in the "NULL assignment error" being printed before the 
  14285. program terminates. 
  14286.  
  14287. Here is an overview of a good debugging technique for this sort of error: 
  14288.  
  14289.    1. use the Watcom Debugger to debug the program 
  14290.  
  14291.    2. let the program execute 
  14292.  
  14293.    3. find out what memory has been incorrectly modified 
  14294.  
  14295.    4. set a watchpoint on the modified memory address 
  14296.  
  14297.    5. restart the program with the watchpoint active 
  14298.  
  14299.    6. let the program execute, for a second time 
  14300.  
  14301.    7. when the memory location is modified, execution will be suspended 
  14302.  
  14303.  We will go through the commands that are executed for this debugging session. 
  14304.  First of all, we invoke the Watcom Debugger from the command line as follows: 
  14305.  
  14306.  
  14307.     C>wd myprog 
  14308.  
  14309.  Once we are in the debugger type: 
  14310.  
  14311.  
  14312.     DBG>go 
  14313.  
  14314.  The program will now execute to completion.  At this point we can look at the 
  14315.  output screen with the debugger command, "FLIP". 
  14316.  
  14317.  
  14318.     DBG>flip 
  14319.  
  14320.  We would see that the program had the run-time error "NULL assignment 
  14321.  detected".  At this point, all we have to do is find out what memory locations 
  14322.  were modified by the program. 
  14323.  
  14324.  The following command will display the lower 16 bytes of "near" memory. 
  14325.  
  14326.  
  14327.     DBG>examine __nullarea 
  14328.  
  14329.  The command should display 16 bytes of value 0x01.  Press the space bar to 
  14330.  display the next 16 bytes of memory.  This should also display 16 bytes of 
  14331.  value 0x01.  Notice that the following data has two bytes which have been 
  14332.  erroneously modified by the program. 
  14333.  
  14334.  
  14335.     __nullarea   01 01 56 12 01 01 01 01-01 01 01 01 01 01 01 01 
  14336.     __nullarea+16  01 01 01 01 01 01 01 01-01 01 01 01 01 01 01 01 
  14337.  
  14338.  The idea behind this debugging technique is to set a watchpoint on the 
  14339.  modified memory so that execution of the program will be suspended when it 
  14340.  modifies the memory.  The following command will "watch" the memory for you. 
  14341.  
  14342.  
  14343.     DBG>watch __nullarea+2 
  14344.  
  14345.  There has to be a way to restart the program without leaving the Watcom 
  14346.  Debugger so that the watchpoint is active during a subsequent execution of the 
  14347.  program.  The Watcom Debugger command "NEW" will reload the program and 
  14348.  prepare for a new invocation of the program. 
  14349.  
  14350.  
  14351.     DBG>new 
  14352.     DBG>go 
  14353.  
  14354.  The Watcom Debugger command "GO" will start execution of the program.  You may 
  14355.  notice that the program executes much slower than usual but eventually the 
  14356.  debugger will show the part of the program that modified the two bytes.  At 
  14357.  this point, you might want to clear the watchpoint and proceed to debug why 
  14358.  the memory was modified.  The command to clear the watchpoint is: 
  14359.  
  14360.  
  14361.     DBG>watch/clear 1 
  14362.  
  14363.  The "1" indicates that you want watchpoint number 1 to be cleared.  Typing 
  14364.  "WATCH" by itself will print out all active watchpoints.  The above technique 
  14365.  is generally useful for any type of memory overwrite error provided you know 
  14366.  which memory location has been overwritten. 
  14367.  
  14368.  Hint:  The Watcom Debugger allows many commands to have short forms.  For 
  14369.  instance, the "EXAMINE" command can be shortened to an "E".  We used the full 
  14370.  commands in the examples for clarity. 
  14371.  
  14372.  
  14373. ΓòÉΓòÉΓòÉ 44.9. What "Stack Overflow!" means ΓòÉΓòÉΓòÉ
  14374.  
  14375.  
  14376. The memory used for local variables is allocated from the function call stack 
  14377. although the Watcom compilers will often use registers for local variables. 
  14378. The size of the function call stack is limited at link-time and it is possible 
  14379. to exceed the amount of stack space during execution.  The Watcom run-time 
  14380. library will perform checks whenever a large amount of stack space is required 
  14381. by a function but it is up to the user to check stack requirements before 
  14382. calling a Watcom run-time function.  Compiling programs with stack checking 
  14383. will ensure that there is enough stack space to call a Watcom run-time 
  14384. function. 
  14385.  
  14386. There are various ways of protecting against stack overflow errors.  First, one 
  14387. should minimize the number of recursive functions used in an application 
  14388. program.  This can be done by recoding recursive functions to use loops.  Keep 
  14389. the amount of stack used in functions to a minimum by using and reusing static 
  14390. arrays whenever possible.  These techniques will reduce the amount of stack 
  14391. space required but there still may be times where the default amount of stack 
  14392. space (2048 bytes for 16-bit applications and 4096 bytes for 32-bit 
  14393. applications) is insufficient.  The Watcom Linker (WLINK) allows the user to 
  14394. set the amount of stack space at link-time through the directive "OPTION 
  14395. STACK=size" where size may be specified in bytes with an optional "k" suffix 
  14396. for kilobytes (1024 bytes). 
  14397.  
  14398. Example: 
  14399.  
  14400.    option stack=9k 
  14401.  
  14402. Debugging a program that reports a stack overflow error can be accomplished 
  14403. with the following sequence. 
  14404.  
  14405.    1. Load your application into the debugger 
  14406.  
  14407.    2. Set a breakpoint at __STKOVERFLOW 
  14408.  
  14409.    3. Run the application until the breakpoint at __STKOVERFLOW is triggered 
  14410.  
  14411.    4. Issue the debugger "show calls" command.  This will display a stack 
  14412.       traceback giving you the path of calls that led up to the stack overflow 
  14413.       situation. 
  14414.  
  14415.  The solution to the stack overflow problem at this point depends on the 
  14416.  programmer. 
  14417.  
  14418.  
  14419. ΓòÉΓòÉΓòÉ 44.10. Why redefinition errors are issued from WLINK ΓòÉΓòÉΓòÉ
  14420.  
  14421.  
  14422. This question comes up often in discussions about porting old UNIX or Microsoft 
  14423. C programs.  The problem stems from the forgiving nature of early UNIX linkers. 
  14424. In early C code, it was common to define header files like this: 
  14425.  
  14426. Example: 
  14427.  
  14428.    /* define global variables */ 
  14429.    int line_count; 
  14430.    int word_count; 
  14431.    int char_count; 
  14432.  
  14433. The header file would then be included in many different modules.  The C 
  14434. compiler would generate a definition of each variable in each module and leave 
  14435. it to the linker to pick one and resolve all references to one variable.  The 
  14436. development of the ANSI C standard made this practice non-conforming.  The 
  14437. Watcom C compiler is an ANSI C compiler and as such, is not required to support 
  14438. this obsolete behavior.  The effect is that WLINK will report redefinition 
  14439. errors.  The header file must be coded in such a way that the variables are 
  14440. defined in one module.  One way to do this is as follows: 
  14441.  
  14442. Example: 
  14443.  
  14444.    #ifdef DEFINE_HERE 
  14445.    #define GLOBAL 
  14446.    #else 
  14447.    #define GLOBAL  extern 
  14448.    #endif 
  14449.    /* define global variables */ 
  14450.    GLOBAL int line_count; 
  14451.    GLOBAL int word_count; 
  14452.    GLOBAL int char_count; 
  14453.  
  14454. In most modules, the macro "DEFINE_HERE" will not be defined so the file will 
  14455. be equivalent to: 
  14456.  
  14457. Example: 
  14458.  
  14459.    /* define global variables */ 
  14460.    extern int line_count; 
  14461.    extern int word_count; 
  14462.    extern int char_count; 
  14463.  
  14464. In one module, the macro "DEFINE_HERE" must be defined before the header file 
  14465. is included.  This can be done by defining the macro on the command line or by 
  14466. coding like this: 
  14467.  
  14468. Example: 
  14469.  
  14470.    #define DEFINE_HERE 
  14471.    #include "globals.h" 
  14472.  
  14473.  
  14474. ΓòÉΓòÉΓòÉ 44.11. How more than 20 files at a time can be opened ΓòÉΓòÉΓòÉ
  14475.  
  14476.  
  14477. The number of file handles allowed by Watcom C/C++ is initialized to 20 in 
  14478. STDIO.H, but this can be changed by the application developer.  To change the 
  14479. number of file handles allowed with Watcom C/C++, follow the steps outlined 
  14480. below. 
  14481.  
  14482.    1. Let n represent the number of files the application developer wishes to 
  14483.       have open.  Ensure that the stdin, stdout, stderr, stdaux, and stdprn 
  14484.       files are included in the count. 
  14485.  
  14486.    2. Change the CONFIG.SYS file to include "files=n" where "n" is the number 
  14487.       of file handles required by the application plus an additional 5 handles 
  14488.       for the standard files (this applies to DOS 5.0).  The number "n" may 
  14489.       vary depending on your operating system and version.  If you are running 
  14490.       a network such as Novell's NetWare, this will also affect the number of 
  14491.       available file handles.  In this case, you may have to increase the 
  14492.       number specified in the "files=n" statement. 
  14493.  
  14494.    3. Add a call to _grow_handles in your application. 
  14495.  
  14496.  The following example illustrates the use of _grow_handles. 
  14497.  
  14498.  Example: 
  14499.  
  14500.     /* 
  14501.     *  HANDLES.C 
  14502.     *  This C program grows the number of file handles so 
  14503.     *  more than 16 files can be opened. This program 
  14504.     *  illustrates the interaction between _grow_handles and 
  14505.     *  the DOS 5.0 file system. If you are running a network 
  14506.     *  such as Novell's NetWare, this will also affect the 
  14507.     *  number of available file handles. In the actual trial, 
  14508.     *  FILES=40 was specified in CONFIG.SYS. 
  14509.     */ 
  14510.  
  14511.  
  14512.     #include <stdio.h> 
  14513.  
  14514.     void main() 
  14515.     { 
  14516.       int   i, j, maxh, maxo; 
  14517.       FILE  *temp_files[50]; 
  14518.  
  14519.       for( i = 25; i < 40; i++ ) { 
  14520.         /* count 5 for stdin,stdout,stderr,stdaux,stdprn */ 
  14521.         printf( "Trying for %2.2d handles...", 5 + i ); 
  14522.         maxh = _grow_handles( 5 + i ); 
  14523.         maxo = 0; 
  14524.         for( j = 0; j < maxh; j++ ) { 
  14525.           temp_files[j] = tmpfile(); 
  14526.           if( temp_files[j] == NULL )break; 
  14527.           maxo++; 
  14528.         } 
  14529.         printf( " %d/%d temp files opened\n", maxo, maxh ); 
  14530.         for( j = 0; j < maxo; j++ ) { 
  14531.           fclose( temp_files[j] ); 
  14532.         } 
  14533.       } 
  14534.     } 
  14535.  
  14536.  
  14537. ΓòÉΓòÉΓòÉ 44.12. How source files can be seen in the debugger ΓòÉΓòÉΓòÉ
  14538.  
  14539.  
  14540. The selection and use of debugging information is important for getting the 
  14541. most out of the Watcom Debugger.  If you are not able to see your source code 
  14542. in the Watcom Debugger source window, there are three areas where things may 
  14543. have gone wrong, namely: 
  14544.  
  14545.    1. using the correct option for the Watcom C/C++. 
  14546.  
  14547.    2. using the correct directives for the Watcom Linker. 
  14548.  
  14549.    3. using the right commands in the Watcom Debugger. 
  14550.  
  14551.  The Watcom C/C++ compiler takes C/C++ source and creates an object file 
  14552.  containing the generated code.  By default, no debugging information is 
  14553.  included in the object file.  The compiler will output debugging information 
  14554.  into the object file if you specify a debugging option during the compile. 
  14555.  There are two levels of debugging information that the compiler can generate: 
  14556.  
  14557.    1. Line numbers and local variables ("d2" option) 
  14558.  
  14559.    2. Line numbers ("d1" option) 
  14560.  
  14561.  The options are used to determine how much debugging information will be 
  14562.  visible when you are debugging a particular module.  If you use the "d2" 
  14563.  option, you will be able to see your source file and display your local 
  14564.  variables. The "d1" option will display the source but will not give you 
  14565.  access to local variable information. 
  14566.  
  14567.  The Watcom Linker (WLINK) is the tool that puts together a complete program 
  14568.  and sets up the debugging information for all the modules in the executable 
  14569.  file.  There is a linker directive that indicates to the linker when it should 
  14570.  include debugging information from the modules.  There are five levels of 
  14571.  debugging information that can be collected during the link.  These are: 
  14572.  
  14573.    1. global names (DEBUG) 
  14574.  
  14575.    2. global names, line numbers (DEBUG LINE) 
  14576.  
  14577.    3. global names, types (DEBUG TYPES) 
  14578.  
  14579.    4. global names, local variables (DEBUG LOCALS) 
  14580.  
  14581.    5. all of the above (DEBUG ALL) 
  14582.  
  14583.  Notice that global names will always be included in any request for debugging 
  14584.  information.  The debugging options can be combined 
  14585.  
  14586.  
  14587.     DEBUG LINE, TYPES 
  14588.  
  14589.  with the above directive resulting in full line number and typing information 
  14590.  being available during debugging.  The directives are position dependent so 
  14591.  you must precede any object files and libraries with the debugging directive. 
  14592.  For instance, if the file MYLINK.LNK contained: 
  14593.  
  14594.  
  14595.     # 
  14596.     # invoke with: wlink @mylink 
  14597.     # 
  14598.     file main 
  14599.     debug line 
  14600.     file input, output 
  14601.     debug all 
  14602.     file process 
  14603.  
  14604.  then the modules INPUT and OUTPUT will have global names and source line 
  14605.  information available during debugging.  All debugging information in the 
  14606.  module PROCESS will be available during debugging. 
  14607.  
  14608.  Hint:  A subtle point to debugging information is that all the modules will 
  14609.  have global names available if any debugging directive is used.  In the above 
  14610.  example, the module MAIN will have global name information even though it does 
  14611.  not have a DEBUG directive preceding it. 
  14612.  
  14613.  It is preferable to have one DEBUG directive before any FILE and LIBRARY 
  14614.  directives.  You might wonder if this increases the size of the executable 
  14615.  file so that it will occupy too much memory during debugging.  The debugging 
  14616.  information is loaded "on demand" by the debugger during the debugging 
  14617.  session.  A small amount of memory (40k default, selectable with the Watcom 
  14618.  Debugger "dynamic" command line option) is used to hold the most recently used 
  14619.  module debugging information.  In practice, this approach saves a lot of 
  14620.  memory because most debugging information is never used.  The overhead of 
  14621.  accessing the disk for debugging information is negligible compared to 
  14622.  accessing the source file information.  In other words, you can have as much 
  14623.  debugging information as you want included in the executable file without 
  14624.  sacrificing memory required by the program.  See the section entitled "The 
  14625.  DEBUG Directive" in the Watcom Linker User's Guide for more details. 
  14626.  
  14627.  If the previous steps have been followed, you should be well on your way to 
  14628.  debugging your programs with source line information.  There are instances 
  14629.  where the Watcom Debugger cannot find the appropriate source file even though 
  14630.  it knows all the line numbers.  The problem that has surfaced involves how the 
  14631.  source file is associated with the debugging information of the module.  The 
  14632.  original location of the source file is included in the debugging information 
  14633.  for a module. The name that is included in the debugging information is the 
  14634.  original name that was on the Watcom C/C++ command line.  If the original 
  14635.  filename is no longer valid (i.e., you have moved the executable to another 
  14636.  directory), the Watcom Debugger must be told where to find the source files. 
  14637.  The Watcom Debugger "Source Path" menu item (under "File") can be used to 
  14638.  supply new directories to search for source files.  If your source files are 
  14639.  located in two directories, the following paths can be added in the Watcom 
  14640.  Debugger: 
  14641.  
  14642.  
  14643.     c:\program\c\*.c 
  14644.     c:\program\new\c\*.c 
  14645.  
  14646.  The "*" character indicates where the module name will be inserted while the 
  14647.  Watcom Debugger is searching for the source file.  See the description of the 
  14648.  "Source Path" menu item in the Watcom Debugger User's Guide for more details. 
  14649.  
  14650.  
  14651. ΓòÉΓòÉΓòÉ 44.13. The difference between the "d1" and "d2" compiler options ΓòÉΓòÉΓòÉ
  14652.  
  14653.  
  14654. The reason that there are two levels of debugging information available is that 
  14655. the code optimizer can perform many more optimizations and still maintain "d1" 
  14656. (line) information.  The "d2" option forces the code optimizer to ensure that 
  14657. any local variable can be displayed at any time in the function.  To illustrate 
  14658. why this results in less optimum code being generated for a function, let us 
  14659. look at a simple array initialization. 
  14660.  
  14661.  
  14662.    extern int a[100]; 
  14663.  
  14664.    void init_a( void ) 
  14665.    { 
  14666.      int i; 
  14667.  
  14668.      for( i = 0; i < 100; ++i ) { 
  14669.        a[i] = 3*i; 
  14670.      } 
  14671.    } 
  14672.  
  14673. The code optimizer will ensure that you can print the value of the variable "i" 
  14674. at any time during the execution of the loop.  The "d2" option will always 
  14675. generate code and debugging information so that you can print the value of any 
  14676. variable during the execution of the function.  In order to get the best code 
  14677. possible and still see your source file while debugging, the "d1" option only 
  14678. generates line number information into the object file.  With line number 
  14679. information, much better code can be generated.  Here is the C equivalent of 
  14680. the code generated for the array initialization example. 
  14681.  
  14682.  
  14683.    extern int a[100]; 
  14684.  
  14685.    void init_a( void ) 
  14686.    { 
  14687.      int *t1; 
  14688.      int t2; 
  14689.  
  14690.      /* for( i = 0; i < 100; ++i ) { */ 
  14691.      t1 = a; 
  14692.      t2 = 0; 
  14693.      do { 
  14694.        /* a[i] = 3*i; */ 
  14695.        *t1 = t2; 
  14696.        ++t1; 
  14697.        t2 += 3; 
  14698.      /* } */ 
  14699.      } while( t1 != a + 100 ); 
  14700.    } 
  14701.  
  14702. The above code executes very quickly but notice that the variable "i" has been 
  14703. split into two different variables.  One of the variables handles the use of 
  14704. "i" as an array index and the other handles the calculation of "3*i".  The 
  14705. debugging of programs that have undergone extensive optimization can be 
  14706. difficult, but with the source line information it is much easier.  To 
  14707. summarize, use the "d2" compiler option if you are developing a module and you 
  14708. would like to be able to display each local variable.  The "d1" compiler option 
  14709. will give you line number information and the best generated code possible. 
  14710. There is absolutely no reason not to specify the "d1" option because the code 
  14711. quality will be identical to code generated without the "d1" option.