home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / PFAQ21AS.ZIP / PROGFAQ.TXT
Text File  |  1993-06-17  |  220KB  |  6,826 lines

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