home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 14 Text / 14-Text.zip / pfaq221.zip / ProgFAQ.TXT < prev    next >
Text File  |  1993-12-03  |  220KB  |  6,394 lines

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