home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / vrac_os2 / pfaq32.zip / PROGFAQ.TXT < prev    next >
Text File  |  1994-11-24  |  238KB  |  7,675 lines

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