home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 14 Text / 14-Text.zip / pfaq34.zip / ProgFAQ.INF (.txt) next >
OS/2 Help File  |  1995-06-04  |  214KB  |  7,135 lines

  1.  
  2. ΓòÉΓòÉΓòÉ 1. Introduction and Credits ΓòÉΓòÉΓòÉ
  3.  
  4.             OS/2 2.x Frequently Asked Questions, Programmer's Edition
  5.  
  6.                             Version 3.4, June 4, 1995
  7.                            Compiled by Andreas Almroth
  8.  
  9.                        Pre-3.x versions by Jeff M. Garzik
  10.                         Pre-2.x versions by Barry Jaspan
  11.  
  12.                       Copyright (c) 1995 by Andreas Almroth
  13.                               All Rights Reserved.
  14.  
  15. For changes, suggestions, or additions please mail andreas@traci.almroth.pp.se 
  16. or write to: 
  17.  
  18. Andreas Almroth
  19. Fanrik Stals Gata 153
  20. S-754 39 UPPSALA
  21. SWEDEN
  22.  
  23. Mention of a product does not constitute an endorsement.  Customers outside the 
  24. United States should not necessarily rely on 800 telephone numbers, page 
  25. numbers, part numbers, or upgrade policies contained in this List.  Electronic 
  26. mail addresses are in Internet form; use addressing appropriate to your mail 
  27. system. 
  28.  
  29. This FAQ is freely distributable for noncommercial purposes.  (For commercial 
  30. purposes, please contact the author.)  If you redistribute the FAQ, please 
  31. include all the original files. 
  32.  
  33. This FAQ is updated quarterly and is distributed through various computer 
  34. networks and online services, including the Internet and many BBSes. 
  35.  
  36. Both ASCII text and OS/2 Information Presentation Facility (INF) versions of 
  37. the FAQ are provided.  To view the INF version of the List, go to any OS/2 
  38. command line prompt (e.g. double click on "OS/2 Window") and type: 
  39.  
  40. VIEW PROGFAQ.INF
  41.  
  42. The ASCII text version may be viewed using any text editor, word processor, or 
  43. file listing utility.  The text version is intended to answer any questions you 
  44. may have before actually obtaining and using OS/2.  You will find that the INF 
  45. version provides a much more attractive interface, with hypertext links, fast 
  46. indexing, and, increasingly, illustrations. 
  47.  
  48. If you have not received all three files (README.CMD, PROGFAQ.INF, and 
  49. PROGFAQ.TXT), please ask your system operator to make sure he/she is receiving 
  50. the correct and complete package. 
  51.  
  52. Many of the answers in this FAQ refer to anonymous ftp site FTP-OS2.CDROM.COM 
  53. (192.153.46.2). The name 'cdrom.com' is used as a shorthand to refer to this 
  54. site.  It has become, by default, the Internet storehouse for OS/2 files.  If 
  55. you cannot get files from this site (for whatever reason), then check OS/2 
  56. Software Sources for a source near you. You may find a more convenient method 
  57. of getting files than from cdrom.com.  (Non-US readers will note ftp.luth.se, 
  58. is the main overseas FTP site.) 
  59.  
  60.  
  61. Related Information:
  62.  
  63. Release Notes
  64. OS/2 Software Sources
  65. Obtaining this FAQ / Contacting the Author
  66.  
  67.  
  68. ΓòÉΓòÉΓòÉ 2. Release Notes ΓòÉΓòÉΓòÉ
  69.  
  70. Text which has been revised or updated since the last release will appear in 
  71. the same color as this paragraph. 
  72.  
  73. Version 3.4: 
  74. Updated some answers and added some answers. 
  75.  
  76. Version 3.3: 
  77. Updated some answers and added some answers. 
  78.  
  79. Version 3.2: 
  80. Updated some answers and added some answers. 
  81. Added a lot of books 
  82.  
  83. Version 3.1: 
  84. Added index search facility (but only to some extent, sorry) 
  85. As usual, questions and answers have been added or changed. 
  86.  
  87. Version 3.0: A new maintainer of the OS/2 Programming FAQ: Andreas Almroth 
  88. Some answers changed or added. 
  89.  
  90. Version 2.3:  This release does not include very many new sections, but the 
  91. information has been reorganized for greater readability and easier maintenence 
  92. (for me).  Major changes include title re-wording for brevity, revision 
  93. coloring, and updated information. 
  94.  
  95.  
  96. Related Information:
  97.  
  98. Introduction and Credits
  99. OS/2 Software Sources
  100. Obtaining this FAQ / Contacting the Author
  101.  
  102.  
  103. ΓòÉΓòÉΓòÉ 3. Questions Covered in this Release ΓòÉΓòÉΓòÉ
  104.  
  105. Languages, Compilers, Debuggers
  106.   What programming languages come with OS/2?
  107.   Programming language availability
  108.   Which of these compilers can be used to generate PM apps?
  109.   Which assemblers can produce OS/2 32-bit code?
  110.   The two GNU C/C++/ObjC packages
  111.   What is REXX?  How do I write and run a REXX program?
  112.   What debuggers are available for OS/2?
  113.    CSD levels for IBM C Set++?
  114. Tools, Toolkits, Accessories
  115.   How do I use PATCH, maybe with my own programs?
  116.   What programming editors are available for OS/2?
  117.   What programming tools/toolkits/accessories are available for OS/2?
  118.   TOUCH-GUI 2.0 for OS/2 2.x
  119.   Prominare Designer for OS/2 2.x
  120.   JAM for OS/2 2.x
  121.   What GNU tools are available and where can I find them?
  122.   Is a socket library available?  How can I use it?
  123. Compiling
  124.   Can I distribute the C-Set++ runtime DLL?
  125.   How do I statically link my C/C++ program with C-Set++?
  126.   How big should my stacksize be?
  127.   How do I determine what C/C++ compilator is compiling my code?
  128.   How do I perform parallel compilation?
  129.   What is an RC of 87 (invalid param) from the API?
  130.   GCC/2 crashes with a trap when I try to compile a program.  Why?
  131.   How do I recompile EPM (easily)?
  132.   How to I get BC++ for DOS/Windows to run?
  133. Documentation, Help
  134.   Where can I get information on OS/2 APIs and programming?
  135.   Where can I get sample code?
  136.   Are there any OS/2 programming classes or seminars?
  137.   What are good ref. books for programming in OS/2 and PM?
  138.   What are good OS/2 programming magazines?
  139.   What are the OS/2 redbooks, and how do I get them?
  140.   How can I view the GNU C documentation?
  141.   Where can I get documentation on the OBJ/LIB/EXE format used by OS/2 2.x?
  142.   Where can I find information on HPFS?
  143. PM Programming
  144.   Printing
  145.     Are there any SIMPLE examples of printing?
  146.     Is there an easy way to get printer output (another opinion)?
  147.     How do I print a bitmap?
  148.     How do I do my own Print Screen?
  149.   Menus
  150.     How do I add a menu to a dialog box?
  151.     How do I make a dynamically changing menu?
  152.     How do I create a conditional cascade menu?
  153.     How do I remove a separator from a menu?
  154.   Container Controls
  155.     How do I stop a container from flashing every time I add a record?
  156.     How do I get my containers to use Mini-icons?
  157.     How do I sort a container control?
  158.     How do I query all records in a container - tree view?
  159.   I can't get different colors in text control windows
  160.   How can I toggle my titlebar on and off?
  161.   How can I get transparent regions in bitmaps?
  162.   How do I create a status bar at the bottom of my window?
  163.   How to have a frame/client and still have a std window?
  164.   How do I use printf() in a PM program?
  165.   I have a SOM DLL. How do I register it?
  166.   How do I save and restore my window size and position?
  167.   How do you make a window float above all other?
  168.   How to ensure the sizing's correct so the dlg "fits" in the notebook...?
  169.   How do I prevent Shutdown from stopping my app?
  170.   When I pass a structure to WinCreateWindow, sometimes it doesn't work!
  171.   How do I use type filtering in 2.0's open dlg?
  172.   When minimizing, my dialog box is overwriting my icon!
  173.   How do I make a multi-column listbox?
  174.   How do I create my own Master Help Index?
  175.   How do I change the font in an MLE?
  176.   Why can't I import files larger than 64KB into my MLE?
  177.   How do I get PM screen size?
  178.   How do I attach Instance data to window created with WinCreateStdWindow?
  179.   How do I get a list of fonts?
  180.   How do I create a folder in C and put my pgm in it?
  181.   How do I do it in REXX?
  182.   How do I use the Font dialog (WinFontDlg)?
  183.   How do I take control of frame sizing?
  184.   How do I use the 16-bit EPM toolkit?
  185.   How do I get error info after using WinGetLastError()?
  186.   Do you have code to save/restore the clipboard?
  187.   How do I know what item was selected in a Combo box?
  188.   How do I get a bitmap into a dialog in a DLL?
  189.   How does programming PM compare to programming X?
  190.   How do I put bitmaps on buttons?
  191.   Can a PM program tell if there's a previous instance of itself running?
  192.   How to avoid crash when using Drag and Drop?
  193.   Are there any PM bindings for GNU Ada?
  194. Miscellaneous Programming
  195.   Explain the SYS_DLL keywords.
  196.   How do I start another session?
  197.   How do I check if a filename is valid?
  198.   Why should I use _beginthread instead of DosCreateThread?
  199.   How do I open a file that is already in use?
  200.   Can we use Vio in v2.0? Where are the docs for it?
  201.   Can I redirect stdin and stdout in a child process?
  202.   How do I use DosMon*() to stuff the kbd buf?
  203.   How do I determine what file system a drive uses?
  204.   How do I get the error message from a DOS API call?
  205.   How do I set an exception handler?
  206.   How can I determine a diskette format and if a disk is in a drive?
  207.   What do all those keywords mean when making a DLL?
  208.   Where can I find serial port sample code?
  209.   How do I disable <Ctrl><Alt><Del>?
  210.   Why doesn't printf() produce output when I expect it to?
  211.   How do I write an OS/2 device driver?
  212.   How do I change the master environment?
  213.   What is the best way to communicate between processes?
  214.   What is the best way to communicate between threads?
  215.   How to I write an IFS?
  216.   How do I interface with OS/2's SCSI support?
  217.   How do I program full-screen graphics?
  218.   How do I program MMPM/2 programs?
  219.   How do I peripheral memory or an I/O port?
  220. Porting
  221.   How do I port my DOS keyboard TSR to OS/2?
  222.   How can I simulate (Unix feature) under OS/2?
  223.   How can I recompile public domain/shareware source code for OS/2?
  224.   How can I port my DOS program to OS/2?
  225.   How can I port my Windows program to OS/2?
  226. Miscellaneous
  227.   Is OS/2 suitable for real time programs?
  228.   What is available for multimedia programming under OS/2?
  229.   What is available for AI/neural net programming under OS/2?
  230.   Special software offers
  231.   Technical Support
  232.   Developer's Assistance Program (DAP)
  233.  
  234.  
  235. ΓòÉΓòÉΓòÉ 4. Languages, Compilers, Debuggers ΓòÉΓòÉΓòÉ
  236.  
  237. This section covers the programming tools currently available for OS/2.  The 
  238. following topics are available: 
  239.  
  240. What programming languages come with OS/2?
  241. Programming language availability
  242. Which of these compilers can be used to generate PM apps?
  243. Which assemblers can produce OS/2 32-bit code?
  244. The two GNU C/C++/ObjC packages
  245. What is REXX?  How do I write and run a REXX program?
  246. What debuggers are available for OS/2?
  247. CSD levels for C Set++2?
  248.  
  249.  
  250. ΓòÉΓòÉΓòÉ 4.1. What programming languages come with OS/2? ΓòÉΓòÉΓòÉ
  251.  
  252. The original BASIC and BASICA (for systems with BASIC in ROM, mainly IBM 
  253. systems), DOS's QBASIC, and OS/2's REXX comes with OS/2 2.x. 
  254.  
  255. REXX is basically the official command language of OS/2. 
  256.  
  257.  
  258. Related Information:
  259.  
  260. What is REXX?  How do I write and run a REXX program?
  261.  
  262.  
  263. ΓòÉΓòÉΓòÉ 4.2. Programming language availability ΓòÉΓòÉΓòÉ
  264.  
  265. Virtually all of them: Assembler, C, C++, COBOL, Pascal, Fortran, Smalltalk, 
  266. Modula-2, LISP, Forth, Perl, and more.  The OS/2 Tools Guide on cdrom.com 
  267. (os2/all/info/tinf34.zip) contains information on these and more.  Also check 
  268. the User's Edition for information on IBM's Development Tools Guide.  It's a 
  269. free catalog from IBM. 
  270.  
  271. All prices listed are "list price," as listed in Fall/Winter Programmer's 
  272. Paradise catalog.  All entries marked "Freely Available" can be obtained from 
  273. cdrom.com unless otherwise noted. 
  274.  
  275.  1. Ada 
  276.  
  277.    o GNU Ada 2.04 for OS/2; freely available; under development; cs.nyu.edu in 
  278.      the pub/gnat directory 
  279.    o Alsys AdaWorld OS/2 
  280.  
  281.  2. Assembly Language 
  282.  
  283.    o IBM Macro Assembler, $288 
  284.    o GNU assembler v2.3, included in emx 0.9a package 
  285.    o GNU assembler v1.38, included in GCC/2 v2.5.4 package 
  286.    o Turbo Assembler v3.21, included in Borland C++ for OS/2 package 
  287.  
  288.  3. BASIC 
  289.  
  290.    o CA-REALIZER, $100 
  291.    o ObjectView PM Basic, $899 
  292.  
  293.  4. C/C++ 
  294.  
  295.    o Borland C++ for OS/2 v1.00, $495 
  296.    o CA-C++ for OS/2, $449 
  297.    o emx/gcc 0.9a (v2.6.3), freely available 
  298.    o GCC/2 v2.4.5, freely available 
  299.    o IBM C-Set++ 2.x FirstStep (without optimization) $85 (CD-ROM) 
  300.    o IBM C-Set++ 2.x , $595 
  301.    o IBM VisualAge C++ 3.0, price: ???. 
  302.    o Objective C, $249 (not to be confused with the Objective-C language 
  303.      included free with emx/gcc and GCC/2) 
  304.    o TopSpeed C Pro, $297 
  305.    o TopSpeed C Standard, $198 
  306.    o WATCOM C/C++ 16 9.5, $495 
  307.    o WATCOM C/C++ 32 9.5, $599 
  308.    o Metaware High C/C++ 
  309.  
  310.  5. CSP 
  311.  
  312.    o IBM CSP/2, $??? 
  313.  
  314.  6. COBOL 
  315.  
  316.    o MicroFocus Workbench with COBOL, tools and editor, $1,250. Call 1 
  317.      800-872-6265 for more information 
  318.  
  319.  7. FORTRAN 
  320.  
  321.    o GNU Fortran (g77-0.5.14). Freely available 
  322.      (ftp.uni-stuttgart.de:/pub/systems/os2/emx0.9a/contrib) 
  323.    o f2c [Fortran to C translator], freely available 
  324.    o IBM Fortran/2 OS/2, $761 
  325.    o WATCOM FORTRAN 77 16 9.5, $495 
  326.    o WATCOM FORTRAN 77 32 9.5, $599 
  327.  
  328.  8. LISP 
  329.  
  330.    o CLISP, freely available 
  331.      (ma2s2.mathematik.uni-karlsruhe.de:/pub/lisp/clisp/binaries/os2/clisp.zip) 
  332.    o XLisp, freely available 
  333.  
  334.  9. Pascal 
  335.  
  336.    o Borland Pascal v7.0, $495 (requires patch) 
  337.    o MicroWay, $??? 
  338.    o Power Pascal/2, freely available, req. MASM 6.00 
  339.    o p2c [Pascal to C translator], freely available 
  340.    o pasos2, freely available, supports EMX/GCC (ftp.eb.ele.tue.nl) 
  341.    o SPEED-Pascal/2 for OS/2 GAMMA (March 95), (available at hobbes.nmsu.edu as 
  342.      speed2.zip) 
  343.    o TopSpeed, $??? 
  344.  
  345. 10. PERL 
  346.  
  347.    o GNU PERL v4.0pl36, freely available 
  348.  
  349. 11. PL/I 
  350.  
  351.    o IBM PL/I for OS/2 
  352.  
  353. 12. Prolog 
  354.  
  355.    o SWI Prolog for OS/2, available at ftp.cdrom.com:os2/2_x/unix/plbin.zip 
  356.  
  357. 13. Modula-2 
  358.  
  359.    o TopSpeed, $??? 
  360.    o Stonybrook, $??? 
  361.  
  362. 14. Scheme 
  363.  
  364.    o XScheme for OS/2, freely available 
  365.    o MIT Scheme for OS/2, freely available 
  366.      (swiss-ftp.ai.mit.edu:/pub/scheme-os2/) 
  367.  
  368. 15. SmallTalk 
  369.  
  370.    o SmallTalk/V PM, $995 
  371.    o Parc Place Smalltalk, $??? 
  372.  
  373.  
  374. Related Information :
  375.  
  376. The two GNU C/C++/ObjC packages
  377.  
  378.  
  379. ΓòÉΓòÉΓòÉ 4.3. The two GNU C/C++/ObjC packages ΓòÉΓòÉΓòÉ
  380.  
  381. The two versions of GNU C that are available were ported to OS/2 with different 
  382. goals and philosophies in mind and therefore have different characteristics. 
  383. However, both systems include a fairly complete C library and can be used to 
  384. compile useful programs, although their support of Unix-specific semantics 
  385. differs.  Furthermore, both systems are being actively developed and are 
  386. constantly improving. 
  387.  
  388. The goal of GCC/2 is to create a pure, freely redistributable OS/2 2.x 
  389. development environment.  It is based on GNU C 2.5.4, supports C, C++, and 
  390. Objective C, and can create PM programs.  It produces "native" 32 bit .OBJ 
  391. files that are linked with OS/2's LINK386.EXE, and can be linked together with 
  392. .OBJ files produced by IBM C-Set++ and other compatible compilers.  The mailing 
  393. list os2gcc@netcom.com exists for discussion of this port; send mail to 
  394. os2gcc-request@netcom.com for subscription information. 
  395.  
  396. emx/gcc 0.9a, based on the GNU compiler 2.x.x, supports C, C++, and Objective C 
  397. and can create PM programs.  emx's goal is to make porting Unix programs easier 
  398. by emulating Unix semantics as closely as possible. It produces programs that 
  399. can run under OS/2 using EMX.DLL, it produces programs that can run under OS/2 
  400. without any DLL requirements (linked with OS/2's LINK386), and it can produce 
  401. MS-DOS 32-bit executables (emx.exe DOS extender required for MS-DOS 
  402. executables).  emx/gcc uses standard Unix development tools like ld and nm, and 
  403. fully supports Unix-isms like select() and fork().  A version of gdb exists 
  404. that can debug emx/gcc programs. An emx-related mailing list exists; send mail 
  405. to LISTSERV@eb.ele.tue.nl with a message body of "help" for subscription 
  406. information. 
  407.  
  408.  
  409. ΓòÉΓòÉΓòÉ 4.4. Which of these compilers can be used to generate PM apps? ΓòÉΓòÉΓòÉ
  410.  
  411. Basically, all the compilers except the following can generate PM applications: 
  412.  
  413. o CLISP 
  414. o XLisp 
  415. o PERL 
  416. o XScheme 
  417.  
  418.  
  419. ΓòÉΓòÉΓòÉ 4.5. What is REXX?  How do I write and run a REXX program? ΓòÉΓòÉΓòÉ
  420.  
  421. REXX is the IBM SAA (Systems Application Architecture) standard, user-friendly 
  422. programming language.  It is available for IBM mainframes, Unix, the Amiga, DOS 
  423. (Quercus's Personal REXX), Windows, and other platforms.  It has been a part of 
  424. standard OS/2 since Version 1.3.  Programs written in REXX that do not use 
  425. system-specific libraries are fully portable. 
  426.  
  427. OS/2 2.x comes with an online REXX reference, and printed REXX documentation is 
  428. available (Mike Cowlishaw's REXX book, IBM's twin guides).  The Usenet group 
  429. comp.lang.rexx discusses REXX programming. 
  430.  
  431. It should be stressed, however, that OS/2's online REXX reference is a 
  432. reference, not really a tutor.    Paul Prescod 
  433. (papresco@undergrad.math.uwaterloo.ca) is working on a free REXX tutor, which 
  434. will be available on cdrom.com. 
  435.  
  436. Watcom also makes VX REXX and Hockware makes VisPro/REXX.  Both of these 
  437. products allow quick and easy development of REXX PM programs. 
  438.  
  439.  
  440. ΓòÉΓòÉΓòÉ 4.6. What debuggers are available for OS/2? ΓòÉΓòÉΓòÉ
  441.  
  442. IPMD, a PM-based debugger, ships with C-Set++.  It is capable of source- and 
  443. assembly-level debugging multithreaded 16 bit and 32 bit OS/2 applications 
  444.  
  445. emx/gcc comes with gdb 4.11, the GNU debugger. 
  446.  
  447. Borland C++/2 comes with a PM-based debugger called Turbo Debugger GX which has 
  448. the same basic functionality as IPMD. 
  449.  
  450. There are also several commercial debuggers on the market.  WATCOM C and 
  451. FORTRAN come with WVIDEO, a full-screen source or assembly level debugger that 
  452. handles multithreaded 16 and 32 bit OS/2 programs. Multiscope (no longer 
  453. available for 32-bit OS/2) and Periscope are others.  CodeView is still 
  454. applicable for 16-bit OS/2 apps, but it is not recommended for 32-bit apps. 
  455.  
  456.  
  457. ΓòÉΓòÉΓòÉ 4.7. Which assemblers can produce OS/2 32-bit code? ΓòÉΓòÉΓòÉ
  458.  
  459. o Masm 5.2 and 6.0B can produce 32 bit, 2.x compatible code. 
  460. o Masm 6.1 no longer supports OS/2. 
  461. o Tasm 1.0 (OS/2) generates 2.x code, when proper options are given. 
  462. o Tasm 3.2.1 (DOS) can produce OS/2 compatible .OBJ files with the /oi option. 
  463. o Turbo Assembler 4.1 for OS/2 (in Borland C++ for OS/2) 
  464. o GAS (GNU Assembler) 1.38.1 
  465. o GAS (GNU Assembler) 2.3 
  466. o IBM has an assembler for 2.x, but they won't release it to the public. 
  467.  
  468.  
  469. ΓòÉΓòÉΓòÉ 4.8. CSD levels for IBM C Set++? ΓòÉΓòÉΓòÉ
  470.  
  471. Following CSD's are current 
  472.  
  473. o CTC0011 - IBM C/C++ Tools (Compiler) 2.0 and 2.01 
  474. o CTU0003 - IBM C/C++ Tools (Utilities) 2.0 and 2.01 
  475. o CTL0009 - IBM C/C++ Tools (Class Libraries) 2.0 
  476. o CTM0009 - IBM C/C++ Tools (Class Libraries) 2.01 
  477.  
  478. Be careful with CTL0009 and CTM0009. Do NOT install wrong CSD. Check with the 
  479. OS/2 command SYSLEVEL the version level of the class libraries. IBM C/C++ 
  480. packages bought later than November 1993 should be 2.01 or higher. 
  481.  
  482.  
  483. ΓòÉΓòÉΓòÉ 5. Tools, Toolkits, Accessories ΓòÉΓòÉΓòÉ
  484.  
  485. This section covers tools, toolkits, and accessories available to OS/2 
  486. programmers. 
  487.  
  488.  
  489. ΓòÉΓòÉΓòÉ 5.1. How do I use PATCH, maybe with my own programs? ΓòÉΓòÉΓòÉ
  490.  
  491. The file format is actually quite simple - you just need a text file which 
  492. consists of lines each starting with one of the following commands: 
  493.  
  494.   FILE <filename>     e.g. FILE test.exe 
  495.  
  496. specifies the file to which the following instructions are to be applied. A 
  497. patch file may contain multiple FILE directives. 
  498.  
  499.   VER <offset> <data>   e.g. VER 00001234 abcdef 
  500.  
  501. checks if the specified data is present at the given file offset [all values in 
  502. hex, data can be just a string of digits with no blanks in between; up to 16 
  503. bytes are allowed in one statement]. If the check fails, the patch process is 
  504. aborted resp. the program skips to the next FILE statement. 
  505.  
  506.   CHA <offset> <data>   e.g. CHA 00001234 012345 
  507.  
  508. changes the data at the given offset - syntax is same as in VER. It is a good 
  509. idea to do all VERification before starting the first CHA. 
  510.  
  511. Blank lines and data lines starting with a ";" are ignored. 
  512.  
  513. As you can see from this, there seems to be no way to _insert_ or _delete_ 
  514. bytes in the file. To make patches applicable to multiple versions of the same 
  515. file, you can specifiy more than one FILE directive for the same filename - 
  516. only a patch with all VER commands matching is executed. 
  517.  
  518. Credit:  Marcus Groeber 
  519.  
  520.  
  521. ΓòÉΓòÉΓòÉ 5.2. What programming editors are available for OS/2? ΓòÉΓòÉΓòÉ
  522.  
  523. OS/2 comes with the Enhanced Editor (EPM). 
  524.  
  525. GNU Emacs 19.27 is available.It supports PM windows, VIO windows and 
  526. full-screen sessions. Emacs is available on cdrom.com in 
  527. os2/2_x/unix/gnu/emacs. (If you want to recompile emacs, you will need the full 
  528. emx distribution; see question 1.2.) Also, you must have HPFS installed to use 
  529. GNU emacs. You can read, write, and edit files that exist on a DOS partition, 
  530. but you must have GNU emacs installed on an HPFS partition. 
  531.  
  532. Several public-domain vi clones are available, including elvis, Stevie and 
  533. levee. The MKS Toolkit also includes vi. 
  534.  
  535. Many other text editors are available. 
  536.  
  537. Epsilon, by Luguru, (412) 421-5678.  DOS upgrade to OS/2 is $90.  Character 
  538. based editor. 
  539.  
  540. QEdit 3.0, by SemWare, (404) 641-9002.  Character based editor. Supports long 
  541. filenames and extended attributes. Semware can be reached by EMail: 
  542. tech.support@semware.atl.ga.us or sales@semware.atl.ga.us. 
  543.  
  544. Brief, KEDIT, others? [Vendors, phone numbers, prices?] 
  545.  
  546. EHP, a text mode editor, was recently ported by Axel Uhl to PM, and is 
  547. available on cdrom.com. 
  548.  
  549. THE (The Hessling Editor), is a free text-mode editor, based on IBM's VM/CMS 
  550. XEDIT and Mansfield Software's KEDIT.  THE has full REXX macro capabilities. 
  551. Versions also exist for DOS and most Unices. 
  552.  
  553. BOXER 6.0 for OS/2. Shareware and commercial versions available. Some features; 
  554. multi-level undo, multiple windows, syntax highlighting. Commercial version 
  555. priced at $89. Boxer Software can be contacted at; phone: 800-982-6937, 
  556. Internet: 70242.2126@compuserve.com 
  557.  
  558. Slick for DOS/Windows, by MicroEdge. 
  559.  
  560. Visual Slickedit for OS/2, by MicroEdge. Price: $295 (US). 
  561.  
  562. Preditor/2 V2.1, by Compuware Corp.. Introductory price: $149 /US). Demo 
  563. version available at ftp.cdrom.com. 
  564.  
  565. ZED for OS/2. PM-based editor with lots of features. Shareware. Available at 
  566. hobbes.nmsu.edu:/os2/editors or ftp-os2.cdrom.com:/os2/incoming. 
  567.  
  568.  
  569. ΓòÉΓòÉΓòÉ 5.3. What programming tools/toolkits/accessories are available for OS/2? ΓòÉΓòÉΓòÉ
  570.  
  571. C-Set++ includes the following tools (excluding the compiler & debugger 
  572. themselves): 
  573.  
  574. o EXTRA - Execution trace analyzer 
  575. o A Class browser 
  576.  
  577. The IBM Programmer's Toolkit, included in Workset/2 and also in C-Set++, 
  578. includes many tools: 
  579.  
  580. o A dialog editor 
  581. o A SOM compiler 
  582. o A font editor 
  583. o An icon editor 
  584. o An IPF compiler 
  585. o Message compile & bind tools 
  586. o Resource compile & bind tools 
  587. o KwikInf 
  588. o ...and a couple others 
  589.  
  590. Borland C++ for OS/2 also includes a number of utilities, such as the Resource 
  591. Workshop. 
  592.  
  593. The MKS Toolkit, available from MKS ($299 USD, 800-265-2797 or 
  594. inquiry@mks.com), has over 160 Unix tools, including Korn shell, tar, vi, awk, 
  595. grep, tail, cpio, and so forth.  It also contains a Lex and Yacc capable of 
  596. generating C, C++, and Turbo Pascal code. 
  597.  
  598. There is a product called ARGO/UX which provides a BSD environment for OS/2. 
  599. [details?] 
  600.  
  601. SOFTPRO GmbH has announced its 32bit C++ class library TOUCH-GUI 2.0 for OS/2 
  602. 2.x. 
  603.  
  604.  
  605. ΓòÉΓòÉΓòÉ 5.4. TOUCH-GUI 2.0 for OS/2 2.x ΓòÉΓòÉΓòÉ
  606.  
  607. SOFTPRO GmbH has announced its 32bit C++ class library TOUCH-GUI 2.0 for OS/2 
  608. 2.x. The product contains more than 130 classes which support windows, menu 
  609. bars, multi-threading, controls, dialog boxes, graphics, printer control, MDI, 
  610. DDE, Drag and Drop, loadable resources from DLL's, and management of profiles 
  611. (.INI files). Other features include auxiliary classes for data manipulation 
  612. and storage management. Additionally, TOUCH-GUI 2.0 contains high-level classes 
  613. like toolbars, formatted entry fields, tables, and complete NLS. 
  614.  
  615. Supported C++ compilers are: Borland, GNU (emx), IBM, and WATCOM 
  616.  
  617. The product includes online (.INF) and printed documentation, a demo program, 
  618. and samples. 
  619.  
  620. TOUCH-GUI 2.0 costs DM 1.720,00 excl. VAT (ca. $1075), the runtime DLL's may be 
  621. distributed royalty free. Special project licenses are available, contact the 
  622. supplier. 
  623.  
  624. Contact:
  625. SOFTPRO GmbH, Stadtgrabenstr. 21, 71032 Boeblingen, Germany
  626. Tel.: +49 7031 6606-0
  627. Fax: +49 7031 6606-66
  628. Mr. Frank Fuchs (extension -50)
  629. Internet email: ffu@softpro.de
  630. IBMMAIL (IEA): DEJP9SK9
  631.  
  632.  
  633. ΓòÉΓòÉΓòÉ 5.5. Prominare Designer for OS/2 ΓòÉΓòÉΓòÉ
  634.  
  635. Prominare Inc, of Canada have launched a development tool for creating GUI's 
  636. for OS/2. The tool can generate code for multiple class libraries and multiple 
  637. compilers. 
  638.  
  639. Supported Platforms are OS/2, Windows 3.1 and Windows NT. 
  640.  
  641. The tool supports all PM controls, MMOS/2 and Pen for OS/2. 
  642.  
  643. Suggested retail price: $699 (US). 
  644.  
  645. A complete list of qualified resellers can found through Prominare's WWW server 
  646. at http://www.prominare.com/prominare. 
  647.  
  648.  
  649. ΓòÉΓòÉΓòÉ 5.6. JAM for OS/2 ΓòÉΓòÉΓòÉ
  650.  
  651. JYACC, Inc. have released JAM (JYACC Application Manager), their tool for 
  652. building 32-bit client/server GUI applications. 
  653.  
  654. Over 100+ platforms are supported, including OS/2, MS-Windows, DOS, Motif, 
  655. VAX/VMS, Macintosh and many UNIX-implementations. 
  656.  
  657. Suggested retail price: $2000 (US). 
  658.  
  659. The toolkits includes; Database drivers for JDB (JYACC database) and one of the 
  660. drivers for Oracle, Sybase, Informix or DB2 (customers choice), and complete 
  661. documentation. 
  662.  
  663.  
  664. ΓòÉΓòÉΓòÉ 5.7. What GNU tools are available and where can I find them? ΓòÉΓòÉΓòÉ
  665.  
  666. Nearly all the GNU utilities have been ported to OS/2 2.x - and nearly all of 
  667. those ports are located on cdrom.com in os2/2_x/unix/gnu. Other, more involved 
  668. (or independent) ports of GNU software is scattered about cdrom.com, including 
  669. a PM version of GhostView and GhostScript. 
  670.  
  671.  
  672. ΓòÉΓòÉΓòÉ 5.8. Is a socket library available?  How can I use it? ΓòÉΓòÉΓòÉ
  673.  
  674. emx 0.9a supports sockets without the Programmer's Toolkit.  The socket support 
  675. of emx is `seamless': fdopen(), for instance, can be used on sockets. 
  676.  
  677. IBM's TCP/IP 2.0 ($200) includes an optional Programmer's Toolkit ($500, part 
  678. #02G6973).  It includes a socket library, and support for Sun RPC, NCS RPC, and 
  679. a limited Kerberos capability.  It requires IBM C-Set++ or another compiler 
  680. that understands 16-bit code. 
  681.  
  682. For REXX programs there is a socket library called REXXSOCK available from 
  683. cdrom.com as os2/ibm/ews/rxsock.zip.  It can be used to write TCP/IP 
  684. applications such as Gopher, IRC, etc. 
  685.  
  686. FTP Software, Inc., has an OS/2 version of its TCP/IP product.  They can be 
  687. reached at (617) 246-0900 or info@ftp.com. 
  688.  
  689. If you have the IBM TCP/IP 2.0 base package and IBM C-Set++, you can use the 
  690. TCPIPDLL.DLL directly. 
  691.  
  692.  
  693. ΓòÉΓòÉΓòÉ 6. Compiling ΓòÉΓòÉΓòÉ
  694.  
  695. This section covers compiling OS/2 programs and accessories.  The following 
  696. topics are available: 
  697.  
  698. Can I distribute the C-Set++ runtime DLL?
  699. How do I statically link my C/C++ programs with C-Set++?
  700. How big should my stacksize be?
  701. How do I perform parallel compilation?
  702. What is an RC of 87 (invalid param) from the API?
  703. GCC/2 crashes with trap when I try to compile a program. Why?
  704. How do I recompile EPM (easily)?
  705. How to I get BC++ for DOS/Windows to run?
  706.  
  707.  
  708. ΓòÉΓòÉΓòÉ 6.1. Can I distribute the C-Set++ runtime DLL? ΓòÉΓòÉΓòÉ
  709.  
  710. Yes, you can! (But it is not as simple as that really...) 
  711.  
  712. You can not distribute the runtime DLL that comes with C-Set++ in its native 
  713. form, you must rebuild the DLLs you want to distribute and delete functions in 
  714. the .DEF files, so that your DLL files only contains functions your program 
  715. need. Read more about this topic in C/C++ Tools - Programming Guide pages 
  716. 195-222, that comes with C-Set++ (2.x). 
  717.  
  718.  
  719. ΓòÉΓòÉΓòÉ 6.2. How do I statically link my C/C++ program with C-Set++? ΓòÉΓòÉΓòÉ
  720.  
  721. There are several flags you must use to get static linking work. 
  722.  
  723. Add the flag /Tdp when compiling C/C++ sources. This flag ensures that any 
  724. template functions are resolved correctly. 
  725.  
  726. When linking the program, make sure that the /B flag looks like this: 
  727. /B"/pmtype:pm /NOI /NOE /NOD". 
  728.  
  729. /NOD   Tells the linker to disregard default libraries
  730.  
  731. /NOE   Tells the linker to ignore extended library information
  732.      found in the object files.
  733.  
  734. /NOI   Maintains the case sensitivity for identifier names.
  735.  
  736. Linking a typical PM program might look like this: 
  737.  
  738. myapp.exe: $(OBJS) myapp.res
  739. icc $(CFLAGS) /Gn+ /Ge+ /Gd- /Gm+ /Fe myapp.exe $(OBJS) myapp.def \
  740. /B"/pmtype:pm /NOI /NOE /NOD" DDE4MBS.LIB DDE4MUIB.LIB \
  741. DDE4MUIC.LIB DDE4MUID.LIB DDE4CC.LIB OS2386.LIB
  742. rc myapp.res myapp.exe
  743.  
  744. Credit: Lyle Sutton 
  745.  
  746.  
  747. ΓòÉΓòÉΓòÉ 6.3. How do I determine what C/C++ compilator is compiling my code? ΓòÉΓòÉΓòÉ
  748.  
  749. If your source code is written for several compilers, one need to know what 
  750. uniqe defines these compilers use. 
  751.  
  752.  
  753.  IBM C/C++            __IBMCPP__
  754.  
  755.  Borland C++ for OS/2 __BORLANDC__
  756.  
  757.  EMX/GCC              __EMX__
  758.  
  759.  Watcom C/C++         __WATCOMC__
  760.  
  761.  
  762. ΓòÉΓòÉΓòÉ 6.4. How big should my stacksize be? ΓòÉΓòÉΓòÉ
  763.  
  764. o For non-PM programs: At least 8k for every thread. 
  765. o It is critical to avoid stack sizes where byte 2 has a value of 2 or 4, e.g.: 
  766.  
  767.    0x00020000 (128k) 
  768.    0x00040000 (256k) 
  769.    0x33023678 
  770.    0x11041111 
  771.  
  772. Otherwise, when executing under OS/2 2.0GA there may be various and always 
  773. differing runtime error behaviors.  (This is documented in OMF.INF, an online 
  774. reference from IBM concerning OBJ/EXE file formats for 16 and 32 bits.) 
  775.  
  776.  
  777. ΓòÉΓòÉΓòÉ 6.5. How do I perform parallel compilation? ΓòÉΓòÉΓòÉ
  778.  
  779. You can accomplish parallel compilation in one of two ways. The first involves 
  780. GNU Make, the second involves DMAKE. 
  781.  
  782. GNU Make: 
  783.  
  784. To perform parallel compilation with GNU Make simply do two things: 
  785.  
  786. o Make sure your make file does not execute the make utility (again) from 
  787.   inside the make file. 
  788. o On the GNU Make command line, specify '--jobs x', where 'x' is the maximum 
  789.   number of concurrent jobs you will allow GNU Make to execute. If you do not 
  790.   wish to have a maximum, then you may specify simply '--jobs' and GNU Make 
  791.   will execute as many jobs as possible at one time. 
  792.  
  793. DMAKE: 
  794.  
  795. The ini file comes in the dmake archive in a few different flavours.  Take the 
  796. file with the extension .msc and rename it to dmake.ini.  Set an environment 
  797. variable in config.sys 
  798.  
  799. SET MAKESTARTUP=d:\COMPILER\DMAKE.INI 
  800.  
  801. ====== Makefile 
  802.  
  803. CC=icc
  804. COPTS=/Sm /Gt+ /Ti+ /O- /Gs+
  805. CONLY=-c
  806.  
  807. LIBS=os2
  808.  
  809. INCS=psfax2.h
  810.  
  811. MAXPROCESS=2
  812.  
  813. all: psfax2.exe sendfax.exe
  814.  
  815. modem.obj:  modem.c $(INCS)
  816.    $(CC) $(CONLY) $(COPTS) modem.c
  817.  
  818. psfax2.obj: psfax2.c $(INCS)
  819.    $(CC) $(CONLY) $(COPTS) psfax2.c
  820.  
  821. psfax2.exe: psfax2.obj modem.obj
  822.    link386 /ST:32768 /CO psfax2+modem;
  823.  
  824. sendfax.obj: sendfax.c $(INCS)
  825.    $(CC) $(CONLY) $(COPTS) sendfax.c
  826.  
  827. sendfax.exe: sendfax.obj modem.obj
  828.    link386 /ST:32768 /CO sendfax+modem;
  829.  
  830. ====== End of makefile 
  831.  
  832. Couple of gotchas.  There is a bug in the MAXPROCESS handling of the copy I 
  833. use.  Set it to 1, and you get a typical make, ie one at a time. Set it to 2, 
  834. and the thing launches 3 processes. Ie with more than 1, you actually get n+1 
  835. processes running. 
  836.  
  837. Another caveat 
  838.  
  839. xxx.yy: aaa.bbb
  840.     command1
  841.     command2
  842.     command3
  843.  
  844. The above structure does not work.  The reason is that all 3 commands will be 
  845. spawned together in parallel sessions.  To serialize them you must make up 
  846. dependancies in the makefile.  I ran into this becuase I have one makefile that 
  847. completes every link stage by copying the result onto a network drive.  I had 
  848. to take all the links that previously had 2 commands, and break them into 2 
  849. blocks with the second being a dependancy of the remote file on the local file, 
  850. and the copy command. 
  851.  
  852. One more word of warning, dmake is not to pleased with those convoluted things 
  853. that workframe spits out in the name of makefiles.  You may have to do a 
  854. significant amount of makefile editing, depending on how you makefile look now. 
  855.  
  856. Provided that 3 simultaneous copies of your compiler doesn't push your machine 
  857. into excessive swapping, the improvements in build speed are amazing.  Before 
  858. dmake I'd never seen a build actually top the cpu meter here, the process was 
  859. always waiting for disk as it loaded compilers/headers etc.    Now the compiler 
  860. sits in ram and just gets re-used, and the headers are coming directly from 
  861. cache all the time. Build time cut in half, and my cpu guage is pegged at 100% 
  862. when a build is running. 
  863.  
  864.  
  865. ΓòÉΓòÉΓòÉ 6.6. What is an RC of 87 (invalid param) from the API? ΓòÉΓòÉΓòÉ
  866.  
  867. You are (most likely) not including the prototype.  Use the following flags to 
  868. get a good balance of warning messages: 
  869.  
  870.     /Kbperc 
  871.  
  872. For C Set++, I use these flags as the approximate equivalent 
  873.  
  874.     /Wall /Wext- /Wgnr- /Wgot- /Wpor- /Wppt- /Wtrd /Wuni- /Wvft- 
  875.  
  876. I have these set as part of my ICC string in CONFIG.SYS, so I don't have to add 
  877. them to each compile.  I have found that these settings give me a good 
  878. combination of thorough warning messages without too many warnings. 
  879.  
  880.  
  881. ΓòÉΓòÉΓòÉ 6.7. GCC/2 crashes with a trap when I try to compile a program.  Why? ΓòÉΓòÉΓòÉ
  882.  
  883. Because you didn't read the README or INSTALL files, probably.  There are three 
  884. general reasons GCC/2 will crash: 
  885.  
  886.  1. You did not set up the environment variables in CONFIG.SYS properly.  Read 
  887.     doc/INSTALL for instructions. 
  888.  
  889.  2. Some program that gcc expects to be in the PATH is not; unfortunately, gcc 
  890.     crashes instead of just printing an error message.  You may have forgotten 
  891.     to install something, or your PATH may be wrong; see above.  Giving gcc the 
  892.     -v option will cause it to print each command line as it executes it; this 
  893.     will tell you which program is missing. 
  894.  
  895.  3. You are trying to get gcc to link your program for you. It cannot because 
  896.     ld does not exist, and so it crashes (see item 2).  You must specify -c, 
  897.     -E, or -S on every invokation of gcc, and then use LINK386.EXE to create an 
  898.     executable.  See the sample makefiles for an example of how to do this. 
  899.  
  900. [Colin Jensen, the current maintainer of GCC/2, also adds the following...] 
  901.  
  902. Not true as of gcc/2 2.3.3.  Gcc will invoke a small stub program called ld.exe 
  903. that in turn will invoke link386 for you.  If the command line is too long for 
  904. the ever-pathetic link386 to handle, ld will properly create a response file. 
  905.  
  906. It is easier to use gcc/2 to call link386 than to do it yourself since gcc/2 
  907. will also arrange to call a subprogram called "collect" that is required before 
  908. linking a C++ program. 
  909.  
  910. Also, gcc/2 is just plain easier to use than link386, for example: 
  911.  
  912.          gcc -o foobar.exe mydef.def foobar.cpp mylib.lib
  913.  
  914. will compile foobar.cpp, link with mylib.lib, and pass the linker definition 
  915. file mydef.def to link386 in the correct order.  Link386 demands that you know 
  916. which types of files can be put between which sets of commas on the command 
  917. line. 
  918.  
  919.  
  920. ΓòÉΓòÉΓòÉ 6.8. How do I recompile EPM (easily)? ΓòÉΓòÉΓòÉ
  921.  
  922. I have a small CMD file to automatically compile all needed macros.  It is from 
  923. Larry Margolis (IBM), one of the authros of EPM. 
  924.  
  925. You need to have at aleast minimum knowledge of EPM.  The online manual 
  926. describes most things.    Concerning the E macros (.E) the best thing to do is, to 
  927. look in the online documentation for general questions (like: What does 
  928. 'getpminfo' do?) and then look into the supplied standard E macros for detailed 
  929. reference on hwo to use the EPM functions exactly. 
  930.  
  931. Online documentation files are: EPMTECH.INF and EPMUSERS.INF 
  932.  
  933. Here is MAKEEPM.CMD: 
  934.  
  935. @echo off
  936. set EPMPATH=h:\e;h:\e\emacros;h:\e\ebookie;h:\e\lamacros;h:\e\mye;
  937. rem Command file to call ETPM and beep in case of error.  Can be given
  938. rem a list of macro files to compile; the default is to compiler all of
  939. rem the distributed .ex files.            by Larry Margolis
  940. setlocal
  941. @if .%1 == . goto all
  942. :loop
  943. etpm %1 /v || echo 'Error in %1!'
  944. @shift
  945. @if .%1 == . goto end
  946. @goto loop
  947. :all
  948. etpm EPM /v      || echo 'Error in EPM!'
  949. etpm EPMLIST /v  || echo 'Error in EPMLIST!'
  950. etpm LAMEXTRA /v || echo 'Error in LAMEXTRA!'
  951. etpm MAILLIST /v || echo 'Error in MAILLIST!'
  952. etpm EXTRA /v    || echo 'Error in EXTRA!'
  953. etpm BKEYS /v    || echo 'Error in BKEYS!'
  954. etpm E3EMUL /v   || echo 'Error in E3EMUL!'
  955. etpm BOX /v      || echo 'Error in BOX!'
  956. etpm DRAW /v     || echo 'Error in DRAW!'
  957. etpm GET /v      || echo 'Error in GET!'
  958. etpm MATHLIB /v  || echo 'Error in MATHLIB!'
  959. etpm PUT /v      || echo 'Error in PUT!'
  960. etpm HELP /v     || echo 'Error in HELP!'
  961. etpm EPMLEX /v   || echo 'Error in EPMLEX!'
  962. etpm MAKETAGS /v || echo 'Error in MAKETAGS!'
  963. :end
  964. endlocal
  965.  
  966.  
  967. ΓòÉΓòÉΓòÉ 6.9. How to I get BC++ for DOS/Windows to run? ΓòÉΓòÉΓòÉ
  968.  
  969. Open up the Settings folder for the executable, and under "DOS Settings" set 
  970. DPMI_DOS_API to ENABLED. 
  971.  
  972.  
  973. ΓòÉΓòÉΓòÉ 7. Documentation, Help ΓòÉΓòÉΓòÉ
  974.  
  975. This section covers documentation and help available for OS/2 programming. 
  976.  
  977.  
  978. ΓòÉΓòÉΓòÉ 7.1. Where can I get information on OS/2 APIs and programming? ΓòÉΓòÉΓòÉ
  979.  
  980. The IBM Programmer's Toolkit, included in Workset/2, includes a complete 
  981. on-line syscall reference. 
  982.  
  983. You can FTP the documentation for the 16-bit calls (IBM does not supply them), 
  984. such as Vio*(), Kbd*(), Mou*(), from cdrom.com as os2/2_x/program/inf16bit.zip. 
  985.  
  986. You can order the seventeen volume IBM OS/2 Technical Library (possibly at a 
  987. discount, see question 1.2) and/or order various volumes individually. 
  988.  
  989. Most of these volumes are now published by Que books also, and can be found in 
  990. many bookstores. 
  991.  
  992. All this information is also on the OS/2 Online Library Omnibus Edition: OS/2 
  993. Collection CD-ROM (SK2T-2176), and the Professional Developer's Kit CD-ROMs 
  994. have this information as well. 
  995.  
  996.  
  997. Related Information:
  998.  
  999. What are good reference books for programming in OS/2 and PM?
  1000.  
  1001.  
  1002. ΓòÉΓòÉΓòÉ 7.2. Where can I get sample code? ΓòÉΓòÉΓòÉ
  1003.  
  1004. There is a lot of sample code included in the IBM Toolkit, and four sample 
  1005. programs (with source) included with C-Set++.  GNU C/C++, from cdrom.com, 
  1006. includes a sample C, C++, and C++ PM program.  The OS/2 Redbooks also have some 
  1007. sample code.  cdrom.com also has little bits of OS/2 and PM source code lying 
  1008. around in the os2/2_x/program directory. 
  1009.  
  1010.  
  1011. Related Information:
  1012.  
  1013. What are the OS/2 redbooks, and how do I get them?
  1014.  
  1015.  
  1016. ΓòÉΓòÉΓòÉ 7.3. Are there any OS/2 programming classes or seminars? ΓòÉΓòÉΓòÉ
  1017.  
  1018. Yes.  Call IBM at either 1-800-3-IBM-OS2 in U.S. (or the PS/2 Help Center). 
  1019. Local IBM branches frequently hold OS/2 classes and seminars. 
  1020.  
  1021. See os2/2_x/info/ivleague.txt on cdrom.com or the User's Edition for a list of 
  1022. third-party support organizations. 
  1023.  
  1024. Make sure to check your local software companies.  Many of them offer OS/2 
  1025. specific classes also. 
  1026.  
  1027.  
  1028. ΓòÉΓòÉΓòÉ 7.4. What are good ref. books for programming in OS/2 and PM? ΓòÉΓòÉΓòÉ
  1029.  
  1030. Van Nostrand Reinhold publishes a number of books on OS/2 2.x.  Those that 
  1031. relate to programming are: 
  1032.  
  1033. INTEGRATING APPLICATIONS WITH OS/2 2.0
  1034. By William H. Zack
  1035. 0-422-01234-9
  1036.  
  1037. CLIENT/SERVER PROGRAMMING WITH OS/2 2.0, 2nd Edition
  1038. By Robert Orfali and Daniel Harkey, IBM Corporation
  1039. 0-422-01219-5
  1040.  
  1041. WRITING OS/2 2.0 DEVICE DRIVERS IN C
  1042. By Steven J. Mastrianni; Foreword by John Soyring, IBM Corporation
  1043. 0-442-01141-5
  1044.  
  1045. OS/2 2.0 PRESENTATION MANAGER GPI: A Programming Guide to Text, Graphics, And Printing
  1046. By Graham C.E. Winn, IBM Corporation
  1047. 0-442-00739-6
  1048.  
  1049. THE COBOL PRESENTATION MANAGER PROGRAMMING GUIDE
  1050. By David M. Dill, Consultant
  1051. 0-442-01293-4
  1052.  
  1053. LEARNING TO PROGRAM OS/2 2.0 PRESENTATION MANAGER BY EXAMPLE: Putting the Pieces Together
  1054. By Stephen Knight, IBM Corportaion
  1055. 0-442-01292-6
  1056.  
  1057. THE ART OF OS/2 2.1 C PROGRAMMING
  1058. By Panov, Salomon, and Panov
  1059. 620p, $39.95 US (suggested) includes disk with samples
  1060. ISBN 0-89435-446-9
  1061.  
  1062. OS/2 PRESENTATION MANAGER PROGRAMMING
  1063. By Charles Petzold
  1064. Ziff-Davis Press
  1065. ISBN 1-56276-123-4
  1066.  
  1067. DESIGN OF OS/2, SECOND EDITION
  1068. By Kogan & Deitel
  1069. Addison-Wesley
  1070. 0-201-52886-X
  1071.  
  1072. ULTIMATE OS/2 PROGRAMMER's MANUAL
  1073. Mueller
  1074. McGraw-Hill Professional Computing
  1075. 0-07-043972-9
  1076.  
  1077. EFFECTIVE MULTITHREADING IN OS/2
  1078. By Dorfman & Neuberger, McGraw-Hill Professional Computing
  1079. 0-07-017841-0,
  1080.  
  1081. OS/2 REMOTE COMMUNICATIONS: Async to sync
  1082. By Stonecipher
  1083. Van Nostrand Reinhold
  1084. 0-0442-01814-2,
  1085.  
  1086. OS/2 V2 C++ CLASS LIBRARY: Power GUI Programming using C Set++
  1087. By Kevin Leong, William Law, Robert Love, Hiroshi Tsuji and Bruce Olson
  1088. Van Nostrand Reinhold
  1089. $36.95
  1090. 0-442-01795-2
  1091.  
  1092. OBJECTS FOR OS/2 2.1
  1093. By S. Danforth, P Koenen and Tate et al
  1094. Van Nostrand Reinhold
  1095. ISBN 0-442-01738-3
  1096.  
  1097. OS/2 AND NETWARE PROGRAMMING: Netware Client API
  1098. By Gauthier
  1099. Van Nostrand Reinhold
  1100. ISBN 0-442-01815-0
  1101.  
  1102. OS/2 PROGRAMMING: Your Fast-Track Guide to OS/2
  1103. By Herbert Schildt & Robert Goosey
  1104. 306p, $29.95
  1105. ISBN 0-07-881910-5
  1106.  
  1107. ADVANCED ASSEMBLY LANGUAGE
  1108. Steven Holzner and Peter Norton Computing Inc.
  1109. Brady Books, A division of Simon & Schuster, New York, NY, USA
  1110. 1991  ISBN 0-13-633014-6
  1111.  
  1112. OBJECT-ORIENTED PROGRAMMING WITH SOM AND DSOM
  1113. Christina Lau
  1114. Van Nostrand Reinhold
  1115. ISBN 0-442-01948-3
  1116.  
  1117. REAL WORLD PROGRAMMING FOR OS/2 2.1
  1118. By Blain, Delimon and English
  1119. SAMS
  1120. ISBN 0-673-30300-0
  1121.  
  1122. RUNNING WINDOWS APPLICATIONS IN OS/2:  A Power User's Guide
  1123. Ayo Anise, Teresa Beck and Jean Shortley
  1124.  
  1125. DYNAMIC DATA EXCHANGE FOR OS/2 PROGGRAMMERS
  1126. By Glenn T. Puchtel
  1127. Disk included.
  1128.  
  1129. LOTUS NOTES RELEASE 3 IN THE OS/2 ENVIROMENT
  1130. By Tony Walsh
  1131.  
  1132. Books announced to be released Dec '94 and early '95. 
  1133.  
  1134. THE OS/2 SURVIVAL KIT
  1135. By Proffit
  1136. Addison-Wesley
  1137.  
  1138. STEPPING UP TO OS/2 WARP
  1139. Abacus
  1140.  
  1141. THE OS/2 WARP BIBLE
  1142. Abacus
  1143.  
  1144. THE PHOTO CD BOOK (with OS/2 Warp applications disk)
  1145. Abacus
  1146.  
  1147. OS/2 FOR DUMMIES (2nd Edition)
  1148. By Rathbone
  1149. IDG Books
  1150. ISBN 1-56884-205-8
  1151.  
  1152. YOUR OS/2 CONSULTANT (Warp Edition)
  1153. By Tyson
  1154. Sams
  1155.  
  1156. OS/2 Unleashed (Warp Edition)
  1157. Moskowitz & Kerr
  1158. Sams
  1159.  
  1160. MASTERING OS/2 WARP
  1161. By Dyson
  1162. Sybex
  1163.  
  1164. USING OS/2 WARP
  1165. By Clifford et al
  1166. QUE
  1167.  
  1168. TEACH YOURSELF OS/2 PROGRAMMING
  1169. Sams
  1170.  
  1171. Quick Reference Library for OS/2 Functions: Vol 3 - Workplace Shell
  1172. By Scholin
  1173. VNR
  1174. ISBN 0-442-01899-1
  1175.  
  1176. Developing Multimedia Applications Under OS/2
  1177. By Lopez
  1178. VNR
  1179. ISBN 0-442-01929-7
  1180.  
  1181. OS/2 Warp Advanced Graphics GPI
  1182. By Knight and Ryan
  1183. John Wiley & Sons
  1184.  
  1185. OS/2 Remote Communications: Asynchronous to Synchronous T&T
  1186. Stonecipher
  1187. VNR
  1188. ISBN 0-442-01814-2
  1189.  
  1190. Quick Reference Library for OS/2 Functions: Vol 4 - GPI Functions
  1191. By Scholin
  1192. VNR
  1193. ISBN 0-442-01900-9
  1194.  
  1195. Quick Reference Library for OS/2 Functions: Vol 5 - DOS Functions
  1196. By Scholin
  1197. VNR
  1198. ISBN 0-442-01901-7
  1199.  
  1200. OS/2 Warp Presentation Manager Programming for Power Programmers
  1201. By Stern and Morrow
  1202. Wiley-QED
  1203. ISBN 0-471-05839-4
  1204.  
  1205. OS/2 Warp Control Program API
  1206. By Stock
  1207. Wiley-QED
  1208. ISBN 0-471-03887-3
  1209.  
  1210. Secrets of the OS/2 Masters
  1211. By Sullivan
  1212. VNR
  1213. ISBN 0-442-01991-2
  1214.  
  1215. OS/2 Presentation Manager
  1216. By Drapkin
  1217. VNR
  1218. ISBN 0-442-01989-0
  1219.  
  1220.  
  1221. REXX Reference Summary Handbook
  1222. Dick Goran
  1223. ISBN 0-9639854-2-6
  1224.  
  1225. OS/2 Warp for Dummies
  1226. ISBN 1-56884-205-8, $19.95 (US)
  1227. Andy Rathbone
  1228. IDG Books
  1229.  
  1230. Programming the OS/2 Warp Version 3 GPI
  1231. ISBN 0-471-10718-2, $39.95 (US)
  1232. Stephen Knight and Jeffrey Ryan
  1233. John Wiley & Sons
  1234.  
  1235. Books mentioned below was scheduled to be released April'95, maybe they are
  1236. out in the bookstores now.
  1237.  
  1238. The REXX Cookbook
  1239. ISBN 0-9632773-4-0, $27.95 (US)
  1240. Optional companion disk (ISBN # 0-9632773-5-9, $14.95 (US) )
  1241. Merrill Callaway
  1242. Whitestone
  1243.  
  1244. Quick Reference Library for OS/2 Functions: Vol 6 - Misc Functions
  1245. Scholin
  1246. VNR
  1247. ISBN 0-442-01902-5
  1248.  
  1249. Making OS/2 Work for You: Installing, Configuring & Using OS/2 Warp
  1250. Azzarito & Green
  1251. ISBN 0-471-06083-6,
  1252. Wiley-QED,
  1253.  
  1254. The Art of OS/2 Warp C Programming
  1255. Panov et al
  1256. ISBN 0-471-08633-9
  1257. Wiley-QED,
  1258.  
  1259. OS/2 Warp Presentation Manager API
  1260. Stock
  1261. ISBN 0-471-03873-3
  1262. Wiley-QED
  1263.  
  1264. IBM has a .INF file where all IBM OS/2 related books are listed. 
  1265.  
  1266.  
  1267. Related Information:
  1268.  
  1269. What are the OS/2 redbooks, and how do I get them?
  1270.  
  1271.  
  1272. ΓòÉΓòÉΓòÉ 7.5. What are good OS/2 programming magazines? ΓòÉΓòÉΓòÉ
  1273.  
  1274. OS/2 Developer 
  1275.  
  1276. For new orders and customer service, call (800) WANT-OS2 (800-926-8672) or 
  1277. (708) 647-5960.  IBM employees and branch office customers can subscribe to 
  1278. OS/2 Developer through IBM Mechanicsburg's Systems Library Services (SLSS) 
  1279. using OS/2 Developer's order number G362-0001.  POSTMASTER: Please send address 
  1280. changes to OS/2 Developer, P.O. Box 1079, Skokie, IL, 60076-8079. 
  1281.  
  1282. Electronic Developers' Magazine/2 
  1283.  
  1284. Excellent electronic magazine for OS/2 developers.  Available somewhat monthly 
  1285. from ftp-os2.cdrom.com in 2_x/program/newsltr/edmi*.zip. 
  1286.  
  1287. PC Magazine 
  1288.  
  1289. While this is not by any means a dedicated OS/2 programming magazine, it 
  1290. includes several gems from Charles Petzold, most notably a nice series on font 
  1291. handling. 
  1292.  
  1293.  
  1294. ΓòÉΓòÉΓòÉ 7.6. What are the OS/2 redbooks, and how do I get them? ΓòÉΓòÉΓòÉ
  1295.  
  1296. (see end note for FTP information) 
  1297.  
  1298. IBM publishes so-called "redbooks" on many products, including OS/2 2.x.  They 
  1299. seem to be a combination of power-user's guides and design information that may 
  1300. be of use to both users and programmers [I haven't received my copies yet, so I 
  1301. cannot say for sure.]  These are usually intended only for special IBM 
  1302. customers and contain documentation that is generally unavailable anywhere 
  1303. else.  You can order these books directly from IBM (see below).  All of the 
  1304. following names are implicitly preceeded by "OS/2 Version 2.0." 
  1305.  
  1306. Volume 1: Control Program: GG24-3730, $4.15 
  1307.      Technical information on Memory Management, Task Mangement, Support, 
  1308.      Installation Considerations, Hardware Considerations, Boot Manager, 
  1309.      National Language Considerations, Intel 386 architecture, Channel 
  1310.      Architecture and SCSI.    Documents config.sys. 
  1311.  
  1312. Volume 2: DOS and Windows Environment, GG24-3731, $6.20 
  1313.      MVDM,8086 Emulation,MVDM DOS emulation, Device Drivers, Memory Extender 
  1314.      Support, Installing and Migrating Applications, Windows Applications, 
  1315.      DPMI, Running DOS apps,DOS settings, VMB. 
  1316.  
  1317. Volume 3:  PM and Workplace Shell GG24-3732, $3.65 
  1318.      Available now, but I don't know precisely what's in it. 
  1319.  
  1320. Volume 4: Application Development GG24-3774, $5.25 
  1321.      Technical programming info (includes list in C) Overview, Object-Oriented 
  1322.      Apps, PM application model, flat memory model, building PM app, Workplace 
  1323.      AOAShell and System Object Model, Direct Manipulation (Drag/drop), PM 
  1324.      resources, Multitasking Considerations, SAA CUA considerations, App 
  1325.      Migration, Mixing 16 and 32 bit application modules, compiling and link 
  1326.      editing (SOM), Adding Online Help, Problem Determination, Managing 
  1327.      Development, Naming conventions. 
  1328.  
  1329. Volume 5: Print Subsystem, GG24-3775, $5.20 
  1330.      Information on programming the print subsystem. 
  1331.  
  1332. The special part number GBOF-2254 is for all currently available volumes 
  1333. (presently 1-5). 
  1334.  
  1335. ORDERING INFORMATION: 
  1336.  
  1337. The OS/2 2.x Redbooks are available from IBM's TeleServices customer support 
  1338. number.  The number is 1-800-7654-IBM (1-800-765-4426).  You can pay by credit 
  1339. card or mail in a check after calling.  The order will take about 2 weeks but 
  1340. can be sped up by paying for faster shipping. 
  1341.  
  1342. You can also order the redbooks from your local IBM Branch Office library. 
  1343. Some possibly useful phone numbers are included here. 
  1344.  
  1345.     IBM Central Library, Los Angeles CA: (213) 621-6710
  1346.         P.O. Box 60737
  1347.         Los Angeles, CA 90060
  1348.     Canada: (800) 465-1234, ext 4205 ($33.52)
  1349.     UK: (0256) 478166, (#36.51, credit cards accepted)
  1350.     Australia (Victoria): 698-1234 ($46.80 A)
  1351.         IBM Australia
  1352.         The Library
  1353.         211 Sturt Street
  1354.         South Melbourne, 3205
  1355.         Att: Kate Seeley
  1356.     Denmark: 33 32 40 55 (dkk 310)
  1357.  
  1358. The redbooks are also FTP'able from cdrom.com as the os2/ibm/misc/redbk*.zip. 
  1359. The source code that accompanies the first three redbooks can FTP'able from 
  1360. cdrom.com as os2/2_x/program/rb37*.zip. 
  1361.  
  1362. Various OS/2 technical programming books can be found on the Developers 
  1363. Connection CDROM.  The entire OS/2 Library can be found on the "OS/2 Online 
  1364. Book Collection CDROM", Order Number S53G-2166-00. 
  1365.  
  1366.  
  1367. ΓòÉΓòÉΓòÉ 7.7. How can I view the GNU C documentation? ΓòÉΓòÉΓòÉ
  1368.  
  1369. GNU C/C++ comes with documentation from the Free Software Foundation in texinfo 
  1370. (.texi) format.  This documentation is about gcc in general, and has no 
  1371. OS/2-specific information. 
  1372.  
  1373. All utilities needed to compile/view/tex the texinfo files are readily 
  1374. available for OS/2.  The GNU texinfo package, available on cdrom.com in 
  1375. os2/all/unix/gnu/gnuinfo.zip, includes makeinfo.exe for compiling texinfo, 
  1376. info.exe for viewing them, and texinfo.tex and texindex.exe for TeXing them. 
  1377.  
  1378. An ASCII text version of the gcc documentation is also available on cdrom.com, 
  1379. in the file os2/2_x/unix/gnu/gcc2_233/gcc_inf.zip. 
  1380.  
  1381. An INF hypertext version of the gcc (and related programs) documentation was 
  1382. uploaded recently to cdrom.com. 
  1383.  
  1384. emx/gcc includes its own hypertext style reader and texinfo files for all the 
  1385. GNU tools that come with it. 
  1386.  
  1387. GCC/2 includes the hypertext manuals for gcc, gas, and gnumake as well as a PM 
  1388. reader for the manuals. 
  1389.  
  1390. GNU Emacs for OS/2 reads GNU info files in their native format, with no 
  1391. conversion necessary on the user's part. 
  1392.  
  1393.  
  1394. ΓòÉΓòÉΓòÉ 7.8. Where can I get documentation on the OBJ/LIB/EXE format used by OS/2 2.x? ΓòÉΓòÉΓòÉ
  1395.  
  1396. o The .EXE format was described briefly in PC Magazine, Vol 11 No. 12 (June 30, 
  1397.   1992?); it was also described in a 1988 issue. 
  1398. o The glib source code contains a full description of the 32 bit OBJ and LIB 
  1399.   formats.  It is found at cdrom.com:/os2/2_x/unix/gnu/gcc2_233/glibs115.zip. 
  1400. o It is available in text form from cdrom.com as os2/2_x/program/lxexe.doc. 
  1401. o OMF.INF from IBM (the IBM BBS) comes highly recommended. 
  1402.  
  1403.  
  1404. ΓòÉΓòÉΓòÉ 7.9. Where can I find information on HPFS? ΓòÉΓòÉΓòÉ
  1405.  
  1406. There is a Microsoft Systems Journal article about it (64k ZIPped, so it has a 
  1407. lot of information) in ftp-os2.cdrom.com in all/info.hpfs.zip. 
  1408.  
  1409.  
  1410. ΓòÉΓòÉΓòÉ 8. PM Programming ΓòÉΓòÉΓòÉ
  1411.  
  1412. This section covers Presentation Manager programming. 
  1413.  
  1414.  
  1415. ΓòÉΓòÉΓòÉ 8.1. Printing ΓòÉΓòÉΓòÉ
  1416.  
  1417. This section covers Presentation Manager printing. 
  1418.  
  1419.  
  1420. ΓòÉΓòÉΓòÉ 8.1.1. Are there any SIMPLE examples of printing? ΓòÉΓòÉΓòÉ
  1421.  
  1422. Here is some sample code, but also check out PRINTQ12.ZIP on cdrom.com in 
  1423. 2_x/program. PRINTQ12.ZIP contains a DLL that encapselates alot of the messy 
  1424. details. 
  1425.  
  1426. Here is the working code for allowing the user to change the printer setup. 
  1427. I've also included the code that I use to start and end printing, so you can 
  1428. see how it all works. 
  1429.  
  1430. If you have any questions or comments, feel free to write. 
  1431.  
  1432. PrinterSetup() is the routine that gets the printer setup information from the 
  1433. user. 
  1434.  
  1435. GetPrinterHPS() is the routine that gets the DC and PS for the printer, and 
  1436. starts the document. 
  1437.  
  1438. EndPrint() is the routine that ends the document, and closes the DC. 
  1439.  
  1440. First, here's a little sample of how to use PrinterSetup(), GetPrinterHPS(), 
  1441. and EndPrint(): 
  1442.  
  1443. {
  1444.    HPS          hPrinterPS;
  1445.    HDC          hPrinterDC;
  1446.    DEVOPENSTRUC dops;
  1447.  
  1448.    ...
  1449.  
  1450.    dops->pszLogAddress = NULL;  // in case PrinterSetup fails, this will tell
  1451.                                 // GetPrinterHPS() to use default printer info
  1452.  
  1453.    PrinterSetup(&dops);
  1454.  
  1455.    hPrinterPS = GetPrinterHPS(&dops, &hPrinterDC,
  1456.                               "Document Name", 0L, 0L);
  1457.    if (hPrinterPS != GPI_ERROR) {
  1458.       // do your printing here
  1459.  
  1460.       EndPrint(hPrinterPS, hPrinterDC, "Document Name");
  1461.    }
  1462.  
  1463.    ...
  1464. }
  1465.  
  1466.  
  1467. /*
  1468. ******************************************************************************
  1469. **  FUNCTION: PrinterSetup
  1470. **  PURPOSE :   This function allows the user to change printer settings.
  1471. **
  1472. **  PARAMS  :   lpdos - the printer info
  1473. **  RETURN  :   BOOL   (TRUE = success)
  1474. **
  1475. **  DATE    :   11-Dec-1992
  1476. **  AUTHOR  :   Carl Samos
  1477. ******************************************************************************
  1478. **  Modified: Date:     Description of changes
  1479. **  CNS     :   11-Dec-1992 Initial version
  1480. ******************************************************************************
  1481. */
  1482. BOOL PrinterSetup(DEVOPENSTRUC FAR *lpdos)
  1483. {
  1484.    PDRIVDATA     pDriveData;      /*  The drive data  */
  1485.    unsigned long ulSize;          /*  The buffer size required  */
  1486.    char          szPrinter[32];   /*  The printer name  */
  1487.    PSZ           pszDriver;       /*  The driver name  */
  1488.    PSZ           pszLogicalPort;  /*  The logical port  */
  1489.    char          szDeviceName[32];/*  The printer's name */
  1490.  
  1491.  
  1492.    // get the printer driver, name and logical port
  1493.    // GetPrinterInformation allocates space for pszDriver and pszLogicalPort
  1494.    if (!GetPrinterInformation(szPrinter, &pszDriver,
  1495.                               szDeviceName,&pszLogicalPort))
  1496.       return(FALSE);
  1497.  
  1498.  
  1499.    // get the size needed for the DRIVDATA struct
  1500.    ulSize = DevPostDeviceModes(habMain, NULL, pszDriver, NULL, szPrinter, 0L);
  1501.  
  1502.  
  1503.    if (ulSize != DPDM_NONE && ulSize != DPDM_ERROR) {
  1504.       pDriveData = (PDRIVDATA) _fmalloc(ulSize);
  1505.       pDriveData->cb = ulSize;
  1506.  
  1507.       // bring up the dialog boxes, and fill the DRIVDATA struct
  1508.       ulSize = DevPostDeviceModes(habMain, pDriveData, pszDriver, NULL,
  1509.                                   szPrinter, 0L);
  1510.  
  1511.       if (ulSize == DEV_OK) {
  1512.           // if there is a printer name, copy it into the DRIVDATA
  1513.           if (szDeviceName[0] != '\0')
  1514.              strcpy(pDriveData->szDeviceName, szDeviceName);
  1515.  
  1516.           // remove the old information
  1517.           if (lpdos->pszLogAddress != NULL) {
  1518.              _ffree(lpdos->pszLogAddress);
  1519.           }
  1520.           if (lpdos->pszDriverName != NULL) {
  1521.              _ffree(lpdos->pszDriverName);
  1522.           }
  1523.           if (lpdos->pdriv != NULL)
  1524.              _ffree(lpdos->pdriv);
  1525.  
  1526.           /*  Setup the DEVOPENSTRUC  */
  1527.           lpdos->pszLogAddress = pszLogicalPort;
  1528.           lpdos->pszDriverName = pszDriver;
  1529.           lpdos->pszDataType   = NULL;
  1530.           lpdos->pdriv         = pDriveData;
  1531.       }
  1532.       else {
  1533.           _ffree(pszDriver);
  1534.           _ffree(pszLogicalPort);
  1535.           _ffree(pDriveData);
  1536.       }
  1537.    }
  1538.    else {
  1539.       _ffree(pszDriver);
  1540.       _ffree(pszLogicalPort);
  1541.    }
  1542.  
  1543.    return(TRUE);
  1544. }
  1545.  
  1546.  
  1547. /*
  1548. ******************************************************************************
  1549. **  FUNCTION:   GetPrinterInformation
  1550. **  PURPOSE :   This function gets the current printer information from the
  1551. **                    os2.ini file.
  1552. **
  1553. **  PARAMS  :   PSZ pszPrinter
  1554. **              PSZ pszDriver
  1555. **              PSZ pszDeviceName
  1556. **              PSZ pszLogicalPort
  1557. **
  1558. **  RETURN  :   void
  1559. **
  1560. **  DATE    :   11-Dec-1992
  1561. **  AUTHOR  :   Carl Samos
  1562. ******************************************************************************
  1563. **  Modified: Date:     Description of changes
  1564. **  CNS     :   11-Dec-1992 Initial version
  1565. ******************************************************************************
  1566. */
  1567. BOOL GetPrinterInformation(PSZ pszPrinter, PSZ FAR *lpszDriver,
  1568.                            PSZ pszDeviceName, PSZ FAR *lpszLogicalPort)
  1569. {
  1570.    int  cb;
  1571.    char szDetails[256];
  1572.    PSZ  pszBegin;
  1573.    PSZ  pszTemp;
  1574.    char szPort[64];
  1575.    char szDriver[64];
  1576.    char szLogPort[64];
  1577.  
  1578.    /*  Get the printer name  */
  1579.    cb = WinQueryProfileString(habMain, "PM_SPOOLER",
  1580.                               "PRINTER", "", pszPrinter,32);
  1581.    pszPrinter[cb-2] = 0;
  1582.  
  1583.  
  1584.    /*  Get the other details  */
  1585.    WinQueryProfileString(habMain, "PM_SPOOLER_PRINTER", pszPrinter, "",
  1586.                          szDetails, 256);
  1587.  
  1588.    // the profile string has the following format:
  1589.    // PORT;DRIVER;LOGICAL PORT;NETWORK INFO;
  1590.    // fields can have more than one entry, separated by a comma
  1591.    // the printer's name will follow the driver, separated by a period.
  1592.  
  1593.    pszBegin = szDetails;
  1594.  
  1595.    // get the printer port
  1596.    pszTemp = strchr(pszBegin, ';');
  1597.    if (pszTemp != NULL) {
  1598.       *pszTemp = '\0';
  1599.       strcpy(szPort, pszBegin);
  1600.       *pszTemp = ';';
  1601.       pszBegin = pszTemp + 1;
  1602.  
  1603.       // check for a comma in the string
  1604.       pszTemp = strchr(szPort, ',');
  1605.       if (pszTemp != NULL) *pszTemp = '\0';
  1606.    }
  1607.    else {
  1608.       return(FALSE);
  1609.    }
  1610.  
  1611.    // now get the driver and printer name
  1612.    pszTemp = strchr(pszBegin, ';');
  1613.    if (pszTemp != NULL) {
  1614.       *pszTemp = '\0';
  1615.       strcpy(szDriver, pszBegin);
  1616.       *pszTemp = ';';
  1617.       pszBegin = pszTemp + 1;
  1618.  
  1619.       // check for a period (printer name follows it)
  1620.       pszTemp = strchr(szDriver, '.');
  1621.       if (pszTemp != NULL) {
  1622.          strcpy(pszDeviceName, pszTemp+1);
  1623.          *pszTemp = '\0';
  1624.       }
  1625.       else {
  1626.          pszDeviceName[0] = '\0';
  1627.       }
  1628.  
  1629.       // check for a comma in the string
  1630.       pszTemp = strchr(szDriver, ',');
  1631.       if (pszTemp != NULL)
  1632.         *pszTemp = '\0';
  1633.    }
  1634.    else {
  1635.       return(FALSE);
  1636.    }
  1637.  
  1638.  
  1639.    // now get the logical port
  1640.    pszTemp = strchr(pszBegin, ';');
  1641.    if (pszTemp != NULL) {
  1642.       *pszTemp = '\0';
  1643.       strcpy(szLogPort, pszBegin);
  1644.       *pszTemp = ';';
  1645.       pszBegin = pszTemp + 1;
  1646.  
  1647.       // check for a comma in the string
  1648.       pszTemp = strchr(szLogPort, ',');
  1649.       if (pszTemp != NULL)
  1650.         *pszTemp = '\0';
  1651.    }
  1652.    else {
  1653.       return(FALSE);
  1654.    }
  1655.  
  1656.    *lpszDriver = _fmalloc(sizeof(char) * (strlen(szDriver)+1));
  1657.    strcpy(*lpszDriver, szDriver);
  1658.  
  1659.    *lpszLogicalPort = _fmalloc(sizeof(char) * (strlen(szLogPort)+1));
  1660.    strcpy(*lpszLogicalPort, szLogPort);
  1661.  
  1662.    return(TRUE);
  1663. }
  1664.  
  1665.  
  1666. /*
  1667. ******************************************************************************
  1668. **  FUNCTION: GetPrinterHPS
  1669. **  PURPOSE :   Gets the presentation space for a printer, and starts the doc
  1670. **  PARAMS  :   lpdos
  1671. **          :   lphDC           - the printer's hdc
  1672. **          :   pszDocName      - the name of the document
  1673. **          :   lWidth          - the width of the document
  1674. **          :   lHeight         - the height of the document
  1675. **  RETURN  : hPS
  1676. **  DATE    :   11-Dec-1992
  1677. **  AUTHOR  :   Carl Samos
  1678. ******************************************************************************
  1679. **  Modified: Date:     Description of changes
  1680. **  CNS     :   11-Dec-1992 Initial version
  1681. ******************************************************************************
  1682. */
  1683. HPS GetPrinterHPS(DEVOPENSTRUC FAR *lpdos, HDC FAR* lphDC, PSZ pszDocName,
  1684.           LONG lWidth, LONG lHeight)
  1685. {
  1686.    LONG  lReturn;
  1687.    SIZEL sizl;
  1688.    HPS   hPS;
  1689.  
  1690.    if (lpdops->pszLogAddress == NULL) {  // get the default settings
  1691.       char szPrinter[32];   /*  The printer name    */
  1692.       PSZ  pszDriver;       /*  The driver name  */
  1693.       PSZ  pszLogicalPort;  /*  The logical port    */
  1694.       char szDeviceName[32];/*  The printer's name */
  1695.  
  1696.       // GetPrinterInformation allocates space for pszDriver and pszLogicalPort
  1697.       if (!GetPrinterInformation(szPrinter, &pszDriver, szDeviceName,
  1698.                                  &pszLogicalPort))
  1699.       return(GPI_ERROR);
  1700.  
  1701.       lpdops->pszLogAddress = pszLogicalPort;
  1702.       lpdops->pszDriverName = pszDriver;
  1703.       lpdops->pszDataType   = NULL;
  1704.       lpdops->pdriv         = NULL;
  1705.    }
  1706.  
  1707.    // open the printer DC
  1708.    *lphDC = DevOpenDC (habMain, OD_QUEUED, "*", 4L, lpdops, (HDC) NULL);
  1709.    if (*lphDC == DEV_ERROR) {
  1710.       return(GPI_ERROR);
  1711.    }
  1712.  
  1713.    // start the document
  1714.    lReturn = DevEscape(*lphDC, DEVESC_STARTDOC, strlen(pszDocName),
  1715.                        pszDocName,NULL, NULL);
  1716.  
  1717.    // get the PS for the printer
  1718.    if (lReturn == DEV_OK) {
  1719.        sizl.cx = lWidth;
  1720.        sizl.cy = lHeight;
  1721.  
  1722.        if (lWidth == 0) {
  1723.           hPS =  GpiCreatePS (habMain, *lphDC, &sizl,
  1724.                               PU_LOENGLISH | GPIF_DEFAULT |
  1725.                               GPIT_NORMAL | GPIA_ASSOC);
  1726.           return(hPS);
  1727.        }
  1728.        else {
  1729.           hPS = GpiCreatePS (habMain, *lphDC, &sizl,
  1730.                               PU_ARBITRARY | PU_LOENGLISH |
  1731.                               GPIF_DEFAULT | GPIT_NORMAL |
  1732.                               GPIA_ASSOC);
  1733.           return(hPS);
  1734.       }
  1735.    }
  1736.  
  1737.    return(GPI_ERROR);
  1738. }
  1739.  
  1740.  
  1741. /*
  1742. ******************************************************************************
  1743. **  FUNCTION: EndPrint
  1744. **  PURPOSE : To close the hdc and end the document
  1745. **  PARAMS  : hpsPrinter - the printer's presentation space
  1746. **     : hdcPrinter - the printer's device context
  1747. **     : pszDocName - the name of the document
  1748. **  RETURN  : nothing
  1749. **  DATE    :   11-Dec-1992
  1750. **  AUTHOR  :   Carl Samos
  1751. ******************************************************************************
  1752. **  Modified: Date:     Description of changes
  1753. **  CNS     :   11-Dec-1992 Initial version
  1754. ******************************************************************************
  1755. */
  1756. void EndPrint(HPS hpsPrinter, HDC hdcPrinter, PSZ pszDocName)
  1757. {
  1758. DevEscape(hdcPrinter, DEVESC_ENDDOC, strlen(pszDocName),
  1759. pszDocName, NULL,NULL);
  1760. GpiAssociate(hpsPrinter, (HDC) NULL);
  1761. DevCloseDC(hdcPrinter);
  1762. GpiDestroyPS(hpsPrinter);
  1763. }
  1764.  
  1765. Credit:  Carl Samos 
  1766.  
  1767.  
  1768. ΓòÉΓòÉΓòÉ 8.1.2. Is there an easy way to get printer output (another opinion)? ΓòÉΓòÉΓòÉ
  1769.  
  1770. A reader who desires to remain anonymous writes: 
  1771.  
  1772. Generally:  My understanding was that OS/2 would handle printing for me.  That 
  1773. is to say that I wouldn't have to create separate printer drivers for every 
  1774. printer under the sun (or any for that matter).  Since I am creating an image 
  1775. on the screen that is device independent (well, mostly anyway), is there an 
  1776. easy way to get printer output? 
  1777.  
  1778. PM achieves a level of device independence by defining a logical output space. 
  1779. This logical output space is then bound to a physical output space, which 
  1780. creates a mapping of logical characteristics to their physical counterparts. 
  1781. The logical and physical output spaces are referred to as the presentation 
  1782. space and the device context (HPS and HDC) and are bound to one another by 
  1783. using either the GpiAssociate function or by specifying GPIA_ASSOC to the 
  1784. GpiCreatePS function. 
  1785.  
  1786. The easiest way to accomplish what you desire is to organize your drawing code 
  1787. into one or more functions with a single entrypoint that accepts an HPS as a 
  1788. parameter.  Then, when you want to draw to the screen, you can call 
  1789. WinGetPS/WinBeginPaint to get an HPS and call the function. When you want 
  1790. hardcopy, you call DevOpenDC to get an HDC and GpiCreatePS to get an HPS and 
  1791. call the function. 
  1792.  
  1793. Note that to get hardcopy, you need to perform some additional setup to get 
  1794. things to work properly.  The two most important things are that you initialize 
  1795. the DEVOPENSTRUC structure properly before calling DevOpenDC and that you send 
  1796. the following escape codes (via DevEscape) at the following times: 
  1797.  
  1798.   hdcPrn=DevOpenDC(...);
  1799.   hpsPrn=GpiCreatePS(...);
  1800.  
  1801.   DevEscape(...,DEVESC_STARTDOC,...);
  1802.  
  1803.   if (!doDraw(hpsPrn)) {
  1804.      DevEscape(...,DEVESC_ABORTDOC,...);
  1805.   } /* endif */
  1806.  
  1807.   DevEscape(...,DEVESC_ENDDOC,...);
  1808.  
  1809.   GpiDestroyPS(hpsPrn);
  1810.   DevCloseDC(hdcPrn);
  1811.  
  1812. I'm not sure because I can't seem to find my copy anywhere, but I belive that 
  1813. the book by Graham Winn (entitled something to the effect of "Building 
  1814. applications using the OS/2 Presentation Manager") dedicates a chapter to the 
  1815. nuances of printing. 
  1816.  
  1817. (Quoted almost directly from EDMI/2 Edition 1) 
  1818.  
  1819.  
  1820. Related Information:
  1821.  
  1822. What are good reference books for programming in OS/2 and PM?
  1823.  
  1824.  
  1825. ΓòÉΓòÉΓòÉ 8.1.3. How do I print a bitmap? ΓòÉΓòÉΓòÉ
  1826.  
  1827. Here's my code for sending a bitmap to the printer I'm leaving out the part 
  1828. where I maintain an aspect ratio between the screen and the printer page. 
  1829.  
  1830.     SIZEL sizl = {0,0};
  1831.     // Get DC/PS for printer
  1832.     hdcPrinter = GetPrinterDC( hab, PM_Q_STD );
  1833.     hpsPrinter = GpiCreatePS( hab, hdcPrinter, &sizl,
  1834.                               PU_PELS | GPIF_DEFAULT |
  1835.                               GPIT_NORMAL | GPIA_ASSOC);
  1836.  
  1837.     // Get DC/PS for memory DC compatible with printer
  1838.     hdcPrtMem = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, hdcPrinter );
  1839.     hpsPrtMem = GpiCreatePS( hab, hdcPrtMem, &sizl,
  1840.                              PU_PELS | GPIF_DEFAULT |
  1841.                              GPIT_MICRO | GPIA_ASSOC );
  1842.  
  1843.     // Get DC/PS for memory DC compatible with display
  1844.     hdcMemory = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE );
  1845.     hpsMemory = GpiCreatePS( hab, hdcMemory, &sizl,
  1846.                              PU_PELS | GPIF_DEFAULT |
  1847.                              GPIT_MICRO | GPIA_ASSOC );
  1848.  
  1849.     // Get PS for a window to be printed
  1850.     hpsToPrint = WinGetPS( hwndToPrint );
  1851.  
  1852.     // Set up memory BitBlt
  1853.     BITMAPINFOHEADER2 bmih;
  1854.     LONG alBitmapStuff[ 2 ];
  1855.     WinQueryWindowPos( hwndToPrint, &swp );
  1856.     bmih.cbFix = sizeof( BITMAPINFOHEADER2 );
  1857.     bmih.cx = swp.cx;
  1858.     bmih.cy = swp.cy;
  1859.     GpiQueryDeviceBitmapFormats( hpsToPrint, 2L, alBitmapStuff );
  1860.     bmih.cPlanes = (USHORT) alBitmapStuff[ 0 ];
  1861.     bmih.cBitCount = (USHORT) alBitmapStuff[ 1 ];
  1862.  
  1863.     // ....Set up aptl[0],[1],[2],[3] for the memory BitBlt
  1864.  
  1865.     // Do BitBlt from Display memory PS to Printer memory PS
  1866.     hbmToPrint = GpiCreateBitmap( hpsMemory, &bmih, 0, NULL, NULL );
  1867.     GpiSetBitmap( hpsMemory, hbmToPrint );
  1868.     GpiBitBlt( hpsMemory, hpsToPrint, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE );
  1869.     GpiSetBitmap( hpsMemory, NULLHANDLE );
  1870.  
  1871.     GpiSetBitmap( hpsPrtMem, hbmToPrint );
  1872.  
  1873.     // ....Set up aptl[0],[1],[2],[3] for the printer BitBlt
  1874.  
  1875.     // BitBlt to printer PS from Printer memory PS
  1876.     DevEscape( hdcPrinter, DEVESC_STARTDOC,strlen( szDocName ), szDocName,
  1877.                &lBytes, NULL );
  1878.     GpiBitBlt( hpsPrinter, hpsPrtMem, 4L, aptl, ROP_SRCCOPY,BBO_IGNORE );
  1879.     DevEscape( hdcPrinter, DEVESC_ENDDOC, 0, NULL, &lBytes, NULL );
  1880.     GpiSetBitmap( hpsPrtMem, NULLHANDLE );
  1881.     GpiDeleteBitmap( hbmToPrint );
  1882.  
  1883.     // Release all hdc's and hps's
  1884.  
  1885. Credit:  Rick Fishman 
  1886.  
  1887.  
  1888. ΓòÉΓòÉΓòÉ 8.1.4. How do I do my own Print Screen? ΓòÉΓòÉΓòÉ
  1889.  
  1890. The following code segments are drawn from a much larger system that I manage 
  1891. at work.  The intent is to show how to provide a graphical print screen 
  1892. capability in a PM program.  We install a hook to watch for the print screen 
  1893. key and then take a bit map snapshot of the screen.  This bit map is then sent 
  1894. to the printer. Forgive me if I don't go into all the details about the 
  1895. non-related data structures -- it's late and my mind is a bit foggy. 
  1896.  
  1897. Feel free to use anything here.  Please add some kind of acknowledgement, if 
  1898. you use them as is, like: 
  1899.  
  1900.   "Print routines (c) 1990, 1991 Applied Signal Technology, Inc." 
  1901.  
  1902. Comment, questions, ridicule should be directed to:
  1903.  
  1904.   Jeff Hitchcock
  1905.   CompuServe 71601,260
  1906.  
  1907.   or U.S. Mail to
  1908.  
  1909.   Applied Signal Technology, Inc.
  1910.   470 Spring Park Place, Suite 700
  1911.   Herndon, VA 22070
  1912.  
  1913.   or phone to
  1914.  
  1915.   703/478-5619
  1916.  
  1917. /*****************************************************************************/ 
  1918.  
  1919. 1.  During the WM_CREATE message processing, add the following: 
  1920.  
  1921.    // Set the print screen hook
  1922.  
  1923.    WinSetHook (hab, HMQ_CURRENT, HK_INPUT, (PFN) PrintScreenHook,
  1924.                (HMODULE) NULL);
  1925.  
  1926. /*****************************************************************************/ 
  1927.  
  1928. 2.  Somewhere, have this function: 
  1929.  
  1930. BOOL CALLBACK PrintScreenHook (HAB hab, PQMSG pQmsg, USHORT fs)
  1931. {
  1932.    if ( pQmsg->msg == WM_CHAR )
  1933.       if ( ( SHORT1FROMMP(pQmsg->mp1) & KC_KEYUP) &&
  1934.            ( SHORT1FROMMP(pQmsg->mp1) & KC_VIRTUALKEY ) &&
  1935.            ( SHORT2FROMMP(pQmsg->mp2) == VK_PRINTSCRN) )
  1936.              PrintScreen (hab);
  1937.    return FALSE;
  1938. }
  1939.  
  1940. /*****************************************************************************/ 
  1941.  
  1942. 3.  Here's the "driver:" 
  1943.  
  1944. VOID EXPENTRY PrintScreen (HAB hab)
  1945. {
  1946.     HBITMAP     hbm;
  1947.  
  1948.     hbm = ScreenToBitmap (hab);
  1949.     PrintBitMap(hbm);
  1950. }
  1951.  
  1952. /*****************************************************************************/ 
  1953.  
  1954. 4.  Here's a general print-related structure we use.  We often have many print 
  1955. threads running concurrently, but we only allow one to "run" at a time.  We use 
  1956. a semaphore to show availability of the printer (so to speak), and only one 
  1957. thread at a time gets it.    If we didn't do this, and more than a few print 
  1958. threads are running (especially graphical prints), even a 486/33 with 16 MB of 
  1959. RAM begins to C-R-A-W-L.  So, for what it's worth, these are the structures 
  1960. that we use: 
  1961.  
  1962. /**************************************************************
  1963. *                                                             *
  1964. *   PRINTTHREADPARAMS structure                               *
  1965. *                                                             *
  1966. *   Parameters that are used to manage separate print threads *
  1967. *                                                             *
  1968. *   Item             Contents/Use                             *
  1969. *   --------------   ---------------------------------------- *
  1970. *                                                             *
  1971. *   sJobNumber       Print job number, used for cancelling    *
  1972. *   aiThreadStack    Thread's stack                           *
  1973. *   hwndNotify       Window to which notif. msgs are sent     *
  1974. *   tidPrint         System task id                           *
  1975. *   hssmPrinter...   Semaphore for printer available          *
  1976. *   fSemSet          TRUE if semaphore was made and cleared   *
  1977. *   szSummary        Print summary (e.g., fax printout)       *
  1978. *   fStart           Can't start until TRUE (default FALSE)   *
  1979. *   fContinue        Quit if FALSE (default is TRUE)          *
  1980. *   fHold            Hold if TRUE (default is FALSE)          *
  1981. *   sStartingPage    For multipage, start here                *
  1982. *   sEndingPage      For multipage, end here                  *
  1983. *   usParam          Module-dependent USHORT                  *
  1984. *   ulParam          Module-dependent ULONG                   *
  1985. *   pPrintData       PVOID to the print data                  *
  1986. *                                                             *
  1987. *   PAGESETUP structure                                       *
  1988. *                                                             *
  1989. *   Parameters used to describe the appearance                *
  1990. *                                                             *
  1991. *   Item             Contents/Use                             *
  1992. *   --------------   ---------------------------------------- *
  1993. *                                                             *
  1994. *   szFont           The name of the font to use              *
  1995. *   sLinesPerPage    Used to scale font                       *
  1996. *   sCharsPerLine    Used to scale font                       *
  1997. *   sLeft            Used to position on page, in chars       *
  1998. *   sRight           Used to position on page, in char        *
  1999. *   sTop             Used to position on page, in lines       *
  2000. *   sBottom          Used to position on page, in lines       *
  2001. *   szHeader         Text to place on top of each page        *
  2002. *   fIncludeSummary  If TRUE, include SRI summary on page 1   *
  2003. *   fHeaderEveryPage TRUE for every page, false for pg 1      *
  2004. *   fHeaderUnderline TRUE for underline                       *
  2005. *   szFooter         Text to place at bottom of each page     *
  2006. *   fFooterEveryPage TRUE for every page, false for pg 1      *
  2007. *   fOverlineFooter  TRUE for overline                        *
  2008. *                                                             *
  2009. *   HEADER AND FOOTER OPTIONS:                                *
  2010. *                                                             *
  2011. *   Special Flags that should be supported in each module:    *
  2012. *                                                             *
  2013. *           &l  Left justify                                  *
  2014. *           &c  Center                                        *
  2015. *           &r  Right justify                                 *
  2016. *           &d  Date                                          *
  2017. *           &t  Time                                          *
  2018. *           &p  Page number                                   *
  2019. *                                                            *
  2020. **************************************************************/
  2021.  
  2022. typedef struct
  2023.     {
  2024.     CHAR       szFont[FACESIZE] ;
  2025.     SHORT      sLinesPerPage ;
  2026.     SHORT      sCharsPerLine ;
  2027.     SHORT      sLeft ;
  2028.     SHORT      sRight ;
  2029.     SHORT      sTop ;
  2030.     SHORT      sBottom ;
  2031.     BOOL       fIncludeSummary ;
  2032.     CHAR       szHeader[HEADERFOOTERLENGTH] ;
  2033.     BOOL       fHeaderEveryPage ;
  2034.     BOOL       fUnderlineHeader ;
  2035.     CHAR       szFooter[HEADERFOOTERLENGTH] ;
  2036.     BOOL       fFooterEveryPage ;
  2037.     BOOL       fOverlineFooter ;
  2038.     }
  2039.     PAGESETUP ;
  2040.  
  2041. typedef PAGESETUP FAR *PPAGESETUP ;
  2042.  
  2043. typedef struct
  2044.     {
  2045.     SHORT        sJobNumber ;
  2046.     int          aiThreadStack[STACKSIZE / sizeof (int)] ;
  2047.     HWND         hwndNotify ;
  2048.     HSYSSEM      hssmPrinterAvailable ;
  2049.     BOOL         fSemSet ;
  2050.     CHAR         szSummary[HEADERFOOTERLENGTH] ;
  2051.     BOOL         fStart ;
  2052.     BOOL         fRunning ;
  2053.     BOOL         fContinue ;
  2054.     BOOL         fHold ;
  2055.     SHORT        sStartingPage ;
  2056.     SHORT        sEndingPage ;
  2057.     PAGESETUP    page ;
  2058.     USHORT       usParam ;
  2059.     ULONG        ulParam ;
  2060.     VOID huge    *pPrintData ;
  2061.     }
  2062.     PRINTTHREADPARAMS ;
  2063.  
  2064. typedef PRINTTHREADPARAMS FAR *PPRINTTHREADPARAMS ;
  2065.  
  2066. /*****************************************************************************/ 
  2067.  
  2068. 5.  This function saves the screen display to a bitmap. 
  2069.  
  2070. HBITMAP ScreenToBitmap (HAB hab)
  2071. {
  2072.      BITMAPINFOHEADER bmp ;
  2073.      HBITMAP          hbm ;
  2074.      HDC              hdcMemory ;
  2075.      HPS              hpsScreen, hpsMemory ;
  2076.      LONG             alBitmapFormats [2] ;
  2077.      POINTL           aptl[3] ;
  2078.      SIZEL            sizl ;
  2079.      SHORT            cxScreen;
  2080.      SHORT            cyScreen;
  2081.      BOOL             fMonochrome = FALSE;
  2082.                       // Create memory DC and PS
  2083.  
  2084.      cxScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
  2085.      cyScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
  2086.  
  2087.      hdcMemory = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ;
  2088.  
  2089.      sizl.cx = sizl.cy = 0 ;
  2090.      hpsMemory = GpiCreatePS (hab, hdcMemory, &sizl,
  2091.                               PU_PELS | GPIF_DEFAULT |
  2092.                               GPIT_MICRO | GPIA_ASSOC) ;
  2093.  
  2094.                               // Create bitmap for destination
  2095.  
  2096.      bmp.cbFix = sizeof bmp ;
  2097.  
  2098.      if (fMonochrome)
  2099.      {
  2100.         bmp.cPlanes = 1 ;
  2101.         bmp.cBitCount = 1 ;
  2102.      }
  2103.      else
  2104.      {
  2105.         GpiQueryDeviceBitmapFormats (hpsMemory, 2L, alBitmapFormats) ;
  2106.  
  2107.         bmp.cPlanes = (USHORT) alBitmapFormats[0] ;
  2108.         bmp.cBitCount = (USHORT) alBitmapFormats[1] ;
  2109.      }
  2110.  
  2111.      bmp.cx = cxScreen ;
  2112.      bmp.cy = cyScreen ;
  2113.  
  2114.      hbm = GpiCreateBitmap (hpsMemory, &bmp, 0L, NULL, NULL) ;
  2115.  
  2116.                               // Copy from screen to bitmap
  2117.  
  2118.      if (hbm != NULL)
  2119.      {
  2120.         GpiSetBitmap (hpsMemory, hbm) ;
  2121.         hpsScreen = WinGetScreenPS (HWND_DESKTOP) ;
  2122.  
  2123.         aptl[0].x = 0 ;
  2124.         aptl[0].y = 0 ;
  2125.         aptl[1].x = cxScreen ;
  2126.         aptl[1].y = cyScreen ;
  2127.         aptl[2].x = 0 ;
  2128.         aptl[2].y = 0 ;
  2129.  
  2130.         WinLockVisRegions (HWND_DESKTOP, TRUE) ;
  2131.  
  2132.         GpiBitBlt (hpsMemory, hpsScreen, 3L, aptl,
  2133.                    fMonochrome ? ROP_NOTSRCCOPY : ROP_SRCCOPY, BBO_IGNORE) ;
  2134.  
  2135.         WinLockVisRegions (HWND_DESKTOP, FALSE) ;
  2136.  
  2137.         WinReleasePS (hpsScreen) ;
  2138.         GpiDestroyPS (hpsMemory) ;
  2139.         DevCloseDC (hdcMemory) ;
  2140.      }
  2141.  
  2142.      return hbm ;
  2143. }
  2144.  
  2145. /***************************************************************************** 
  2146.  
  2147. 6.  The "core" function: 
  2148.  
  2149. This function prints a bitmap to the printer.  The bitmap is scaled according 
  2150. to the size of the printer.  No distortion is allowed of the bitmap image. 
  2151.  
  2152. Returns False : if an error occurrs 
  2153. Returns True : no Error occurred 
  2154.  
  2155. Known bug(s): 
  2156.  
  2157. Areas on the screen that have a black foreground and a gray background are 
  2158. completely black when printed.  For example, when a window does not have the 
  2159. focus, it's title bar becomes black lettering on a gray background.  When this 
  2160. window is printed, the entire title bar is black and no title can be read. 
  2161. This is using the Hewlett Packard LaserJet Series II printer. 
  2162.  
  2163. According to MicroSoft online help this is a known bug with the printer device 
  2164. driver.    To fix the bug you must go to the control panel and change the colors 
  2165. of the inactive window. 
  2166.  
  2167. ************************************************************************/
  2168. SHORT  sBitmapToPrinter(PPRINTTHREADPARAMS pptp,
  2169. HPS   hpsPrinter,
  2170. HDC   hdcPrinter,
  2171. HAB   habPrinter,
  2172. SIZEL *psizlPage,
  2173. SIZEL *psizlChar)
  2174. {
  2175.     HDC    hdcPrinterMemory;
  2176.     HPS    hpsPrinterMemory;
  2177.     POINTL ptl;
  2178.     SHORT  sPage = 1;
  2179.     RECTL  rcl;     // Coordinates of region
  2180.  
  2181.     long  lCapsHRes;
  2182.     long  lCapsVRes;
  2183.     float fYAspectRatio;
  2184.     float fXAspectRatio;
  2185.     SIZEL sizl;
  2186.  
  2187.     HBITMAP hbm;
  2188.     POINTL  aptl [4] ;
  2189.     SHORT   cxScreen;
  2190.     SHORT   cyScreen;
  2191.     float   fltScale;
  2192.  
  2193.     // Skip down top margin, ...
  2194.  
  2195.     ptl.x = pptp->page.sLeft * psizlChar->cx ;
  2196.     ptl.y = psizlPage->cy - (pptp->page.sTop * psizlChar->cy) ;
  2197.  
  2198.     // Print header, if requested
  2199.  
  2200.     if (pptp->page.szHeader[0] != '\0')
  2201.     {
  2202.        PrintHeaderFooter (hpsPrinter, &ptl, pptp,
  2203.                           psizlPage, psizlChar,
  2204.                           pptp->page.szHeader,
  2205.                           sPage, PRINT_HEADER) ;
  2206.     }
  2207.  
  2208.     hbm = pptp->pPrintData;
  2209.  
  2210.     // Find the aspect ratio of the printer
  2211.  
  2212.     DevQueryCaps(hdcPrinter,CAPS_HORIZONTAL_RESOLUTION,1L,&lCapsHRes);
  2213.     DevQueryCaps(hdcPrinter,CAPS_VERTICAL_RESOLUTION,1L,&lCapsVRes);
  2214.  
  2215.     if ( (lCapsVRes == 0) || (lCapsHRes == 0) ) {
  2216.        fXAspectRatio = (float) 1;
  2217.        fYAspectRatio = (float) 1;
  2218.     }
  2219.     else {
  2220.        fXAspectRatio = (float) ((float) lCapsVRes / (float) lCapsHRes);
  2221.        fYAspectRatio = (float) ((float) lCapsHRes / (float) lCapsVRes);
  2222.     }
  2223.  
  2224.     // determine coordinates to print on printer
  2225.  
  2226.     rcl.xLeft =  pptp->page.sLeft * psizlChar->cx; // Printer left
  2227.  
  2228.     rcl.xRight = psizlPage->cx -
  2229.                  (pptp->page.sRight * psizlChar->cx); // Printer right
  2230.  
  2231.     rcl.yBottom = (pptp->page.sBottom + 1) * psizlChar->cy; // Printer bottom
  2232.  
  2233.     rcl.yTop = psizlPage->cy -
  2234.               ( (pptp->page.sTop + 1) * psizlChar->cy);     // Printer top
  2235.  
  2236.     cxScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
  2237.     cyScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
  2238.  
  2239.     ScaleToWindowSize ((SHORT) (rcl.xRight - rcl.xLeft),   // sXtarget
  2240.                        (SHORT) (rcl.yTop - rcl.yBottom),   // sYTarget
  2241.                        cxScreen,                           // sXSource
  2242.                        cyScreen,                           // sYSource
  2243.                        &fltScale) ;
  2244.  
  2245.     // Create a memory device context
  2246.     // Memory device contexts are used to contain bitmaps
  2247.  
  2248.     hdcPrinterMemory = DevOpenDC (habPrinter, OD_MEMORY, "*", 0L,
  2249.                                   NULL, hdcPrinter);
  2250.  
  2251.     if ( hdcPrinterMemory == DEV_ERROR ) return FALSE;
  2252.  
  2253.     sizl.cx = 0;
  2254.     sizl.cy = 0;
  2255.  
  2256.     // Create a presentation space and associate it the memory device context
  2257.  
  2258.     hpsPrinterMemory = GpiCreatePS (habPrinter, hdcPrinterMemory, &sizl,
  2259.                                     PU_PELS | GPIF_DEFAULT |
  2260.                                     GPIT_NORMAL | GPIA_ASSOC);
  2261.  
  2262.     if( ! hpsPrinterMemory) {
  2263.        DevCloseDC (hdcPrinterMemory);
  2264.        return FALSE;
  2265.     }
  2266.  
  2267.     GpiSetBitmap(hpsPrinterMemory,hbm);
  2268.  
  2269.     aptl [0].x = rcl.xRight - (long) ((float) cxScreen * fltScale);
  2270.     aptl [0].y = rcl.yTop - (long) ((float) cyScreen * fltScale *
  2271.                  fYAspectRatio);
  2272.     aptl [1].x = rcl.xRight;
  2273.     aptl [1].y = rcl.yTop;
  2274.     aptl [2].x = 0;
  2275.     aptl [2].y = 0;
  2276.     aptl [3].x = cxScreen;
  2277.     aptl [3].y = cyScreen;
  2278.  
  2279.     GpiBitBlt(hpsPrinter,hpsPrinterMemory,4L,aptl,ROP_SRCCOPY,BBO_IGNORE);
  2280.  
  2281.     GpiAssociate   (hpsPrinterMemory, NULL) ;
  2282.     GpiDestroyPS   (hpsPrinterMemory);
  2283.     DevCloseDC     (hdcPrinterMemory);
  2284.  
  2285.     // If a footer is defined, ...
  2286.  
  2287.     if (pptp->page.szFooter[0] != '\0')
  2288.     {
  2289.        // ... compute its position ...
  2290.  
  2291.        ptl.x = pptp->page.sLeft * psizlChar->cx ;
  2292.        ptl.y = pptp->page.sBottom * psizlChar->cy ;
  2293.  
  2294.        // ... and print it.
  2295.  
  2296.        PrintHeaderFooter (hpsPrinter, &ptl, pptp,
  2297.                           psizlPage, psizlChar,
  2298.                           pptp->page.szFooter,
  2299.                          sPage, PRINT_FOOTER) ;
  2300.    }
  2301.    return( TRUE);
  2302. }
  2303.  
  2304.  
  2305. ΓòÉΓòÉΓòÉ 8.2. Menus ΓòÉΓòÉΓòÉ
  2306.  
  2307. This section covers Presentation Manager menus. 
  2308.  
  2309.  
  2310. ΓòÉΓòÉΓòÉ 8.2.1. How do I add a menu to a dialog box? ΓòÉΓòÉΓòÉ
  2311.  
  2312. Do a WinLoadMenu and then WM_UPDATEFRAME. 
  2313.  
  2314.  
  2315. ΓòÉΓòÉΓòÉ 8.2.2. How do I make a dynamically changing menu? ΓòÉΓòÉΓòÉ
  2316.  
  2317. Create the menu with all the items that it will ever contain, then dynamically 
  2318. remove and insert the items as required. After loading menu, Query and maintain 
  2319. a copy of the menuitem(s) that will be removed. 
  2320.  
  2321.  // Obtain and keep a copy of the convert submenuitem
  2322.   if (!WinSendMsg (pwd->hwndAB, MM_QUERYITEM,
  2323.       MPFROM2SHORT (IDM_KanCnvMnu, TRUE), MPFROMP (&pwd->miCnvMnu))) {
  2324.  
  2325.   // And the convert submenu text
  2326.   if (!WinSendMsg (pwd->hwndAB, MM_QUERYITEMTEXT,
  2327.     MPFROM2SHORT (IDM_KanCnvMnu, sizeof (pwd->szCnvMnuTxt)),
  2328.                   MPFROMP (&pwd->szCnvMnuTxt)) ){
  2329.  
  2330. When menu is to updated, insert/remove as necessary 
  2331.  
  2332.     // This is layout, is the submenu already in place?
  2333.     if (!pwd->fCnvMenu) {
  2334.  
  2335.       // The submenu is not installed, so insert the submenu
  2336.       WinSendMsg (pwd->hwndAction, MM_INSERTITEM,
  2337.                   MPFROMP (&pwd->miCnvMnu), MPFROMP (pwd->szCnvMnuTxt));
  2338.  
  2339.       // And remove the convert menuitem
  2340.       WinSendMsg (pwd->hwndAB, MM_REMOVEITEM,
  2341.                   MPFROM2SHORT (IDM_KanCnv, TRUE), 0L);
  2342.  
  2343.       // Set the submenu flag
  2344.       pwd->fCnvMenu = TRUE;
  2345.     }
  2346.  
  2347. Credit:  Matthew S. Osborn 
  2348.  
  2349.  
  2350. ΓòÉΓòÉΓòÉ 8.2.3. How do I create a conditional cascade menu? ΓòÉΓòÉΓòÉ
  2351.  
  2352. The following works for me to set a submenu as a conditional-cascade menu, then 
  2353. set it's default id (hwndMenu is the hwnd of the top-level menu): 
  2354.  
  2355.    MENUITEM mi;
  2356.  
  2357.    WinSendMsg( hwndMenu, MM_QUERYITEM,
  2358.                MPFROM2SHORT( idSubMenu, TRUE ), &mi );
  2359.  
  2360.    // Set the MS_CONDITIONALCASCADE bit for the submenu.
  2361.  
  2362.    WinSetWindowBits( mi.hwndSubMenu, QWL_STYLE, MS_CONDITIONALCASCADE,
  2363.                      MS_CONDITIONALCASCADE );
  2364.  
  2365.    // Set cascade menu default
  2366.  
  2367.    WinSendMsg( mi.hwndSubMenu, MM_SETDEFAULTITEMID,
  2368.                MPFROMSHORT( idDefaultItem ), NULL );
  2369.  
  2370. Then I do this to query the default item: 
  2371.  
  2372.  MENUITEM mi;
  2373.  
  2374.  WinSendMsg( hwndMenu, MM_QUERYITEM, MPFROM2SHORT( idSubMenu, TRUE ),
  2375.              &mi );
  2376.  
  2377.  id = (USHORT) WinSendMsg( mi.hwndSubMenu,
  2378.                            MM_QUERYDEFAULTITEMID, NULL, NULL );
  2379.  
  2380. Credit:  Rick Fishman 
  2381.  
  2382.  
  2383. ΓòÉΓòÉΓòÉ 8.2.4. How do I remove a separator from a menu? ΓòÉΓòÉΓòÉ
  2384.  
  2385. Here are two methods of doing that.  The first is from the PMHINTS file, and 
  2386. the second is from Gpf.  PMHINTS takes the approach of removing SC_CLOSE and 
  2387. the nearby separator.  The Gpf solution takes the approach of deleting 
  2388. everything that it doesn't explicitly want.  I've extended it to, among other 
  2389. things, conditionally delete the "Window List" menu item as well. 
  2390.  
  2391. The deletion problems get messier in application menus when there are multiple 
  2392. separaters in different pull-downs.  That is when assigning the separators an 
  2393. id really pays off. 
  2394.  
  2395. Both examples are 16-bit OS/2 1.x code. 
  2396.  
  2397. PMHINTS: 
  2398.  
  2399.  VOID  DelClose(HWND hwnd)
  2400.  {
  2401.    HWND        hSysMenu,
  2402.                hSysSubMenu;
  2403.    MENUITEM    SysMenu;
  2404.    SHORT       idItem,
  2405.                idSep,
  2406.                idSysMenu;
  2407.  
  2408.    hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE),
  2409.                               FID_SYSMENU);
  2410.  
  2411.    idSysMenu = SHORT1FROMMR(WinSendMsg(hSysMenu, MM_ITEMIDFROMPOSITION,
  2412.                             NULL, NULL));
  2413.  
  2414.    WinSendMsg(hSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu, FALSE),
  2415.               MPFROMP(&SysMenu));
  2416.  
  2417.    hSysSubMenu = SysMenu.hwndSubMenu;
  2418.  
  2419.    idItem = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMPOSITIONFROMID,
  2420.                          MPFROM2SHORT(SC_CLOSE, FALSE), NULL));
  2421.    if (idItem != MIT_ERROR)
  2422.    {
  2423.      idSep = idItem + 1;  // Get separator ID
  2424.  
  2425.      idSep  = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMIDFROMPOSITION,
  2426.                            MPFROMSHORT(idSep), NULL));
  2427.  
  2428.      WinSendMsg(hSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_CLOSE, TRUE),
  2429.                 MPFROMSHORT(NULL));
  2430.  
  2431.      WinSendMsg(hSysSubMenu, MM_DELETEITEM, MPFROM2SHORT(idSep, FALSE), NULL);
  2432.    }
  2433.  }
  2434.  
  2435. Derived from Gpf, adapted for a client, with some of my changes expurgated (so 
  2436. it won't compile as is): 
  2437.  
  2438.  /*****
  2439.   *
  2440.   *  UtilDlgSysMenu
  2441.   *
  2442.   *      Remove unavailable items from system menu of dialog box.
  2443.   *
  2444.   *  History:
  2445.   *      8/31/92  gts  Adapted from Gpf's GpfSetDialogBoxSysMenu
  2446.   *               with slight modifications.
  2447.   *
  2448.   *****/
  2449.  
  2450.  void _export UtilDlgSysMenu (          /* Remove unwanted system menu items */
  2451.  HWND hwndFrame)                      /* I - Handle to dialog window */
  2452.  {
  2453.     HWND     hwndSubMenu;             /* sys menu pull-down handle  */
  2454.     MENUITEM miTemp;                  /* menu item template         */
  2455.     SHORT    sItemId;                 /* system menu item ID        */
  2456.     SHORT    sItemIndex;              /* system menu item index     */
  2457.     MRESULT  mresult;
  2458.  
  2459.     /********************************************************************/
  2460.     /* Get the handle of the system menu pull-down.            */
  2461.     /********************************************************************/
  2462.     hwndSubMenu = WinWindowFromID( hwndFrame, FID_SYSMENU );
  2463.     WinSendMsg( hwndSubMenu,
  2464.                 MM_QUERYITEM,
  2465.                 MPFROM2SHORT( SC_SYSMENU, FALSE ),
  2466.                 MPFROMP( (PSZ)&miTemp ) );
  2467.     hwndSubMenu = miTemp.hwndSubMenu;
  2468.  
  2469.     /********************************************************************/
  2470.     /* Remove all items from the system menu pull-down that are no    */
  2471.     /* longer wanted.                            */
  2472.     /********************************************************************/
  2473.     mresult = WinSendMsg( hwndSubMenu,
  2474.                          MM_QUERYITEMCOUNT,
  2475.                          MPFROMSHORT(0),
  2476.                          MPFROMSHORT(0) );
  2477.     sItemIndex = SHORT1FROMMR(mresult);
  2478.     for (sItemId = 0; sItemIndex != -1; sItemIndex--)
  2479.     {
  2480.        mresult = WinSendMsg( hwndSubMenu,
  2481.                              MM_ITEMIDFROMPOSITION,
  2482.                              MPFROMSHORT(sItemIndex),
  2483.                              MPFROMSHORT(0) );
  2484.        sItemId = SHORT1FROMMR(mresult);
  2485.        if ( sItemId != MIT_ERROR
  2486.              &&sItemId != SC_MOVE
  2487.              &&sItemId != SC_CLOSE
  2488.              &&(sItemId != SC_TASKMANAGER
  2489.              || (flFlags & MAXONLY)) )   // <- application controls
  2490.        {
  2491.           WinSendMsg( hwndSubMenu,
  2492.                       MM_DELETEITEM,
  2493.                       MPFROM2SHORT(sItemId,FALSE),
  2494.                       MPFROMSHORT(0) );
  2495.        }
  2496.     }
  2497.  }
  2498.  
  2499. Credit:  Guy Scharf 
  2500.  
  2501.  
  2502. ΓòÉΓòÉΓòÉ 8.3. Container Controls ΓòÉΓòÉΓòÉ
  2503.  
  2504. This section covers Presentation Manager container controls. 
  2505.  
  2506.  
  2507. ΓòÉΓòÉΓòÉ 8.3.1. How do I stop a container from flashing every time I add a record? ΓòÉΓòÉΓòÉ
  2508.  
  2509. Disable/Enable the container window before and after the insertion/deletion. 
  2510.  
  2511.  
  2512. ΓòÉΓòÉΓòÉ 8.3.2. How do I get my containers to use Mini-icons? ΓòÉΓòÉΓòÉ
  2513.  
  2514. Here is some sample code that displays mini icons.  First, supply a missing 
  2515. #define: 
  2516.  
  2517.  #ifndef CCS_MINIICONS
  2518.      #define CCS_MINIICONS 0x0800
  2519.  #endif // not CCS_MINIICONS
  2520.  
  2521. Use CCS_MINIICONS as part of your container style (when you create the 
  2522. container).  Now, fill in the RECORDCORE structure pointed to by 'pRecordCore'; 
  2523. 'pUserRecord' also points to 'pRecordCore', which is part of a "user data" 
  2524. structure: 
  2525.  
  2526.  // Fill in fields of container record.
  2527.  #ifdef USE_MINIRECORDCORE
  2528.      pRecordCore->cb = sizeof (MINIRECORDCORE) ;
  2529.  #else
  2530.      pRecordCore->cb = sizeof (RECORDCORE) ;
  2531.  #endif // USE_MINIRECORDCORE
  2532.      pRecordCore->flRecordAttr = 0 ; // CRA_DROPONABLE ;
  2533.      // pRecordCore->ptlIcon is left to zeros.
  2534.      pRecordCore->pszIcon = pUserRecord->szName ;
  2535.      if (*DDirRecord.szIconName)
  2536.         LoadIcon (pUserRecord) ;
  2537.      // pRecordCore->hptrMiniIcon is left to zeros.
  2538.      // pRecordCore->hbmBitmap is left to zeros.
  2539.      // pRecordCore->hbmMiniBitmap is left to zeros.
  2540.      // pRecordCore->pTreeItemDesc is left to zeros.
  2541.  
  2542.  #ifndef USE_MINIRECORDCORE
  2543.      pRecordCore->pszText = pUserRecord->szName ;
  2544.      pRecordCore->pszName = pUserRecord->szName ;
  2545.      pRecordCore->pszTree = pUserRecord->szName ;
  2546.  #endif // not USE_MINIRECORDCORE
  2547.  
  2548. Now, if your user asks for mini-icons (via a popup menu, presumably), you send 
  2549. a CM_SETCNRINFO message to your container, after ORing in the CV_MINI style to 
  2550. CnrInfo.flWindowAttr, or removing it to restore full-size icons.  Hope this 
  2551. helps. 
  2552.  
  2553. Credit:  Wayne Kovsky 
  2554.  
  2555.  
  2556. ΓòÉΓòÉΓòÉ 8.3.3. How do I sort a container control? ΓòÉΓòÉΓòÉ
  2557.  
  2558. /*
  2559.  * Note that PSESSION is my own instance data structure.
  2560.  * I use it here to retrieve the type of field comparison I should do.
  2561.  */
  2562.  
  2563.  static SHORT APIENTRY Compare (PMINIRECORDCORE pmrc1,
  2564.                                 PMINIRECORDCORE pmrc2,
  2565.                                 PVOID pvStorage)
  2566.  {
  2567.     PSESSION pSession = (PSESSION) pvStorage ;
  2568.     PFIELDINFO pFieldInfo = pSession->pFieldInfoSort ;
  2569.     PPVOID pField1 = (PPVOID) ((PBYTE) pmrc1 +
  2570.        pFieldInfo->offStruct) ;
  2571.     PPVOID pField2 = (PPVOID) ((PBYTE) pmrc2 +
  2572.        pFieldInfo->offStruct) ;
  2573.     SHORT sResult = 0 ;
  2574.  
  2575.     if (pFieldInfo->flData & CFA_STRING) {
  2576.        sResult = strcmp ((PCHAR) *pField1, (PCHAR) *pField2) ;
  2577.     }
  2578.     else if (pFieldInfo->flData & CFA_ULONG) {
  2579.        if ((ULONG) *pField1 < (ULONG) *pField2)
  2580.           sResult = -1 ;
  2581.        else if ((ULONG) *pField1 > (ULONG) *pField2)
  2582.           sResult = 1 ;
  2583.        else
  2584.           sResult = 0 ;
  2585.     }
  2586.     else if (pFieldInfo->flData & CFA_DATE) {
  2587.        sResult = CompareDate ((PCDATE) (PVOID) pField1,
  2588.                               (PCDATE) (PVOID) pField2) ;
  2589.     }
  2590.     else if (pFieldInfo->flData & CFA_TIME) {
  2591.        sResult = CompareTime ((PCTIME) (PVOID) pField1,
  2592.                               (PCTIME) (PVOID) pField2) ;
  2593.     }
  2594.  
  2595.     // Any other data type gets treated as equal;
  2596.     // no sorting can be done. Now handle reverse sequence.
  2597.     if (pSession->fSortReverse && sResult)
  2598.        sResult = -sResult ;
  2599.     return sResult ;
  2600.  }
  2601.  
  2602. Here is how I invoke the sort: 
  2603.  
  2604.  // Send container a sort message.
  2605.  ulRC = LONGFROMMR (WinSendMsg (
  2606.                     pSession->hwndContainer,
  2607.                     CM_SORTRECORD,
  2608.                     MPFROMP (Compare), MPFROMP (pSession))) ;
  2609.  if (!ulRC) {
  2610.     // Report error.
  2611.  }
  2612.  
  2613. Credit:  Wayne Kovsky 
  2614.  
  2615.  
  2616. ΓòÉΓòÉΓòÉ 8.3.4. How do I query all records in a container - tree view? ΓòÉΓòÉΓòÉ
  2617.  
  2618. The following code works for querying all records in a tree structure but 
  2619.  
  2620.  USHORT usParentCmd = CMA_FIRST, usChildCmd;
  2621.  PUSERREC purParent = NULL, purChild;
  2622.  
  2623.  for( ; ; )
  2624.  {
  2625.     purParent = (PUSERREC) WinSendMsg( hwndCnr, CM_QUERYRECORD,
  2626.                                        MPFROMP( purParent ),
  2627.                                        MPFROM2SHORT( usParentCmd, CMA_ITEMORDER ) );
  2628.     if( !purParent )
  2629.        break;
  2630.  
  2631.     DoWhatever( purParent );
  2632.  
  2633.     usChildCmd = CMA_FIRSTCHILD;
  2634.     purChild = NULL;
  2635.     for( ; ; )
  2636.     {
  2637.        purChild = (PUSERREC) WinSendMsg( hwndCnr, CM_QUERYRECORD,
  2638.                                          MPFROMP( purChild ),
  2639.                                          MPFROM2SHORT( usChildCmd, CMA_ITEMORDER ));
  2640.        if( !purChild )
  2641.           break;
  2642.  
  2643.        DoWhatever( purChild );
  2644.        usChildCmd = CMA_NEXT;
  2645.     }
  2646.  
  2647.     usCmdParent = CMA_NEXT;
  2648.  }
  2649.  
  2650. Credit:  Rick Fishman 
  2651.  
  2652.  
  2653. ΓòÉΓòÉΓòÉ 8.4. I can't get different colors in text control windows ΓòÉΓòÉΓòÉ
  2654.  
  2655. I've finally got static text control windows (WS_STATIC, SS_TEXT) working with 
  2656. a different color pres. parameter set ! Thanks, Rick, Dan and Wayne. Code as 
  2657. follows: 
  2658.  
  2659.  RGB2 rgb2 ;   // RGB2 structure
  2660.  HWND hwnd ;   // window handle
  2661.  
  2662.  // Set RGB values for a SYSCLR_BACKGROUND (light gray) color
  2663.  rgb2.bred = 204 ;     // Found these in 'WinSetSysColors' API
  2664.  rgb2.bgreen = 204 ;
  2665.  rgb2.bblue = 204 ;
  2666.  rgb2.fcOptions = 0 ;
  2667.  // Set background color
  2668.  WinSetPresParam (hwnd, PP_BACKGROUNDCOLOR, (ULONG) sizeof (RGB2),
  2669.                   &rgb2) ;
  2670.  // Set RGB values for black
  2671.  rgb2.bred = 0 ;
  2672.  rgb2.bgreen = 0 ;
  2673.  rgb2.bblue = 0 ;
  2674.  rgb2.fcOptions = 0 ;
  2675.  // Set text foreground color
  2676.  WinSetPresParam (hwnd, PP_FOREGROUNDCOLOR, (ULONG) sizeof (RGB2),
  2677.                   &rgb2) ;
  2678.  // Set text border color (important for outline fonts)
  2679.  WinSetPresParam (hwnd, PP_BORDERCOLOR, (ULONG) sizeof (RGB2), &rgb2) ;
  2680.  
  2681. Three big caveats here: 
  2682.  
  2683.  1. The OS/2 internal code for static text control windows is *definitely* 
  2684.     using RGB colors, not index colors when it draws the text string. Thus, the 
  2685.     PP_*INDEX presentation parameter values will *not* work. 
  2686.  2. You *must* use a set of colors that are already loaded in the color table. 
  2687.     If the RGB color is not found, the background will be dithered affecting 
  2688.     the text appearance (washed out). If you are not sure the RGB color is 
  2689.     loaded do a GpiQueryNearestColor to get the nearest color. 
  2690.  3. You *must* use the RGB2 structure and *not* the RGB structure. This is 
  2691.     *NOT* documented, but it appears in general that all OS/2 2.0 APIs should 
  2692.     use RGB2 *instead* of RGB. 
  2693.  
  2694. Credit:  Bill Kenning 
  2695.  
  2696.  
  2697. ΓòÉΓòÉΓòÉ 8.5. How can I toggle my titlebar on and off? ΓòÉΓòÉΓòÉ
  2698.  
  2699. Basically, move frame window controls from being children of the frame to being 
  2700. children of the background HWND_OBJECT.  You can then reverse the process to 
  2701. bring them back into view.  Following function implements this code. 
  2702.  
  2703. /* --------------------------------------------------------------
  2704. -- Function:  ToggleFrame
  2705. --
  2706. -- Description:  Toggles frame control visible/invisible
  2707. --
  2708. -- Notes: Code stolen from someone who stole it from an MS sample
  2709. ----------------------------------------------------------------- */
  2710. void ToggleFrame(HWND hwndFrame) {
  2711.  
  2712.  if (! Hidden) {     /* hide contorls */
  2713.     hwndTitle = WinWindowFromID( hwndFrame, FID_TITLEBAR );
  2714.     hwndSys   = WinWindowFromID( hwndFrame, FID_SYSMENU );
  2715.         ... repeat for FID_MINMAX, etc ...
  2716.     WinSetParent(hwndTitle, HWND_OBJECT, FALSE );
  2717.     WinSetParent(hwndSys,   HWND_OBJECT, FALSE );
  2718.         ... repeat for FID_MINMAX, etc ...
  2719.  }
  2720.  else { /* restore controls */
  2721.     WinSetParent( hwndTitle, hwndFrame, FALSE );
  2722.     WinSetParent( hwndSys, hwndFrame, FALSE );
  2723.         ... basically reverse of above ...
  2724.  }
  2725.  WinSendMsg( hwndFrame, WM_UPDATEFRAME,
  2726.       (MPARAM)(FCF_TITLEBAR | FCF_SYSMENU | ...), NULL);
  2727.  SizeTheWindow( hwndFrame );
  2728.  Hidden = ! Hidden;
  2729.  return;
  2730. }
  2731.  
  2732. Credit:  Mike Thompson 
  2733.  
  2734.  
  2735. ΓòÉΓòÉΓòÉ 8.6. How can I get transparent regions in bitmaps? ΓòÉΓòÉΓòÉ
  2736.  
  2737. Currently, you can get the same effect with PM if you use the method used with 
  2738. icons: 
  2739.  
  2740.  1. Use a monochrome mask to prep the destination area. The mask would define 
  2741.     which areas would be transparent and which would show the bitmap. The bits 
  2742.     would be defined as 1=transparent,0=bitmap. You would blit the mask to the 
  2743.     destination using ROP_SRCAND. This would blacken out the area that would 
  2744.     display the non-transparent bits of the bitmap. 
  2745.  2. Now blit the bitmap to the destination using ROP_SRCPAINT. Note that the 
  2746.     "transparent" areas of the bitmap must have the color black (i.e. bits=0). 
  2747.     This ORs the bitmap onto the prep area. Viola - "transparent" bitmap. 
  2748.  
  2749. Credit:  John Webb 
  2750.  
  2751.  
  2752. ΓòÉΓòÉΓòÉ 8.7. How do I create a status bar at the bottom of my window? ΓòÉΓòÉΓòÉ
  2753.  
  2754. You need to intercept several frame messages: 
  2755.  
  2756. WM_CALCFRAMERECT to calculate the new location of the client.  You should send 
  2757. it to the frame superclass then modify the result.  This message is invoked 
  2758. during frame formatting and whenever WinCalcFrameRect is called against your 
  2759. frame window handle. 
  2760.  
  2761. WM_FRAMECTLCOUNT to tell the frame superclass the number of frame controls you 
  2762. expect to format.  If you're adding a status line as a child of the frame 
  2763. (below the client, I suspect), you would add 1 to the result returned by your 
  2764. frame superclass. 
  2765.  
  2766. WM_FORMATFRAME is where you actually position/size the frame controls. The 
  2767. message gives you an array of SWP's.  Call your frame superclass and modify the 
  2768. result (in your case, I would expect only FID_CLIENT and your status line). 
  2769.  
  2770. Sample follows... 
  2771.  
  2772.     /*
  2773.      * FYI, WinDefFrameProc is just a macro I defined to
  2774.      * call my superclass frame window procedure, ie,
  2775.      *    (*vpfnFrameWndProc) (h,m,p1,p2).
  2776.      *
  2777.      * This example splits the client area space 1/3
  2778.      * and 2/3 horizontally with the old client area
  2779.      * and a new sibling.
  2780.      */
  2781.  
  2782.     case WM_CALCFRAMERECT:
  2783.       mr = WinDefFrameProc(hwnd, msg, mp1, mp2);
  2784.  
  2785.       /*
  2786.        * Calculate the position of the client rectangle
  2787.        * Otherwise,  we'll see a lot of redraw when we move the
  2788.        * client during WM_FORMATFRAME.
  2789.        */
  2790.  
  2791.       if (mr && mp2)
  2792.       {
  2793.          prectl = (PRECTL) mp1;
  2794.          prectl->xLeft += ((prectl->xRight - prectl->xLeft) / 3);
  2795.       }
  2796.       break;
  2797.  
  2798.     case WM_FORMATFRAME:
  2799.       sCount = (SHORT) WinDefFrameProc(hwnd, msg, mp1, mp2);
  2800.  
  2801.       /*
  2802.        * Reformat the frame to move the client
  2803.        * over and make room for the his/her sibling.
  2804.        */
  2805.  
  2806.       pswp = (PSWP) mp1;
  2807.       pswpClient = pswp + sCount - 1;
  2808.       pswpNew = pswpClient + 1;
  2809.  
  2810.       *pswpNew = *pswpClient;
  2811.       swpClient = *pswpClient;
  2812.  
  2813.       pswpNew->hwnd = WinWindowFromID(hwnd, ID_SIBLING);
  2814.       pswpNew->cx = pswpClient->cx / 3;
  2815.  
  2816.       pswpClient->x = pswpNew->x + pswpNew->cx - 1;
  2817.       pswpClient->cx = swpClient.cx - pswpNew->cx + 1;
  2818.  
  2819.       sCount++;
  2820.       mr = MRFROMSHORT(sCount);
  2821.       break;
  2822.  
  2823.     case WM_QUERYFRAMECTLCOUNT:
  2824.       sCount = (SHORT) WinDefFrameProc(hwnd, msg, mp1, mp2);
  2825.       sCount++;
  2826.       mr = MRFROMSHORT(sCount);
  2827.       break;
  2828.  
  2829. Credit:  Dan Kehn 
  2830.  
  2831.  
  2832. ΓòÉΓòÉΓòÉ 8.8. How to have a frame/client and still have a std window? ΓòÉΓòÉΓòÉ
  2833.  
  2834.  FRAMECDATA fcdata;
  2835.  
  2836.  fcdata.cb          = sizeof( FRAMECDATA );
  2837.  fcdata.flCreateFlags = FCF_TASKLIST | FCF_MENU, etc.;
  2838.  fcdata.hmodResources = 0; // or the hmod of the DLL containing the resources
  2839.  fcdata.idResources   = ID_RESOURCES;  // ID of the resources, as usual
  2840.  
  2841.  hwndFrame = WinCreateWindow( HWND_DESKTOP, WC_FRAME, NULL, 0, 0, 0, 0, 0,
  2842.                               NULLHANDLE, HWND_TOP, ID_RESOURCES,
  2843.                               &fcdata, NULL);
  2844.  
  2845.  hwndClient = WinCreateWindow( hwndFrame, szClientClass, NULL, 0, 0, 0, 0, 0,
  2846.                                NULLHANDLE, HWND_TOP, FID_CLIENT, NULL, NULL );
  2847.  
  2848.  WinSetWindowPos( hwndFrame, HWND_TOP, x, y, cx, cy,
  2849.                   SWP_ZORDER | SWP_SIZE | SWP_MOVE |
  2850.                   SWP_SHOW | SWP_ACTIVATE );
  2851.  
  2852. If you want to then add new controls, like the system menu, you would do this: 
  2853.  
  2854.  fcdata.flCreateFlags = FCF_SYSMENU;
  2855.  WinCreateFrameControls( hwndFrame, &fcdata, NULL );
  2856.  WinSendMsg( hwndFrame, WM_UPDATEFRAME,
  2857.              MPFROMLONG( FCF_SYSMENU ), NULL );
  2858.  
  2859. The same thing applies to all the other controls like FCF_SIZEBORDER, 
  2860. FCF_TITLEBAR, FCF_HORZSCROLL, FCF_MINMAX, etc. You could also OR more than one 
  2861. together if you wanted to add more than one frame control in the same shot. On 
  2862. the titlebar, you need to also send this message: 
  2863.  
  2864.  WinSendMsg( WinWindowFromID( hwndFrame, FID_TITLEBAR ),
  2865.              TBM_SETHILITE, MPFROMSHORT( TRUE ), NULL );
  2866.  
  2867. If you want to delete frame controls, you would do this (assuming system menu): 
  2868.  
  2869.  WinDestroyWindow( WinWindowFromID( hwndFrame, FID_SYSMENU ) );
  2870.  WinSendMsg( hwndFrame, WM_UPDATEFRAME,
  2871.              MPFROMLONG( FCF_SYSMENU ), NULL );
  2872.  
  2873. Unfortunately this doesn't fit completely well with OOP, since the controls 
  2874. really are not themselves objects independent of the frame window. One of the 
  2875. problems here is that in order to make them independent objects, you need to 
  2876. know the internals of the frame window proc. For instance, you would think that 
  2877. the MIN and MAX are two WC_BUTTON controls, but they are really one menu with 
  2878. two bitmap menuitems (at least in 1.x they were). So if you were to do a 
  2879. WinCreateWindow for either, you'd have to know where to get the bitmaps, and 
  2880. hope that doesn't change. 
  2881.  
  2882. Similarly you'd have to be able to construct the system menu after creating a 
  2883. WC_MENU window. This isn't a tough feat, but if a later version of OS/2 adds a 
  2884. new menu item to the system menu, you'd have to become aware of it. 
  2885.  
  2886. The titlebar and the scrollbars aren't a problem since they have their own 
  2887. public window classes - WC_TITLEBAR and WC_SCROLLBAR respectively. You can, for 
  2888. instance, do a WinCreateWindow( ..., WC_SCROLLBAR,..., FID_HORZSCROLL, ..), 
  2889. then send the frame a WM_UPDATEFRAME message for FCF_HORZSCROLL and this would 
  2890. work. But there is no WC_SIZEBORDER so you couldn't use this method to add the 
  2891. sizing border later. So for the sizing border you need to use the method I 
  2892. first posted above. 
  2893.  
  2894. I spoke too soon about the sizing border. If you want to add or remove it from 
  2895. a frame window, you need to add or remove the FS_SIZEBORDER style from the 
  2896. frame, then send the frame an UPDATEFRAME message for FCF_SIZEBORDER. 
  2897.  
  2898. To change the style, here is a technique that John Webb just turned me on to. 
  2899. To add the style: 
  2900.  
  2901.  WinSetWindowBits( hwndFrame, QWL_STYLE, FS_SIZEBORDER, FS_SIZEBORDER );
  2902.  
  2903. To remove it: 
  2904.  
  2905.  WinSetWindowBits( hwndFrame QWL_STYLE, 0, FS_SIZEBORDER );
  2906.  
  2907. Also, if you want to add or remove just one of the MIN or the MAX, you 
  2908. basically need to get the window handle of the MINMAX menu, then do a 
  2909. MM_REMOVEITEM for the one you want to remove. I did this in 1.x but haven't yet 
  2910. in 2.0. 
  2911.  
  2912. Credit:  Rick Fishman 
  2913.  
  2914.  
  2915. ΓòÉΓòÉΓòÉ 8.9. How do I use printf() in a PM program? ΓòÉΓòÉΓòÉ
  2916.  
  2917. Use PMPRINTF, check your local BBS's, CIS, BIX or cdrom.com or redirect stdout 
  2918. and stderr to files. 
  2919.  
  2920.     // Redirect 'stderr'.
  2921.     (void) freopen ("stderr.txt", "w", stderr) ;
  2922.  
  2923.     // Redirect 'stdout'.
  2924.     (void) freopen ("stdout.txt", "w", stdout) ;
  2925.  
  2926.  
  2927. ΓòÉΓòÉΓòÉ 8.10. I have a SOM DLL. How do I register it? ΓòÉΓòÉΓòÉ
  2928.  
  2929. Here's an example I use for registering.  It checks if the DLL is valid before 
  2930. continuing: 
  2931.  
  2932. #define INCL_WPCLASS
  2933. #define INCL_WIN
  2934. #define INCL_DOS
  2935. #include <os2.h>
  2936. #include <string.h>
  2937. #include <stdio.h>
  2938.  
  2939. int main(int argc, char *argv[]) {
  2940.    HMQ hmq;
  2941.    HAB hab;
  2942.    CHAR szText[256];
  2943.    USHORT usResponse;
  2944.    CHAR szLoadError[128];
  2945.    HMODULE hmod;
  2946.    APIRET rc;
  2947.  
  2948.    if (argc != 3)
  2949.      return 0;
  2950.  
  2951.    hab = WinInitialize(0);
  2952.    hmq = WinCreateMsgQueue(hab, 0);
  2953.  
  2954.    WinDeregisterObjectClass(argv[1]);
  2955.  
  2956.    sprintf(szText, "Register %s DLL '%s'?", argv[1], argv[2]);
  2957.    usResponse = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szText,
  2958.       "Register WPS Class", 0, MB_YESNO | MB_MOVEABLE | MB_ICONQUESTION);
  2959.  
  2960.    if (usResponse != MBID_YES)
  2961.      return 0;
  2962.  
  2963.    rc = DosLoadModule(szLoadError, sizeof(szLoadError), argv[2], &hmod);
  2964.  
  2965.    if (rc != 0)
  2966.    {
  2967.      sprintf(szText, "Return code = %u, error module = '%s'.",
  2968.              rc, szLoadError);
  2969.      WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szText,
  2970.                    "DosLoadModule Failed", 0,
  2971.                    MB_ENTER | MB_MOVEABLE | MB_ERROR);
  2972.  
  2973.      return 0;
  2974.   }
  2975.  
  2976.  
  2977.   if (WinRegisterObjectClass(argv[1], argv[2]))
  2978.   {
  2979.     if (WinCreateObject(argv[1], argv[1], " ",
  2980.         "<WP_DESKTOP>", CO_REPLACEIFEXISTS))
  2981.       WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Created.",argv[1],
  2982.                     0, MB_ENTER | MB_MOVEABLE | MB_INFORMATION);
  2983.     else
  2984.     {
  2985.       DosFreeModule(hmod);
  2986.       WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Failed.",argv[1],
  2987.                     0,MB_ENTER | MB_MOVEABLE | MB_ERROR);
  2988.     }
  2989.   }
  2990.   else
  2991.   {
  2992.     DosFreeModule(hmod);
  2993.     WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Registration failed.",
  2994.                   argv[1], 0,MB_ENTER | MB_MOVEABLE | MB_ERROR);
  2995.   }
  2996.  
  2997.   return 0; }
  2998.  
  2999. FYI, when WPS registers your DLL with SOM, SOM checks if your DLL has a module 
  3000. entry point called SOMInitModule.  If it does, it is called (most use 
  3001. SOMInitModule for registering DLLs that have more than one class). Otherwise, 
  3002. it checks for YourClassNewClass, and tries to call it (where 'YourClass' is the 
  3003. parameter you specified on the WinRegisterObjectClass). SOM generates 
  3004. 'YourClassNewClass' in the .IH file; if you're still stuck, verify it is being 
  3005. called and that it doesn't fail (eg, because of version number check). 
  3006.  
  3007. I suggest registering with a full DLL filespec, eg, C:\MYSTUFF\MYCAR.DLL. Saves 
  3008. on the length of the LIBPATH. 
  3009.  
  3010. Credit:  Dan Kehn 
  3011.  
  3012.  
  3013. ΓòÉΓòÉΓòÉ 8.11. How do I save and restore my window size and position? ΓòÉΓòÉΓòÉ
  3014.  
  3015. Here is code I use to restore a saved window position, which includes checks to 
  3016. make sure the user hasn't saved a window position at one screen resolution and 
  3017. then restored it at a different screen resolution (which might cause the 
  3018. window's frame controls to be completely off the display -- we've all seen 
  3019. that, right???): 
  3020.  
  3021.  BOOL SetWindowPosition (const HAB hab, const HWND hwndFrame,
  3022.                          const SWP swpConfig)
  3023.  {
  3024.      SWP swp ;
  3025.      APIRET ulRC ;
  3026.  
  3027.      // Initialize the window positioning flags.
  3028.      swp.fl = SWP_ACTIVATE | SWP_MOVE | SWP_SIZE | SWP_SHOW ;
  3029.  
  3030.      /* Check for saved user preferences for screen width/height in
  3031.       * config file.  Did user want to start maximized?
  3032.       */
  3033.      if (swpConfig.fl & SWP_MAXIMIZE)
  3034.      {
  3035.          // Get maximized frame window position and size.
  3036.          ulRC = WinGetMaxPosition (hwndFrame, &swp) ;
  3037.          if (!ulRC)
  3038.          {
  3039.              // Report error, and then ...
  3040.              return TRUE ;
  3041.          }
  3042.          swp.fl |= SWP_MAXIMIZE ;
  3043.      }
  3044.  
  3045.      // Did user want to start minimized?
  3046.      else if (swpConfig.fl & SWP_MINIMIZE)
  3047.      {
  3048.          // Get minimized frame window position and size.
  3049.          ulRC = WinGetMinPosition (hwndFrame, &swp, (PPOINTL) NULL) ;
  3050.          if (!ulRC)
  3051.          {
  3052.              // Report error, and then ...
  3053.              return TRUE ;
  3054.          }
  3055.          swp.fl |= SWP_MINIMIZE ;
  3056.      }
  3057.  
  3058.      // Did user have a saved starting position and size?
  3059.      else if (swpConfig.cy || swpConfig.cx || swpConfig.x || swpConfig.y)
  3060.      {
  3061.          LONG cxClientMax ;
  3062.          LONG cyClientMax ;
  3063.          LONG cyTitleBar ;
  3064.          LONG cxSizeBorder ;
  3065.          LONG cySizeBorder ;
  3066.  
  3067.          // Get maximum client window size.
  3068.          cxClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CXFULLSCREEN) ;
  3069.          cyClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CYFULLSCREEN) ;
  3070.          cyTitleBar = WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR) ;
  3071.          cxSizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER) ;
  3072.          cySizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER) ;
  3073.  
  3074.          // Maximum client window size excludes title bar.
  3075.          cyClientMax += cyTitleBar ;
  3076.  
  3077.          // Make sure x origin is within display boundaries.
  3078.          swp.x = swpConfig.x ;
  3079.          if (swp.x < -cxSizeBorder)
  3080.              swp.x = 0 ;
  3081.  
  3082.          // Make sure window isn't too wide, or negative value.
  3083.          swp.cx = swpConfig.cx ;
  3084.          if (swp.cx >= cxClientMax || swp.cx < 0)
  3085.          {
  3086.              swp.cx = cxClientMax ;
  3087.              swp.x = 0 ;
  3088.          }
  3089.  
  3090.           if ((swp.x + swp.cx) > (cxClientMax + cxSizeBorder))
  3091.              swp.x = cxClientMax + cxSizeBorder - swp.cx ;
  3092.  
  3093.          // Make sure y origin is within display boundaries.
  3094.          swp.y = swpConfig.y ;
  3095.          if (swp.y < -cySizeBorder)
  3096.              swp.y = 0 ;
  3097.  
  3098.          // Make sure window isn't too high, or negative value.
  3099.          swp.cy = swpConfig.cy ;
  3100.          if (swp.cy > cyClientMax || swp.cy < 0)
  3101.          {
  3102.              swp.cy = cyClientMax ;
  3103.              swp.y = 0 ;
  3104.          }
  3105.  
  3106.          if ((swp.y + swp.cy) > (cyClientMax + cySizeBorder))
  3107.              swp.y = cyClientMax + cySizeBorder - swp.cy ;
  3108.      }
  3109.  
  3110.      // No saved position -- move window to FCF_SHELLPOSITION location.
  3111.      else
  3112.      {
  3113.          // Get default window size and position.
  3114.          ulRC = WinQueryTaskSizePos (hab, 0, &swp) ;
  3115.          if (ulRC)
  3116.          {
  3117.              // Report error, and then ...
  3118.              return TRUE ;
  3119.          }
  3120.          swp.fl = SWP_ACTIVATE | SWP_MOVE | SWP_SIZE | SWP_SHOW ;
  3121.      }
  3122.  
  3123.      // Position and size this frame window.
  3124.      ulRC = WinSetWindowPos (hwndFrame, HWND_TOP,
  3125.        swp.x, swp.y, swp.cx, swp.cy, swp.fl) ;
  3126.      if (!ulRC)
  3127.      {
  3128.          // Report error, and then ...
  3129.          return TRUE ;
  3130.      }
  3131.  
  3132.      return FALSE ;
  3133.  }
  3134.  
  3135. Credit:  Wayne Kovsky 
  3136.  
  3137.  
  3138. ΓòÉΓòÉΓòÉ 8.12. How do you make a window float above all others? ΓòÉΓòÉΓòÉ
  3139.  
  3140. Here's a sample program showing floating windows (derived from dvipm).  The 
  3141. advantages over the WM_TIMER approach [which was presented in v2.2 -ed] are: 
  3142.  
  3143. o there's no delay 
  3144. o repainting is minimized 
  3145. o avoids timing problems 
  3146. o the floating windows are not unconditionally moved to the very top (that is, 
  3147.   when moving the base window B (with floating window F) behind a window W, the 
  3148.   order of the windows is this: BFW, not BWF!) 
  3149.  
  3150. The excessive repainting caused by other solutions was quite annoying with 
  3151. dvipm as recomputing the dvipm status window is slow. 
  3152.  
  3153. Credit: Eberhard Mattes 
  3154.  
  3155. /* floatwin.c */
  3156.  
  3157. /* This program shows how to implement floating windows.  The source
  3158.    code works with both 16-bit and 32-bit C compilers.
  3159.  
  3160.    If the Z-order of the base window is changed, the floating window
  3161.    will be moved on top of the base window.
  3162.  
  3163.    Generalizing this approach to many windows floating on many windows
  3164.    (floating on many windows ...) is left as exercise. */
  3165.  
  3166. #define INCL_WIN
  3167. #define INCL_GPI
  3168. #include <os2.h>
  3169.  
  3170. /* Syntactic sugar for supporting both 16-bit and 32-bit compilers. */
  3171.  
  3172. #ifdef __32BIT__
  3173. #define MSG ULONG
  3174. #define FLAGS fl
  3175. #else
  3176. #define MSG USHORT
  3177. #define FLAGS fs
  3178. #endif
  3179. #ifndef NULLHANDLE
  3180. #define NULLHANDLE NULL
  3181. #endif
  3182.  
  3183. /* The original frame window procedure. */
  3184. static PFNWP pfOldBaseFrameProc = NULL;
  3185.  
  3186. /* The handle of the floating window. */
  3187. static HWND hwndFloat = NULLHANDLE;
  3188.  
  3189. /* This frame window procedure is used for subclassing base windows.
  3190.    When changing the Z-order of the frame window, the floating window
  3191.    is moved instead of the base window and the hwndInsertBehind field
  3192.    is modified to move the base window behind the floating window. */
  3193.  
  3194. MRESULT EXPENTRY
  3195. BaseFrameProc (HWND hwnd, MSG msg, MPARAM mp1, MPARAM mp2)
  3196. {
  3197.   PSWP pswp;
  3198.  
  3199.   switch (msg)
  3200.     {
  3201.     case WM_ADJUSTWINDOWPOS:
  3202.       pswp = PVOIDFROMMP (mp1);
  3203.       if ((pswp->FLAGS & SWP_ZORDER) && hwndFloat != NULLHANDLE
  3204.            && WinIsWindowVisible (hwndFloat))
  3205.         {
  3206.           WinSetWindowPos (hwndFloat, pswp->hwndInsertBehind,
  3207.                            0, 0, 0, 0, SWP_ZORDER);
  3208.           /* This is the trick! */
  3209.           pswp->hwndInsertBehind = hwndFloat;
  3210.         }
  3211.       break;
  3212.     }
  3213.   return pfOldBaseFrameProc (hwnd, msg, mp1, mp2);
  3214. }
  3215.  
  3216.  
  3217. /* Common client window procedure for base windows and floating
  3218.    windows.  Display TXT and use CLR for filling the background. */
  3219.  
  3220. MRESULT CommonClientWndProc (HWND hwnd, MSG msg, MPARAM mp1, MPARAM mp2,
  3221.                              PCH txt, COLOR clr)
  3222. {
  3223.   HPS hps;
  3224.   RECTL rcl;
  3225.  
  3226.   switch (msg)
  3227.     {
  3228.     case WM_PAINT:
  3229.       hps = WinBeginPaint (hwnd, 0L, 0L);
  3230.       WinQueryWindowRect (hwnd, &rcl);
  3231.       GpiSetColor (hps, CLR_DARKCYAN);
  3232.       GpiSetBackColor (hps, clr);
  3233.       WinDrawText (hps, -1, txt, &rcl, 0, 0,
  3234.                    DT_TEXTATTRS | DT_CENTER | DT_VCENTER | DT_ERASERECT);
  3235.       WinEndPaint (hps);
  3236.       return 0;
  3237.     }
  3238.   return WinDefWindowProc (hwnd, msg, mp1, mp2);
  3239. }
  3240.  
  3241.  
  3242. /* Client window procedure for floating windows. */
  3243.  
  3244. MRESULT EXPENTRY FloatClientWndProc (HWND hwnd, MSG msg, MPARAM mp1, MPARAM mp2)
  3245. {
  3246.   return CommonClientWndProc (hwnd, msg, mp1, mp2, "Floating Window", CLR_RED);
  3247. }
  3248.  
  3249. /* Client window procedure for base windows. */
  3250.  
  3251. MRESULT EXPENTRY BaseClientWndProc (HWND hwnd, MSG msg, MPARAM mp1, MPARAM mp2)
  3252. {
  3253.   return CommonClientWndProc (hwnd, msg, mp1, mp2, "Base Window", CLR_YELLOW);
  3254. }
  3255.  
  3256.  
  3257. /* Start here. */
  3258.  
  3259. int main (void)
  3260. {
  3261.   static char szBaseClientClass[] = "floatwin.base";
  3262.   static char szFloatClientClass[] = "floatwin.float";
  3263.   ULONG flFrameFlags;
  3264.   HAB hab;
  3265.   HMQ hmq;
  3266.   QMSG qmsg;
  3267.   HWND hwndBase;
  3268.  
  3269.   /* Initialize Presentation Manager. */
  3270.  
  3271.   hab = WinInitialize (0);
  3272.   hmq = WinCreateMsgQueue (hab, 0);
  3273.  
  3274.   /* Create client window classes. */
  3275.  
  3276.   WinRegisterClass (hab, szBaseClientClass, BaseClientWndProc,
  3277.                     CS_SIZEREDRAW, 0);
  3278.   WinRegisterClass (hab, szFloatClientClass, FloatClientWndProc,
  3279.                     CS_SIZEREDRAW, 0);
  3280.  
  3281.   /* Create the base window and the floating window.  Note: the
  3282.      windows are initially invisible. */
  3283.  
  3284.   flFrameFlags = (FCF_TITLEBAR      | FCF_SYSMENU |
  3285.                   FCF_SIZEBORDER    | FCF_MINMAX  |
  3286.                   FCF_TASKLIST);
  3287.  
  3288.   /* Create and subclass the base window. */
  3289.  
  3290.   hwndBase = WinCreateStdWindow (HWND_DESKTOP, 0,
  3291.                                  &flFrameFlags, szBaseClientClass,
  3292.                                  "floatwin - Base Window",
  3293.                                  0L, 0, 1, NULL);
  3294.   pfOldBaseFrameProc = WinSubclassWindow (hwndBase, BaseFrameProc);
  3295.  
  3296.   /* Create the floating window. */
  3297.  
  3298.   hwndFloat = WinCreateStdWindow (HWND_DESKTOP, 0,
  3299.                                   &flFrameFlags, szFloatClientClass,
  3300.                                   "floatwin - Floating Window",
  3301.                                   0L, 0, 1, NULL);
  3302.  
  3303.   /* Set the position, size and Z-order of the windows and make them
  3304.      visible.  It's important to use SWP_ZORDER for the base
  3305.      window. */
  3306.  
  3307.   WinSetWindowPos (hwndFloat, HWND_TOP, 10, 10, 300, 80,
  3308.                    SWP_SHOW | SWP_MOVE | SWP_SIZE | SWP_ZORDER);
  3309.   WinSetWindowPos (hwndBase, HWND_TOP, 100, 50, 300, 80,
  3310.                    SWP_SHOW | SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_ACTIVATE);
  3311.  
  3312.   /* The message loop. */
  3313.  
  3314.   while (WinGetMsg (hab, &qmsg, 0L, 0, 0))
  3315.     WinDispatchMsg (hab, &qmsg);
  3316.  
  3317.   /* Clean up. */
  3318.  
  3319.   WinDestroyWindow (hwndBase);
  3320.   WinDestroyWindow (hwndFloat);
  3321.   WinDestroyMsgQueue (hmq);
  3322.   WinTerminate (hab);
  3323.  
  3324.   return 0;
  3325. }
  3326.  
  3327.  
  3328. ΓòÉΓòÉΓòÉ 8.13. How to ensure the sizing's correct so the dlg "fits" in the notebook...? ΓòÉΓòÉΓòÉ
  3329.  
  3330. Override wpclsQuerySettingsPageSize (or some such verbage, I don't have docs at 
  3331. home).  I don't know if this API made it into the on-line docs, but it is 
  3332. definitely public (see \TOOLKT20\C\OS2H\WPOBJECT.H). There you are given the 
  3333. opportunity to adjust the size up to accomodate your dialog, if necessary. 
  3334.  
  3335. The PAGEINFO structure is used by the Settings page code to delay the loading 
  3336. of the dialog required for a page until the user turns to it for the first 
  3337. time.  It has the resource ID, module handle (which is incorrectly named in the 
  3338. structure, 'resid' or some nonsense, grr-r), dialog procedure, and pointer of 
  3339. your choice to receive on WM_INITDLG (most choose the object pointer, somSelf). 
  3340. When the user selects the notebook tab, WPS calls WinLoadDlg based on the 
  3341. parameters in PAGEINFO. 
  3342.  
  3343.  
  3344. ΓòÉΓòÉΓòÉ 8.14. How do I prevent Shutdown from stopping my app? ΓòÉΓòÉΓòÉ
  3345.  
  3346. In our application, the WM_CLOSE message processor determines the state of the 
  3347. application, issues all the "Are you sure?" questions, etc. If the close is to 
  3348. be continued, a WM_QUIT message is posted and a value of FALSE is returned. 
  3349. Otherwise a value of TRUE is returned. 
  3350.  
  3351. The window receiving the WMU_EndTask message handles it by posting a WM_CLOSE 
  3352. message to itself, and letting the WM_CLOSE processing handle it. The only 
  3353. reason it is not translated to a WM_CLOSE within the message loop is allow 
  3354. future use. This message requires no special handling. 
  3355.  
  3356. The window receiving the WMU_ShutDown message handles it by sending (not 
  3357. posting) a WM_CLOSE message to itself. If the WM_CLOSE message returns TRUE, 
  3358. then a WinCancelShutdown (hmq, FALSE) call is issued to cancel this instance of 
  3359. the shutdown. 
  3360.  
  3361. If you issue a WinCancelShutdown (hmq, TRUE), a WM_QUIT message will never be 
  3362. sent to your message queue, so will not have an opportunity to stop the 
  3363. shutdown.  This is intended for secondary message queues that do not have a 
  3364. message loop. 
  3365.  
  3366.   while (1) {
  3367.  
  3368.     HWND hwndClient;
  3369.  
  3370.     // Get next message from queue
  3371.     if (!WinGetMsg (hab, &qmsg, NULLHANDLE, 0, 0)) {
  3372.  
  3373.       // The WM_QUIT message has three sources:
  3374.       //   1. The task manager 'End task' pulldown
  3375.       //   2. System shutdown from desktop manager
  3376.       //   3. Posted by the application
  3377.  
  3378.       // This is a WM_QUIT message.  Check the window handle, if the
  3379.       // handle matches mp2, it is from switch list close
  3380.       if (qmsg.hwnd == HWNDFROMMP (qmsg.mp2)) {
  3381.  
  3382.         // This is from close on the task list, convert to our message
  3383.         qmsg.msg = WMU_EndTask;
  3384.  
  3385.         // Get the intended client's window handle
  3386.         if (!(hwndClient = WinWindowFromID (qmsg.hwnd, FID_CLIENT))) {
  3387.  
  3388.           // Failed to find client. No idea who this belongs to,
  3389.           // give it to default window for processing
  3390.           hwndClient = hwndDefault
  3391.         }
  3392.  
  3393.         // Otherwise, readdress the message to the appropriate client
  3394.         qmsg.hwnd = hwndClient;
  3395.  
  3396.         // We can use mp1 and mp2 for anything we want.
  3397.         // Currently, just clear both
  3398.         qmsg.mp1  = qmsg.mp2 = 0L;
  3399.  
  3400.       } else if (qmsg.hwnd == NULLHANDLE) {
  3401.  
  3402.         // This message is from shutdown,
  3403.         // Address it to default window for processing
  3404.         qmsg.hwnd = hwndDefault;
  3405.  
  3406.         // And set the message to our shutdown message,
  3407.         qmsg.msg = WMU_SysShutdown;
  3408.  
  3409.       } else {
  3410.  
  3411.         // If here, we posted the WM_QUIT message, so break out of
  3412.         // the message loop
  3413.         break;
  3414.       }
  3415.     }
  3416.  
  3417.     // This is not a WM_QUIT message, intercept all other
  3418.     // messages intended for the NULL window
  3419.     if (qmsg.hwnd == NULLHANDLE) {
  3420.  
  3421.       // Pass all NULL window messages to the NULL window handler
  3422.       NullMsg (qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
  3423.  
  3424.     } else {
  3425.  
  3426.       // This is not a WM_QUIT message, nor is it intended for the NULL
  3427.       // window.  Pass this message to the message filter hook for
  3428.       // processing.
  3429.       if (!WinCallMsgFilter (hab, (PQMSG) &qmsg, 0)) {
  3430.  
  3431.         // Filter hook has not cancelled the message, so dispatch
  3432.         // the message to the proper window
  3433.         WinDispatchMsg (hab, &qmsg);
  3434.       }
  3435.     }
  3436.   }
  3437.  
  3438. Credit:  Matt Osborn 
  3439.  
  3440.  
  3441. ΓòÉΓòÉΓòÉ 8.15. When I pass a structure to WinCreateWindow, sometimes it doesn't work! ΓòÉΓòÉΓòÉ
  3442.  
  3443. Put the size of the structure as the first word. 
  3444.  
  3445.  
  3446. ΓòÉΓòÉΓòÉ 8.16. How do I use type filtering in 2.0's open dlg? ΓòÉΓòÉΓòÉ
  3447.  
  3448. It's broken in 2.0GA, fixed in 2.0's service pak. 
  3449.  
  3450.  
  3451. ΓòÉΓòÉΓòÉ 8.17. When minimizing, my dialog box is overwriting my icon! ΓòÉΓòÉΓòÉ
  3452.  
  3453. In the WM_MINMAXFRAME message hide the offending control. 
  3454.  
  3455.     case WM_MINMAXFRAME:
  3456.       {
  3457.         PSWP pswp; /* pos change structure */
  3458.  
  3459.         /* hide list box when minimized so it doesn't overwrite icon */
  3460.         pswp = PVOIDFROMMP( mp1 );
  3461.         WinShowWindow(
  3462.           WinWindowFromID( hwnd, IDD_FILES ),
  3463.           !(pswp->fs & SWP_MINIMIZE)
  3464.         );
  3465.       }
  3466.       break;
  3467.  
  3468.  
  3469. ΓòÉΓòÉΓòÉ 8.18. How do I make a multi-column listbox? ΓòÉΓòÉΓòÉ
  3470.  
  3471. Use the container in details view.  If you just have to use a list box: 
  3472.  
  3473. Here is an extract from my dialog box procedure that produces a two-column list 
  3474. box. 
  3475.  
  3476. In this example there is only one list box, so I don't have to worry about 
  3477. which control is involved.  In this example, a blank is used to separate the 
  3478. first and second column.  You could use tabs or any other sort of separator 
  3479. character.  You could also draw anything you wanted in the list box item, 
  3480. including bit maps, colors, other fonts, etc. 
  3481.  
  3482. This is not a complete program, of course, but does show the details of 
  3483. handling a multi-column list box. 
  3484.  
  3485. /******************** Dialog Box Procedure ******************************/
  3486.  
  3487. MRESULT EXPENTRY SelectDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  3488. {
  3489.     HPS     hPS;                 /* Handle to the presentation space */
  3490.     FONTMETRICS FontMetrics;     /* Metrics of default font */
  3491.     CHAR    pszItemText[MAX_ITEM_TEXT_LENGTH];
  3492.     CHAR    *s;
  3493.     OWNERITEM FAR *poi;          /* Pointer to owner item structure */
  3494.     RECTL   rcl;                 /* Rectangle for writing */
  3495.     COLOR   clrForeGround;
  3496.     COLOR   clrBackGround;
  3497.  
  3498.     switch (msg)
  3499.         {
  3500.         case WM_INITDLG:   /* Initialize the list box */
  3501.  
  3502.             FillCfgListBox (hwnd);     /* Fill the list box */
  3503.  
  3504.             return (FALSE);
  3505.  
  3506.  
  3507.         case WM_MEASUREITEM:     /* Measure text height */
  3508.  
  3509.             hPS = WinGetPS (hwnd);     /* Get handle to presentation space */
  3510.             GpiQueryFontMetrics (hPS, (LONG) sizeof (FONTMETRICS),
  3511.                                  &FontMetrics);
  3512.             WinReleasePS (hPS);        /* Release the presentation space */
  3513.  
  3514.             return (FontMetrics.lMaxBaselineExt);
  3515.  
  3516.  
  3517.         case WM_DRAWITEM:      /* Draw a list box entry */
  3518.  
  3519.             poi = mp2;               /* Get address of owner item */
  3520.  
  3521.             if (poi->fsState == TRUE)  /* Is this cell to be highlighted? */
  3522.             {                          /* Yes, use highlight attributes */
  3523.                 clrForeGround = SYSCLR_HILITEFOREGROUND;
  3524.                 clrBackGround = SYSCLR_HILITEBACKGROUND;
  3525.             }
  3526.             else                       /* No, use normal attributes */
  3527.             {
  3528.                 clrForeGround = CLR_NEUTRAL;
  3529.                 clrBackGround = CLR_BACKGROUND;
  3530.             }
  3531.  
  3532.             WinSendMsg (poi->hwnd,     /* Get item text */
  3533.                         LM_QUERYITEMTEXT,
  3534.                         (MPARAM) MAKEULONG (poi->idItem,
  3535.                         MAX_ITEM_TEXT_LENGTH),
  3536.                         (MPARAM) pszItemText);
  3537.  
  3538.             rcl.xLeft    = poi->rclItem.xLeft;  /* Set co-ordinates */
  3539.             rcl.xRight    = poi->rclItem.xRight; /* of rectangle */
  3540.             rcl.yTop    = poi->rclItem.yTop;
  3541.             rcl.yBottom = poi->rclItem.yBottom;
  3542.  
  3543.             s = strchr (pszItemText, ' ');  /* Find first blank */
  3544.             if (s)
  3545.               *s = '\0';               /* Terminate first column here */
  3546.  
  3547.             WinDrawText (poi->hps,     /* Draw the first column */
  3548.                          -1,           /* Null-terminated string */
  3549.                          pszItemText,  /* File name is here */
  3550.                          &rcl,     /* Rectangle to draw in */
  3551.                          clrForeGround,/* Foreground color */
  3552.                          clrBackGround,/* Background color */
  3553.                          DT_LEFT | DT_VCENTER | DT_ERASERECT);
  3554.  
  3555.             if (s)               /* If there is a second column */
  3556.             {
  3557.               rcl.xLeft = 100;         /* It starts out here */
  3558.                                        /* Spacing calculations could be */
  3559.                                        /* much cleverer than this very */
  3560.                                        /* crude use of an absolute position */
  3561.                                        /* (which is not transportable */
  3562.                                        /* to different display types, as */
  3563.                                        /* between 8514 and VGA) */
  3564.                 s++;                   /* Point to beginning of text */
  3565.                 WinDrawText (poi->hps, /* Draw the second column */
  3566.                              -1,       /* Also a null-terminated string */
  3567.                              s,        /* File Description */
  3568.                              &rcl, /* Rectangle to draw in */
  3569.                              clrForeGround,  /* Colors are same as */
  3570.                              clrBackGround,  /* before */
  3571.                              DT_LEFT | DT_VCENTER);
  3572.             }
  3573.  
  3574.                 /* If fsState || fsStateOld and return TRUE, then */
  3575.                 /* control will invert the rectangle -- not what */
  3576.                 /* we want.  Tell control not do do anything like that! */
  3577.  
  3578.             poi->fsState = poi->fsStateOld = FALSE;
  3579.  
  3580.             return (TRUE); /* Say we did it */
  3581.  
  3582. ... case statements for rest of program ...
  3583.  
  3584. Credit:  Guy Scharf 
  3585.  
  3586.  
  3587. ΓòÉΓòÉΓòÉ 8.19. How do I create my own Master Help Index? ΓòÉΓòÉΓòÉ
  3588.  
  3589. I talked with the owner of the Master Index, and she said there is no problem 
  3590. with using a like index to view online documentation for your application. 
  3591. There are just a few catches: 
  3592.  
  3593.  1. The documentation must be compiled as an .HLP file and not an .INF file. 
  3594.     Note that this is the default for IPFC. 
  3595.  
  3596.  2. The tagged indexed entries must have the "global" attribute. For example: 
  3597.  
  3598.    :i1 global.giving examples 
  3599.  
  3600.    or: 
  3601.  
  3602.    :i1 id=examp global.giving examples 
  3603.  
  3604.  3. The Index executable is a WPS object, not a standalone application. You 
  3605.     will need to create your own copy of the object (instance) of class Mindex, 
  3606.     either by using a REXX script  (e.g. SysCreateObject()) or within your app 
  3607.     (e.g. WinCreateObject()). 
  3608.  
  3609.     For a REXX example: 
  3610.  
  3611.             CALL   SysCreateObject  "Mindex", "Title", "<WP_DESKTOP>",
  3612.                                     "INDEX=MYFILE;OBJECTID=<MY_INDEX>"
  3613.  
  3614.     where MYFILE can be an environmental variable set to the path or filespec 
  3615.     of your .HLP files, or it can be the actual filespec itself (e.g. 
  3616.     INDEX=c:\myapp\myfile.hlp ). Note too that files can be concatenated (e.g. 
  3617.     INDEX=c:\myapp\myfile.hlp+c:\yourapp\yourfile.hlp). 
  3618.  
  3619.  4. Objects of Mindex class CAN NOT be subclassed. There are no public methods 
  3620.     in this class and it must be used as is. 
  3621.  
  3622. Credit:  John Webb 
  3623.  
  3624.  
  3625. ΓòÉΓòÉΓòÉ 8.20. How do I change the font in an MLE? ΓòÉΓòÉΓòÉ
  3626.  
  3627. How do I change the font in an MLE?  WinSetPresParms doesn't work. 
  3628.  
  3629. This is a function I used in 1.x to set the font for an MLE (haven't ported it 
  3630. yet but it should be the same). I pass it the parent hwnd of the MLE, the MLE's 
  3631. id, a facename, a pointsize, the maximum height for an outline font, and 
  3632. fsSelection (FATTR_SEL_BOLD, etc). It first tries to match on pointsize and 
  3633. facename. If it can't it uses an outline font with the height requested. 
  3634.  
  3635.  VOID EXPENTRY UtlSetMleFont( HWND hwndParent, USHORT usMleId, PSZ szFacename,
  3636.                               USHORT usPointSize, LONG lMaxHeight,
  3637.                               USHORT fsSelection )
  3638.  {
  3639.      PFONTMETRICS pfm;
  3640.      HDC          hdc;
  3641.      HPS          hps;
  3642.      HWND         hwndMle;
  3643.      LONG         lHorzRes, lVertRes, lRequestFonts = 0, lNumberFonts;
  3644.      FATTRS       fat;
  3645.      SHORT        sOutlineIndex = -1;
  3646.      INT          i;
  3647.  
  3648.      (void) memset( &fat, 0, sizeof( FATTRS ) );
  3649.      fat.usRecordLength  = sizeof( FATTRS );
  3650.      fat.fsSelection     = fsSelection;
  3651.      strcpy( fat.szFacename, szFacename );
  3652.      hwndMle = WinWindowFromID( hwndParent, usMleId );
  3653.      hps = WinGetPS( hwndMle );
  3654.      hdc = GpiQueryDevice( hps );
  3655.      DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1L, &lHorzRes );
  3656.      DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES,   1L, &lVertRes );
  3657.      lNumberFonts = GpiQueryFonts( hps, QF_PUBLIC, szFacename,
  3658.                                    &lRequestFonts, 0L, NULL);
  3659.      pfm = malloc( (SHORT) lNumberFonts * sizeof( FONTMETRICS ) );
  3660.      GpiQueryFonts( hps, QF_PUBLIC, szFacename,
  3661.                     &lNumberFonts, (LONG) sizeof( FONTMETRICS ), pfm );
  3662.      for( i = 0; i < (USHORT) lNumberFonts; i++ )
  3663.      {
  3664.          if( pfm[ i ].fsDefn & 1 )
  3665.          {
  3666.              sOutlineIndex = (SHORT) i;
  3667.              continue;
  3668.          }
  3669.  
  3670.          if (pfm[ i ].sXDeviceRes == (SHORT) lHorzRes &&
  3671.              pfm[ i ].sYDeviceRes == (SHORT) lVertRes &&
  3672.              pfm[ i ].sNominalPointSize == (SHORT) (usPointSize * 10) )
  3673.          {
  3674.              fat.lMatch          = pfm[ i ].lMatch;
  3675.              fat.lMaxBaselineExt = pfm[ i ].lMaxBaselineExt;
  3676.              fat.lAveCharWidth   = pfm[ i ].lAveCharWidth;
  3677.              break;
  3678.          }
  3679.      }
  3680.  
  3681.      if( i >= (USHORT) lNumberFonts )
  3682.          if( sOutlineIndex >= 0 )
  3683.              if( lMaxHeight )
  3684.              {
  3685.                  fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
  3686.                  if( !(fat.usCodePage = pfm[ sOutlineIndex ].usCodePage) )
  3687.                      fat.usCodePage  = 850;
  3688.                  fat.lMaxBaselineExt = lMaxHeight;
  3689.                  WinSendMsg( hwndMle, MLM_SETFONT, MPFROMP( &fat ), 0 );
  3690.              }
  3691.      WinSendMsg( hwndMle, MLM_SETFONT, MPFROMP( &fat ), 0 );
  3692.      WinReleasePS( hps );
  3693.      free( pfm );
  3694.  }
  3695.  
  3696. Credit:  Rick Fishman 
  3697.  
  3698.  
  3699. ΓòÉΓòÉΓòÉ 8.21. Why can't I import files larger than 64KB into my MLE? ΓòÉΓòÉΓòÉ
  3700.  
  3701. A MLE can not import or export text in bigger chunks than 64K. The below code 
  3702. shows how to solve this. 
  3703.  
  3704. void Editor::impTxt(const char *filename)
  3705. {
  3706.   FILE *ptr;
  3707.   long dummy=-1;
  3708.   long result;
  3709.  
  3710.   ptr = fopen(filename,"rb");
  3711.   fseek(ptr,0,SEEK_END);
  3712.   unsigned long size = ftell(ptr);
  3713.  
  3714.   fseek(ptr,0,SEEK_SET);
  3715.   void *buf = malloc(0xF000);
  3716.  
  3717.   mle->sendEvent(MLM_SETIMPORTEXPORT, buf, (unsigned long)  0xF000);
  3718.  
  3719.   mle->sendEvent(MLM_FORMAT, MLFIE_CFTEXT, NULL);
  3720.  
  3721.   while (feof(ptr) == 0) {
  3722.     result = fread(buf, 1, 0xE000, ptr);
  3723.     mle->sendEvent(MLM_IMPORT, &dummy, result);
  3724.   }
  3725.   fclose(ptr);
  3726.   free(buf);
  3727. }
  3728.  
  3729. The same applies to export. If the MLE contains >64K text you have to export 
  3730. the text in chunks like this: 
  3731.  
  3732. void Editor::saveFile(void)
  3733. {
  3734.   IString filename;
  3735.   IEventData rc;
  3736.   IFileDialog::Settings settings;
  3737.  
  3738.   settings.setTitle("Save textfile");
  3739.   settings.setFileName(fname);
  3740.   settings.setOKButtonText("Save file");
  3741.   settings.setSaveAsDialog();
  3742.  
  3743.   IFileDialog file(desktopWindow(),this,settings,
  3744.                    IFileDialog::defaultStyle()
  3745.                    | IFileDialog::selectableListbox);
  3746.   if (file.pressedOK() == false)
  3747.     return ;
  3748.   filename = file.fileName();
  3749.   if (filename.size() == 0)
  3750.     return;
  3751.   mle->exportToFile(filename);
  3752.  
  3753.   void *buf = malloc(0xF000);
  3754.   long ppt=0;
  3755.  
  3756.   mle->sendEvent(MLM_SETIMPORTEXPORT, buf, (unsigned long)  0xF000);
  3757.  
  3758.   mle->sendEvent(MLM_FORMAT, MLFIE_NOTRANS, NULL);
  3759.   ofstream fil(filename);
  3760.  
  3761.   do
  3762.     {
  3763.       long amount = 0xE000;
  3764.       rc = mle->sendEvent(MLM_EXPORT, &ppt, &amount);
  3765.       fil.write((char *) buf, rc.asUnsignedLong());
  3766.     } while (rc.asUnsignedLong() > 0);
  3767. }
  3768.  
  3769. Credit: Ivar E. Hosteng 
  3770.  
  3771.  
  3772. ΓòÉΓòÉΓòÉ 8.22. How do I get PM screen size? ΓòÉΓòÉΓòÉ
  3773.  
  3774. By calling the function WinQuerySysValue() with the tags; SV_CYSCREEN and 
  3775. SV_CXSCREEN. One should always check screen size before creating windows in PM, 
  3776. and size to the right it width and height. PM does not guarantee that your 
  3777. window will be dimensioned right. Below is an example: 
  3778.  
  3779.         .
  3780.         .
  3781.         .
  3782.  
  3783.     lHeight = WinQuerySysValue(HWND_DESKTOP,SV_CYSCREEN);
  3784.     lWidth  = WinQuerySysValue(HWND_DESKTOP,SV_CXSCREEN);
  3785.  
  3786.         .
  3787.         .
  3788.         .
  3789.  
  3790. With these values you size and position your window with WinSetWindowPos(). 
  3791.  
  3792. Credit: Andreas Almroth 
  3793.  
  3794.  
  3795. ΓòÉΓòÉΓòÉ 8.23. How do I attach Instance data to window created with WinCreateStdWindow? ΓòÉΓòÉΓòÉ
  3796.  
  3797. I always use the two call to WinCreateWindow() method,    instead of the 
  3798. WinCreateStdWindow() method,  because the latter does not allow you to set 
  3799. instance data before your winproc is called for the first time. 
  3800.  
  3801. Here's a cset/2 program (icc /Ss+ /W3 /Se /B"/pm:pm" foo.c): 
  3802.  
  3803.  #define INCL_PM
  3804.  #include <os2.h>
  3805.  
  3806.  typedef struct _mydata {
  3807.      HWND hwndFrame;
  3808.      HWND hwndClient;
  3809.      char whatever[100];
  3810.  }MYDATA;
  3811.  
  3812.  static MRESULT EXPENTRY WinProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  3813.  {
  3814.      MYDATA *mine;
  3815.  
  3816.     mine = (MYDATA *)WinQueryWindowPtr(hwnd, 0);  // will be null for WM_CREATE
  3817.      switch(msg){
  3818.          case WM_CREATE:
  3819.              mine = (MYDATA *)mp1;
  3820.              WinSetWindowPtr(hwnd, 0, mine);
  3821.              break;
  3822.          case WM_ERASEBACKGROUND:
  3823.              return (MRESULT)TRUE;
  3824.          default:
  3825.             return WinDefWindowProc(hwnd, msg, mp1, mp2);
  3826.      }
  3827.      return 0;
  3828.  }
  3829.  
  3830.  void main(void)
  3831.  {
  3832.      HAB hab;
  3833.      HMQ hmq;
  3834.      QMSG qmsg;
  3835.      char *class = "foo";
  3836.      FRAMECDATA fcdata;  /* frame creation data */
  3837.      MYDATA mydat;
  3838.  
  3839.      hab = WinInitialize(0);
  3840.      hmq = WinCreateMsgQueue(hab, hmq);
  3841.  
  3842.      WinRegisterClass(hab, class, WinProc, 0, sizeof(MYDATA *));
  3843.  
  3844.      /* create frame window (WC_FRAME) */
  3845.      fcdata.cb = sizeof(FRAMECDATA);
  3846.      fcdata.flCreateFlags = FCF_TITLEBAR | FCF_SYSMENU |
  3847.                             FCF_SHELLPOSITION | FCF_TASKLIST |
  3848.                             FCF_SIZEBORDER | FCF_MINMAX ;
  3849.  
  3850.      fcdata.hmodResources = 0;
  3851.      fcdata.idResources   = 1;         /* resource id */
  3852.      mydat.hwndFrame = WinCreateWindow(HWND_DESKTOP, WC_FRAME, "Title",
  3853.                                        0, 0, 0, 0, 0,
  3854.                                        0,  /* no owner */
  3855.                                        HWND_TOP,fcdata.idResources,&fcdata,NULL);
  3856.  
  3857.      if(!mydat.hwndFrame)
  3858.          exit(3);
  3859.  
  3860.      /* WinProc() has not been called yet */
  3861.  
  3862.      /* Create Client window: */
  3863.      mydat.hwndClient = WinCreateWindow(mydat.hwndFrame, class, "text",
  3864.                          0, 0, 0, 0, 0,
  3865.                          mydat.hwndFrame,    /* frame is owner */
  3866.                          HWND_TOP, FID_CLIENT,
  3867.                          &mydat, /* passed as mp1 to wm_create */
  3868.                          NULL);
  3869.  
  3870.      WinShowWindow(mydat.hwndFrame, TRUE);
  3871.  
  3872.      while(WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0))
  3873.          WinDispatchMsg(hab, &qmsg);
  3874.  
  3875.  }
  3876.  
  3877. Credit:  Peter Fitzsimmons 
  3878.  
  3879.  
  3880. ΓòÉΓòÉΓòÉ 8.24. How do I get a list of fonts? ΓòÉΓòÉΓòÉ
  3881.  
  3882. Shown is code for For v1.3.  Petzold has had a nice series on fonts in PC MAG 
  3883. from about Nov 92-June 93. 
  3884.  
  3885. #define INCL_DEV
  3886. #define INCL_DOSMEMMGR
  3887. #define INCL_GPILCIDS
  3888. #define INCL_WINWINDOWMGR
  3889. #define INCL_WINLISTBOXES
  3890. #include <os2.h>
  3891. #include <stdio.h>
  3892.  
  3893. VOID EXPENTRY FntQueryList(hwnd)
  3894. HWND hwnd; // listbox handle
  3895.   {
  3896.   PFONTMETRICS pfm;
  3897.   HDC          hdc;
  3898.   HPS          hps;
  3899.   LONG         alDevInfo[2];
  3900.   LONG         lFonts;
  3901.   LONG         lFontCnt = 0L;
  3902.   CHAR         pch[64];
  3903.   SEL          sel;
  3904.   USHORT       i;
  3905.  
  3906.   hdc = WinOpenWindowDC(hwnd);
  3907.   DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 2L, alDevInfo);
  3908.   hps = WinGetPS(hwnd);
  3909.   lFonts = GpiQueryFonts(hps, QF_PUBLIC, (PSZ)0, &lFontCnt,
  3910.                          (LONG)sizeof(FONTMETRICS), (PFONTMETRICS)0 );
  3911.   DosAllocSeg((USHORT)lFonts * sizeof(FONTMETRICS), &sel, SEG_NONSHARED);
  3912.   pfm = (PFONTMETRICS)MAKEP(sel, 0);
  3913.   GpiQueryFonts(hps, QF_PUBLIC, (PSZ)0, &lFonts,
  3914.                 (LONG)sizeof(FONTMETRICS), pfm );
  3915.   for (i = 0; i < (USHORT)lFonts; i++) {
  3916.     if (!(pfm[i].fsDefn & FM_DEFN_OUTLINE)) {
  3917.       if ((pfm[i].sXDeviceRes == (SHORT)alDevInfo[0]) &&
  3918.           (pfm[i].sYDeviceRes == (SHORT)alDevInfo[1]) ) {
  3919.             sprintf(pch, "%2d.%s",
  3920.                     pfm[i].sNominalPointSize / 10,
  3921.                     pfm[i].szFacename );
  3922.         WinSendMsg(hwnd, LM_INSERTITEM,
  3923.                    MPFROMSHORT(LIT_END), MPFROMP(pch) );
  3924.         }
  3925.       }
  3926.     }
  3927.   DosFreeSeg(sel);
  3928.   WinReleasePS(hps);
  3929.   return;
  3930.   }
  3931.  
  3932.  
  3933. ΓòÉΓòÉΓòÉ 8.25. How do I create a folder in C and put my pgm in it? ΓòÉΓòÉΓòÉ
  3934.  
  3935. /* Create our folder on the desktop */
  3936.  
  3937. HOBJECT hFolder, hObject;
  3938.  
  3939. hFolder = WinCreateObject ("wpFolder", "My Folder",
  3940.                            "OBJECTID=<MY_FOLDER>", "<WP_DESKTOP>",
  3941.                            CO_REPLACEIFEXISTS);
  3942.  
  3943. /* Now, put our object into the folder. */
  3944.  
  3945. hObject = WinCreateObject ("wpProgram", "My Online Book",
  3946.                            "EXENAME=VIEW.EXE;PARAMETERS=MYBOOK.INF;\
  3947.                            OBJECTID=<MY_BOOK>", "<MY_FOLDER>",
  3948.                            CO_REPLACEIFEXISTS);
  3949.  
  3950. What that little code snippet does is create a folder called "My Folder"
  3951. on the desktop, and puts a program object for an online book in it.
  3952. Check out the documentation on the following functions for more
  3953. information:
  3954.  
  3955. WinCreateObject
  3956. wpSetup (for information on the setup string parameter to WinCreateObj)
  3957. WPFolder (for information on the setup strings of folders)
  3958. WPProgram programs etc.
  3959.  
  3960.  
  3961. ΓòÉΓòÉΓòÉ 8.26. How do I do it in REXX? ΓòÉΓòÉΓòÉ
  3962.  
  3963. You may have seen the Paradox 4.0 install script, which uses SysCreateObject to 
  3964. make a WPS object 
  3965.  
  3966. Hope they don't mind me posting a fragment of the script by: 
  3967.  
  3968. /* Rob Gordon  Borland International 6/8/92  */
  3969.  
  3970. title = "Paradox 4.0"
  3971. classname = 'WPProgram'
  3972. location = '<WP_DESKTOP>'
  3973. setup = 'PROGTYPE=WINDOWEDVDM;EXENAME='pdoxpath'paradox.exe;
  3974.   STARTUPDIR='pdoxpath';SET DPMI_DOS_API=ENABLED;
  3975.   SET DPMI_MEMORY_LIMIT=4;ICONFILE 'pdoxpath'pdoxos2.ico;'
  3976.  
  3977. BldObj:
  3978. call charout , 'Building : 'title
  3979. result = SysCreateObject(classname, title, location, setup)
  3980.  
  3981.  
  3982. ΓòÉΓòÉΓòÉ 8.27. How do I use the Font dialog (WinFontDlg)? ΓòÉΓòÉΓòÉ
  3983.  
  3984. FIRST:  make your stack huge (>32K)  It is sparsely allocated and you only use 
  3985. what you need. Here's some code: 
  3986.  
  3987.  FONTDLG fontdlg ;
  3988.  FONTMETRICS fm ;
  3989.  CHAR            szBuf [200] ;
  3990.  CHAR            szFamily [CCHMAXPATH] ;
  3991.  static CHAR     szTitle [] = "Fonts Dialog" ;
  3992.  static CHAR     szMsgBoxTitle [] = "Result from 'WinFontDlg ()'" ;
  3993.  static CHAR     szPreview [] = "We hold these truths to be self-evident ..." ;
  3994.  
  3995.  // Here, get an HPS and then do a WinQueryFontMetrics.
  3996.  // Continuing ...
  3997.  
  3998.  memset ((void *) &fontdlg, 0, sizeof (FONTDLG)) ;
  3999.  fontdlg.cbSize = sizeof (FONTDLG) ;
  4000.  fontdlg.hpsScreen = WinGetScreenPS (HWND_DESKTOP) ;
  4001.  fontdlg.hpsPrinter = NULLHANDLE ;
  4002.  fontdlg.pszTitle = szTitle ;
  4003.  fontdlg.pszPreview = szPreview ;
  4004.  fontdlg.pfnDlgProc = NULL ;
  4005.  strcpy (szFamily, fm.szFamilyname) ;
  4006.  fontdlg.pszFamilyname = szFamily ;
  4007.  fontdlg.usFamilyBufLen = sizeof (szFamily) ;
  4008.  fontdlg.fxPointSize = MAKEFIXED (fm.sNominalPointSize / 10, 0) ;
  4009.  fontdlg.fl = FNTS_CENTER | FNTS_HELPBUTTON |
  4010.      FNTS_INITFROMFATTRS | FNTS_NOSYNTHESIZEDFONTS |
  4011.      FNTS_RESETBUTTON ;
  4012.  fontdlg.sNominalPointSize = fm.sNominalPointSize ;
  4013.  fontdlg.flType = (LONG) fm.fsType ;
  4014.  fontdlg.clrFore = CLR_NEUTRAL ;
  4015.  fontdlg.clrBack = CLR_BACKGROUND ;
  4016.  fontdlg.usWeight = fm.usWeightClass ;
  4017.  fontdlg.usWidth = fm.usWidthClass ;
  4018.  
  4019.  hwndDlg = WinFontDlg (HWND_DESKTOP, hwnd, &fontdlg) ;
  4020.  
  4021. Credit: Wayne Kovsky 
  4022.  
  4023.  
  4024. ΓòÉΓòÉΓòÉ 8.28. How do I take control of frame sizing? ΓòÉΓòÉΓòÉ
  4025.  
  4026. I want to "subclass" the Window Frame Class to allow me to control the size of 
  4027. my main window when it's resized by the mouse. I want to control the steps it 
  4028. take to resize too, (ie: by 8x8 steps). 
  4029.  
  4030. --- CUT --- CUT ---- .H file --- CUT --- 
  4031.  
  4032. HWND APIENTRY WinCreateMBWindow(
  4033.  
  4034.   HWND hwndParent,
  4035.   ULONG flStyle,
  4036.   PULONG pflCreateFlags,
  4037.   PSZ pszClientClass,
  4038.   PSZ pszTitle,
  4039.   ULONG styleClient,
  4040.   HMODULE hmod,
  4041.   USHORT idResources,
  4042.   PHWND phwndClient);
  4043.  
  4044.  
  4045. #define HMODFROMMP(mp) ((USHORT)(ULONG)(mp))
  4046.  
  4047. #define MB_CHILD_SIZE  WM_USER+204
  4048.           //Sent from child to frame indicating the new
  4049.           //requested size of the child area.  (high&width in MP1)
  4050.           //If ChildMax is shrinking below current size,
  4051.           // frame is redused, and evt scroll bars is hidden.
  4052.           //If Child is growing
  4053.           //   MP2=True -> grows frame to contain maximized child
  4054.           //   MP2=False-> enables scroll bars, keeps size.
  4055.  
  4056. #define MB_FIX_N       0x1 //Fix north border when sizing
  4057. #define MB_FIX_E       0x2 //Fix east  border when sizing
  4058.  
  4059. #define MB_FIX_NE       0x3 //Fix north east corner when sizing
  4060. #define MB_FIX_SE       0x2 //Fix south east corner when sizing
  4061. #define MB_FIX_NW       0x1 //Fix north west corner when sizing
  4062. #define MB_FIX_SW       0x0 //Fix south west corner when sizing
  4063.  
  4064. #define MB_QCHILD_SIZE_MAX     WM_USER+205
  4065.            //Sent from frame to child to queryw
  4066.            //max size of the child area.  (h&w in MR)
  4067.            //Used when sizing to determin if scroll bars are ness.
  4068.  
  4069. #define MB_QCHILD_GRID     WM_USER+206
  4070.            //Sent from frame to child before tracking
  4071.            //Child supposed to return x&y granularity in MR
  4072.  
  4073. #define MB_CREATE          WM_USER+207  //Internally shipped command.
  4074.  
  4075. typedef struct _FRM_DTA { /* Fram data */
  4076.     PFNWP    oldProc;
  4077.     SHORT    nTrkCnr,nYSclHor,nXSclVer,nTitle;
  4078.     SHORT    xMax,yMax;    //Max size of Client in PIX
  4079.     SHORT    ScrMaxX,ScrMaxY;
  4080.     POINTL   ptlBdr;
  4081.     HWND     hVert,hHori;
  4082.     SHORT    xCur,yCur;    //Current size of Client in PIX
  4083.     SHORT    nCorner;      //Which corner is to be stable
  4084. } FRM_DTA;
  4085. typedef FRM_DTA FAR * PFRM_DTA;
  4086.  
  4087. --- CUT --- CUT --- .C file --- CUT --- CUT --- 
  4088.  
  4089. HWND    APIENTRY WinCreateMBWindow(HWND hParent, ULONG flStyle,
  4090.                                    PULONG pflCreate, PSZ pszClientClass,
  4091.                                    PSZ pszTitle, ULONG styleClient,
  4092.                                    HMODULE hmod,
  4093.                                    USHORT idResources, PHWND phClient)
  4094. {
  4095.   HWND         hFrame;
  4096.   PFRM_DTA     pFrm;
  4097.  
  4098.   hFrame = WinCreateStdWindow(hParent,flStyle,pflCreate,pszClientClass,
  4099.                               pszTitle,styleClient,hmod,idResources,phClient);
  4100.  
  4101.   //Allocate some storage for local parameters, and initialize it
  4102.   pFrm=malloc(sizeof( FRM_DTA));
  4103.   memset(pFrm,0,sizeof( FRM_DTA));
  4104.  
  4105.   WinSetWindowPtr(hFrame,QWL_USER,(PVOID) pFrm);
  4106.  
  4107.   pFrm->oldProc= WinSubclassWindow(hFrame,newFrameProc);
  4108.  
  4109.   //Now window is setup:
  4110.  
  4111.   WinSendMsg(hFrame,MB_CREATE,MP0,MP0);    //My own WM_CREATE
  4112.  
  4113.   WinShowWindow(hFrame,TRUE);
  4114.  
  4115.   WinUpdateWindow(hFrame);
  4116.   return hFrame;
  4117. }
  4118.  
  4119. VOID GetChildMax(HWND hFrame, PFRM_DTA    pFrm)
  4120. { MRESULT mr;
  4121.   mr = WinSendMsg(WinWindowFromID(hFrame,FID_CLIENT),
  4122.                   MB_QCHILD_SIZE_MAX,MP0,MP0);
  4123.   pFrm->xMax=SHORT1FROMMR(mr);
  4124.   pFrm->yMax=SHORT2FROMMR(mr);
  4125. }
  4126.  
  4127. #define CLIENT_PROVIDED  FALSE
  4128. #define FRAME_PROVIDED     TRUE
  4129.  
  4130. BOOL WinCalcFrameSWP(HWND hwnd, PSWP pSWP, BOOL bFrame)
  4131. { //    TRUE       Frame rectangle provided
  4132.   //    FALSE      Client-area rectangle provided.
  4133.   RECTL rcl;
  4134.   BOOL bSuccess;
  4135.  
  4136.   rcl.xLeft   = pSWP->x;
  4137.   rcl.yBottom = pSWP->y;
  4138.   rcl.xRight  = pSWP->x+pSWP->cx;
  4139.   rcl.yTop    = pSWP->y+pSWP->cy;
  4140.  
  4141.   bSuccess = WinCalcFrameRect(hwnd, &rcl, bFrame );
  4142.  
  4143.   pSWP->x  =(SHORT) rcl.xLeft;
  4144.   pSWP->y  =(SHORT) rcl.yBottom;
  4145.   pSWP->cx =(SHORT) (rcl.xRight-rcl.xLeft);
  4146.   pSWP->cy =(SHORT) (rcl.yTop  -rcl.yBottom);
  4147.  
  4148.   return(bSuccess);
  4149. }
  4150.  
  4151.  
  4152. VOID SclBarEnable(HWND hwnd, PSWP pSWP, PFRM_DTA  pFrm)
  4153. {
  4154.  
  4155.   .....
  4156.  
  4157.  Your routines to determine and en/disable scroll bars 
  4158.  
  4159.   .....
  4160. /*    Part of my code */
  4161.   swpClient = *(pSWP);
  4162.   WinCalcFrameSWP(hwnd, &swpClient, FRAME_PROVIDED);
  4163.   if (swpClient.cx >= pFrm->xMax-1)
  4164.   { //Turn off horisontal scroll bar
  4165.     WinSetParent(pFrm->hHori,HWND_OBJECT ,FALSE);
  4166.     nUpdt = FCF_HORZSCROLL;
  4167.   }  /* code for enabling left out..... */
  4168.  
  4169.   if (nUpdt != 0)
  4170.   {
  4171.     WinSendMsg (hwnd, WM_UPDATEFRAME, MPFROMSHORT(nUpdt), MP0);
  4172.   }
  4173. */
  4174. }
  4175.  
  4176. /***************** Start of frame subclass procedure *****************/
  4177.  
  4178. MRESULT  EXPENTRY newFrameProc( HWND hwnd, USHORT msg,
  4179. MPARAM mp1, MPARAM mp2 )
  4180.  
  4181. { PSWP        pSWP;
  4182.   PFNWP     oldProc;
  4183.   PFRM_DTA  pFrm;
  4184.  
  4185.   pFrm=(PFRM_DTA)WinQueryWindowPtr(hwnd,QWL_USER);
  4186.   oldProc=pFrm->oldProc;
  4187.  
  4188.   switch(msg)
  4189.   {
  4190.     case MB_CREATE:
  4191.       //Start hiding scroll bars
  4192.       pFrm->hVert  = WinWindowFromID(hwnd,FID_VERTSCROLL);
  4193.       WinSetParent(pFrm->hVert,HWND_OBJECT ,FALSE);
  4194.       pFrm->nYSclHor = 0;
  4195.     break;
  4196.  
  4197.     case WM_MINMAXFRAME:
  4198.     { SWP swpClient;
  4199.       pSWP=(PSWP) PVOIDFROMMP(mp1);
  4200.       pSWP->fs |= SWP_SIZE;
  4201.  
  4202.       GetChildMax(hwnd, pFrm);
  4203.  
  4204.       if (pSWP->fs & SWP_MAXIMIZE) //MaxiMizeing Operation
  4205.       {
  4206.         //tprintf("WM_MINMAXFRAME SWP_MAXIMIZE FS: %X┬á",pSWP->fs);
  4207.         if ((0!=pFrm->xMax) && (0!=pFrm->yMax))
  4208.         { //I have no data for all of screen, so act as Windowed OS/2
  4209.  
  4210.           memset(&swpClient,0,sizeof(swpClient));
  4211.           swpClient.cx=pFrm->xMax;
  4212.           swpClient.cy=pFrm->yMax;
  4213.           WinCalcFrameSWP(hwnd, &swpClient,CLIENT_PROVIDED);
  4214.  
  4215.           pSWP->cx = swpClient.cx;
  4216.           pSWP->cy = swpClient.cy;
  4217.  
  4218.           pSWP->y  = pFrm->ScrMaxY - swpClient.cy + (SHORT)pFrm->ptlBdr.y;
  4219.  
  4220.  
  4221.           SclBarEnable(hwnd, pSWP, pFrm);
  4222.  
  4223.           return MRFROMSHORT(FALSE);
  4224.         }
  4225.       }
  4226.  
  4227.       if (pSWP->fs & SWP_RESTORE) //MiniMizeing Operation
  4228.  
  4229. ??? (restore i guess) 
  4230.  
  4231.       {
  4232.         //tprintf("WM_MINMAXFRAME SWP_RESTORE FS: %X┬á",pSWP->fs);
  4233.         if ((0!=pFrm->xMax) && (0!=pFrm->yMax))  //Why do I need this?
  4234.         {
  4235.           return MRFROMSHORT(FALSE);
  4236.         }
  4237.       }
  4238.     }
  4239.     return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
  4240.  
  4241.  
  4242.     case WM_QUERYTRACKINFO:
  4243.     {
  4244.       PTRACKINFO pTI;
  4245.       LONG i;
  4246.  
  4247.       if (TF_MOVE <= SHORT1FROMMP(mp1))
  4248.       {
  4249.         pFrm->nTrkCnr= 0;
  4250.         return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
  4251.       }
  4252.  
  4253.       pTI = (PTRACKINFO) PVOIDFROMMP (mp2);  //Get structure pointer;
  4254.       //tprintf("@+WM_QUERYTRACKINFO FS: %X┬á",pTI->fs);
  4255.       if ((*oldProc)(hwnd, msg, mp1, mp2)==0) return MRFROMSHORT(FALSE);
  4256.  
  4257.       GetChildMax(hwnd, pFrm);
  4258.       if ((0!=pFrm->xMax) && (0!=pFrm->yMax))
  4259.       { //Setup track info structure
  4260.         pTI->ptlMaxTrackSize.x = (LONG) pFrm->xMax;
  4261.         pTI->ptlMaxTrackSize.y = (LONG) pFrm->yMax;
  4262.  
  4263.         WinCalcFrameRect(hwnd, &(pTI->rclTrack), FRAME_PROVIDED );
  4264.  
  4265.         { MRESULT mr;
  4266.           mr = WinSendMsg(WinWindowFromID(hwnd,FID_CLIENT),
  4267.                           MB_QCHILD_GRID,MP0,MP0);
  4268.           if (NULL!=mr)
  4269.           {
  4270.             pTI->cxGrid  = SHORT1FROMMR(mr);
  4271.             pTI->cyGrid  = SHORT2FROMMR(mr);
  4272.  
  4273.             //Setting height of client to integral cyGrid
  4274.             i = (pTI->rclTrack.yTop - pTI->rclTrack.yBottom)/pTI->cyGrid;
  4275.             pTI->rclTrack.yTop = i * pTI->cyGrid + pTI->rclTrack.yBottom;
  4276.  
  4277.             pTI->fs    |= TF_GRID;
  4278.             pFrm->nTrkCnr= WM_QUERYTRACKINFO;
  4279.             //Used in WM_ADJUSTWINODWPOS
  4280.           }
  4281.         }
  4282.       }
  4283.       return MRFROMSHORT(TRUE);
  4284.     }
  4285.     break;
  4286.  
  4287.     case WM_ADJUSTWINDOWPOS:
  4288.     { RECTL rcl;
  4289.       pSWP=(PSWP) PVOIDFROMMP(mp1);
  4290.  
  4291.       if (pSWP->fs & (SWP_SIZE | SWP_MOVE | SWP_MAXIMIZE))
  4292.       {
  4293.         GetChildMax(hwnd, pFrm);
  4294.         if (WM_QUERYTRACKINFO==pFrm->nTrkCnr)
  4295.           //As a result of tracking
  4296.         {
  4297.           //Go from client to frame values
  4298.           WinCalcFrameSWP(hwnd, pSWP, CLIENT_PROVIDED);
  4299.         }
  4300.  
  4301.         pFrm->nTrkCnr     = 0;
  4302.  
  4303.         SclBarEnable(hwnd, pSWP, pFrm);
  4304.       }
  4305.       return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
  4306.     }
  4307.     break;
  4308.  
  4309.     case MB_CHILD_SIZE:      //xCur,yCur
  4310.     { SWP swp;
  4311.  
  4312. ............. do your actions as responce to client resize request (Change of 
  4313. fontsize for instance) 
  4314.  
  4315.  
  4316.       return (MRESULT)TRUE;
  4317.     }
  4318.     break;
  4319.  
  4320.     default:
  4321.     break;
  4322.   }
  4323.   return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
  4324. }
  4325.  
  4326. A lot is deleted (Som is very application specific), but i hope you get the 
  4327. general picture. 
  4328.  
  4329. Credit:  Henrik Wahlberg 
  4330.  
  4331.  
  4332. ΓòÉΓòÉΓòÉ 8.29. How do I use the 16-bit EPM toolkit? ΓòÉΓòÉΓòÉ
  4333.  
  4334. Since there were a few requests, here are the changes I made to get the ESIMPLE 
  4335. example from the EPM Toolkit to work with the C-Set++ compiler. The ETK DLLs 
  4336. are 16-bit and need to be thunked to be called from a 32-bit app. Since I was 
  4337. playing around, some of the changes were not necessary to get the program to 
  4338. run.  Changes are in DIFF format. 
  4339.  
  4340. **** Changes to EDLL.H ****
  4341. 254a255
  4342. > #pragma pack(2)
  4343. 259,263c260,264
  4344. <    PSWP   pswp;         // positioning of edit window
  4345. <    PSZ    filename;     // file to be edited (with wildcard)
  4346. <    PVOID  hEditPtr;     // handle to editor pointer icon.
  4347. <    PVOID  hMarkPtr;     // handle to mark pointer icon.
  4348. <    PVOID  hEditorIcon;  // editor ICON.
  4349. >    PSWP _Seg16   pswp;         // positioning of edit window
  4350. >    PSZ _Seg16    filename;     // file to be edited (with wildcard)
  4351. >    HPOINTER  hEditPtr;  // handle to editor pointer icon.
  4352. >    HPOINTER  hMarkPtr;  // handle to mark pointer icon.
  4353. >    PVOID _Seg16  hEditorIcon;  // editor ICON.
  4354. 267,269c268,270
  4355. <    PSZ    exfile;       // pre-compiled macro code file (EPM.EX)
  4356. <    PSZ    topmkr;       // top and bottom of file marker
  4357. <    PSZ    botmkr;       //
  4358. ---
  4359. >    PSZ _Seg16    exfile;       // pre-compiled macro code file (EPM.EX)
  4360. >    PSZ _Seg16    topmkr;       // top and bottom of file marker
  4361. >    PSZ _Seg16    botmkr;       //
  4362. 271,272c272,273
  4363. <    PSZ    exsearchpath; // a set of paths to search for ex's files
  4364. <    PSZ    exe_path;     // path where the application started
  4365. ---
  4366. >    PSZ _Seg16    exsearchpath; // a set of paths to search for ex's files
  4367. >    PSZ _Seg16    exe_path;     // path where the application started
  4368. 275c276,277
  4369. < typedef EDITORINFO far *PEDITORINFO;
  4370. ---
  4371. > typedef EDITORINFO * PEDITORINFO;
  4372. > #pragma pack()
  4373. 280c282
  4374. < #define ETKENTRY _loadds
  4375. ---
  4376. > #define ETKENTRY CDECL16
  4377. 285,286c287,288
  4378. < PSZ     ETKENTRY EtkRegister( HAB hab, ULONG class_style );
  4379. < USHORT ETKENTRY EtkCreate( PEDITORINFO epm_p, PHWND hEwnd_p);
  4380. ---
  4381. > PSZ _Seg16    ETKENTRY EtkRegister( HAB hab, ULONG class_style );
  4382. > USHORT ETKENTRY EtkCreate( PEDITORINFO _Seg16 epm_p, PHWND _Seg16 hEwnd_p);
  4383. 304c306,307
  4384. < SHORT  ETKENTRY EtkSetSelection( HWND  hwndClient, LINE_INDEX_G  firstline,
  4385. ---
  4386. > SHORT  ETKENTRY EtkSetSelection( HWND  hwndClient, LINE_INDEX_G  firstline,
  4387. >    FIDType fileid);
  4388.  
  4389. **** Changes to ESIMPLE.C ****
  4390. 28a29,30
  4391. >
  4392. > #include "thunk.h"
  4393. 47a50
  4394. >    HWND hwndEditFrame;
  4395. 52c55
  4396. <
  4397. ---
  4398. >    swp.fl = SWP_MOVE | SWP_SIZE;
  4399. 58c61
  4400. <    epm.filename    = (PSZ)Fname;      // file to be edited (with wildca
  4401. ---
  4402. >    epm.filename    = Fname;           // file to be
  4403. > edited (with wildca
  4404. 64,65c67,70
  4405. <    epm.editorstyle = EDIT_STYLE_ACTIVATEFOCUS | EDIT_STYLE_DISABLEOWNERAFFECT
  4406. <                      EDIT_STYLE_CURSORON;
  4407. ---
  4408. >    epm.editorstyle = EDIT_STYLE_ACTIVATEFOCUS |
  4409. >                      EDIT_STYLE_CURSORON |
  4410. >                      EDIT_STYLE_STATUSLINE |
  4411. >                      EDIT_STYLE_MESSAGELINE;
  4412. 67,68c72,73
  4413. <    epm.pmstyle     = FCF_TITLEBAR | FCF_SIZEBORDER | FCF_VERTSCROLL;
  4414. <
  4415. ---
  4416. >    epm.pmstyle     = FCF_TITLEBAR | FCF_SIZEBORDER |
  4417. > FCF_VERTSCROLL | FCF_MIN
  4418. >    epm.font = TRUE;  // large font
  4419. 70,71c75,76
  4420. <    epm.topmkr      =                        // top and bottom file indicator
  4421. <    epm.botmkr      = (PSZ)" ╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧╤₧";
  4422. ---
  4423. >    epm.topmkr      = (PSZ)"<Top>";
  4424. > // top and bottom fi
  4425. >    epm.botmkr      = (PSZ)"<Bottom>";
  4426. 75c80
  4427. <
  4428. ---
  4429. >    epm.hini = NULLHANDLE;
  4430. 77,79c82,86
  4431. <    EtkCreate( (EDITORINFO far *)&epm, (PHWND)&hwndEdit );
  4432. <
  4433. <    return( (HWND)hwndEdit );
  4434. ---
  4435. >    EtkCreate( &epm, &hwndEdit );
  4436. >       hwndEditFrame = WinQueryWindow(hwndEdit, QW_PARENT);
  4437. >       WinSetWindowPos(hwndEditFrame, NULLHANDLE, swp.x, swp.y,
  4438. >           swp.cx, swp.cy, SWP_MOVE | SWP_SIZE);
  4439. >    return( hwndEdit );
  4440. 95c102
  4441. < MRESULT FAR PASCAL TestWndProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2
  4442. ---
  4443. > MRESULT EXPENTRY TestWndProc( HWND hwnd, USHORT msg,
  4444. > MPARAM mp1, MPARAM mp2 )
  4445. 144,146c151,155
  4446. <   case EPM_EDIT_ACTIVEHWND:
  4447. <      WinSetActiveWindow(HWND_DESKTOP,(HWND)mp1 );
  4448. <      break;
  4449. ---
  4450. > case EPM_EDIT_ACTIVEHWND:
  4451. >   {
  4452. >      WinSetActiveWindow(HWND_DESKTOP,(HWND)mp1 );
  4453. >   }
  4454. >   break;
  4455. 160c169
  4456. <                     (PSZ)mp1,
  4457. ---
  4458. >                     (PSZ)_DosSelToFlat(mp1),
  4459. 162c171
  4460. <                     NULL,
  4461. ---
  4462. >                     NULLHANDLE,
  4463. 235c244
  4464. <     hab = WinInitialize(NULL);              // Initialize app as a PM app
  4465. ---
  4466. >     hab = WinInitialize(NULLHANDLE);        // Initialize app as a PM app
  4467. 247c256
  4468. <
  4469.  
  4470. Credit:  Mat Kramer 
  4471.  
  4472.  
  4473. ΓòÉΓòÉΓòÉ 8.30. How do I get error info after using WinGetLastError()? ΓòÉΓòÉΓòÉ
  4474.  
  4475. One should only use WinGetLastError() after a bad return value, ERRORID is not 
  4476. always zeroed after a successful call to PM API. 
  4477.  
  4478. ShowError Function: 
  4479.  
  4480. /*
  4481.  * ShowError -- for debugging: outputs (via printf) the last error;
  4482.  *    to use this, redirect the output of this program to a file and
  4483.  *    check the results in that file.
  4484.  *    Updated to display the error text in a MESSAGE BOX; ID_MSGBOX must be
  4485.  *    defined.
  4486.  */
  4487.  void ShowError(void)
  4488.  {
  4489.     PERRINFO p;
  4490.     char *cp;
  4491.     extern HAB hab;   /* kinda kludgy, should be a parameter */
  4492.  
  4493.     printf("ShowError: ");
  4494.     if((p = WinGetErrorInfo(hab)) == NULL)
  4495.        printf("NO ERROR\n");
  4496.     else
  4497.     {
  4498.        printf("idError = %#X\n", p->idError);
  4499.        cp = (char *)((ULONG)p + *(ULONG *)((ULONG)p + p->offaoffszMsg));
  4500.        printf("\"%s\"\n", cp);
  4501.        WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ)cp, (PSZ)"Show Error",
  4502.                      ID_MSGBOX, MB_OK | MB_ICONEXCLAMATION);
  4503.        WinFreeErrorInfo(p);
  4504.     }
  4505.  }
  4506.  
  4507. Credit:  Justin V Frank 
  4508.  
  4509.  
  4510. ΓòÉΓòÉΓòÉ 8.31. Do you have code to save/restore the clipboard? ΓòÉΓòÉΓòÉ
  4511.  
  4512.  typedef struct _CLPBRDDATA // INFORMATION ABOUT A CLIPBOARD FORMAT
  4513.  {
  4514.     ULONG ulFormat; // The format type
  4515.     PVOID pvData;   // Pointer to the data for this format
  4516.  } CLPBRDDATA, *PCLPBRDDATA;
  4517.  
  4518.  //***************
  4519.  // Save formats
  4520.  //***************
  4521.  INT SaveClipboardData( HAB hab, PCLPBRDDATA *ppcd )
  4522.  {
  4523.     INT iFmtCount = 0;
  4524.  
  4525.     if( WinOpenClipbrd( hab ) )
  4526.     {
  4527.        ULONG ulNextFmt, ulPrevFmt = 0;
  4528.  
  4529.        ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
  4530.        while( ulNextFmt )
  4531.        {
  4532.           iFmtCount++;
  4533.           ulPrevFmt = ulNextFmt;
  4534.           ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
  4535.        }
  4536.  
  4537.        if( iFmtCount )
  4538.        {
  4539.           *ppcd = (PCLPBRDDATA) malloc( sizeof( CLPBRDDATA ) * iFmtCount );
  4540.           if( *ppcd )
  4541.           {
  4542.              memset( *ppcd, 0, sizeof( CLPBRDDATA ) * iFmtCount );
  4543.               if( !GetClipboardFmts( hab, *ppcd ) )
  4544.                  iFmtCount = 0;
  4545.           }
  4546.           else
  4547.           {
  4548.              iFmtCount = 0;
  4549.              Msg( "Out of memory in SaveClipboardData" );
  4550.           }
  4551.        }
  4552.        WinCloseClipbrd( hab );
  4553.     }
  4554.     else
  4555.        Msg( "SaveClipboardData could not open the clipboard" );
  4556.  
  4557.     return iFmtCount;
  4558.  }
  4559.  
  4560.  BOOL GetClipboardFmts( HAB hab, PCLPBRDDATA pcd )
  4561.  {
  4562.     BOOL  fSuccess = TRUE;
  4563.     ULONG ulNextFmt, ulPrevFmt = 0;
  4564.  
  4565.     ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
  4566.     while( ulNextFmt )
  4567.     {
  4568.        pcd->ulFormat = ulNextFmt;
  4569.        switch( ulNextFmt )
  4570.        {
  4571.           case CF_TEXT:
  4572.              StoreClipboardText( hab, pcd );
  4573.              break;
  4574.           case CF_BITMAP:
  4575.              StoreClipboardBmp( hab, pcd );
  4576.              break;
  4577.           case CF_METAFILE:
  4578.              StoreClipboardMeta( hab, pcd );
  4579.              break;
  4580.           default:
  4581.              break;
  4582.        }
  4583.  
  4584.        pcd++;
  4585.        ulPrevFmt = ulNextFmt;
  4586.        ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
  4587.     }
  4588.     return fSuccess;
  4589.  }
  4590.  
  4591.  VOID StoreClipboardText( HAB hab, PCLPBRDDATA pcd )
  4592.  {
  4593.     PSZ szClipText = (PSZ) WinQueryClipbrdData( hab, CF_TEXT );
  4594.     if( szClipText )
  4595.     {
  4596.        pcd->pvData = malloc( strlen( szClipText ) + 1 );
  4597.        if( pcd->pvData )
  4598.           strcpy( pcd->pvData, szClipText );
  4599.        else
  4600.           Msg( "Out of memory in StoreClipboardText" );
  4601.     }
  4602.     else
  4603.        Msg( "StoreClipboardText found no TEXT in the clipboard" );
  4604.  }
  4605.  
  4606.  VOID StoreClipboardBmp( HAB hab, PCLPBRDDATA pcd )
  4607.  {
  4608.     HBITMAP hbmClip = WinQueryClipbrdData( hab, CF_BITMAP );
  4609.     if( hbmClip )
  4610.        pcd->pvData = (PVOID) CopyBitmap( hab, hbmClip );
  4611.     else
  4612.        Msg( "StoreClipboardBmp found no BITMAP in the clipboard" );
  4613.  }
  4614.  
  4615.  VOID StoreClipboardMeta( HAB hab, PCLPBRDDATA pcd )
  4616.  {
  4617.     HMF hmfClip = WinQueryClipbrdData( hab, CF_METAFILE );
  4618.     if( hmfClip )
  4619.     {
  4620.        HMF hmfNew = GpiCopyMetaFile( hmfClip );
  4621.        if( hmfNew == GPI_ERROR )
  4622.           Msg( "StoreClipboardMeta GpiCopyMetaFile RC = %x",
  4623.           (USHORT) WinGetLastError( hab ) );
  4624.        else
  4625.           pcd->pvData = (PVOID) hmfNew;
  4626.     }
  4627.     else
  4628.        Msg( "StoreClipboardMeta found no METAFILE in the clipboard" );
  4629.  }
  4630.  
  4631.  //******************
  4632.  // Restore formats
  4633.  //******************
  4634.  VOID RestClipboardData( HAB hab, INT iFmtCount, PCLPBRDDATA pcd )
  4635.  {
  4636.     PCLPBRDDATA pcdSave = pcd;
  4637.     INT  i;
  4638.     BOOL fFormatsExist = FALSE;
  4639.  
  4640.     for( i = 0; i < iFmtCount; i++, pcd++ )
  4641.     {
  4642.        if( pcd->ulFormat && pcd->pvData )
  4643.        {
  4644.           fFormatsExist = TRUE;
  4645.           break;
  4646.        }
  4647.     }
  4648.  
  4649.     pcd = pcdSave;
  4650.     if( fFormatsExist )
  4651.        if( WinOpenClipbrd( hab ) )
  4652.        {
  4653.           WinEmptyClipbrd( hab );
  4654.           for( i = 0; i < iFmtCount; i++, pcd++ )
  4655.           {
  4656.              switch( pcd->ulFormat )
  4657.              {
  4658.                 case 0:
  4659.                    break;
  4660.                 case CF_TEXT:
  4661.                    if( pcd->pvData )
  4662.                    {
  4663.                       RestClipboardText( hab, pcd->pvData );
  4664.                       free( pcd->pvData );
  4665.                    }
  4666.                    break;
  4667.                 case CF_BITMAP:
  4668.                    if( pcd->pvData )
  4669.                    RestClipboardBmp( hab, (HBITMAP) pcd->pvData );
  4670.                    break;
  4671.                 case CF_METAFILE:
  4672.                    if( pcd->pvData )
  4673.                       RestClipboardMeta( hab, (HMF) pcd->pvData );
  4674.                    break;
  4675.                 default:
  4676.                    break;
  4677.              }
  4678.           }
  4679.           WinCloseClipbrd( hab );
  4680.        }
  4681.        else
  4682.           Msg( "RestClipboardData could not open the clipboard" );
  4683.     free( pcdSave );
  4684.  }
  4685.  
  4686.  VOID RestClipboardText( HAB hab, PSZ szTextIn )
  4687.  {
  4688.     PSZ szTextOut = NULL;
  4689.     ULONG ulRC =
  4690.     DosAllocSharedMem( (PVOID) &szTextOut, NULL,
  4691.                        strlen( szTextIn ) + 1,
  4692.                        PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE );
  4693.     if( !ulRC )
  4694.     {
  4695.        strcpy( szTextOut, szTextIn );
  4696.        if( !WinSetClipbrdData( hab, (ULONG) szTextOut, CF_TEXT,
  4697.                                CFI_POINTER ) )
  4698.           Msg( "RestClipboardText WinSetClipbrdData failed" );
  4699.     }
  4700.     else
  4701.        Msg( "RestClipboardText DosAllocSharedMem RC: %u", ulRC );
  4702.  }
  4703.  
  4704.  VOID RestClipboardBmp( HAB hab, HBITMAP hbm )
  4705.  {
  4706.   if( !WinSetClipbrdData( hab, (ULONG) hbm, CF_BITMAP, CFI_HANDLE ) )
  4707.      Msg( "RestClipboardBmp WinSetClipbrdData failed" );
  4708.  }
  4709.  
  4710.  VOID RestClipboardMeta( HAB hab, HMF hmf )
  4711.  {
  4712.   if( !WinSetClipbrdData( hab, (ULONG) hmf, CF_METAFILE, CFI_HANDLE ) )
  4713.      Msg( "RestClipboardMeta WinSetClipbrdData failed" );
  4714.  }
  4715.  
  4716.  HBITMAP CopyBitmap( HAB hab, HBITMAP hbmIn )
  4717.  {
  4718.     BITMAPINFOHEADER2 bmih;
  4719.     HBITMAP           hbmOut = NULLHANDLE;
  4720.     HDC               hdcIn = NULLHANDLE, hdcOut = NULLHANDLE;
  4721.     HPS               hpsIn = NULLHANDLE, hpsOut = NULLHANDLE;
  4722.     POINTL            aptl[ 3 ];
  4723.     SIZEL             sizel = {0,0};
  4724.  
  4725.     hdcIn = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE );
  4726.     if( !hdcIn )
  4727.     {
  4728.        Msg( "CopyBitmap DevOpenDC for hdcIn RC = %x",
  4729.             (USHORT) WinGetLastError( hab ) );
  4730.        goto BYEBYE;
  4731.     }
  4732.  
  4733.     hdcOut = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE );
  4734.     if( !hdcOut )
  4735.     {
  4736.        Msg( "CopyBitmap DevOpenDC for hdcOut RC = %x",
  4737.             (USHORT) WinGetLastError( hab ) );
  4738.        goto BYEBYE;
  4739.     }
  4740.  
  4741.     hpsIn  = GpiCreatePS( hab, hdcIn, &sizel,PU_PELS |
  4742.                           GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  4743.     if( !hpsIn )
  4744.     {
  4745.        Msg( "CopyBitmap GpiCreatePS for hpsIn RC = %x",
  4746.             (USHORT) WinGetLastError( hab ) );
  4747.        goto BYEBYE;
  4748.     }
  4749.  
  4750.     hpsOut = GpiCreatePS( hab, hdcOut, &sizel,PU_PELS |
  4751.                           GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  4752.     if( !hpsOut )
  4753.     {
  4754.        Msg( "CopyBitmap GpiCreatePS for hpsOut RC = %x",
  4755.             (USHORT) WinGetLastError( hab ) );
  4756.        goto BYEBYE;
  4757.     }
  4758.  
  4759.     bmih.cbFix = sizeof( BITMAPINFOHEADER2 );
  4760.     if( !GpiQueryBitmapInfoHeader( hbmIn, &bmih ) )
  4761.     {
  4762.        Msg( "CopyBitmap GpiQueryBitmapInfoHeader for hbmIn RC = %x",
  4763.             (USHORT) WinGetLastError( hab ) );
  4764.        goto BYEBYE;
  4765.     }
  4766.  
  4767.     hbmOut = GpiCreateBitmap( hpsOut, &bmih, 0, NULL, NULL );
  4768.     if( hbmOut )
  4769.     {
  4770.        if( HBM_ERROR == GpiSetBitmap( hpsIn, hbmIn ) )
  4771.        {
  4772.           Msg( "CopyBitmap GpiSetBitmap for hpsIn RC = %x",
  4773.                (USHORT) WinGetLastError( hab ) );
  4774.           hbmOut = NULLHANDLE;
  4775.           goto BYEBYE;
  4776.        }
  4777.  
  4778.        if( HBM_ERROR == GpiSetBitmap( hpsOut, hbmOut ) )
  4779.        {
  4780.           Msg( "CopyBitmap GpiSetBitmap for hpsOut RC = %x",
  4781.                (USHORT) WinGetLastError( hab ) );
  4782.           hbmOut = NULLHANDLE;
  4783.           goto BYEBYE;
  4784.        }
  4785.  
  4786.        aptl[ 0 ].x = 0;
  4787.        aptl[ 0 ].y = 0;
  4788.        aptl[ 1 ].x = bmih.cx;
  4789.        aptl[ 1 ].y = bmih.cy;
  4790.        aptl[ 2 ].x = 0;
  4791.        aptl[ 2 ].y = 0;
  4792.  
  4793.        if( GPI_ERROR == GpiBitBlt( hpsOut, hpsIn, 3, aptl, ROP_SRCCOPY,
  4794.                                    BBO_IGNORE ) )
  4795.        {
  4796.           Msg( "CopyBitmap GpiBitBlt for hpsOut RC = %x",
  4797.                (USHORT) WinGetLastError( hab ) );
  4798.           hbmOut = NULLHANDLE;
  4799.        }
  4800.     }
  4801.     else
  4802.        Msg( "CopyBitmap GpiCreateBitmap for hbmOut RC = %x",
  4803.             (USHORT) WinGetLastError( hab ) );
  4804.  
  4805.  BYEBYE:
  4806.  
  4807.     if( hpsIn )
  4808.        GpiDestroyPS( hpsIn );
  4809.     if( hpsOut )
  4810.        GpiDestroyPS( hpsOut );
  4811.     if( hdcIn )
  4812.        DevCloseDC( hdcIn );
  4813.     if( hdcOut )
  4814.        DevCloseDC( hdcOut );
  4815.     return hbmOut;
  4816.  }
  4817.  
  4818. Credit:  Rick Fishman 
  4819.  
  4820.  
  4821. ΓòÉΓòÉΓòÉ 8.32. How do I know what item was selected in a Combo box? ΓòÉΓòÉΓòÉ
  4822.  
  4823. Catch the LN_SELECT message from the combo box, then send an LM_QUERYSELECTION 
  4824. to get the index of the selection, then a LM_QUERYITEMTEXT to get the selected 
  4825. text. 
  4826.  
  4827. Credit:  Pete Norloff 
  4828.  
  4829.  
  4830. ΓòÉΓòÉΓòÉ 8.33. How do I get a bitmap into a dialog in a DLL? ΓòÉΓòÉΓòÉ
  4831.  
  4832. You've hit on a known problem with bitmaps in dialogs in dlls. This also used 
  4833. to be a problem for icons but that appears to be working now. 
  4834.  
  4835. First, define your bitmap in your dialog like this (notice no mention of 
  4836. SS_BITMAP). It is strictly text at this point. PM can handle this when loading 
  4837. the dialog: 
  4838.  
  4839. Below are all the files necessary to create dllbitmp.exe and dlgdll.dll. Dlgdll 
  4840. has the dialog box and bitmap. Dllbitmp.exe calls DllDialog() in dlgdll.dll to 
  4841. bring up the dialog box from the dll's resource file... 
  4842.  
  4843. DLLBITMP.C: 
  4844.  
  4845.  #define  INCL_GPI
  4846.  #define  INCL_WIN
  4847.  #include <os2.h>
  4848.  #include "dllbitmp.h"
  4849.  
  4850.  #define FRAME_FLAGS  (FCF_TASKLIST | FCF_TITLEBAR   |
  4851.                        FCF_MENU     | FCF_SYSMENU    |
  4852.                        FCF_MINMAX   | FCF_SIZEBORDER |
  4853.                        FCF_SHELLPOSITION)
  4854.  #define CLIENT_CLASS "DllBitmp"
  4855.  
  4856.  
  4857.  INT main( VOID );
  4858.  VOID EXPENTRY DllDialog( HWND );
  4859.  FNWP wpClient;
  4860.  
  4861.  
  4862.  INT main( VOID )
  4863.  {
  4864.     HAB   hab;
  4865.     HMQ   hmq;
  4866.     QMSG  qmsg;
  4867.     HWND  hwndFrame, hwndClient;
  4868.     ULONG flFrame = FRAME_FLAGS;
  4869.  
  4870.     hab = WinInitialize( 0 );
  4871.     hmq = WinCreateMsgQueue( hab, 0 );
  4872.     WinRegisterClass( hab, CLIENT_CLASS, wpClient, 0, 0 );
  4873.     hwndFrame = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE,
  4874.                                     &flFrame,CLIENT_CLASS, NULL,
  4875.                                     0,NULLHANDLE, ID_RESOURCES,
  4876.                                     &hwndClient );
  4877.     while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
  4878.        WinDispatchMsg( hab, &qmsg );
  4879.  
  4880.     WinDestroyWindow( hwndFrame );
  4881.     WinDestroyMsgQueue( hmq );
  4882.     WinTerminate( hab );
  4883.     return 0;
  4884.  }
  4885.  
  4886.  
  4887.  MRESULT EXPENTRY wpClient( HWND hwnd, ULONG msg,
  4888.                             MPARAM mp1, MPARAM mp2 )
  4889.  {
  4890.     switch( msg )
  4891.     {
  4892.        case WM_ERASEBACKGROUND:
  4893.           return (MRESULT) TRUE;
  4894.        case WM_COMMAND:
  4895.        switch( SHORT1FROMMP( mp1 ) )
  4896.        {
  4897.           case IDM_DOIT:
  4898.           {
  4899.              DllDialog( hwnd );
  4900.              return 0;
  4901.           }
  4902.        }
  4903.  
  4904.        break;
  4905.     }
  4906.     return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  4907.  }
  4908.  
  4909. DLLBITMP.H: 
  4910.  
  4911.  #define ID_RESOURCES    1
  4912.  #define IDD_DOIT    100
  4913.  #define IDM_DOIT    110
  4914.  #define ID_BITMAP    1100
  4915.  #define ID_BITMAPID    1200
  4916.  
  4917. DLLBITMP.DEF: 
  4918.  
  4919.  NAME        DLLBITMP      WINDOWAPI
  4920.  PROTMODE
  4921.  HEAPSIZE    16384
  4922.  STACKSIZE    16384
  4923.  
  4924. DLLBITMP.RC: 
  4925.  
  4926.  #include <os2.h>
  4927.  #include "dllbitmp.h"
  4928.  
  4929.  
  4930.  MENU ID_RESOURCES
  4931.  {
  4932.      MENUITEM "!~DoIt", IDM_DOIT
  4933.  }
  4934.  
  4935. DLGDLL.C: 
  4936.  
  4937.  #define  INCL_DOS
  4938.  #define  INCL_GPI
  4939.  #define  INCL_WIN
  4940.  #include <os2.h>
  4941.  #include "dllbitmp.h"
  4942.  
  4943.  
  4944.  FNWP wpDlg;
  4945.  
  4946.  
  4947.  VOID EXPENTRY DllDialog( HWND hwnd )
  4948.  {
  4949.     HMODULE hmod;
  4950.  
  4951.     DosQueryModuleHandle( "DLGDLL", &hmod );
  4952.     WinDlgBox( HWND_DESKTOP, hwnd, wpDlg, hmod, IDD_DOIT, NULL );
  4953.  }
  4954.  
  4955.  
  4956.  MRESULT EXPENTRY wpDlg( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2 )
  4957.  {
  4958.     switch (msg)
  4959.     {
  4960.        case WM_INITDLG:
  4961.        {
  4962.           HWND    hwndBmp = WinWindowFromID( hwndDlg, ID_BITMAPID );
  4963.           HPS     hps = WinGetPS( hwndDlg );
  4964.           HBITMAP hbm;
  4965.           HMODULE hmod;
  4966.  
  4967.           DosQuieryModuleHandle( "DLGDLL", &hmod );
  4968.           hbm = GpiLoadBitmap( hps, hmod, ID_BITMAP, 0, 0 );
  4969.           WinSetWindowBits(hwndBmp,QWL_STYLE,SS_BITMAP,SS_BITMAP | 0x7f);
  4970.           WinSendMsg( hwndBmp, SM_SETHANDLE, MPFROMP( hbm ), NULL );
  4971.           WinSetWindowULong( hwndDlg, QWL_USER, (ULONG) hbm );
  4972.           WinReleasePS( hps );
  4973.           break;
  4974.        }
  4975.        case WM_DESTROY:
  4976.        {
  4977.           HBITMAP hbm = (HBITMAP) WinQueryWindowULong(hwndDlg,QWL_USER );
  4978.           GpiDeleteBitmap( hbm );
  4979.           break;
  4980.        }
  4981.     }
  4982.     return WinDefDlgProc( hwndDlg, msg, mp1, mp2 );
  4983.  }
  4984.  
  4985. DLGDLL.DLG: 
  4986.  
  4987.  DLGTEMPLATE IDD_DOIT LOADONCALL MOVEABLE DISCARDABLE
  4988.  BEGIN
  4989.    DIALOG "", IDD_DOIT, 0, 0, 210, 154, FS_NOBYTEALIGN | FS_DLGBORDER |
  4990.               WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_TITLEBAR
  4991.    BEGIN
  4992.        CONTROL "foo", ID_BITMAPID, 98, 56, 32, 32, WC_STATIC,
  4993.                SS_TEXT | DT_LEFT | DT_TOP | WS_VISIBLE
  4994.    END
  4995.  END
  4996.  
  4997. DLGDLL.DEF: 
  4998.  
  4999.  LIBRARY    DLGDLL        INITINSTANCE    TERMINSTANCE
  5000.  PROTMODE
  5001.  CODE        LOADONCALL
  5002.  DATA        LOADONCALL    MULTIPLE    NONSHARED
  5003.  EXPORTS    DllDialog
  5004.  
  5005. DLGDLL.RC: 
  5006.  
  5007.  #include <os2.h>
  5008.  #include "dllbitmp.h"
  5009.  
  5010.  
  5011.  BITMAP  ID_BITMAP "dlgdll.bmp"
  5012.  
  5013.  
  5014.  rcinclude dlgdll.dlg
  5015.  
  5016. MAKEFILE: 
  5017.  
  5018.  all: dlgdll.dll dllbitmp.exe
  5019.  
  5020.  dlgdll.dll: $*.obj $*.res
  5021.      link386 /NOI /NOE /MAP /DE /NOL $*, $*.dll,, os2386, $*
  5022.      rc $*.res $*.dll
  5023.      implib $*.lib $*.def
  5024.  
  5025.  dllbitmp.exe: $*.obj $*.def $*.res
  5026.      link386  /NOI /NOE /MAP /DE /NOL $*,,, os2386 dlgdll, $*
  5027.      rc $*.res $*.exe
  5028.  
  5029.  dllbitmp.obj: $*.c
  5030.      icc /Q+ /Ss /W3 /Kbcepr /Gm- /Gd- /Ge+ /Ti+ /O- /C $*.c
  5031.  
  5032.  dllbitmp.res: $*.rc
  5033.      rc -r $*
  5034.  
  5035.  dlgdll.obj: $*.c
  5036.      icc /Q+ /Ss /W3 /Kbcepr /Gm- /Gd- /Ge- /Ti+ /O- /C $*.c
  5037.  
  5038.  dlgdll.res: $*.rc $*.dlg
  5039.      rc -r $*
  5040.  
  5041. Credit:  Rick Fishman 
  5042.  
  5043.  
  5044. ΓòÉΓòÉΓòÉ 8.34. How does programming PM compare to programming X? ΓòÉΓòÉΓòÉ
  5045.  
  5046. Many people have said "PM is much cleaner."  Until I hear from someone I trust 
  5047. with extensive experience with both (I only know X), however, this FAQ will 
  5048. take no position. 
  5049.  
  5050. There was an unsubstantiated rumor that someone was porting an X library to 
  5051. OS/2 (X-Windows, not X-Mode or any other X), I dunno whether this has been 
  5052. substantiated or not. 
  5053.  
  5054. IBM and a few other manufacturers have built their own X servers for OS/2. 
  5055. [details?] 
  5056.  
  5057. [Colin Jensen...] 
  5058.  
  5059. I have some limited experience with X and PM.  Raw Xlib is harder to program 
  5060. than PM.  However most, if not all, of the X11 Toolkits are *easier* to use 
  5061. than PM.  I have experience comparing XView to PM. A friend of mine has 
  5062. experience with Windows versus Xt, and has the same opinion (Windows isn't that 
  5063. far off conceptually from PM). 
  5064.  
  5065.  
  5066. ΓòÉΓòÉΓòÉ 8.35. How do I put bitmaps on buttons? ΓòÉΓòÉΓòÉ
  5067.  
  5068. Stefan Gruendal (Stefan_Gruendel@wue.maus.de) writes: 
  5069.  
  5070. But to my question:  How do I build my own "smart icons", i.e. bitmaps on 
  5071. pushbuttons, that optically "move into the screen"? I didn't find any way to 
  5072. achieve this with the Toolkit's Dialog Editor.  But as mentioned above, I know 
  5073. there's a way. 
  5074.  
  5075. Starting with OS/2 2.x, a new button style was added - BS_ICON - which allows 
  5076. you to do what you are trying to accomplish.  It works, as far as I know, only 
  5077. for pushbuttons, and the icon or bitmap is taken from the resource file, whose 
  5078. resource id is specified in the pushbutton text. 
  5079.  
  5080. For example: 
  5081.  
  5082. In FOO.H: 
  5083.  
  5084. #define IDBM_BUTTON 256
  5085. #define IDPB_BUTTON 257
  5086.  
  5087. In FOO.RC: 
  5088.  
  5089. BITMAP IDBM_BUTTON BUTTON.BMP
  5090.  
  5091. In FOO.C: 
  5092.  
  5093. sprintf(achText,"#%d",IDBM_BUTTON);
  5094.  
  5095. hwndButton=WinCreateWindow(hwndClient,WC_BUTTON,achText,
  5096.                            WS_VISIBLE|BS_PUSHBUTTON|BS_ICON,
  5097.                            10,10,32,32,hwndClient,HWND_TOP,
  5098.                            IDPB_BUTTON,NULL,NULL);
  5099.  
  5100. The bitmap is stretched or compressed to fill the button. 
  5101.  
  5102. (Quoted almost directly from EDMI/2 Edition 1) 
  5103.  
  5104.  
  5105. ΓòÉΓòÉΓòÉ 8.36. Can a PM program tell if there's a previous instance of itself running? ΓòÉΓòÉΓòÉ
  5106.  
  5107. Raja Thiagarajan (sthiagar@bronze.ucs.indiana.edu) writes: 
  5108.  
  5109. Can a PM program tell if there's a previous instance of itself running?  In 
  5110. Win3.x (but apparently NOT Win32), there's a hPrevInst handle; is there an OS/2 
  5111. 2.x equivalent?  Basically, I'm thinking in terms of a program that would try 
  5112. to borrow resources from a previous instance if a previous instance is running. 
  5113. (Specifically, if my palette animation program gets started twice, the second 
  5114. instance oughta share palettes with the first instance!) 
  5115.  
  5116. What you're really asking is two questions: 
  5117.  
  5118.  1. How can I determine if a previous instance of my application is already 
  5119.     running? 
  5120.  2. How can I share resources between multiple instances of my application? 
  5121.  
  5122. There are some ways to achieve this; You can use semaphores or/and shared 
  5123. memory or the other method described below. Try to open your named semaphore, 
  5124. if it's there, your application is already running, else create a semaphore... 
  5125. To share data, use shared memory. There are some excellent examples in Schildt 
  5126. & Goosey "OS/2 Programming". 
  5127.  
  5128. To answer your first question, you need to enumerate all of the main windows 
  5129. present on the desktop, and figure out if any of them are yours. This is 
  5130. achieved using the following code: 
  5131.  
  5132. HWND queryAppInstance(PCHAR pchClassWanted)
  5133. {
  5134.    HENUM heEnum;
  5135.    HWND hwndTop;
  5136.    HWND hwndClient;
  5137.    CHAR achClass[256];
  5138.  
  5139.    heEnum=WinBeginEnumWindows(HWND_DESKTOP);
  5140.  
  5141.    hwndTop=WinGetNextWindow(heEnum);
  5142.    while (hwndTop!=NULLHANDLE) {
  5143.       hwndClient=WinWindowFromID(hwndTop,FID_CLIENT);
  5144.       if (hwndClient!=NULLHANDLE) {
  5145.          WinQueryClassName(hwndClient,sizeof(achClass),achClass);
  5146.          if (strcmp(achClass,pchClassWanted)==0) {
  5147.             WinEndEnumWindows(heEnum);
  5148.             return hwndClient;
  5149.          } /* endif */
  5150.       } /* endif */
  5151.  
  5152.       hwndTop=WinGetNextWindow(heEnum);
  5153.    } /* endwhile */
  5154.  
  5155.    WinEndEnumWindows(heEnum);
  5156.    return NULLHANDLE;
  5157. }
  5158.  
  5159. To answer your second question, the only way that I know of to share resources 
  5160. is to place them in a DLL.  The procedure to do this is as follows: 
  5161.  
  5162. o Create a dummy source file with an empty procedure in it. 
  5163. o Compile the source file and link as a DLL. 
  5164. o Add your resources to the DLL in the same manner as you would to an 
  5165.   executable. 
  5166.  
  5167. Then, when your application starts, you simply call WinLoadLibrary  (the 
  5168. preferred way) or DosLoadModule to load the DLL.  These functions return a 
  5169. handle to the DLL which must then be used in any function which loads resources 
  5170. (e.g. GpiLoadBitmap, WinLoadPointer, etc.). 
  5171.  
  5172. Note that this procedure does not require knowing the window handle of any 
  5173. previous instance of your application because OS/2 implements DLLs in a shared 
  5174. fashion (which I suspect is one of the reasons they were created in the first 
  5175. place).  All you need to know is the name of the DLL.  This technique can also 
  5176. be used to share resources between different applications. 
  5177.  
  5178. (Quoted almost directly from EDMI/2 Edition 1) 
  5179.  
  5180.  
  5181. ΓòÉΓòÉΓòÉ 8.37. How to avoid crash when using Drag and Drop? ΓòÉΓòÉΓòÉ
  5182.  
  5183. You can avoid this by doing; 
  5184.  
  5185. 1) Call any DRG*() function in your application
  5186. 2) Call DosLoadModule() to load the PMDRAG.DLL file
  5187.  
  5188. Credit: Q 
  5189.  
  5190.  
  5191. ΓòÉΓòÉΓòÉ 8.38. Are there any PM bindings for GNU Ada? ΓòÉΓòÉΓòÉ
  5192.  
  5193. Yes. There are some PM bindings for gnat 2.03 or higher. 
  5194. They can be found at cs.nyu.edu:/pub/gnat/contrib/os2/PM. 
  5195.  
  5196.  
  5197. ΓòÉΓòÉΓòÉ 9. Miscellaneous Programming ΓòÉΓòÉΓòÉ
  5198.  
  5199. This section covers non-Presentation Manager programming. 
  5200.  
  5201.  
  5202. ΓòÉΓòÉΓòÉ 9.1. Explain the SYS_DLLS keywords. ΓòÉΓòÉΓòÉ
  5203.  
  5204. Actually there are three key names that exist for the app name SYS_DLLS. 
  5205.  
  5206. They are: 
  5207.  
  5208. Load 
  5209.           DLL loaded and ordinal 1 entry point called for every msg queue 
  5210.           created in the system 
  5211.  
  5212. LoadPerProcess 
  5213.           DLL loaded and ordinal 1 entry point called for only the first 
  5214.           message queue created on a process 
  5215.  
  5216. LoadOneTime 
  5217.           DLL loaded and ordinal 1 entry point called for only the shell's 
  5218.           message queue (the first PM queue in the system) 
  5219.  
  5220. You would use one over another depending on the type of initialization that you 
  5221. require.  Most DLL's only need to be initialized once for the system and are 
  5222. thus LoadOneTime, some DLLs like PMCTLS have per process initialization and 
  5223. thus are LoadPerProcess, and then there is the very rare case of DLLs that need 
  5224. to perform some function every time a message queue is created and these are 
  5225. specified as Load.  Note: that anything other than LoadOneTime is a significant 
  5226. performance hit on the system.  Note: also that in addition to your 
  5227. INITIALIZATION/TERMINATION function specified in the DEF file for your DLL 
  5228. (which is a new feature in 2.0), your ORDINAL 1 entry point in your DLL is also 
  5229. called.  Be careful with this as I have seen some pretty strange results if you 
  5230. have an ordinal 1 entry point that has nothing to do with initialization.  In 
  5231. addition, remember to never ever create a message queue inside of your 
  5232. initialization routine.  Always call WinQueryAnchorBlock if you need a HAB for 
  5233. some API. 
  5234.  
  5235. As for shared resources, if you need resources on multiple processes then they 
  5236. need to be created on multiple processes as they won't be valid on any process 
  5237. other than the one you loaded.  I believe that this is the reason PMCTLS is 
  5238. LoadPerProcess.  You have a few options here, 1) you can store your resources 
  5239. in shared memory, and 2) for icons you can call WinSetPoinerOwner to make your 
  5240. icons shared across the entire system. 
  5241.  
  5242.  
  5243. ΓòÉΓòÉΓòÉ 9.2. How do I start another session? ΓòÉΓòÉΓòÉ
  5244.  
  5245. This small program will start any program synchronously using 
  5246. DosStartSession(). The important thing is the queue. When you specify 
  5247. SSF_RELATED_CHILD and a TermQ name, OS/2 will write the return code to the 
  5248. specified queue when the session terminates. I use this in an event scheduler 
  5249. by creating a separate thread that does reads from the queue but you can just 
  5250. as easily block on the main thread to catch the return code. That will, in 
  5251. effect, provide for synchronous execution. Note that one problem with 
  5252. SSF_RELATED_CHILD is that if the program that started the child dies, so does 
  5253. the child. 
  5254.  
  5255.  #define  INCL_DOSERRORS
  5256.  #define  INCL_DOSPROCESS
  5257.  #define  INCL_DOSQUEUES
  5258.  #define  INCL_DOSSESMGR
  5259.  #include <os2.h>
  5260.  #include <stdio.h>
  5261.  #include <stdlib.h>
  5262.  #include <string.h>
  5263.  
  5264.  #define QUEUE_NAME    "\\QUEUES\\STRTSYNC.QUE"
  5265.  
  5266.  int main( int argc, char *argv[] );
  5267.  
  5268.  int main( int argc, char *argv[] )
  5269.  {
  5270.      APIRET rc;
  5271.      HQUEUE hque;
  5272.  
  5273.      if( argc < 2 )
  5274.          return 1;
  5275.  
  5276.      rc = DosCreateQueue( &hque, QUE_FIFO | QUE_CONVERT_ADDRESS, QUEUE_NAME );
  5277.      if( !rc )
  5278.      {
  5279.          STARTDATA   stdata;
  5280.          PID         pidSession;
  5281.          CHAR        szObjFail[ 50 ];
  5282.          ULONG       ulLength, idSession;
  5283.          REQUESTDATA rd;
  5284.          PUSHORT     pusInfo = NULL;
  5285.          BYTE        bPriority;
  5286.  
  5287.          (void) memset( &stdata, 0, sizeof( stdata ) );
  5288.  
  5289.          stdata.Length       = sizeof( STARTDATA );
  5290.          stdata.FgBg         = SSF_FGBG_FORE;
  5291.          stdata.TraceOpt     = SSF_TRACEOPT_NONE;
  5292.          stdata.PgmTitle     = "Rick's Program";
  5293.          stdata.InheritOpt   = SSF_INHERTOPT_SHELL;
  5294.          stdata.SessionType  = SSF_TYPE_DEFAULT;
  5295.          stdata.PgmControl   = SSF_CONTROL_VISIBLE;
  5296.          stdata.ObjectBuffer = szObjFail;
  5297.          stdata.ObjectBuffLen= sizeof( szObjFail );
  5298.          stdata.Related      = SSF_RELATED_CHILD;
  5299.          stdata.TermQ        = QUEUE_NAME;
  5300.          stdata.PgmName      = argv[ 1 ];
  5301.  
  5302.          rc = DosStartSession( &stdata, &idSession, &pidSession );
  5303.  
  5304.          if( rc && rc != ERROR_SMG_START_IN_BACKGROUND )
  5305.          {
  5306.              printf( "DosStartSession RC(%u)\n", rc );
  5307.              return (INT) rc;
  5308.          }
  5309.  
  5310.          rc = DosReadQueue( hque, &rd, &ulLength, (PPVOID) &pusInfo, 0,
  5311.                             DCWW_WAIT, &bPriority, 0 );
  5312.  
  5313.          if( rc && rc != ERROR_QUE_EMPTY )
  5314.          {
  5315.              printf( "DosReadQueue RC(%u)\n", rc );
  5316.              return (INT) rc;
  5317.          }
  5318.  
  5319.          printf( "RetCode from Session %u: %u\n",
  5320.                   pusInfo[ 0 ], pusInfo[ 1 ]);
  5321.  
  5322.          DosCloseQueue( hque );
  5323.      }
  5324.      else
  5325.      {
  5326.          printf( "DosCreateQueue RC(%u)\n", rc );
  5327.          return (INT) rc;
  5328.      }
  5329.  
  5330.      return 0;
  5331.  }
  5332.  
  5333. Credit:  Rick Fishman 
  5334.  
  5335.  
  5336. ΓòÉΓòÉΓòÉ 9.3. How do I check if a filename is valid? ΓòÉΓòÉΓòÉ
  5337.  
  5338. Here's some code that should help.  I found that you have to look at each 
  5339. return code to see if it's really an error.  This routine does do syntax 
  5340. checking, it's just a little more complicated than before :^) 
  5341.  
  5342. #define INCL_DOSFILEMGR
  5343. #define INCL_DOSERRORS
  5344. #include <os2.h>
  5345. #include <stdio.h>
  5346.  
  5347. int main( int argc, char **argv )
  5348. {
  5349.         int         rc;
  5350.         FILESTATUS3 piBuffer;
  5351.  
  5352.         if ( argc !=2 )
  5353.         {
  5354.                 printf( "Must pass filename on command line!\n");
  5355.                 return( -1 );
  5356.         }
  5357.         else
  5358.         {
  5359.                 printf( "Checking on %s, ", argv[ 1 ] );
  5360.                 rc = DosQueryPathInfo( (PSZ)argv[1], FIL_STANDARD, &piBuffer,
  5361.                                        sizeof(FILESTATUS3));
  5362.  
  5363.                 if ( rc == 0 )
  5364.                         printf( "syntax valid and file exists\n" );
  5365.                 else
  5366.                 if ( rc == ERROR_FILE_NOT_FOUND )
  5367.                         printf( "syntax valid and file doesn't exist.\n");
  5368.                 else
  5369.                 if ( rc == ERROR_PATH_NOT_FOUND )
  5370.                         printf( "syntax valid, somthing in path was not found\n");
  5371.                 else
  5372.                 {
  5373.                         printf( "bad, rc=%d, ",rc );
  5374.                         switch( rc )
  5375.                         {
  5376.                                 case ERROR_INVALID_DRIVE:
  5377.                                         printf( "drive name does not exist\n");
  5378.                                         break;
  5379.  
  5380.                                 case ERROR_INVALID_NAME:
  5381.                                         printf( "invalid syntax for drive name\n");
  5382.                                         break;
  5383.  
  5384.                                 case ERROR_FILENAME_EXCED_RANGE:
  5385.                                         printf( "dir name and/or filename too long\n");
  5386.                                         break;
  5387.  
  5388.                                 case ERROR_SHARING_VIOLATION:
  5389.                                         printf( "sharing violation\n");
  5390.                                         break;
  5391.  
  5392.                                 case ERROR_BUFFER_OVERFLOW:
  5393.                                         printf( "buffer overflow\n");
  5394.                                         break;
  5395.  
  5396.                                 case ERROR_INVALID_LEVEL:
  5397.                                         printf( "invalid level requested\n");
  5398.                                         break;
  5399.  
  5400.                                 case ERROR_INVALID_EA_NAME:
  5401.                                         printf( "invalid EA name\n");
  5402.                                         break;
  5403.  
  5404.                                 case ERROR_EA_LIST_INCONSISTENT:
  5405.                                         printf( "EA list inconsistent\n");
  5406.                                         break;
  5407.  
  5408.                                 default:
  5409.                                         printf("Undocumented return value.\n");
  5410.                         }
  5411.                         return( -1 );
  5412.             }
  5413.             return( 0 );
  5414.         }
  5415. }
  5416.  
  5417. Credit:  Mike Brown 
  5418.  
  5419.  
  5420. ΓòÉΓòÉΓòÉ 9.4. Why should I use _beginthread instead of DosCreateThread? ΓòÉΓòÉΓòÉ
  5421.  
  5422. You must if you want to use the C runtime library. 
  5423.  
  5424.  
  5425. ΓòÉΓòÉΓòÉ 9.5. How do I open a file that is already in use? ΓòÉΓòÉΓòÉ
  5426.  
  5427. Use DosOpen with OPEN_SHARE_DENYNONE. 
  5428.  
  5429. /* this will copy an open program */
  5430.  
  5431. #define INCL_NOPM
  5432. #define INCL_DOS
  5433. #include <os2.h>
  5434. #include <stdio.h>
  5435. #include <string.h>
  5436.  
  5437. void usage(void)
  5438. {
  5439.     printf("USAGE: CopyOpen <source file> <dest file>\n\n");
  5440.     printf("       This program,  unlike the normal copy and xcopy commands,\n");
  5441.     printf("       will copy an open file.\n");
  5442.     printf("NOTE:  Wildcards are not supported\n");
  5443. }
  5444.  
  5445. int cdecl main(int argc, char **argv)
  5446. {
  5447.     HFILE hf, hfOut;
  5448.     USHORT usAction, rc, bytesRead, bytesWriten ;
  5449.     static BYTE buf[4096];
  5450.     long total=0l;
  5451.     int error = FALSE;
  5452.  
  5453.     if(argc!=3){
  5454.         usage();
  5455.         return 1;
  5456.     }
  5457.     rc = DosOpen(strupr(argv[1]),
  5458.         &hf,
  5459.         &usAction,
  5460.         0L,
  5461.         FILE_NORMAL,
  5462.         FILE_OPEN,
  5463.         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
  5464.         0L);
  5465.     if(rc){
  5466.         printf("SYS%04u: Could not open %s for read.\n", rc, argv[1]);
  5467.         return 3;
  5468.     }
  5469.     rc = DosOpen(strupr(argv[2]),
  5470.         &hfOut,
  5471.         &usAction,
  5472.         0L,
  5473.         FILE_NORMAL,
  5474.         FILE_CREATE | FILE_TRUNCATE,
  5475.         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
  5476.         0L);
  5477.     if(rc){
  5478.         printf("SYS%04u: Could not open %s for write.\n", rc, argv[2]);
  5479.         return 3;
  5480.     }
  5481.     else{
  5482.         do{
  5483.             rc = DosRead(hf, buf, sizeof(buf), &bytesRead);
  5484.             if(!rc){
  5485.                rc = DosWrite(hfOut, buf, bytesRead, &bytesWriten);
  5486.                if(!rc) total += bytesWriten;
  5487.             }
  5488.         }while(!rc &&
  5489.                sizeof(buf) == bytesRead &&
  5490.                bytesRead == bytesWriten);
  5491.         if(rc){
  5492.             printf("SYS%04u: while copying.\n", rc);
  5493.             error = TRUE;
  5494.         }
  5495.         if(bytesRead != bytesWriten){
  5496.             printf("Disk full?\n");
  5497.             error = TRUE;
  5498.         }
  5499.         DosClose(hf);
  5500.         if(!error)
  5501.             printf("%lu bytes copied.\n", total);
  5502.     }
  5503.     return( error? 3 : 0);
  5504. }
  5505.  
  5506. Credit:  Peter Fitzsimmons 
  5507.  
  5508.  
  5509. ΓòÉΓòÉΓòÉ 9.6. Can we use Vio in v2.0? Where are the docs for it? ΓòÉΓòÉΓòÉ
  5510.  
  5511. Yes; check cdrom.com for PRCP.ZIP. 
  5512.  
  5513.  
  5514. ΓòÉΓòÉΓòÉ 9.7. Can I redirect stdin and stdout in a child process? ΓòÉΓòÉΓòÉ
  5515.  
  5516. This is what I use to redirect stderr, stdout to a file from a program I start 
  5517. using DosStartSession. You could do the same type of thing using a pipe. 
  5518.  
  5519.     ULONG  ulAction;
  5520.     ULONG  ulNew;
  5521.     HFILE  hfFile, hfNewStdOut = -1, hfNewStdErr = -1,
  5522.            hfStdOut = 1, hfStdErr = 2;
  5523.  
  5524.     // Open output file
  5525.     DosOpen( szOutputFile, &hfFile, &ulAction, 1, 0,
  5526.              FILE_OPEN | FILE_CREATE,
  5527.              OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, 0L );
  5528.     // Duplicate handles
  5529.     DosDupHandle( hfStdOut, phfNewStdOut );
  5530.     DosDupHandle( hfStdErr, phfNewStdErr );
  5531.     // Close existing handles for current process
  5532.     DosClose( hfStdOut );
  5533.     DosClose( hfStdErr );
  5534.     // Redirect existing handles to new file
  5535.     DosDupHandle( hfFile, &hfStdOut );
  5536.     DosDupHandle( hfFile, &hfStdErr );
  5537.     // Let started program inherit handles from parent
  5538.     stdata.InheritOpt = SSF_INHERITOPT_PARENT;
  5539.     // Start new session
  5540.     DosStartSession( &stdata, &ulSessionID, &pidSession );
  5541.     // Get back original handles
  5542.     DosDupHandle( hfNewStdOut, &hfStdOut );
  5543.     DosDupHandle( hfNewStdErr, &hfStdErr );
  5544.     // Close the duplicated handles - no longer needed
  5545.     DosClose( hfNewStdOut );
  5546.     DosClose( hfNewStdErr );
  5547.  
  5548. Credit:  Rick Fishman 
  5549.  
  5550.  
  5551. ΓòÉΓòÉΓòÉ 9.8. How do I use DosMon*() to stuff the kbd buf? ΓòÉΓòÉΓòÉ
  5552.  
  5553. Here's a mini app (all error handling, comments, etc. removed.) 
  5554.  
  5555. (also all this stuff to avoid compile warnings !!!!!). 
  5556.  
  5557. compile with: icc -Sm -Kabgioprx+ -Ss+ -W3 -Gs+ -Gf+ -O+ KEY.C
  5558. start with: detach key
  5559. stop with: F11 or CTRL-F10
  5560. test envir: OS/2 2.0GA+SP, C-Set++ CSD 22.
  5561. no other functionality.
  5562.  
  5563. orginal src part of my glorious DOS/OS2 1.x/OS2 2.0 keyboard roboter which 
  5564. inserts keys into the keyboard monitor queue controlled by an source file (mini 
  5565. language). 
  5566.  
  5567.    (C) Mario Semo 1777,1832,1967-92. 
  5568.  
  5569. ========= TOP OF FILE KEY.C ================ 
  5570.  
  5571. #define INCL_DOS
  5572. #define INCL_KBD
  5573. #define INCL_NOPM
  5574.  
  5575. #include<os2.h>
  5576. #include<stdio.h>
  5577. #include<conio.h>
  5578. #include<process.h>
  5579. #include<stdlib.h>
  5580. #include<string.h>
  5581.  
  5582. #define DosMonOpen  DOS16MONOPEN
  5583. #define DosMonClose DOS16MONCLOSE
  5584. #define DosMonReg   DOS16MONREG
  5585. #define DosMonRead  DOS16MONREAD
  5586. #define DosMonWrite DOS16MONWRITE
  5587.  
  5588. #define MONITOR_DEFAULT 0x0000
  5589. #define MONITOR_BEGIN   0x0001
  5590. #define MONITOR_END     0x0002
  5591.  
  5592. typedef SHANDLE HMONITOR;       /* hmon */
  5593. typedef HMONITOR *PHMONITOR;
  5594.  
  5595. #pragma pack(2)
  5596. typedef struct _MONIN {         /* mnin */
  5597.         USHORT cb;
  5598.         BYTE abReserved[18];
  5599.         BYTE abBuffer[108];
  5600. } MONIN;
  5601. typedef MONIN *PMONIN;
  5602.  
  5603. #pragma pack(2)
  5604. typedef struct _MONOUT {        /* mnout */
  5605.         USHORT cb;
  5606.         UCHAR buffer[18];
  5607.         BYTE abBuf[108];
  5608. } MONOUT;
  5609. typedef MONOUT *PMONOUT;
  5610.  
  5611. APIRET16 APIENTRY16 DosMonOpen(PSZ pszDevName, PHMONITOR phmon);
  5612. APIRET16 APIENTRY16 DosMonClose(HMONITOR hmon);
  5613. APIRET16 APIENTRY16 DosMonReg(HMONITOR hmon, PBYTE pbInBuf,
  5614.              PBYTE pbOutBuf, USHORT fPosition, USHORT usIndex);
  5615. APIRET16 APIENTRY16 DosMonRead(PBYTE pbInBuf, USHORT fWait,
  5616.                                PBYTE pbDataBuf,
  5617.                                PUSHORT pcbData);
  5618. APIRET16 APIENTRY16 DosMonWrite(PBYTE pbOutBuf, PBYTE pbDataBuf,
  5619.                                 USHORT cbData);
  5620.  
  5621. #define DosGetInfoSeg    DOS16GETINFOSEG
  5622. APIRET16 APIENTRY16 DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal);
  5623.  
  5624. #pragma pack(2)
  5625. typedef struct _GINFOSEG { /* gis */
  5626.         ULONG   time; ULONG   msecs; UCHAR   hour;
  5627.         UCHAR   minutes; UCHAR   seconds; UCHAR   hundredths;
  5628.         USHORT  timezone; USHORT cusecTimerInterval; UCHAR   day;
  5629.         UCHAR   month; USHORT  year; UCHAR   weekday;
  5630.         UCHAR   uchMajorVersion; UCHAR uchMinorVersion;
  5631.         UCHAR   chRevisionLetter; UCHAR   sgCurrent;
  5632.         UCHAR   sgMax; UCHAR   cHugeShift;
  5633.         UCHAR   fProtectModeOnly; USHORT pidForeground;
  5634.         UCHAR   fDynamicSched; UCHAR   csecMaxWait;
  5635.         USHORT  cmsecMinSlice; USHORT  cmsecMaxSlice;
  5636.         USHORT  bootdrive; UCHAR   amecRAS[32];
  5637.         UCHAR   csgWindowableVioMax; UCHAR   csgPMMax;
  5638. } GINFOSEG;
  5639. typedef GINFOSEG *PGINFOSEG;
  5640.  
  5641. static PGINFOSEG gdt;
  5642.  
  5643. #define MAKEPGINFOSEG(sel)  ((PGINFOSEG)MAKEP(sel, 0))
  5644. #define MAKEPLINFOSEG(sel)  ((PLINFOSEG)MAKEP(sel, 0))
  5645.  
  5646. #pragma pack(2)
  5647. typedef struct _keypacket
  5648.   {
  5649.    USHORT     mnflags;
  5650.    KBDKEYINFO cp;
  5651.    USHORT     ddflags;
  5652.   } KEYPACKET;
  5653.  
  5654.  
  5655. #define RELEASE     0x40
  5656. #define CTL_F10_KEY 103
  5657. #define F11_KEY     133
  5658.  
  5659. #pragma stack16(8192)
  5660. #pragma seg16(HKBD)
  5661. #pragma seg16(MONIN)
  5662. #pragma seg16(MONOUT)
  5663. #pragma seg16(KEYPACKET)
  5664.  
  5665. static HKBD KBDHandle = (HKBD)0;
  5666. static PGINFOSEG _Seg16 gdt;
  5667. static MONIN monInbuf = {0};
  5668. static MONOUT monOutbuf = {0};
  5669. static HEV hevThreadDone = (HEV)0;
  5670.  
  5671. static void _System keyboard_monitor(ULONG Dummy);
  5672.  
  5673. int main(int argc, char *argv[], char *envp[])
  5674. {
  5675.  SEL gdt_descriptor, ldt_descriptor;
  5676.  PID pidKeybrd;
  5677.  
  5678.  monInbuf.cb  = sizeof(MONIN);
  5679.  monOutbuf.cb = sizeof(MONOUT);
  5680.  
  5681.  DosGetInfoSeg(&gdt_descriptor, &ldt_descriptor);
  5682.  
  5683.  gdt = MAKEPGINFOSEG(gdt_descriptor);
  5684.  
  5685.  DosMonOpen ( "KBD$", &KBDHandle );
  5686.  
  5687.  DosCreateEventSem(NULL, &hevThreadDone,0,FALSE);
  5688.  
  5689.  if (DosCreateThread(&pidKeybrd, &keyboard_monitor, 0L, 2L, 12000L))
  5690.          DosExit(EXIT_PROCESS,0);
  5691.  
  5692.  DosWaitEventSem(hevThreadDone, (ULONG)SEM_INDEFINITE_WAIT);
  5693.  DosMonClose(KBDHandle);
  5694.  
  5695.  DosBeep(100,100);
  5696.  
  5697.  DosExit(EXIT_PROCESS,0);
  5698.  return(0);
  5699. }
  5700.  
  5701.  
  5702. static void _System keyboard_monitor(ULONG Dummy)
  5703. {
  5704.  KEYPACKET keybuff;
  5705.  USHORT count;
  5706.  
  5707.  DosSetPrty(PRTYS_THREAD, PRTYC_TIMECRITICAL,0, 0);
  5708.  
  5709.  DosMonReg( KBDHandle, (PBYTE)&monInbuf, (PBYTE)&monOutbuf,
  5710.             MONITOR_BEGIN, gdt->sgCurrent);
  5711.  
  5712.  DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR,0, 0);
  5713.  
  5714.  for(keybuff.cp.chChar = 0; ; )
  5715.    {
  5716.     count = sizeof(keybuff);
  5717.     DosMonRead( (PBYTE)&monInbuf, IO_WAIT, (PBYTE)&keybuff, &count);
  5718.     if (!(keybuff.ddflags & RELEASE))
  5719.        {
  5720.         if(keybuff.cp.chChar == 0)
  5721.           {
  5722.            switch (keybuff.cp.chScan)
  5723.              {
  5724.               case CTL_F10_KEY   :
  5725.               case F11_KEY       :
  5726.                  DosPostEventSem(hevThreadDone);
  5727.                  DosExit(EXIT_THREAD,0);
  5728.                  break;
  5729.              }
  5730.           }
  5731.        }
  5732.     DosMonWrite((PBYTE)&monOutbuf,(PBYTE)&keybuff,count);
  5733.    }
  5734. }
  5735.  
  5736. Credit:  Mario Semo 
  5737.  
  5738.  
  5739. ΓòÉΓòÉΓòÉ 9.9. How do I determine what file system a drive uses? ΓòÉΓòÉΓòÉ
  5740.  
  5741. 16 bit:  DosQFsInfo().
  5742. 32 but:  DosQueryFSInfo()
  5743.  
  5744. The folling little 16 bit program produces the following output on my computer: 
  5745.  
  5746.  LOCAL  C:  FAT
  5747.  LOCAL  D:  HPFS
  5748.  LOCAL  E:  HPFS
  5749.  LOCAL  F:  FAT
  5750.  REMOTE P:  LAN   \\SERV1\C$
  5751.  REMOTE Q:  LAN   \\SERV1\D$
  5752.  REMOTE R:  LAN   \\SERV1\E$
  5753.  
  5754. Code.... 
  5755.  
  5756.  /* qdisk.c */
  5757.  #define INCL_NOPM
  5758.  #define INCL_DOS
  5759.  #include <os2.h>
  5760.  #include <stdio.h>
  5761.  #include <stdlib.h>
  5762.  
  5763.  
  5764.  void errorRC(USHORT rc)
  5765.  {
  5766.      char msg[256];
  5767.      USHORT bc;
  5768.      if(0 != (rc=DosGetMessage(NULL, 0, msg, sizeof(msg), rc,
  5769.                                "OSO001.MSG", &bc))) {
  5770.          printf("SYS%04u: Unable to access OSO001.MSG\n", rc);
  5771.      }
  5772.      else DosWrite(2, msg, bc, &bc);
  5773.  }
  5774.  
  5775.  void qdisk(char drv)
  5776.  {
  5777.      USHORT rc, len;
  5778.      char dev[3];
  5779.      void *buf;
  5780.      char *p;
  5781.  
  5782.      if(drv < 'C')
  5783.          return;
  5784.      sprintf(dev, "%c:", drv);
  5785.      buf = malloc(2048);
  5786.      len = 2048;
  5787.      rc = DosQFSAttach(dev, 0, FSAIL_QUERYNAME, buf, &len, 0L);
  5788.      if(rc){
  5789.          errorRC(rc);
  5790.          return;
  5791.      }
  5792.      switch((*(PUSHORT)buf)){
  5793.          case FSAT_CHARDEV  : printf("CHAR   "); break;
  5794.          case FSAT_PSEUDODEV: printf("DEV    "); break;
  5795.          case FSAT_LOCALDRV : printf("LOCAL  "); break;
  5796.          case FSAT_REMOTEDRV: printf("REMOTE "); break;
  5797.          default: printf("Unknown "); break;
  5798.      }
  5799.      p = buf;
  5800.      p += sizeof(USHORT);    /* itype */
  5801.      printf("%-3s ", p+sizeof(USHORT));
  5802.      p += (sizeof(USHORT) + (*(USHORT *)p) + 1);    /* cbName */
  5803.      printf("%-8s ", p+sizeof(USHORT));
  5804.      p += (sizeof(USHORT) + (*(USHORT *)p) + 1);    /* cbFSDName */
  5805.      if((*(USHORT *)p))                             /* cbFSAData */
  5806.          printf("%s", p+sizeof(USHORT));
  5807.      printf("\n");
  5808.      free(buf);
  5809.  }
  5810.  
  5811.  void cdecl main(void)
  5812.  {
  5813.      char drv;
  5814.      USHORT usDisk;
  5815.      ULONG ulDrives;
  5816.      DosQCurDisk(&usDisk, &ulDrives); /* gets current drive */
  5817.      for (drv = 'A'; drv <= 'Z'; drv++) {
  5818.          if (ulDrives & 1)              /* if the drive bit is set, */
  5819.              qdisk(drv);
  5820.          ulDrives >>= 1;
  5821.      }
  5822.  }
  5823.  
  5824. ps: DosQSysInfo() will return the max path length that your version of OS/2 
  5825. supports.  But since this API is specific to OS/2,  and not to a particular 
  5826. drive,  it does not answer your original question. 
  5827.  
  5828. Credit: Peter Fitzsimmons 
  5829.  
  5830.  
  5831. ΓòÉΓòÉΓòÉ 9.10. How do I get the error message from a DOS API call? ΓòÉΓòÉΓòÉ
  5832.  
  5833. For DOSAPI calls, you can issue a DosGetMessage as follows: 
  5834.  
  5835.    RC = DosXXXX(...);
  5836.    DosGetMessage(NULL,0,Msg,sizeof(Msg),RC,"OSO001.MSG",&Msg_Length);
  5837.  
  5838. Credit:  Ken Kahn 
  5839.  
  5840.  
  5841. ΓòÉΓòÉΓòÉ 9.11. How do I set an exception handler? ΓòÉΓòÉΓòÉ
  5842.  
  5843. /*
  5844.  * Simple example of an exception handler
  5845.  */
  5846.  
  5847. #define INCL_DOS
  5848. #include <os2.h>
  5849. #include <setjmp.h>
  5850. #include <stdio.h>
  5851. #include <string.h>
  5852.  
  5853. extern int main(void);
  5854.  
  5855.  /*
  5856.  * Exception registration record.  Stored on stack, with first
  5857.  * pointer to next registeration record, second pointer to
  5858.  * exception handler, and the rest defined by the author of
  5859.  * the exception handler.
  5860.  */
  5861.  
  5862. typedef struct {
  5863.   struct _EXCEPTIONREGISTRATIONRECORD * volatile prev_structure;
  5864.    _ERR * volatile ExceptionHandler;
  5865.    jmp_buf env;
  5866. } MYEXCEPTIONREGISTRATIONRECORD, *PMYEXCEPTIONREGISTRATIONRECORD;
  5867.  
  5868. /*
  5869.  * Exception handler that returns traps via longjmp().
  5870.  */
  5871.  
  5872. extern ULONG APIENTRY MyExceptionHandler
  5873.     (PEXCEPTIONREPORTRECORD pReportRecord,
  5874.     PEXCEPTIONREGISTRATIONRECORD pRegRecord,
  5875.     PCONTEXTRECORD pContextRecord, PVOID pReserved)
  5876. {
  5877.   ULONG rc = XCPT_CONTINUE_SEARCH;
  5878.  
  5879.   if (pReportRecord->ExceptionNum == XCPT_ACCESS_VIOLATION)
  5880.     longjmp(((PMYEXCEPTIONREGISTRATIONRECORD) pRegRecord)->env, -1);
  5881.  
  5882.   /*
  5883.    * If we return to here then we could not handle the exception.
  5884.    */
  5885.  
  5886.   return rc;
  5887. }
  5888.  
  5889. extern BOOL Trapper(PSZ psz)
  5890. {
  5891.   MYEXCEPTIONREGISTRATIONRECORD myExceptionRegRecord;
  5892.  
  5893.   /*
  5894.    * Insert my exception handler into the chain.
  5895.    */
  5896.  
  5897.   myExceptionRegRecord.prev_structure = NULL;
  5898.   myExceptionRegRecord.ExceptionHandler = MyExceptionHandler;
  5899.   DosSetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD) &myExceptionRegRecord);
  5900.  
  5901.   if (setjmp(myExceptionRegRecord.env))
  5902.     goto OnException;
  5903.  
  5904.   /*
  5905.    * Now go about my business in safety.
  5906.    */
  5907.  
  5908.   if (strlen(psz))
  5909.     printf("Trapper says okay to '%s'\n", psz);
  5910.   else
  5911.     printf("Trapper says it is empty\n");
  5912.  
  5913.   /*
  5914.    * I'm done, so unchain my exception handler.
  5915.    */
  5916.  
  5917.   DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&myExceptionRegRecord)
  5918.  
  5919.   return TRUE;
  5920.  
  5921.   /*
  5922.    * The code below is only executed if a trap occurs.
  5923.    */
  5924.  
  5925. OnException:
  5926.   printf("Trapper says 'ouch!'\n");
  5927.  
  5928.   DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&myExceptionRegRecord)
  5929.  
  5930.   return FALSE;
  5931. }
  5932.  
  5933. extern int main()
  5934. {
  5935.   Trapper("Hello");
  5936.   Trapper(NULL);
  5937.   Trapper("");
  5938.   Trapper((PSZ) 42);
  5939.   Trapper("Goodbye");
  5940.  
  5941.   return 0;
  5942. }
  5943.  
  5944. Credit:  Dan Kehn 
  5945.  
  5946.  
  5947. ΓòÉΓòÉΓòÉ 9.12. How can I determine a diskette format and if a disk is in a drive? ΓòÉΓòÉΓòÉ
  5948.  
  5949. Let's have a snippet from one of my functions: 
  5950.  
  5951. The 'ifdef M_I386's mean CSet/2 
  5952.  
  5953. --- snip --- 
  5954.  
  5955. EXPORT int GetFileSysAttach ( char cDrv, PVOID pInfo, UnsInt cbInfo )
  5956. {
  5957. CHAR szFileSys [4];
  5958.  
  5959.   szFileSys [0] = (CHAR) toupper ( cDrv );
  5960.   szFileSys [1] = ':';
  5961.   szFileSys [2] = '\0';
  5962.  
  5963.   DosError ( EXCEPTION_DISABLE );
  5964.  
  5965. #ifdef M_I386
  5966.   Errno = DosQueryFSAttach ( szFileSys, 0, FSAIL_QUERYNAME, pInfo, &cbInfo );
  5967. #else
  5968.   Errno = DosQFSAttach ( szFileSys, 0, FSAIL_QUERYNAME, pInfo, &cbInfo, 0L );
  5969. #endif
  5970.  
  5971.   DosError ( EXCEPTION_ENABLE );
  5972.   return Errno ? -1 : 0;
  5973. }
  5974.  
  5975.  
  5976. EXPORT    int    GetFileSysInfo ( PSZ pszFileSys, PFSysInfo pfsi )
  5977. {
  5978. USHORT    idDrv;
  5979. FSALLOCATE fsal;
  5980. FSINFO    fsinfo;
  5981. #ifdef M_I386
  5982. PFSQBUFFER2 fsq = NULL;
  5983. #else
  5984. PFSQBUFFER  fsq = NULL;
  5985. PUSHORT     pus;
  5986. #endif
  5987. CHAR    hbuf [L_FILENAME];
  5988. PCHAR   pch;
  5989. #ifndef _MT
  5990. BOOL    fProt = ProtectedMode ();
  5991. #else
  5992. #define fProt TRUE
  5993. #endif
  5994.  
  5995.   idDrv = tolower ( *pszFileSys ) - ('a' - 1);
  5996.  
  5997.   DosError ( EXCEPTION_DISABLE );
  5998.  
  5999.   if ( ! (Errno = DosQFSInfo ( idDrv, 1, (PBYTE) &fsal, sizeof ( fsal ) )) )
  6000.     Errno = DosQFSInfo ( idDrv, 2, (PBYTE) &fsinfo, sizeof ( fsinfo ) );
  6001.  
  6002.   DosError ( EXCEPTION_ENABLE );
  6003.  
  6004.   if ( Errno )
  6005.   {
  6006.     if ( Errno == ERROR_NO_VOLUME_LABEL )
  6007.       memset ( &fsinfo, 0, sizeof (fsinfo) );
  6008.     else
  6009.       return -1; // No disk inserted
  6010.   }
  6011.  
  6012.   if ( fProt )
  6013.   {
  6014.     if ( GetFileSysAttach ( (CHAR) (idDrv + 'a' - 1), hbuf, L_FILENAME ) )
  6015.       return -1;
  6016.  
  6017. #ifdef M_I386
  6018.     fsq = (PFSQBUFFER2) hbuf;
  6019. #else
  6020.     fsq = (PFSQBUFFER) hbuf;
  6021. #endif
  6022.   }
  6023.  
  6024.   DosError ( EXCEPTION_ENABLE );
  6025.  
  6026.   ...
  6027.  
  6028. --- snap --- 
  6029.  
  6030. I think it's more than you want, the fsal-struct contains the size information, 
  6031. but I think if you want to retrieve ALL information about a logical drive 
  6032. that's what you need. 
  6033.  
  6034. Credit:  Rainer Prem 
  6035.  
  6036.  
  6037. ΓòÉΓòÉΓòÉ 9.13. What do all those keywords mean when making a DLL? ΓòÉΓòÉΓòÉ
  6038.  
  6039. Okay, with the help of some of my peers, I've solved the mystery surrounding 
  6040. the seemingly redundant SINGLE/MULTIPLE and SHARED/NONSHARED attributes. 
  6041.  
  6042. First, some prep up work... 
  6043.  
  6044. Every DLL needs and gets a data segment ("automatic data segment"). It is the 
  6045. place where the DLL stores all its STATIC data--basically the data declared in 
  6046. the DLL module but declared outside any function AND (I venture) variables 
  6047. declared STATIC within a DLL function as well. The STACK is NOT!! part of a 
  6048. DLL's automatic data segment (thoug it seems to be for an EXE). The stack that 
  6049. is used when 'running' a DLL function is that of the calling thread. 
  6050.  
  6051. Now here's the clincher... 
  6052.  
  6053. DLLs CAN ALSO HAVE ADDITIONAL DATA SEGMENTS!! (as can EXEs, I imagine) 
  6054.  
  6055. Bingo! Now we understand why there are two different sets of 
  6056. attributes--specifically, NONE/SINGLE/MULTIPLE and SHARED/NONSHARED. Though 
  6057. they basically do the same thing, they APPLY to different things. 
  6058.  
  6059. NONE/SINGLE/MULTIPLE 
  6060.           applies to the one and only default data segment. This is the data 
  6061.           segment that is "automatically" created for your DLL (or EXE). I 
  6062.           imagine that for 90% of the DLLs written, this is the only type of 
  6063.           data segment that exists. Whether or not this data segment is shared 
  6064.           or whether a private copy is created for each linking application is 
  6065.           A DIRECT FUNCTION OF THIS ATTRIBUTE--'SINGLE'=it's shared, 
  6066.           'MULTIPLE'=everyone get's his own copy. 
  6067.  
  6068. SHARED/NONSHARED 
  6069.           This SETS THE DEFAULT!! FOR ALL DATA SEGMENTS other than the 
  6070.           "automatic" data segment. DEFAULT is the key word, because you can 
  6071.           specify, through the SEGMENTS statement, the characteristics of these 
  6072.           additional segments on an individual basis (which in all certainty, 
  6073.           override this value.) 
  6074.  
  6075. So...to answer my own question 
  6076.  
  6077. >could {someone} explain what the following statements would
  6078. >produce:
  6079. >
  6080. >        DATA MULTIPLE SHARED
  6081.  
  6082. Every application which links to the DLL will have it's own private copy of the 
  6083. automatic data segment. If the DLL has no additional data segments, the SHARED 
  6084. keyword is meaningless and can be omitted. If there are additional data 
  6085. segments, only one copy of each will exist and they will be shared by all 
  6086. applications (unless a SEGMENTS statement follows which overrides this default 
  6087. for a specific segment) 
  6088.  
  6089. >        or
  6090. >        DATA SINGLE NONSHARED
  6091.  
  6092. Every application which links to the DLL will share a single automatic data 
  6093. segment (hence, each app that affects the DLL STATIC data will affect it for 
  6094. all apps). If there are no additional data segments, the NONSHARED keyword is 
  6095. meaningless and can be omitted. If there are, a private copy will be created 
  6096. for each app (unless overriden by a SEGMENTS statement). 
  6097.  
  6098. Note that in the absence of BOTH a SINGLE/MUTLIPLE and SHARED/NONSHARED 
  6099. keyword, the default is for ALL data segments (automatic and additional ones) 
  6100. to be shared (i.e., only one copy). In the absence of one OR the other, but not 
  6101. both, the property of ALL data segments are mandated by the single keyword. In 
  6102. other words, 
  6103.  
  6104. DATA SINGLE
  6105.  and
  6106. DATA SHARED
  6107.  
  6108. do the same exact thing. 
  6109.  
  6110. Credit:  John Cortell 
  6111.  
  6112.  
  6113. ΓòÉΓòÉΓòÉ 9.14. Where can I find serial port sample code? ΓòÉΓòÉΓòÉ
  6114.  
  6115. Q)  Does anyone have any C sample code showing how to use the serial port under 
  6116. OS/2 using DosOpen() and DosDevIoCtl()? 
  6117.  
  6118. A) As a matter of fact, yes.  :-) 
  6119.  
  6120. -=-= extracted from a silly & specialized program =-=-=-=-==-=-=
  6121.  
  6122. /* dtp.c -- D-dial Terminal Program: the first hack */
  6123.  
  6124. //-- an annoying detail
  6125.  
  6126. #define INCL_BASE
  6127. #define INCL_DOSDEVIOCTL  /* docs lie, this is NOT included by BASE */
  6128. #include <os2.h>
  6129.  
  6130. //-- initialization (in main() as written)
  6131.  
  6132.     HFILE portFd;
  6133.     ULONG action;
  6134.  
  6135.     if (DosOpen("COM1", &portFd, &action, 0, FILE_NORMAL, FILE_OPEN,
  6136.       OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, 0) != 0) {
  6137.         fprintf(stderr, "Open of COM1 failed\n");
  6138.         goto error0;
  6139.     }
  6140.  
  6141.     {    DCBINFO di;
  6142.         ULONG dummy;
  6143.  
  6144.         dummy = sizeof(di);
  6145.         if (DosDevIOCtl(portFd, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0,
  6146.                         &di, sizeof(di), &dummy) != 0)
  6147.             fprintf(stderr, "DosDevIOCtl failed\n");
  6148.         else {
  6149.             fprintf(stderr, "Timeouts: read = %u, write = %u\n",
  6150.                     di.usWriteTimeout, di.usReadTimeout);
  6151.             fprintf(stderr, "Flag bytes: %02x, %02x, %02x\n",
  6152.                     di.fbCtlHndShake, di.fbFlowReplace, di.fbTimeout);
  6153.         }
  6154.         di.fbTimeout = (di.fbTimeout & ~(3 << 1)) | (2 << 1);
  6155.                                           /* rcv = wait-for-something */
  6156.         di.usReadTimeout = 250;
  6157.         dummy = sizeof(di);
  6158.         if (DosDevIOCtl(portFd, IOCTL_ASYNC, ASYNC_SETDCBINFO,
  6159.                         &di, sizeof(di), &dummy, 0, 0, 0) != 0)
  6160.             fprintf(stderr, "DosDevIOCtl failed to set parameters!\a\n");
  6161.     }
  6162.  
  6163.     if (initSerialOutput(portFd) != 0)
  6164.         goto error1;
  6165.  
  6166. //-- the "running" variable is sort of a relic, I think
  6167.  
  6168.     running = 1;
  6169.     if (_beginthread(serialInputThread, 0, 8192, (void *)portFd) < 0) {
  6170.         fprintf(stderr, "can't start serial input thread\n");
  6171.         goto error2;
  6172.     }
  6173.  
  6174.     if (_beginthread(serialOutputThread, 0, 8192, (void *)portFd) < 0) {
  6175.         fprintf(stderr, "can't start serial output thread\n");
  6176.         goto error2;
  6177.     }
  6178.  
  6179. //-- wrapup code
  6180.  
  6181.     shutdownSerialOutput();
  6182.     DosClose(portFd);
  6183.  
  6184. //-- the rest of this lives outside of main()...
  6185.  
  6186. //-- input side: gory details omitted
  6187.  
  6188. //-- the port has been setup in "wait for something" mode, so we can request
  6189. //-- more than one character at a time without blocking until the buffer is
  6190. //-- full.  At least, I *think* that's working now: this is used with 300 baud
  6191. //-- systems, so it's hard to tell <g>.  At least it isn't blocking until the
  6192. //-- buffer is filled...
  6193.  
  6194. /*  serialInputThread -- reads port, writes to text window
  6195. *
  6196. *   arg is the port's handle for reading
  6197. */
  6198. void serialInputThread(void *arg)
  6199. {
  6200.     HFILE inFd = (long)arg;
  6201.     FILE *logFile;
  6202.     UCHAR buf[10];
  6203.  
  6204.     ParserState ps = {0};
  6205.  
  6206.     logFile = fopen("dtp.log", "ab");
  6207.  
  6208.     for ( ; ; )
  6209.     {
  6210.         ULONG n;
  6211.         if (DosRead(inFd, buf, 10, &n) == 0)
  6212.         {
  6213.             ULONG i;
  6214.             for (i = 0; i <n; ++i)
  6215.             {
  6216.                 if (logFile != 0)
  6217.                     putc(buf[i], logFile);
  6218.                 if (runParser(&ps, buf[i]) != 0)
  6219.                     postChar(buf[i]);
  6220.             }
  6221.         }
  6222.     }
  6223. }
  6224.  
  6225. /* output side: I rather like this arrangement using queues
  6226.    except that I'd prefer an anonymous queue.
  6227.    For this, having the queue named in the
  6228.    filesystem's name space is at best a minor annoyance. */
  6229.  
  6230. /* * * *    SerialOutput subsystem
  6231. */
  6232.  
  6233. #define MAX_CHUNK_SIZE 50
  6234.  
  6235. typedef struct
  6236. {
  6237.     USHORT nUsed;
  6238.     UCHAR buf[MAX_CHUNK_SIZE];
  6239. } SO_CHUNK;
  6240.  
  6241. #define NUM_SO_CHUNKS 6
  6242.  
  6243.  
  6244. HQUEUE soQueue, freeQueue;
  6245.  
  6246.  
  6247. int initSerialOutput (HFILE outFd)
  6248. {
  6249.     (void) outFd;     /* reserved for more general version */
  6250.  
  6251.     if (DosCreateQueue
  6252.        (&soQueue, QUE_FIFO, "\\queues\\dtp\\soQueue") != 0)
  6253.     {
  6254.         fprintf(stderr, "Failed to create serial output queue\n");
  6255.         goto error0;
  6256.     }
  6257.     if (DosCreateQueue
  6258.        (&freeQueue, QUE_FIFO, "\\queues\\dtp\\freeQueue") != 0)
  6259.     {
  6260.         fprintf(stderr, "Failed to create serial free queue\n");
  6261.         goto error1;
  6262.     }
  6263.     {   SO_CHUNK *p = malloc(sizeof(SO_CHUNK) * NUM_SO_CHUNKS);
  6264.         int i;
  6265.         if (p == 0)
  6266.         {
  6267.             fprintf(stderr,
  6268.             "Failed to allocate memory for serial chunks\n");
  6269.             goto error1;
  6270.         }
  6271.         for (i = NUM_SO_CHUNKS; 0 < i; --i)
  6272.             if (DosWriteQueue(freeQueue, 0, sizeof(SO_CHUNK), p++, 0)
  6273.             != 0)
  6274.             {
  6275.                 fprintf(stderr, "Failed to initialize free queue\n");
  6276.                 goto error1;
  6277.             }
  6278.     }
  6279.  
  6280.     return 0;
  6281.  
  6282. error1:
  6283.     DosCloseQueue(soQueue);
  6284. error0:
  6285.     return -1;
  6286. }
  6287.  
  6288.  
  6289. void shutdownSerialOutput(void)
  6290. {
  6291.     DosCloseQueue(freeQueue);
  6292.     DosCloseQueue(soQueue);
  6293. }
  6294.  
  6295.  
  6296. void writeSerial(UCHAR const *buf, USHORT n)
  6297. {
  6298.  
  6299.     while (0 < n)
  6300.     {
  6301.         REQUESTDATA rd;
  6302.         ULONG dataLength;
  6303.         PVOID data;
  6304.         BYTE priority;
  6305.  
  6306.         if (DosReadQueue(freeQueue, &rd, &dataLength, &data,
  6307.                          0, DCWW_WAIT, &priority, 0) == 0)
  6308.         {
  6309.             SO_CHUNK *sc = data;
  6310.             USHORT m = MAX_CHUNK_SIZE;
  6311.             if (n < m)
  6312.                 m = n;
  6313.             memcpy(sc->buf, buf, m);
  6314.             sc->nUsed = m;
  6315.             DosWriteQueue(soQueue, 0, sizeof(SO_CHUNK), sc, 0);
  6316.             buf += m;
  6317.             n -= m;
  6318.         }
  6319.     }
  6320. }
  6321.  
  6322.  
  6323. void writeSerialString(UCHAR const *buf)
  6324. {
  6325.     writeSerial(buf, strlen(buf));
  6326. }
  6327.  
  6328.  
  6329. void serialOutputThread(void *arg)
  6330. {
  6331.     HFILE outFd = (long)arg;
  6332.     REQUESTDATA rd;
  6333.     ULONG dataLength;
  6334.     PVOID data;
  6335.     BYTE priority;
  6336.  
  6337.     for ( ; ; )
  6338.     {
  6339.         if (DosReadQueue(soQueue, &rd, &dataLength, &data,
  6340.                          0, DCWW_WAIT, &priority, 0) == 0)
  6341.         {
  6342.             if (rd.ulData == 0) {     /* simple data block */
  6343.                 ULONG dummy;
  6344.                 SO_CHUNK *sc = data;
  6345.                 DosWrite(outFd, sc->buf, sc->nUsed, &dummy);
  6346.                 DosWriteQueue(freeQueue, 0, sizeof(SO_CHUNK), sc, 0);
  6347.             }
  6348.             else
  6349.                 ;  /* anything else is a test, ignore it */
  6350.         }
  6351.     }
  6352. }
  6353.  
  6354. The intention was that control messages could be posted to the queue using null 
  6355. data packets (passing the actual message in the REQUESTDATA.ulData field); 
  6356. these would allow for controlling the port's baud rate and other settings. 
  6357. This seems to work under 2.0, and even appears to be intended to work (Deitel & 
  6358. Kogan's description), but I haven't done anything with it yet, as you can see. 
  6359. Haven't needed the facility yet... 
  6360.  
  6361. Credit:  Martin Maney 
  6362.  
  6363.  
  6364. ΓòÉΓòÉΓòÉ 9.15. How do I disable <Ctrl><Alt><Del>? ΓòÉΓòÉΓòÉ
  6365.  
  6366. You need to do a DosDevIOCtl with Category 4, Function 56. Use a 0xFFFF for the 
  6367. Hot Key ID.  Set the other values to 0. This will toggle <Ctrl><Alt><Del> and 
  6368. <Ctrl><Esc> and <Alt><Esc> on then off on the next call. Note that this does a 
  6369. little more than what you want since it also disables <Ctrl><Esc> and 
  6370. <Alt><Esc> so you may run into problems getting around your different sessions 
  6371. when you've got it disabled. Other than this there is NO WAY to disable 
  6372. <Ctrl><Alt><Del> under OS/2 and believe me, people have tried! 
  6373.  
  6374. Credit:  Mike Brown 
  6375.  
  6376.  
  6377. ΓòÉΓòÉΓòÉ 9.16. Why doesn't printf() produce output when I expect it to? ΓòÉΓòÉΓòÉ
  6378.  
  6379. For historical reasons, most Unix C libraries' stdio default to using line 
  6380. buffered streams, whereas most DOS and OS/2 C libraries' stdio default to using 
  6381. fully buffered streams.  ANSI C species that standard output should be line 
  6382. buffered when connected to an interactive device, but not all libraries are 
  6383. ANSI compliant.  You can control the buffering algorithm used for a particular 
  6384. stream with the setvbuf() function. 
  6385.  
  6386. If you didn't understand that paragraph, read on. 
  6387.  
  6388. printf() is part of the Standard I/O (stdio) library, which uses buffered 
  6389. streams for file IO.  ANSI C specifies three algorithms for deciding when to 
  6390. flush the buffer (i.e. when to print buffered data to the file): 
  6391.  
  6392. o not buffered.  Data is flushed to the file as soon as possible, usually 
  6393.   immediately after being received. 
  6394. o line buffered.  Data is flushed to the file when a newline is received (and 
  6395.   the newline is also flushed). 
  6396. o fully buffered.  Data is flushed to the file when the buffer is full. 
  6397.  
  6398. Buffered data is always flushed when the stream is closed or when fflush() is 
  6399. called.  Since standard output is flushed when main() exits, all data printed 
  6400. with printf() will appear at that time, if it has not already.  However, ANSI C 
  6401. does not require that a stream be flushed when scanf() is called on it. 
  6402. Therefore, if you print to a fully buffered stream and then request input on 
  6403. it, it is likely that the input will be read before the printed data appears. 
  6404.  
  6405. You can control the buffering algorithm used for a particular stream with the 
  6406. setvbuf() function.  For example, the statement setvbuf(stdout, NULL, _IOLBF, 
  6407. BUFSIZ) sets standard output to be line-buffered, which is what most Unix 
  6408. programmers expect.  Any decent C reference will cover all of this material. 
  6409.  
  6410. [Colin Jensen...] 
  6411.  
  6412. After reading one too many bug reports about this phenomena, the gcc/2 
  6413. maintainer changed its stdout to not-buffered whenever stdout is interactive. 
  6414. When stdout is sent to a pipe or file, stdout is still fully-buffered. 
  6415.  
  6416.  
  6417. ΓòÉΓòÉΓòÉ 9.17. How do I write an OS/2 device driver? ΓòÉΓòÉΓòÉ
  6418.  
  6419. The preferred method is to buy the OS/2 device driver kit (DDK) from IBM.  It 
  6420. contains samples for display, printer, SCSI, and other drivers. You can develop 
  6421. kernel and PM drivers.    NOTE:  The kernel debugger comes with the IBM Toolkit, 
  6422. sold separately. 
  6423.  
  6424. There's a book called Writing OS/2 2.0 Device Drivers in C from 
  6425. Van Nostrand-Reinhold and also IBM's flood of printed material. 
  6426.  
  6427. As reference to SCSI programming, check SCSI Programming FAQ, available at 
  6428. ftp.regent.e-technik.tu-muenchen.de 
  6429.  
  6430.  
  6431. RelatedInformation :
  6432.  
  6433. What are good reference books for programming in OS/2 and PM?
  6434.  
  6435.  
  6436. ΓòÉΓòÉΓòÉ 9.18. How do I change the master environment? ΓòÉΓòÉΓòÉ
  6437.  
  6438. Quick and simple answer: you don't. 
  6439.  
  6440. In OS/2 it is literally impossible for you to change the master environment 
  6441. from one of your programs.    To be able to do so would fatally disrupt the 
  6442. programming paradigm that has existed for ages:  Your program does not alter 
  6443. the master environment. Your program is the slave, not the master.  Therefore, 
  6444. no capability was built into OS/2 to facilitate this. 
  6445.  
  6446. There is, however, a kludge. 
  6447.  
  6448. As you know, a .CMD file can alter the master environment.  This is the nature 
  6449. of batch files (ok, so I'm a MS-DOG dinosaur and still call them batch files 
  6450. instead of command files or scripts).  Therefore, you can place a sequence of 
  6451. commands in the batch file that will take your program's output and alter the 
  6452. environment of your current shell. 
  6453.  
  6454. That's as close as you are gonna get to the master environment.  You can always 
  6455. create your own sort of environment variables, in the form of shared memory or 
  6456. named pipes. 
  6457.  
  6458.  
  6459. ΓòÉΓòÉΓòÉ 9.19. What is the best way to communicate between processes? ΓòÉΓòÉΓòÉ
  6460.  
  6461. There is more than one way - and you get to decide which is right for you! 
  6462.  
  6463. Shared Memory 
  6464.  
  6465. Shared memory is pretty self-explanatory.  It is a memory segment that is 
  6466. allocated by one program, and then made available to other programs. When all 
  6467. the programs are done with it, then it is disposed of.  You can name shared 
  6468. memory.  So if you want two programs to communicate, then let them look for 
  6469. memory with the same name and communicate that way. 
  6470.  
  6471. Named Pipes 
  6472.  
  6473. Named pipes are a lot like shared memory, but think of a named pipe as a file 
  6474. instead of a single block of memory.  Each process can create, read, write, and 
  6475. destroy a named pipe, much like you can a file. 
  6476.  
  6477. The difference between named pipes and shared memory is that a named pipe link 
  6478. is hot; With shared memory, data can be left in (as a sleeper, if you will), 
  6479. process 1 exits, process 2 accesses the data in memory, then deallocates the 
  6480. memory.  With shared memory, a process doesn't even have to exist to leave a 
  6481. message for another process. 
  6482.  
  6483. Queues 
  6484.  
  6485. An OS/2 queue is either a standard First-In First-Out (FIFO) queue 
  6486. data/operation structure, a LIFO structure, or a user-based-priority structure. 
  6487. However, OS/2 makes it unique because more than one process (or thread) can 
  6488. write to this queue. 
  6489.  
  6490.  
  6491. Related Information:
  6492.  
  6493. What is the best way to communicate between threads?
  6494.  
  6495.  
  6496. ΓòÉΓòÉΓòÉ 9.20. What is the best way to communicate between threads? ΓòÉΓòÉΓòÉ
  6497.  
  6498. The best way to communicate between threads is sometimes also the best way to 
  6499. communicate between processes.  However, when communicating between threads you 
  6500. can utilize two (very important) techniques: 
  6501.  
  6502. Semaphores 
  6503.  
  6504. In order to share application resources, and not write to the same space at the 
  6505. same time, you have to have some kind of flags that tell the thread when it 
  6506. should stop, when it should keep on going, and so on. Semaphores provide this 
  6507. capability.  Semaphores are not for passing data.  They merely exist as simple 
  6508. flags between threads and you should treat them as such. 
  6509.  
  6510. Global Variables 
  6511.  
  6512. "Hey Jeff - I thought this was supposed to be about nifty OS/2-specific 
  6513. tricks!"  It is!  You can now use those old nasty things, global variables, in 
  6514. new ways.  In conjunction with semaphores, you can pass data very easily 
  6515. between threads with global variables.  Here's a simple example: 
  6516.  
  6517.  1. Create a global variable called PassData. 
  6518.  2. Create a semaphore called OkToPassData. 
  6519.  3. Create a semaphore called DataPassed. 
  6520.  4. Have two threads work at the same time: 
  6521.  
  6522.     a. If the semaphore DataPassed is true: 
  6523.  
  6524.        1. Set the semaphore OkToPassData to false. 
  6525.        2. Read the data in the global. 
  6526.        3. Set the semaphore DataPassed to false. 
  6527.        4. Set the semaphore OkToPassData to true. 
  6528.  
  6529.     b. When a thread wants to pass data, wait for the semaphore to be clear. 
  6530.     c. Set the semaphore OkToPassData to false. 
  6531.     d. Put the data in the global. 
  6532.     e. Set the semaphore DataPassed to true. 
  6533.     f. Set the semaphore OkToPassData to true. 
  6534.  
  6535. Of course, there are issues of deadlock and other such nonsense that corporate 
  6536. chaps get paid to consider, but that's beyond the scope of this document. 
  6537.  
  6538.  
  6539. Related Information:
  6540.  
  6541. What is the best way to communicate between processes?
  6542.  
  6543.  
  6544. ΓòÉΓòÉΓòÉ 9.21. How to I write an IFS? ΓòÉΓòÉΓòÉ
  6545.  
  6546. Starting with Issue #3, EDM/2 started carrying a series about writing an IFS. 
  6547.  
  6548.  
  6549. ΓòÉΓòÉΓòÉ 9.22. How do I interface with OS/2's SCSI support? ΓòÉΓòÉΓòÉ
  6550.  
  6551. A complete description and sample code can be found at ftp archive; 
  6552.  
  6553. reseq.regent.e-technik.tu-muenchen.de 
  6554.  
  6555. in /pub/comp/os/os2/drivers/source/scsipg.zip. 
  6556.  
  6557.  
  6558. ΓòÉΓòÉΓòÉ 9.23. How do I program full-screen graphics? ΓòÉΓòÉΓòÉ
  6559.  
  6560. Several compilers come with their own VGA graphics libraries.  A 3rd party 
  6561. developer has even developed an SVGA library (with drivers) for emx/gcc. 
  6562.  
  6563. Full-screen graphics programming is nearly identical to full-screen DOS 
  6564. graphics programming, with the notable exception that you must lock and unlock 
  6565. the screen under OS/2 before you can use it. 
  6566.  
  6567. For fast direct-access screen graphics, check at ftp-os2.cdrom.com, the file 
  6568. dlib06.zip. 
  6569.  
  6570.  
  6571. ΓòÉΓòÉΓòÉ 9.24. How do I program MMPM/2 programs? ΓòÉΓòÉΓòÉ
  6572.  
  6573. IBM has created the MMPM/2 toolkit just for that.  However, if that is too much 
  6574. trouble for you, there is a simple REXX interface to MMPM/2 available in OS/2 
  6575. 2.1. 
  6576.  
  6577. IBM's Ultimedia Builder/2, Ultimedia Perfect Image/2, and Ultimedia Workplace/2 
  6578. are all in beta and scheduled to be released soon. 
  6579.  
  6580. For the Emx/GCC enviroment there is the mm4emx package by Marc Van Woerkom. 
  6581. mm4emx is freeware. All header and lib files included. 
  6582.  
  6583.  
  6584. ΓòÉΓòÉΓòÉ 9.25. How do I peripheral memory or an I/O port? ΓòÉΓòÉΓòÉ
  6585.  
  6586. The basic thing to do is either mark it as IOPL or surround it in a 16-bit 
  6587. module.    emx/gcc and other compilers include some macros and functions to assist 
  6588. you in doing this. 
  6589.  
  6590. Check the file IOPL32.ZIP at ftp.cdrom.com:/pub/os2/os2_x/programs 
  6591.  
  6592.  
  6593. ΓòÉΓòÉΓòÉ 10. Porting ΓòÉΓòÉΓòÉ
  6594.  
  6595. This section covers all aspects of porting programs. 
  6596.  
  6597.  
  6598. ΓòÉΓòÉΓòÉ 10.1. How do I port my DOS keyboard TSR to OS/2? ΓòÉΓòÉΓòÉ
  6599.  
  6600. Use keyboard monitors (for fullscreen sessions) or hooks for the PM session. 
  6601.  
  6602.  
  6603. ΓòÉΓòÉΓòÉ 10.2. How can I simulate (Unix feature) under OS/2? ΓòÉΓòÉΓòÉ
  6604.  
  6605.  1. fork 
  6606.  2. fork/exec 
  6607.  3. select 
  6608.  4. job control 
  6609.  
  6610. A working version of select() is included with the emx/gcc libraries. See the 
  6611. emx/gcc documentation for more information on its usage. 
  6612.  
  6613. A working version of fork() comes with the emx/gcc libraries.  The author 
  6614. cautions that this is not the way to multitask, though, because it eats up a 
  6615. lot of resources (since it literally duplicates the current process, leaving 
  6616. everything but the PID unchanged).  _beginthread() is the suggested solution if 
  6617. at all possible. 
  6618.  
  6619.  
  6620. ΓòÉΓòÉΓòÉ 10.3. How can I recompile public domain/shareware source code for OS/2? ΓòÉΓòÉΓòÉ
  6621.  
  6622. Most publicly available OS/2 programs come with binaries (since there is 
  6623. currently only one OS/2 architecture).  If you are porting source code from 
  6624. another system (for example, Unix), you will first need to acquire a compiler. 
  6625. See section 1 for information on compilers; in particular, note that the GNU C 
  6626. compiler is available. 
  6627.  
  6628. You should realize that many publicly available programs have already been 
  6629. ported to OS/2.  Check the many FTP sites carrying OS/2 programs before you 
  6630. reinvent any wheels (the OS/2 User's FAQ contains information on FTP site). 
  6631.  
  6632. Most Unix applications (through the use of emx/gcc) port with extreme ease; DOS 
  6633. and Windows applications are a tougher problem, and require many changes before 
  6634. they can be recompiled as a native OS/2 program. 
  6635.  
  6636. (It is interesting to note that MicroSoft C v6.0 will compile bound OS/2 
  6637. programs, which will run under DOS and OS/2 without modification.) 
  6638.  
  6639.  
  6640. Related Information:
  6641.  
  6642. How can I port my DOS program to OS/2?
  6643. How can I port my Windows program to OS/2?
  6644.  
  6645.  
  6646. ΓòÉΓòÉΓòÉ 10.4. How can I port my DOS program to OS/2? ΓòÉΓòÉΓòÉ
  6647.  
  6648. To the first approximation, you don't have to --- OS/2 2.x's DOS support is 
  6649. excellent, and your DOS program will probably just work; similarly, OS/2 2.x 
  6650. supports Windows 3.0 (and soon 3.1) programs.  See the OS/2 User's FAQ for 
  6651. details. 
  6652.  
  6653. [That was Barry Jaspan's opinion.  I believe that you should make every effort 
  6654. to recompile your existing DOS programs for OS/2 2.x.  They will run faster in 
  6655. many cases, and both (a) use less memory and (b) be able to use more memory 
  6656. than their DOS counterparts. - Jeff] 
  6657.  
  6658. If you truly want to port your DOS program over to OS/2, then study the 
  6659. libraries available to you.  The core code (if you wrote it correctly) will 
  6660. probably not change much.  You will just have to change the user interface 
  6661. stuff. 
  6662.  
  6663. If your program is a real simple one that uses standard input and output, then 
  6664. you will probably not make very many changes to your program when converting it 
  6665. to OS/2. 
  6666.  
  6667. You should also realize that neato and nifty DOS tricks (like grabbing an 
  6668. interrupt whenever you feel like it, or writing directly to almost anywhere) 
  6669. are completely out of the question. 
  6670.  
  6671.  
  6672. Related Information:
  6673.  
  6674. How can I port my Windows program to OS/2?
  6675.  
  6676.  
  6677. ΓòÉΓòÉΓòÉ 10.5. How can I port my Windows program to OS/2? ΓòÉΓòÉΓòÉ
  6678.  
  6679. A tool called Mirrors is available from Micrographx.  It does not currently 
  6680. support Windows 3.1-specific programs and calls.  (although you *can* call the 
  6681. functions in the new 3.1 DLLs) 
  6682.  
  6683. o Rough ports can be done in under 1 day, but a detailed port still costs you a 
  6684.   lot of effort. 
  6685. o The ported application is heavily dependent on the underlying OS/2 system. 
  6686.  
  6687. There are also several toolkits available that allow you to make calls to a 
  6688. common API library, and your source will work across the two platforms without 
  6689. any changes at all. 
  6690.  
  6691. However, if you want to bite the bullet and port it, then be prepared to make a 
  6692. lot of changes.  Just like porting regular DOS programs, you will have to scrap 
  6693. most, if not all, of your user interface.  Your core code, if modular and 
  6694. abstract enough, should come through the port relatively unscathed. 
  6695.  
  6696. SMART - by One-up Corp is also available on Developers Connection CD. 
  6697.  
  6698.  
  6699. Related Information:
  6700.  
  6701. How can I port my DOS program to OS/2?
  6702.  
  6703.  
  6704. ΓòÉΓòÉΓòÉ 11. Miscellaneous ΓòÉΓòÉΓòÉ
  6705.  
  6706. This section covers questions not covered in previous sections. 
  6707.  
  6708.  
  6709. ΓòÉΓòÉΓòÉ 11.1. Is OS/2 suitable for real time programs? ΓòÉΓòÉΓòÉ
  6710.  
  6711. Yes!  There is a special priority you can assign your programs 
  6712. (ForegroundServer Mode) via DosSetPriority() which will give your process 
  6713. (note, not thread, but process) the maximum allowable CPU time. 
  6714.  
  6715. Another route is to use DosEnterCritSec()/DosExitCritSec().  Calling the former 
  6716. will disable thread switching (hopefully for a short period of time), and 
  6717. calling the latter will enable thread switching again. 
  6718.  
  6719.  
  6720. ΓòÉΓòÉΓòÉ 11.2. What is available for multimedia programming under OS/2? ΓòÉΓòÉΓòÉ
  6721.  
  6722. The OS/2 2.x Multimedia package is now available.  Call the IBM Multimedia 
  6723. office at (800) 426-9402 ext. 150. 
  6724.  
  6725.  
  6726. ΓòÉΓòÉΓòÉ 11.3. What is available for AI/neural net programming under OS/2? ΓòÉΓòÉΓòÉ
  6727.  
  6728. LISP and XScheme are available from cdrom.com.  There are also some AI/neural 
  6729. net tools listed in tinf31.zip. 
  6730.  
  6731.  
  6732. Related Information:
  6733.  
  6734. Programming language availability
  6735.  
  6736.  
  6737. ΓòÉΓòÉΓòÉ 11.4. Special software offers ΓòÉΓòÉΓòÉ
  6738.  
  6739. Here are some of the OS/2 software products that represent particularly good 
  6740. values.  Most prices do not include shipping and handling. 
  6741.  
  6742. o Borland C++ for OS/2.  Available from Below Zero in Calgary (phone 
  6743.   800-461-2777, 403-547-0669, or FAX 403-547-1018) for about $136 U.S., 
  6744.   including shipping.  Add GST in Canada.  Below Zero will export outside North 
  6745.   America. 
  6746.  
  6747. o IBM PL/I.  Not everyone is a PL/I programmer, but IBM is offering free copies 
  6748.   of Workframe/2 with every purchase and free product videos. Phone 
  6749.   800-426-3346 ext. STL10 for more information on the two packages available. 
  6750.  
  6751. (Quoted almost directly from OS/2 General FAQ) 
  6752.  
  6753.  
  6754. ΓòÉΓòÉΓòÉ 11.5. Technical Support ΓòÉΓòÉΓòÉ
  6755.  
  6756. How can I get answers to my OS/2 questions? 
  6757.  
  6758. If your question is not answered in this List, post a note to the appropriate 
  6759. Usenet conference: 
  6760.  
  6761. Newsgroup                           Description 
  6762. comp.os.os2.advocacy                deals with opinions and speculation 
  6763. comp.os.os2.announce                carries important OS/2 announcements 
  6764. comp.os.os2.apps                    carries discussions related to finding or 
  6765.                                     using any application running under OS/2 
  6766. comp.os.os2.beta                    explores beta releases of OS/2 
  6767. comp.os.os2.bugs                    discusses possible bugs found in released 
  6768.                                     versions of the operating system 
  6769. comp.os.os2.games                   covers all question about OS/2 games 
  6770. comp.os.os2.misc                    is for any other OS/2-related discussion 
  6771. comp.os.os2.multimedia              fosters conversation about OS/2 multimedia 
  6772.                                     (including MMPM/2), 
  6773. comp.os.os2.networking              looks at general networking issues 
  6774. comp.os.os2.networking.misc         miscellaneous discussions about networking 
  6775. comp.os.os2.networking.tcp-ip       covers TCP/IP issues 
  6776. comp.os.os2.programmer.misc         addresses anything else related to OS/2 
  6777.                                     programming 
  6778. comp.os.os2.programmer.oop          covers object-oriented programming 
  6779.                                     discussions 
  6780. comp.os.os2.programmer.porting      helps programmers move applications over to 
  6781.                                     OS/2 from other operating systems and 
  6782.                                     environments 
  6783. comp.os.os2.programmer.tools        covers tools for OS/2 application 
  6784.                                     developing 
  6785. comp.os.os2.setup                   REPLACED BY comp.os.os2.setup.misc 
  6786. comp.os.os2.comm                    Modem/Fax hardware/drivers/apps/utils under 
  6787.                                     OS/2 
  6788. comp.os.os2.mail-news               Mail and news apps/utils (on- & offline) 
  6789.                                     under OS/2 
  6790. comp.os.os2.marketplace             forsale/wanted; shopping; commercial ads; 
  6791.                                     job postings 
  6792. comp.os.os2.networking.www          World Wide Web (WWW) apps/utils under OS/2 
  6793. comp.os.os2.setup.misc              Installing/configuring OS/2; Misc 
  6794.                                     hardware/drivers 
  6795. comp.os.os2.setup.video             Base video hardware/drivers under OS/2 
  6796. comp.os.os2.setup.storage           Disk/Tape/CD-ROM hardware/drivers under 
  6797.                                     OS/2 
  6798. comp.os.os2.utilities               General-purpose utils 
  6799.                                     (shells/backup/compression/etc) 
  6800. comp.os.os2.ver1x                   HAS BEEN REMOVED 
  6801. comp.lang.rexx                      discusses REXX programming 
  6802.  
  6803. These groups are also watched closely by OS/2 experts from IBM. 
  6804.  
  6805. A LISTSERVer distributes its own OS/2 conference by mail; send a single line 
  6806. message with the word HELP to listserv@cc1.kuleuven.ac.be for full 
  6807. instructions; or send the same message to listserv@frors12.circe.fr for 
  6808. information on an unedited mailing list.  To subscribe to the Multimedia 
  6809. Presentation Manager/2, send a single line message with the phrase SUBSCRIBE 
  6810. MMOS2-L (Your Name) to mail-server@knex.via.mind.org. 
  6811.  
  6812. Your local FidoNet BBS may carry OS/2 echo conferences and/or OS2NET. If not, 
  6813. ask your system operator to join them.  CompuServe (FIND OS/2) and Prodigy are 
  6814. also excellent resources. 
  6815.  
  6816. The IBM PC Co. BBS's (modem 404-835-6600) message areas, product database, and 
  6817. PS/2 Assistant file(s) are invaluable resources. Information on the new OS/2 
  6818. BBS is included in the OS/2 2.0 package. In the United States IBM has toll free 
  6819. technical support (phone 800-237-5511), an OS/2 Hotline (general information, 
  6820. orders, upgrades, phone 800-3-IBM-OS2; ask about OS/2 videotapes, T-shirts, and 
  6821. other accessories), the HelpWare Center (phone 800-PS2-2227), a software order 
  6822. line (phone 800-IBM-CALL), two FAX information services (phone 800-IBM-4FAX 
  6823. and/or 800-IBM-3395), and an educational inquiries line (phone 800-222-7257). 
  6824. In Canada phone IBM Personal Systems Software at 800-465-1234. 
  6825.  
  6826. Any of the regular DOS or Windows resources (e.g. books, magazines, 
  6827. shareware/freeware sources) will be useful since both environments come with 
  6828. OS/2 2.0. 
  6829.  
  6830. (taken from OS/2 General FAQ) 
  6831.  
  6832.  
  6833. Related Information:
  6834.  
  6835. Developer's Assistance Program
  6836.  
  6837.  
  6838. ΓòÉΓòÉΓòÉ 11.6. Developer's Assistance Program (DAP) ΓòÉΓòÉΓòÉ
  6839.  
  6840. OS/2 2.0 developers should contact the IBM Developer Assistance Program (phone 
  6841. 407-982-6408); membership is free.  (You may also join on CompuServe with GO 
  6842. OS2DAP.) 
  6843.  
  6844. The OS/2 Professional Developer's Kit CD-ROM, containing a wide selection of 
  6845. development tools and code, and the OS/2 2.1 Beta CD-ROM are both available 
  6846. from IBM (phone 800-3-IBM-OS2 to order in the United States for between $15 and 
  6847. $20 each, shipping included; in Canada, phone 800-465-1234; in Australia, phone 
  6848. Rohaini Cain or Mike Voris at 13-2426 ext. 7684; elsewhere, contact the 
  6849. International OS/2 User Group by phoning 285-641175 in the U.K.) 
  6850.  
  6851. The OS/2 Device Driver Development Kit CD-ROM is also now available from IBM. 
  6852. To order phone 407-982-4239 (FAX 407-982-4218) in North America, 61-2-354-7684 
  6853. (FAX 61-2-354-7766) in most of the Far East and Pacific Rim, 81-3-5563-5897 
  6854. (FAX 81-3-5563-4957) in Japan, 81-2-528-1548 (FAX 82-2-528-1414) in Korea, 
  6855. 011-52-627-1846 (FAX 011-52-395-7812) in Latin America, or +49-69-6645-3318 in 
  6856. Germany. 
  6857.  
  6858. (taken from the OS/2 general FAQ) 
  6859.  
  6860.  
  6861. ΓòÉΓòÉΓòÉ 12. OS/2 Software Sources ΓòÉΓòÉΓòÉ
  6862.  
  6863. The following BBSes hold large OS/2 libraries: 
  6864.  
  6865.  
  6866.  Name                      Number
  6867.  
  6868.  Fernwood                  (203) 483-0348
  6869.  
  6870.  OS/2 Shareware            (703) 385-4325
  6871.  
  6872.  Bay Area OS/2             (510) 657-7948
  6873.  
  6874.  Gateway/2                 (314) 554-9313
  6875.  
  6876.  Greater Chicago Online    (708) 895-4042
  6877.  
  6878.  OS/2 Connection (San      (619) 549-4215
  6879.  Diego)
  6880.  
  6881.  OS/2 Las Vegas            (702) 433-5535
  6882.  
  6883.  IBM Germany               049-711-785-777
  6884.  
  6885.  IBM Germany (Another)     +49-69-6645-325
  6886.  
  6887.  IBM Denmark               45-42-88-72-22
  6888.  
  6889.  OS/2 UK                   0454-633197
  6890.  
  6891.  IBM UK                    0256-336655
  6892.  
  6893.  IBM Norway                47-66-99-94-50
  6894.  
  6895.  IBM Sweden                +8-793 22 00
  6896.  
  6897.  OS/2 Norway               47-22-38-09-49
  6898.  
  6899.  OS/2 Australia            61-2-241-2466
  6900.  
  6901. Check OS/2 FAQ for a more extensive list of ftp sites. 
  6902.  
  6903. (The monthly Worldwide OS/2 BBS Listing, available from these BBSes, lists 
  6904. others.)  The IBM PC Company BBS (modem 404-835-6600) has some 
  6905. shareware/freeware as well, along with CSDs and the PS/2 Assistant (an 
  6906. invaluable resource for locating almost any sort of information on OS/2). For 
  6907. information on IBM's new OS/2 BBS phone 800-547-1283.  IBM Canada maintains 
  6908. several support BBSes: 
  6909.  
  6910.    (416) 946-4255 
  6911.    (514) 938-3022 
  6912.    (604) 664-6464 
  6913.    (416) 946-4244 
  6914.  
  6915. The Usenet conference comp.binaries.os2 carries OS/2 software.  And several 
  6916. sites are available via anonymous ftp.  (No ftp?  Send a single line message 
  6917. with the word HELP to bitftp@pucc.bitnet or ftpmail@decwrl.dec.com to learn 
  6918. about ftp mail servers.)  Some are (with Internet node numbers and 
  6919. subdirectories): 
  6920.  
  6921.  
  6922.  Site                           IP Address      Home OS/2 Directory
  6923.  
  6924.  american.megatrends.com        192.239.218.193 pub
  6925.  
  6926.  atitech.ca                     198.133.44.2    pub/support/OS2
  6927.  drivers for ATI video cards
  6928.  
  6929.  boombox.micro.umn.edu          134.84.132.2    pub/gopher/os2
  6930.  home of gopher software
  6931.  
  6932.  cirrus.com                     141.131.7.10    pub/support
  6933.  Cirrus video drivers; further
  6934.  sorted under /desktop,
  6935.  /laptop, etc.
  6936.  
  6937.  ctron.com                      134.141.197.25  pub/drivers
  6938.  Cabletron - OS/2 drivers for
  6939.  their cards
  6940.  
  6941.  ftp.3com.com                   129.213.128.5   /adaptors/drivers
  6942.  drivers for 3com cards
  6943.  
  6944.  ftp.cdrom.com                  192.216.191.11  /pub/os2
  6945.  
  6946.  ftp.creaf.com                  198.95.32.3
  6947.  Creative Labs archive:
  6948.  SoundBlaster drivers etc.
  6949.  
  6950.  ftp.germany.eu.net             192.76.144.75   .../os2
  6951.  see under /newsarchive
  6952.  and /comp
  6953.  
  6954.  ftp.ibm.net                    165.87.194.246  /pub/WebExplorer
  6955.  latest beta
  6956.  
  6957.  hobbes.nmsu.edu                128.123.35.151  pub/os2
  6958.  
  6959.  software.watson.ibm.com        129.34.139.5    pub/os2
  6960.  
  6961.  mtsg.ubc.ca                    137.82.27.1     os2
  6962.  
  6963.  access.usask.ca                128.233.3.1     pub/archives/os2
  6964.  
  6965.  luga.latrobe.edu.au            131.172.2.2     pub/os2
  6966.  
  6967.  funic.funet.fi                 128.214.6.100   pub/os2
  6968.  
  6969.  pdsoft.lancs.ac.uk             148.88.64.2     micros/ibmpc/os2
  6970.  
  6971.  ftp.uni-stuttgart.de           129.69.1.13     /pub/systems/os2
  6972.  
  6973.  zaphod.cs.uwindsor.ca          137.207.224.3   pub/local/os2
  6974.  
  6975.  ftp.luth.se                    130.240.18.2    pub/os2
  6976.  
  6977.  src.doc.ic.ac.uk               146.169.2.1     computing/systems/os2
  6978.  mirrors ftp-os2.nmsu.edu/
  6979.  ftp.cdrom.com
  6980.  
  6981.  ftp.informatik.tu-muenchen.de  131.159.0.198   /pub/comp/os/os2
  6982.  
  6983.  ftp.informatik.uni-rostock.de  139.30.5.23     pub/os2
  6984.  
  6985.  ftp.lexmark.com                192.146.101.4   pub/driver
  6986.  also other directories for
  6987.  os2*.* files
  6988.  
  6989.  ftp.ncr.com                    192.127.252.6   pub
  6990.  PCI SCSI drivers in /ncrchips/
  6991.  scsi/drivers/os2
  6992.  
  6993.  ftp.netcom.com                 192.100.81.1    /pub/kfan
  6994.  Fan's WWW server web2-101.zip
  6995.  
  6996.  ftp.novell.com                 137.65.1.3      pub/updates
  6997.  former NetWire libraries
  6998.  
  6999.  ftp.pcco.ibm.com               198.79.74.29    ? all
  7000.  most dirs contain relevant
  7001.  files
  7002.  
  7003.  ftp.uni-bielefeld.de           129.70.4.55     pub/systems/os2
  7004.  
  7005.  ftp.uni-erlangen.de            131.188.1.43    pub/os2
  7006.  has German updates
  7007.  
  7008.  ftp.uni-kl.de                  131.246.9.95    pub/pc/os2
  7009.  also /incoming/pc/os2
  7010.  
  7011.  ftp.uu.net                     192.48.96.2     /usenet  (e.g.)
  7012.  newsgroup archives - see
  7013.  comp.os.os2.*, among
  7014.  others
  7015.  
  7016.  ftp.uwp.edu                    131.210.1.4     pub/msdos/proaudio
  7017.  FAQ, drivers, etc. for PAS16
  7018.  
  7019. The cdrom.com library is available on CD-ROM from Walnut Creek (phone 
  7020. 510-947-5996).  EMS (phone 301-924-3594) offers an OS/2 shareware/freeware 
  7021. library on diskette. 
  7022.  
  7023. Other sources include CompuServe (FIND OS/2) and archive servers (send a single 
  7024. line message with the word HELP to listserv@cc1.kuleuven.ac.be or 
  7025. mail-server@rus.uni-stuttgart.de for more information, or use ftp). TRICKLE 
  7026. servers are also available outside the United States.  For more information on 
  7027. TRICKLE services, including automatic file subscription procedures, send a 
  7028. single line message with the word HELP to any one of the following sites 
  7029. nearest you: 
  7030.  
  7031. Country      Address 
  7032. Austria      TRICKLE@AWIWUW11.BITNET 
  7033. Belgium      TRICKLE@BANUFS11.BITNET 
  7034. Colombia     TRICKLE@UNALCOL.BITNET 
  7035. France       TRICKLE@FRMOP11.BITNET 
  7036. Germany      TRICKLE@DEARN.BITNET 
  7037. Israel       TRICKLE@TAUNIVM.BITNET 
  7038. Italy        TRICKLE@IMIPOLI.BITNET 
  7039. Netherlands  TRICKLE@HEARN.BITNET 
  7040. Sweden       TRICKLE@SEARN.BITNET 
  7041. Turkey       TRICKLE@TREARN.BITNET 
  7042.              TRICKLE@TRMETU.BITNET 
  7043.  
  7044. IBM has been releasing freely distributable employee written software (e.g. 
  7045. Visual REXX) and OS/2 patches to these sites. 
  7046.  
  7047. (The previous was taken almost verbatim from the OS/2 General FAQ) 
  7048.  
  7049.  
  7050. ΓòÉΓòÉΓòÉ 13. Bugs / Obtaining this FAQ / Contacting the Author ΓòÉΓòÉΓòÉ
  7051.  
  7052. Reporting Bugs and Errors in the FAQ 
  7053.  
  7054. With the advent of all this nifty hypertext IPF stuff, there are bound to be 
  7055. bugs and errors in this FAQ, simply by Murphy's Law.  (Anything that can go 
  7056. wrong, will go wrong)  If you find an error, however, insignificant, please 
  7057. send me a note (through one of the ways listed below) telling me what's wrong 
  7058. with the FAQ. 
  7059.  
  7060. Obtaining this FAQ 
  7061.  
  7062. This FAQ is distributed on a regular basis to: 
  7063.  
  7064.  1. ftp-os2.cdrom.com:/os2/newsltr/pfaqxx.zip, on the Internet 
  7065.  2. hobbes.nmsu.edu:/os2/newsltr/pfaqxx.zip, on the Internet 
  7066.  
  7067. All other sites should receive this FAQ on a trickle-down basis from these 
  7068. sites. 
  7069.  
  7070. This FAQ is distributed in two versions, ASCII and INF.  The INF version is 
  7071. binary and viewable only by the VIEW.EXE program that comes with OS/2.  The 
  7072. ASCII version is text and is viewable by any program that can view text (which 
  7073. includes most word processors).  The filename is PFAQnn.ZIP, where 'nn' is the 
  7074. FAQ version. 
  7075.  
  7076. Contacting the Author 
  7077.  
  7078. I can be contacted in a multitude of ways: 
  7079.  
  7080. o Internet.  This is the preferred method.  E-mail me at 
  7081.   andreas@traci.almroth.pp.se. 
  7082.  
  7083. o Snail Mail 
  7084.  
  7085.    Andreas Almroth 
  7086.    Fanrik Stals Gata 153 
  7087.    S-754 39 UPPSALA 
  7088.    SWEDEN 
  7089.  
  7090.  
  7091. ΓòÉΓòÉΓòÉ 14. Credits ΓòÉΓòÉΓòÉ
  7092.  
  7093. The following people have contributed in numerous and not-so-numerous ways to 
  7094. this document to make it what it is today, and what it will be tomorrow.  Give 
  7095. a big round of applause for... 
  7096.  
  7097. o Barry Jaspan <bjaspan@athena.mit.edu> 
  7098. o Jeff Garzik <jgarzik@pantera.atl.ga.us> 
  7099. o Byers R E James <zoorejb@nusunix2.nus.sg> 
  7100. o Stefan Gruendal <Stefan_Gruendel@wue.maus.de> 
  7101. o Raja Thiagarajan <sthiagar@bronze.ucs.indiana.edu> 
  7102. o Larry Saloman <os2man@panix.com> 
  7103. o Timothy Sipples <sip1@kimbark.uchicago.edu> 
  7104. o Bob Smith <OECN_SMITH@MEC.OHIO.GOV> 
  7105. o Tim Francis <francis@vnet.IBM.COM> 
  7106. o Colin Jensen <cjensen@netcom.com> 
  7107. o Bill Henning <bhenning@wimsey.com> 
  7108. o Axel Uhl <auhl@fzi.de> 
  7109. o R. Mahoney <rmahoney@bix.com> 
  7110. o Frank Fuchs <ffu@softpro.de> 
  7111. o James J. Song <jjs@acd4.acd.com> 
  7112. o Morio Taneda <Morio_Taneda@ka.maus.de> 
  7113. o Timur Tabi <timur@seas.gwu.edu> 
  7114. o Paul Prescod <papresco@undergrad.math.uwaterloo.ca> 
  7115. o Rich Wales <richw@mks.com> 
  7116. o Craig Swanson <Craig_Swanson@f354.n202.z1.fidonet.org> 
  7117. o Ivar E. Hosteng <nit3ieh@odin.oslo.nit.no or nit3ieh@accsys.oslo.nit.no> 
  7118. o Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de> 
  7119. o Phillip E. Parker <pparker@twsuvm.uc.twsu.edu> 
  7120. o Lyle Sutton <lgs@roadnet.ups.com> 
  7121. o William First <wfirst@magi.com> 
  7122.  
  7123. Ok, so the list is a little short right now.  If you contributed to Barry's or 
  7124. Jeff's FAQ, and you are not listed here, then please send me your name and I'll 
  7125. be glad to include you in this list. 
  7126.  
  7127. I have obtained some information from sources other than people also. Besides 
  7128. being credited above, here is another list: 
  7129.  
  7130. o OS/2 Frequently Asked Questions List v2.1  (Available from 
  7131.   ftp-os2.cdrom.com:/os2/newsltr/faq21*.zip) 
  7132.  
  7133. o Electronic Developers' OS/2 Magazine  (Available from 
  7134.   ftp-os2.cdrom.com:os2/newsltr/edmi*.zip) 
  7135.