home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / OS2 / PFAQ30.ZIP / PROGFAQ.TXT < prev   
Text File  |  1994-03-10  |  226KB  |  7,073 lines

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