home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 17 / CD_ASCQ_17_101194.iso / vrac_os2 / pfaq31.zip / PFAQ31.TXT < prev   
Text File  |  1994-08-30  |  235KB  |  7,546 lines

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