home *** CD-ROM | disk | FTP | other *** search
-
- ΓòÉΓòÉΓòÉ 1. Heading ΓòÉΓòÉΓòÉ
-
- OS/2 2.x Frequently Asked Questions, Programmer's Edition
- Version 2.1, June 16, 1993
-
- Compiled by
- Jeff Garzik <jgarzik@nyx.cs.du.edu>
- and
- Barry Jaspan <bjaspan@athena.mit.edu>
-
-
- ΓòÉΓòÉΓòÉ 2. Introduction ΓòÉΓòÉΓòÉ
-
- OS/2 2.x Frequently Asked Questions, Programmer's Edition
- Version 2.1, June 16, 1993
-
- Compiled by
- Jeff Garzik <jgarzik@nyx.cs.du.edu>
- and
- Barry Jaspan <bjaspan@athena.mit.edu>
-
- This FAQ is for programming and development-related issues for OS/2 2.x. It is
- freely distributable. Direct all responses and questions to
- jgarzik@nyx.cs.du.edu. Mention of a product does not constitute an
- endorsement. Answers to questions closer to the bottom of the list may rely on
- information given in prior answers. Customers outside the United States should
- not necessarily rely on 800 telephone numbers, part numbers, or upgrade
- policies contained in this list; all prices are listed in United Stated dollars
- unless otherwise specified.
-
- Sometimes you will find a question that has been asked so often that it
- deserves a place in the FAQ, regardless of whether I saw an answer to that
- question or not. In those cases I will simply put the question in the header
- title, and put "(answer me!)" as the text. This is a hint to help me find
- someone who can answer this question. And don't forget... PLEASE CONTRIBUTE
- ANY INFORMATION YOU CAN.
-
- Many of the answers in this FAQ refer to anonymous ftp site CDROM.COM. The name
- 'cdrom.com' is used as a shorthand to refer to this site. It has become, by
- default, the Internet storehouse for OS/2 files. If you cannot get files from
- this site (for whatever reason), then check OS/2 Software Sources for a source
- near you. You may find a more convenient method of getting files than from
- cdrom.com. (Non-US readers will note Bjorn Fhaller's FTP site, ftp.luth.se, is
- the main overseas FTP site.)
-
-
- Related Information:
-
- OS/2 Software Sources
- Obtaining this FAQ / Contacting the Author
-
-
- ΓòÉΓòÉΓòÉ 3. Release Notes ΓòÉΓòÉΓòÉ
-
- NOTE! NOTE! NOTE! I am looking for organizational suggestions for this FAQ.
- There are currently close to 100 topics in here, and I'm sure they could be
- organized better than they are now. Some psychiatric study suggested that
- normal people, under normal circumstances memorize around 7 related items.
- Therefore, I would ideally like to find a way to have at most 7 main topics,
- then at most 7 subtopics under each main topic, and so on.
-
- Thanks for rmahoney@bix.com for a FAQ from CompuServe! There was so much stuff
- in his list that I can't cover it at all in the release notes, so I'll just let
- you, Faithful Reader, discover these wonderous gems for yourself!
-
- Because of his additions, as well as the ones from Internet, a major revision
- of this FAQ was in order.
-
- cdrom.com was substituted for the main OS/2 FTP site.
-
- TOUCH-GUI product announcement added.
-
-
- ΓòÉΓòÉΓòÉ 4. Questions Covered in this Release ΓòÉΓòÉΓòÉ
-
- Languages, Compilers, Debuggers
- What programming languages come with OS/2 2.x?
- What C/C++ development environments are available?
- What is the difference between the two GNU C packages?
- What other programming languages are available for OS/2?
- Which of these compilers can be used to generate PM apps?
- What is REXX? How do I write and run a REXX program?
- What debuggers are available for OS/2?
- Tools, Toolkits, Accessories
- How do I use PATCH, maybe with my own programs?
- What programming editors are available for OS/2?
- What programming tools/toolkits/accessories are available for OS/2?
- What GNU tools are available and where can I find them?
- Is a socket library available? How can I use it?
- Compiling
- Can I distribute the C-Set/2 runtime DLL?
- How big should my stacksize be?
- How do I perform parallel compilation?
- What is an RC of 67 (invalid param) from the API?
- GCC/2 crashes with a trap when I try to compile a program. Why?
- How do I recompile EPM (easily)?
- Documentation, Help
- Where can I get information on OS/2 APIs and programming?
- Where can I get sample code?
- Are there any OS/2 programming classes or seminars?
- What are good reference books for programming in OS/2 and PM?
- What are the OS/2 redbooks, and how do I get them?
- How can I view the GNU C documentation?
- Where can I get documentation on the OBJ/LIB/EXE format used by OS/2 2.x?
- PM Programming
- Printing
- Are there any SIMPLE examples of printing?
- Is there an easy way to get printer output (another opinion)?
- How do I print a bitmap?
- How do I do my own Print Screen?
- Menus
- How do I add a menu to a dialog box?
- How do I make a dynamically changing menu?
- How do I create a conditional cascade menu?
- How do I remove a separator from a menu?
- Container Controls
- How do I stop a container from flashing every time I add a record?
- How do I get my containers to use Mini-icons?
- How do I sort a container control?
- How do I query all records in a container - tree view?
- I can't get different colors in text control windows
- How can I toggle my titlebar on and off?
- How can I get transparent regions in bitmaps?
- How do I create a status bar at the bottom of my window?
- How to have a frame/client and still have a std window?
- How do I use printf() in a PM program?
- I have a SOM DLL. How do I register it?
- How do I save and restore my window size and position?
- How do you make a window float above all other?
- How to ensure the sizing's correct so the dlg "fits" in the notebook...?
- How do I prevent Shutdown from stopping my app?
- When I pass a structure to WinCreateWindow, sometimes it doesn't work!
- How do I use type filtering in 2.0's open dlg?
- When minimizing, my dialog box is overwriting my icon!
- How do I make a multi-column listbox?
- How do I create my own Master Help Index?
- How do I change the font in an MLE?
- How do I attach Instance data to window created with WinCreateStdWindow?
- How do I get a list of fonts?
- How do I create a folder in C and put my pgm in it?
- How do I do it in REXX?
- How do I use the Font dialog (WinFontDlg)?
- How do I take control of frame sizing?
- How do I use the 16-bit EPM toolkit?
- How do I get error info after using WinGetLastError()?
- Do you have code to save/restore the clipboard?
- How do I know what item was selected in a Combo box?
- How do I get a bitmap into a dialog in a DLL?
- How does programming PM compare to programming X?
- How do I put bitmaps on buttons?
- Can a PM program tell if there's a previous instance of itself running?
- Miscellaneous Programming
- Explain the SYS_DLL keywords.
- How do I start another session?
- How do I check if a filename is valid?
- Why should I use _beginthread instead of DosCreateThread?
- How do I open a file that is already in use?
- Can we use Vio in v2.0? Where are the docs for it?
- Can I redirect stdin and stdout in a child process?
- How do I use DosMon*() to stuff the kbd buf?
- How do I determine what file system a drive uses?
- How do I get the error message from a DOS API call?
- How do I set an exception handler?
- How can I determine a diskette format and if a disk is in a drive?
- What do all those keywords mean when making a DLL?
- Where can I find serial port sample code?
- How do I disable <Ctrl><Alt><Del>?
- Why doesn't printf() produce output when I expect it to?
- How do I write an OS/2 device driver?
- How do I change the master environment?
- What is the best way to communicate between processes?
- What is the best way to communicate between threads?
- Porting
- How do I port my DOS keyboard TSR to OS/2?
- How can I simulate (Unix feature) under OS/2?
- How can I recompile public domain/shareware source code for OS/2?
- How can I port my DOS program to OS/2?
- How can I port my Windows program to OS/2?
- Miscellaneous
- Is OS/2 suitable for real time programs?
- What is available for multimedia programming under OS/2?
- What is available for AI/neural net programming under OS/2?
- Special software offers
- Technical Support
- Developer's Assistance Program (DAP)
-
-
- ΓòÉΓòÉΓòÉ 5. Languages, Compilers, Debuggers ΓòÉΓòÉΓòÉ
-
- This section covers the programming tools currently available for OS/2.
-
-
- ΓòÉΓòÉΓòÉ 5.1. What programming languages come with OS/2 2.x? ΓòÉΓòÉΓòÉ
-
- The original BASIC and BASICA (for systems with BASIC in ROM), DOS's QBASIC,
- and OS/2's REXX come with OS/2 2.x.
-
-
- Related Information:
-
- What is REXX? How do I write and run a REXX program?
-
-
- ΓòÉΓòÉΓòÉ 5.2. What C/C++ development environments are available? ΓòÉΓòÉΓòÉ
-
- Many companies offer C or C++ compilers. The following list is almost
- guaranteed to be incomplete, somewhat inaccurate, and always out of date.
-
- Borland
-
- Borland C++ for OS/2
-
- Glockenspiel
-
- Glockenspiel C++, (+353)-1-733166.
-
- GNU Project
-
- GNU C. Two flavors of the GNU C compiler are available, both on cdrom.com.
- GCC/2 is in os2/2_x/unix/gnu/gcc2_233, and emx/gcc is in
- os2/2_x/unix/gnu/emx08f.
-
- IBM
-
- (C-Set++ replaces IBM's previous OS/2 C compiler, C-Set/2.) It includes many
- new tools, and upgrades to existing tools. Included is:
-
- o C & C++ compiler - as well as C++, there are now new, better optimizations,
- pre-compiled header support, more control over generated warnings and much
- more.
- o IPMD - Version 2 of the debugger - faster, more stable, and with more
- features (such as a built in PM message queue monitor)
- o EXTRA - Execution Trace Analyzer (a profiler and more) (new for v2)
- o Class browser - new for version 2
- o Class libraries - new for version 2 - include:
-
- - user interface class libraries
- - collection class libraries
- - AT&T standard class libraries
-
- o WorkFrame/2 - version 1.1
- o Toolkit - version 2.0, but an update disk is included to add C++ support, and
- to fix some bugs
-
- The entire package is promotionally priced until August 31st ('93)
- New user
- * $149 (CD-ROM), $175 (diskette)
- Upgrade from C Set/2
- * $129 (CD-ROM), $149 (diskette)
-
- Full text of the announcement is available by sending a blank note to
- csetinfo@vnet.ibm.com. Bug reports for C Set ++ can be mailed to
- cset2@vnet.ibm.com, and for Workframe/2 to workframe@vnet.ibm.com, and will go
- straight to the developers.
-
- US and Canadian developers can order it through their favorite programming
- supply store, or from 1-800-IBM-OS2. (The US/Canada fax number is
- 1-800-465-3299.)
-
- JPI
-
- JPI C and C++, (415) 967-3200 (USA), +44 234 267500 (UK/Europe), $180.
-
- Microway
-
- Microway C++, $595.
-
- Watcom
-
- Watcom C 9.0, (519) 886-3700.
-
-
- Related Information:
-
- What is the difference between the two GNU C packages?
-
-
- ΓòÉΓòÉΓòÉ 5.3. What is the difference between the two GNU C packages? ΓòÉΓòÉΓòÉ
-
- The two versions of GNU C that are available were ported to OS/2 with different
- goals and philosophies in mind and therefore have different characteristics.
- However, both systems include a fairly complete C library and can be used to
- compile useful programs, although their support of Unix-specific semantics
- differs. Furthermore, both systems are being actively developed and are
- constantly improving.
-
- The goal of GCC/2 is to create a pure, freely redistributable OS/2 2.x
- development environment with no extra baggage for backwards compatibility; it
- is based on the assumption that DOS will die and is not worth worrying about.
- It is based on GNU C 2.3.3, supports C and C++, and can create PM programs. It
- produces "native" 32 bit .OBJ files that are linked with OS/2's LINK386.EXE,
- and can be linked together with .OBJ files produced by IBM C Set/2 and other
- compatible compilers. The mailing list os2gcc@charon.mit.edu exists for
- discussion of this port; send mail to os2gcc-request@charon.mit.edu for
- subscription information.
-
- emx/gcc 0.8f, also based on GNU C 2.3.3, supports C, C++, and Objective C and
- can create PM programs. emx's goal is to make porting Unix programs easier by
- emulating Unix semantics as closely as possible. It produces programs that can
- run both under OS/2 using EMX.DLL and under DOS using the emx DOS extender.
- emx/gcc uses standard Unix development tools like ld and nm, and attempts to
- support Unix-isms like select() and fork(). A version of gdb exists that can
- debug emx/gcc programs. An emx-related mailing list exists; send mail to
- LISTSERV@ludd.luth.se with a message body of "help" for subscription
- information. (Note that this is a *NEW* address for the emx discussion list.)
-
-
- ΓòÉΓòÉΓòÉ 5.4. What other programming languages are available for OS/2? ΓòÉΓòÉΓòÉ
-
- Virtually all of them: Assembler, COBOL, Pascal, Fortran, Smalltalk, Modula-2,
- LISP, Forth, Perl, and more. The OS/2 Tools Guide on cdrom.com
- (os2/all/info/tinf31.zip) contains information on these and more.
-
- [Vendors, ftp sites, phone numbers, prices?]
-
- Pascal: Microway ($595), JPI ($180)
- Modula-2: JPI ($180), Stonybrook
- Fortran:
-
- Microway ($595), Watcom
- f2c Fortran-to-C translator: cdrom.com
-
- Cobol: IBM Cobol/2
- Smalltalk: Digital Smalltalk/PM V, Parc Place Smalltalk
- Perl 4.0.10: cdrom.com
- LISP:
-
- Common LISP: ma2s2.mathematik.uni-karlsruhe.de
- XLisp: cdrom.com
-
- XScheme: cdrom.com
- J: cdrom.com
-
-
- ΓòÉΓòÉΓòÉ 5.5. Which of these compilers can be used to generate PM apps? ΓòÉΓòÉΓòÉ
-
- IBM C Set/2 can generate PM apps. Workset/2 includes many sample programs and
- the complete on-line reference.
-
- GNU C/C++ 2.1 can generate PM apps, and includes a sample program that does it.
- emx/gcc can too, with some limitations (what are they?).
-
- Most commercial C and C++ compilers can. WATCOM C and FORTRAN and all of JPI's
- can, too. You will probably want the IBM Developer's Toolkit, or similar
- documentation, however.
-
-
- ΓòÉΓòÉΓòÉ 5.6. What is REXX? How do I write and run a REXX program? ΓòÉΓòÉΓòÉ
-
- REXX is the IBM SAA (Systems Application Architecture) standard, user-friendly
- programming language. It is available for IBM mainframes, Unix, the Amiga, DOS
- (Mansfield's Professional REXX), Windows, and many other platforms. It has
- been a part of standard OS/2 since Version 1.3. Programs written in REXX that
- do not use system-specific libraries are fully portable.
-
- OS/2 2.x comes with an online REXX reference, and printed REXX documentation is
- available (Mike Cowlinshaw's REXX book, IBM's twin guides). The Usenet group
- comp.lang.rexx discusses REXX programming.
-
-
- ΓòÉΓòÉΓòÉ 5.7. What debuggers are available for OS/2? ΓòÉΓòÉΓòÉ
-
- IPMD, a PM-based debugger, ships with C Set/2. It is capable of source- and
- assembly-level debugging multithreaded 16 bit and 32 bit OS/2 applications
-
- emx comes with gdb, the GNU debugger.
-
- Borland C++/2 comes with a PM-based debugger (Turbo Debugger GX) which has the
- same basic functionality as IPMD.
-
- There are also several commercial debuggers on the market. WATCOM C and
- FORTRAN come with WVIDEO, a full-screen source or assembly lever debugger that
- handles multithreaded 16 and 32 bit OS/2 programs. Multiscope, others?
-
-
- ΓòÉΓòÉΓòÉ 6. Tools, Toolkits, Accessories ΓòÉΓòÉΓòÉ
-
- This section covers tools, toolkits, and accessories available to OS/2
- programmers.
-
-
- ΓòÉΓòÉΓòÉ 6.1. How do I use PATCH, maybe with my own programs? ΓòÉΓòÉΓòÉ
-
- The file format is actually quite simple - you just need a text file which
- consists of lines each starting with one of the following commands:
-
- FILE <filename> e.g. FILE test.exe
-
- specifies the file to which the following instructions are to be applied. A
- patch file may contain multiple FILE directives.
-
- VER <offset> <data> e.g. VER 00001234 abcdef
-
- checks if the specified data is present at the given file offset [all values in
- hex, data can be just a string of digits with no blanks in between; up to 16
- bytes are allowed in one statement]. If the check fails, the patch process is
- aborted resp. the program skips to the next FILE statement.
-
- CHA <offset> <data> e.g. CHA 00001234 012345
-
- changes the data at the given offset - syntax is same as in VER. It is a good
- idea to do all VERification before starting the first CHA.
-
- Blank lines and data lines starting with a ";" are ignored.
-
- As you can see from this, there seems to be no way to _insert_ or _delete_
- bytes in the file. To make patches applicable to multiple versions of the same
- file, you can specifiy more than one FILE directive for the same filename -
- only a patch with all VER commands matching is executed.
-
- Credit: Marcus Groeber
-
-
- ΓòÉΓòÉΓòÉ 6.2. What programming editors are available for OS/2? ΓòÉΓòÉΓòÉ
-
- OS/2 2.x comes with the Enhanced Editor (EPM).
-
- GNU Emacs 18.58 is available. It requires you to have emx installed on your
- machine, but it comes with all the emx files you will need. Emacs is available
- on cdrom.com in os2/2_x/unix/gnu/emacs. (If you want to recompile emacs, you
- will need the full emx distribution; see question 1.2.) Also, you must have
- HPFS installed to use GNU emacs. You can read, write, and edit files that
- exist on a DOS partition, but you must have GNU emacs installed on an HPFS
- partition.
-
- Several public-domain vi clones are available, including elvis, Stevie and
- levee. The MKS Toolkit also includes vi.
-
- Many other text editors are available.
-
- Epsilon, by Luguru, (412) 421-5678. DOS upgrade to OS/2 is $90. Character
- based editor.
-
- Q-Edit, by SemWare, (404) 641-9002. Character based editor, almost identical
- to Q-Edit for DOS. Does not support long filenames yet.
-
- Brief, KEDIT, others? [Vendors, phone numbers, prices?]
-
- EHP, a text mode editor, was recently ported by Axel Uhl to PM, and is
- available on cdrom.com.
-
-
- ΓòÉΓòÉΓòÉ 6.3. What programming tools/toolkits/accessories are available for OS/2? ΓòÉΓòÉΓòÉ
-
- C-Set++ includes the following tools (excluding the compiler & debugger
- themselves):
-
- o EXTRA - Execution trace analyzer
- o A Class browser
-
- The IBM Programmer's Toolkit, included in Workset/2 and also in C-Set++,
- includes many tools:
-
- o A dialog editor
- o A SOM compiler
- o A font editor
- o An icon editor
- o An IPF compiler
- o Message compile & bind tools
- o Resource compile & bind tools
- o KwikInf
- o ...and a couple others
-
- Borland has released ObjectVision for OS/2. [Details?]
-
- Borland C++ for OS/2 also includes a number of utilities, such as the Resource
- Workshop.
-
- The MKS Toolkit, available from MKS ($349 USD, 800-265-2797 or
- inquiry@mks.com), has over 160 Unix tools, including Korn shell, tar, vi, awk,
- grep, tail, cpio, and so forth. It also contains a Lex and Yacc capable of
- generating C, C++, and Turbo Pascal code.
-
- There is a product called ARGO/UX which provides a BSD environment for OS/2.
- [details?]
-
- SOFTPRO GmbH has announced its 32bit C++ class library TOUCH-GUI 2.0 for OS/2
- 2.x.
-
-
- ΓòÉΓòÉΓòÉ <hidden> TOUCH-GUI 2.0 for OS/2 2.x ΓòÉΓòÉΓòÉ
-
- SOFTPRO GmbH has announced its 32bit C++ class library TOUCH-GUI 2.0 for OS/2
- 2.x. The product contains more than 130 classes which support windows, menu
- bars, multi-threading, controls, dialog boxes, graphics, printer control, MDI,
- DDE, Drag and Drop, loadable resources from DLL's, and management of profiles
- (.INI files). Other features include auxiliary classes for data manipulation
- and storage management. Additionally, TOUCH-GUI 2.0 contains high-level classes
- like toolbars, formatted entry fields, tables, and complete NLS.
-
- Supported C++ compilers are: Borland, GNU (emx), IBM, and WATCOM
-
- The product includes online (.INF) and printed documentation, a demo program,
- and samples.
-
- TOUCH-GUI 2.0 costs DM 1.720,00 excl. VAT (ca. $1075), the runtime DLL's may be
- distributed royalty free. Special project licenses are available, contact the
- supplier.
-
- Contact:
- SOFTPRO GmbH, Stadtgrabenstr. 21, 71032 Boeblingen, Germany
- Tel.: +49 7031 6606-0
- Fax: +49 7031 6606-66
- Mr. Frank Fuchs (extension -50)
- Internet email: ffu@softpro.de
- IBMMAIL (IEA): DEJP9SK9
-
-
- ΓòÉΓòÉΓòÉ 6.4. What GNU tools are available and where can I find them? ΓòÉΓòÉΓòÉ
-
- Nearly all the GNU utilities have been ported to OS/2 2.x - and nearly all of
- those ports are located on cdrom.com in os2/2_x/unix/gnu. Other, more involved
- (or independent) ports of GNU software is scattered about cdrom.com, including
- a PM version of GhostView and GhostScript.
-
-
- ΓòÉΓòÉΓòÉ 6.5. Is a socket library available? How can I use it? ΓòÉΓòÉΓòÉ
-
- IBM's TCP/IP 1.2.1 ($200, part #02G6968) includes an optional Programmer's
- Toolkit ($500, part #02G6973). It includes a socket library, and support for
- Sun RPC, NCS RPC, and a limited Kerberos capability. It requires IBM C Set/2
- or another compiler that understands 16-bit code.
-
- FTP Software, Inc., has an OS/2 version of its TCP/TCP product. They can be
- reached at (617) 246-0900 or info@ftp.com.
-
- Walt Corey, KZ1F, is porting KA9Q to OS/2 and PM. The current version of his
- code is available for ftp from giskard.uthscsa.edu. This is still a work in
- progress, with rough edges here and there, and in particular there's no
- Ethernet (or anything but async serial, i.e. SLIP, PPP, and KISS) support yet,
- though that's high on the priority list. You can email Walt at
- kz1f@giskard.uthscsa.edu.
-
- If you have the IBM TCP/IP 1.2 base package and IBM C Set/2, you can use the
- TCPIPDLL.DLL directly.
-
-
- ΓòÉΓòÉΓòÉ 7. Compiling ΓòÉΓòÉΓòÉ
-
- This section covers compiling OS/2 programs and accessories.
-
-
- ΓòÉΓòÉΓòÉ 7.1. Can I distribute the C-Set/2 runtime DLL? ΓòÉΓòÉΓòÉ
-
- No, you have to create your own Here's a recipie for creating a runtime DLL:
-
- 1. Combine and rename the appropriate DEF files that have been provided in the
- LIB subdirectory of where C Set/2 is installed. ie. for multi-threading:
- DDE4MBS.DEF + DDE4MBM.DEF ==> MYCRTDLL.DEF Remember to change the DLL name
- on the LIBRARY line of the DEF file.
- 2. Remove the STUB line from the DEF file. Remove unwanted functions from the
- DEF file. Remember to not delete anything with a **** comment after it.
- These variables and functions are always required.
- 3. Create an empty source file (yes I mean empty). Suppose you call it
- MYCRTDLL.C
- 4. Compile and link using: ICC /Ge- <options> MYCRTDLL.C MYCRTDLL.DEF where
- options are either: /Gm or /Gm- or /Rn depending on which type of DLL you
- want to build.
- 5. To build the import library use: IMPLIB /NOI MYCRTDLL.LIB MYCRTDLL.DEF
- IMPLIB comes with the Toolkit.
- 6. Add the necessary real objects to the import library by using the LIB
- utility from the Workframe. LIB MYCRTDLL.LIB +DDE4xBSO.LIB; x is either M
- or S or N depending on whether you want multithreading, single threading or
- subsystems development
- 7. Now compile your EXEs or DLLs with /Gn added (no default library info) and
- when linking specify your own libraries including MYCRTDLL.LIB and
- OS2386.LIB.
-
- Credit: Ian Ameline
-
-
- ΓòÉΓòÉΓòÉ 7.2. How big should my stacksize be? ΓòÉΓòÉΓòÉ
-
- For a PM program, >32K, avoid multiples of 64K.
-
-
- ΓòÉΓòÉΓòÉ 7.3. How do I perform parallel compilation? ΓòÉΓòÉΓòÉ
-
- Get DMAKE. Following is an example on how to use it:
-
- The ini file comes in the dmake archive in a few different flavours. Take the
- file with the extension .msc and rename it to dmake.ini. Set an environment
- variable in config.sys
-
- SET MAKESTARTUP=d:\COMPILER\DMAKE.INI
-
- ====== Makefile
-
- CC=icc
- COPTS=/Sm /Gt+ /Ti+ /O- /Gs+
- CONLY=-c
-
- LIBS=os2
-
- INCS=psfax2.h
-
- MAXPROCESS=2
-
- all: psfax2.exe sendfax.exe
-
- modem.obj: modem.c $(INCS)
- $(CC) $(CONLY) $(COPTS) modem.c
-
- psfax2.obj: psfax2.c $(INCS)
- $(CC) $(CONLY) $(COPTS) psfax2.c
-
- psfax2.exe: psfax2.obj modem.obj
- link386 /ST:32768 /CO psfax2+modem;
-
- sendfax.obj: sendfax.c $(INCS)
- $(CC) $(CONLY) $(COPTS) sendfax.c
-
- sendfax.exe: sendfax.obj modem.obj
- link386 /ST:32768 /CO sendfax+modem;
-
- ====== End of makefile
-
- Couple of gotchas. There is a bug in the MAXPROCESS handling of the copy I
- use. Set it to 1, and you get a typical make, ie one at a time. Set it to 2,
- and the thing launches 3 processes. Ie with more than 1, you actually get n+1
- processes running.
-
- Another caveat
-
- xxx.yy: aaa.bbb
- command1
- command2
- command3
-
- The above structure does not work. The reason is that all 3 commands will be
- spawned together in parallel sessions. To serialize them you must make up
- dependancies in the makefile. I ran into this becuase I have one makefile that
- completes every link stage by copying the result onto a network drive. I had
- to take all the links that previously had 2 commands, and break them into 2
- blocks with the second being a dependancy of the remote file on the local file,
- and the copy command.
-
- One more word of warning, dmake is not to pleased with those convoluted things
- that workframe spits out in the name of makefiles. You may have to do a
- significant amount of makefile editing, depending on how you makefile look now.
-
- Provided that 3 simultaneous copies of your compiler doesn't push your machine
- into excessive swapping, the improvements in build speed are amazing. Before
- dmake I'd never seen a build actually top the cpu meter here, the process was
- always waiting for disk as it loaded compilers/headers etc. Now the compiler
- sits in ram and just gets re-used, and the headers are coming directly from
- cache all the time. Build time cut in half, and my cpu guage is pegged at 100%
- when a build is running.
-
- Credit: Gerry Rozema
-
-
- ΓòÉΓòÉΓòÉ 7.4. What is an RC of 67 (invalid param) from the API? ΓòÉΓòÉΓòÉ
-
- You are (most likely) not including the prototype. Use the following flags to
- get a good balance of warning messages:
-
- /Kbperc
-
- For C Set++, I use these flags as the approximate equivalent
-
- /Wall /Wext- /Wgnr- /Wgot- /Wpor- /Wppt- /Wtrd /Wuni- /Wvft-
-
- I have these set as part of my ICC string in CONFIG.SYS, so I don't have to add
- them to each compile. I have found that these settings give me a good
- combination of thorough warning messages without too many warnings.
-
- Credit: Wayne Kovsky
-
-
- ΓòÉΓòÉΓòÉ 7.5. GCC/2 crashes with a trap when I try to compile a program. Why? ΓòÉΓòÉΓòÉ
-
- Because you didn't read the README or INSTALL files, probably. There are three
- general reasons GCC/2 will crash:
-
- 1. You did not set up the environment variables in CONFIG.SYS properly. Read
- doc/INSTALL for instructions.
-
- 2. Some program that gcc expects to be in the PATH is not; unfortunately, gcc
- crashes instead of just printing an error message. You may forgotten to
- install something, or your PATH may be wrong; see above. Giving gcc the -v
- option will cause it to print each command line as it executes it; this
- will tell you which program is missing.
-
- 3. You are trying to get gcc to link your program for you. It cannot because
- ld does not exist, and so it crashes (see item 2). You must specify -c,
- -E, or -S on every invokation of gcc, and then use LINK386.EXE to create an
- executable. See the sample makefiles for an example of how to do this.
-
- [Colin Jensen, the current maintainer of GCC/2, also adds the following...]
-
- Not true as of gcc/2 2.3.3. Gcc will invoke a small stub program called ld.exe
- that in turn will invoke link386 for you. If the command line is too long for
- the ever-pathetic link386 to handle, ld will properly create a response file.
-
- It is easier to use gcc/2 to call link386 than to do it yourself since gcc/2
- will also arrange to call a subprogram called "collect" that is required before
- linking a C++ program.
-
- Also, gcc/2 is just plain easier to use than link386, for example:
-
- gcc -o foobar.exe mydef.def foobar.cpp mylib.lib
-
- will compile foobar.cpp, link with mylib.lib, and pass the linker definition
- file mydef.def to link386 in the correct order. Link386 demands that you know
- which types of files can be put between which sets of commas on the command
- line.
-
-
- ΓòÉΓòÉΓòÉ 7.6. How do I recompile EPM (easily)? ΓòÉΓòÉΓòÉ
-
- (answer me!)
-
-
- ΓòÉΓòÉΓòÉ 8. Documentation, Help ΓòÉΓòÉΓòÉ
-
- This section covers documentation and help available for OS/2 programming.
-
-
- ΓòÉΓòÉΓòÉ 8.1. Where can I get information on OS/2 APIs and programming? ΓòÉΓòÉΓòÉ
-
- The IBM Programmer's Toolkit, included in Workset/2, includes a complete
- on-line syscall reference.
-
- You can FTP the documentation for the 16-bit calls (IBM does not supply them),
- such as Vio*(), Kbd*(), Mou*(), from cdrom.com as os2/2_x/program/inf16bit.zip.
-
- You can order the seventeen volume IBM OS/2 Technical Library (possibly at a
- discount, see question 1.2) and/or order various volumes individually.
-
- Most of these volumes are now published by Que books also, and can be found in
- many bookstores.
-
-
- Related Information:
-
- What are good reference books for programming in OS/2 and PM?
- What C/C++ development environments are available?
-
-
- ΓòÉΓòÉΓòÉ 8.2. Where can I get sample code? ΓòÉΓòÉΓòÉ
-
- There is a lot of sample code included in the IBM Toolkit, and 4 sample
- programs (with source) included with C Set/2. GNU C/C++, from cdrom.com,
- includes a sample C, C++, and C++ PM program. The OS/2 Redbooks also have some
- sample code. cdrom.com also has little bits of OS/2 and PM source code lying
- around in the os2/2_x/program directory.
-
-
- Related Information:
-
- What are the OS/2 redbooks, and how do I get them?
-
-
- ΓòÉΓòÉΓòÉ 8.3. Are there any OS/2 programming classes or seminars? ΓòÉΓòÉΓòÉ
-
- Yes. Call IBM at either 1-800-3-IBM-OS2 in U.S. (or the PS/2 Help Center).
- Local IBM branches frequently hold OS/2 classes and seminars. I haven't seen
- third party efforts in this regard, but I know they exist.
-
- See os2/2_x/info/ivleague.txt on cdrom.com for a list of third-party support
- organizations.
-
-
- ΓòÉΓòÉΓòÉ 8.4. What are good reference books for programming in OS/2 and PM? ΓòÉΓòÉΓòÉ
-
- Van Nostrand Reinhold publishes a number of books on OS/2 2.x. Those that
- relate to programming are:
-
- INTEGRATING APPLICATIONS WITH OS/2 2.0
- By William H. Zack
- 0-422-01234-9
-
- CLIENT SERVER PROGRAMMING WITH OS/2 2.0
- By Robert Orfali and Daniel Harkey, IBM Corporation
- 0-422-01219-5
-
- WRITING OS/2 2.0 DEVICE DRIVERS IN C
- By Steven J. Mastrianni; Foreword by John Soyring, IBM Corporation
- 0-442-01141-5
-
- OS/2 2.0 PRESENTATION MANAGER GPI: A Programming Guide to Text, Graphics, And Printing
- By Graham C.E. Winn, IBM Corporation
- 0-442-00739-6
-
- THE COBOL PRESENTATION MANAGER PROGRAMMING GUIDE
- By David M. Dill, Consultant
- 0-442-01293-4
-
- LEARNING TO PROGRAM OS/2 2.0 PRESENTATION MANAGER BY EXAMPLE: Putting the Pieces Together
- By Stephen Knight, IBM Corportaion
- 0-442-01292-6
-
-
- Related Information:
-
- What are the OS/2 redbooks, and how do I get them?
-
-
- ΓòÉΓòÉΓòÉ 8.5. What are the OS/2 redbooks, and how do I get them? ΓòÉΓòÉΓòÉ
-
- (see end note for FTP information)
-
- IBM publishes so-called "redbooks" on many products, including OS/2 2.x. They
- seem to be a combination of power-user's guides and design information that may
- be of use to both users and programmers [I haven't received my copies yet, so I
- cannot say for sure.] These are usually intended only for special IBM
- customers and contain documentation that is generally unavailable anywhere
- else. You can order these books directly from IBM (see below). All of the
- following names are implicitly preceeded by "OS/2 Version 2.0."
-
- Volume 1: Control Program: GG24-3730, $4.15
- Technical information on Memory Management, Task Mangement, Support,
- Installation Considerations, Hardware Considerations, Boot Manager,
- National Language Considerations, Intel 386 architecture, Channel
- Architecture and SCSI. Documents config.sys.
-
- Volume 2: DOS and Windows Environment, GG24-3731, $6.20
- MVDM,8086 Emulation,MVDM DOS emulation, Device Drivers, Memory Extender
- Support, Installing and Migrating Applications, Windows Applications,
- DPMI, Running DOS apps,DOS settings, VMB.
-
- Volume 3: PM and Workplace Shell GG24-3732, $3.65
- Available now, but I don't know precisely what's in it.
-
- Volume 4: Application Development GG24-3774, $5.25
- Technical programming info (includes list in C) Overview, Object-Oriented
- Apps, PM application model, flat memory model, building PM app, Workplace
- AOAShell and System Object Model, Direct Manipulation (Drag/drop), PM
- resources, Multitasking Considerations, SAA CUA considerations, App
- Migration, Mixing 16 and 32 bit application modules, compiling and link
- editing (SOM), Adding Online Help, Problem Determination, Managing
- Development, Naming conventions.
-
- Volume 5: Print Subsystem, GG24-3775, $5.20
- Not Available yet.
-
- The special part number GBOF-2254 is for all currently available volumes
- (presently 1-4).
-
- ORDERING INFORMATION:
-
- The OS/2 2.x Redbooks are available from IBM's TeleServices customer support
- number. The number is 1-800-7654-IBM (1-800-765-4426). You can pay by credit
- card or mail in a check after calling. The order will take about 2 weeks but
- can be sped up by paying for faster shipping.
-
- You can also order the redbooks from your local IBM Branch Office library.
- Some possibly useful phone numbers are included here.
-
- IBM Central Library, Los Angeles CA: (213) 621-6710
- P.O. Box 60737
- Los Angeles, CA 90060
- Canada: (800) 465-1234, ext 4205 ($33.52)
- UK: (0256) 478166, (#36.51, credit cards accepted)
- Australia (Victoria): 698-1234 ($46.80 A)
- IBM Australia
- The Library
- 211 Sturt Street
- South Melbourne, 3205
- Att: Kate Seeley
- Denmark: 33 32 40 55 (dkk 310)
-
- The redbooks are also FTP'able from cdrom.com as the os2/ibm/misc/redbk*.zip.
- The source code that accompanies the first three redbooks can FTP'able from
- cdrom.com as os2/2_x/program/rb37*.zip.
-
-
- ΓòÉΓòÉΓòÉ 8.6. How can I view the GNU C documentation? ΓòÉΓòÉΓòÉ
-
- GNU C/C++ comes with documentation from the Free Software Foundation in texinfo
- (.texi) format. This documentation is about gcc in general, and has no
- OS/2-specific information.
-
- All utilities needed to compile/view/tex the texinfo files are readily
- available for OS/2. The GNU texinfo package, available on cdrom.com in
- os2/all/unix/gnu/gnuinfo.zip, includes makeinfo.exe for compiling texinfo,
- info.exe for viewing them, and texinfo.tex and texindex.exe for TeXing them.
-
- An ASCII text version of the gcc documentation is also available on cdrom.com,
- in the file os2/2_x/unix/gnu/gcc2_233/gcc_inf.zip.
-
- An INF hypertext version of the gcc (and related programs) documentation was
- uploaded recently to cdrom.com, but has not been moved out of the os2/incoming
- directory yet.
-
- emx/gcc includes its own hypertext style reader and texinfo files for all the
- GNU tools that come with it.
-
- GCC/2 includes the hypertext manuals for gcc, gas, and gnumake as well as a PM
- reader for the manuals.
-
-
- ΓòÉΓòÉΓòÉ 8.7. Where can I get documentation on the OBJ/LIB/EXE format used by OS/2 2.x? ΓòÉΓòÉΓòÉ
-
- The .EXE format was described briefly in PC Magazine, Vol 11 No. 12 (June 30,
- 1992?); it was also described in a 1988 issue.
-
- The glib source code contains a full description of the 32 bit OBJ and LIB
- formats. It is found at cdrom.com:/os2/2_x/unix/gnu/gcc2_233/glibs115.zip.
-
- It is also available in text form from cdrom.com as os2/2_x/program/lxexe.doc.
-
-
- ΓòÉΓòÉΓòÉ 9. PM Programming ΓòÉΓòÉΓòÉ
-
- This section covers Presentation Manager programming.
-
-
- ΓòÉΓòÉΓòÉ 9.1. Printing ΓòÉΓòÉΓòÉ
-
- This section covers Presentation Manager printing.
-
-
- ΓòÉΓòÉΓòÉ 9.1.1. Are there any SIMPLE examples of printing? ΓòÉΓòÉΓòÉ
-
- Here is some sample code, but also check out PRINTQ.ZIP on cdrom.com.
- PRINTQ.ZIP contains a DLL that encapselates alot of the messy details.
-
- Here is the working code for allowing the user to change the printer setup.
- I've also included the code that I use to start and end printing, so you can
- see how it all works.
-
- If you have any questions or comments, feel free to write.
-
- PrinterSetup() is the routine that gets the printer setup information from the
- user.
-
- GetPrinterHPS() is the routine that gets the DC and PS for the printer, and
- starts the document.
-
- EndPrint() is the routine that ends the document, and closes the DC.
-
- First, here's a little sample of how to use PrinterSetup(), GetPrinterHPS(),
- and EndPrint():
-
- {
- HPS hPrinterPS;
- HDC hPrinterDC;
- DEVOPENSTRUC dops;
-
- ...
-
- dops->pszLogAddress = NULL; // in case PrinterSetup fails, this will tell
- // GetPrinterHPS() to use default printer info
-
- PrinterSetup(&dops);
-
- hPrinterPS = GetPrinterHPS(&dops, &hPrinterDC,
- "Document Name", 0L, 0L);
- if (hPrinterPS != GPI_ERROR) {
- // do your printing here
-
- EndPrint(hPrinterPS, hPrinterDC, "Document Name");
- }
-
- ...
- }
-
-
- /*
- ******************************************************************************
- ** FUNCTION: PrinterSetup
- ** PURPOSE : This function allows the user to change printer settings.
- **
- ** PARAMS : lpdos - the printer info
- ** RETURN : BOOL (TRUE = success)
- **
- ** DATE : 11-Dec-1992
- ** AUTHOR : Carl Samos
- ******************************************************************************
- ** Modified: Date: Description of changes
- ** CNS : 11-Dec-1992 Initial version
- ******************************************************************************
- */
- BOOL PrinterSetup(DEVOPENSTRUC FAR *lpdos)
- {
- PDRIVDATA pDriveData; /* The drive data */
- unsigned long ulSize; /* The buffer size required */
- char szPrinter[32]; /* The printer name */
- PSZ pszDriver; /* The driver name */
- PSZ pszLogicalPort; /* The logical port */
- char szDeviceName[32];/* The printer's name */
-
-
- // get the printer driver, name and logical port
- // GetPrinterInformation allocates space for pszDriver and pszLogicalPort
- if (!GetPrinterInformation(szPrinter, &pszDriver,
- szDeviceName,&pszLogicalPort))
- return(FALSE);
-
-
- // get the size needed for the DRIVDATA struct
- ulSize = DevPostDeviceModes(habMain, NULL, pszDriver, NULL, szPrinter, 0L);
-
-
- if (ulSize != DPDM_NONE && ulSize != DPDM_ERROR) {
- pDriveData = (PDRIVDATA) _fmalloc(ulSize);
- pDriveData->cb = ulSize;
-
- // bring up the dialog boxes, and fill the DRIVDATA struct
- ulSize = DevPostDeviceModes(habMain, pDriveData, pszDriver, NULL,
- szPrinter, 0L);
-
- if (ulSize == DEV_OK) {
- // if there is a printer name, copy it into the DRIVDATA
- if (szDeviceName[0] != '\0')
- strcpy(pDriveData->szDeviceName, szDeviceName);
-
- // remove the old information
- if (lpdos->pszLogAddress != NULL) {
- _ffree(lpdos->pszLogAddress);
- }
- if (lpdos->pszDriverName != NULL) {
- _ffree(lpdos->pszDriverName);
- }
- if (lpdos->pdriv != NULL)
- _ffree(lpdos->pdriv);
-
- /* Setup the DEVOPENSTRUC */
- lpdos->pszLogAddress = pszLogicalPort;
- lpdos->pszDriverName = pszDriver;
- lpdos->pszDataType = NULL;
- lpdos->pdriv = pDriveData;
- }
- else {
- _ffree(pszDriver);
- _ffree(pszLogicalPort);
- _ffree(pDriveData);
- }
- }
- else {
- _ffree(pszDriver);
- _ffree(pszLogicalPort);
- }
-
- return(TRUE);
- }
-
-
- /*
- ******************************************************************************
- ** FUNCTION: GetPrinterInformation
- ** PURPOSE : This function gets the current printer information from the
- ** os2.ini file.
- **
- ** PARAMS : PSZ pszPrinter
- ** PSZ pszDriver
- ** PSZ pszDeviceName
- ** PSZ pszLogicalPort
- **
- ** RETURN : void
- **
- ** DATE : 11-Dec-1992
- ** AUTHOR : Carl Samos
- ******************************************************************************
- ** Modified: Date: Description of changes
- ** CNS : 11-Dec-1992 Initial version
- ******************************************************************************
- */
- BOOL GetPrinterInformation(PSZ pszPrinter, PSZ FAR *lpszDriver,
- PSZ pszDeviceName, PSZ FAR *lpszLogicalPort)
- {
- int cb;
- char szDetails[256];
- PSZ pszBegin;
- PSZ pszTemp;
- char szPort[64];
- char szDriver[64];
- char szLogPort[64];
-
- /* Get the printer name */
- cb = WinQueryProfileString(habMain, "PM_SPOOLER",
- "PRINTER", "", pszPrinter,32);
- pszPrinter[cb-2] = 0;
-
-
- /* Get the other details */
- WinQueryProfileString(habMain, "PM_SPOOLER_PRINTER", pszPrinter, "",
- szDetails, 256);
-
- // the profile string has the following format:
- // PORT;DRIVER;LOGICAL PORT;NETWORK INFO;
- // fields can have more than one entry, separated by a comma
- // the printer's name will follow the driver, separated by a period.
-
- pszBegin = szDetails;
-
- // get the printer port
- pszTemp = strchr(pszBegin, ';');
- if (pszTemp != NULL) {
- *pszTemp = '\0';
- strcpy(szPort, pszBegin);
- *pszTemp = ';';
- pszBegin = pszTemp + 1;
-
- // check for a comma in the string
- pszTemp = strchr(szPort, ',');
- if (pszTemp != NULL)
- *pszTemp = '\0';
- }
- else {
- return(FALSE);
- }
-
- // now get the driver and printer name
- pszTemp = strchr(pszBegin, ';');
- if (pszTemp != NULL) {
- *pszTemp = '\0';
- strcpy(szDriver, pszBegin);
- *pszTemp = ';';
- pszBegin = pszTemp + 1;
-
- // check for a period (printer name follows it)
- pszTemp = strchr(szDriver, '.');
- if (pszTemp != NULL) {
- strcpy(pszDeviceName, pszTemp+1);
- *pszTemp = '\0';
- }
- else {
- pszDeviceName[0] = '\0';
- }
-
- // check for a comma in the string
- pszTemp = strchr(szDriver, ',');
- if (pszTemp != NULL)
- *pszTemp = '\0';
- }
- else {
- return(FALSE);
- }
-
-
- // now get the logical port
- pszTemp = strchr(pszBegin, ';');
- if (pszTemp != NULL) {
- *pszTemp = '\0';
- strcpy(szLogPort, pszBegin);
- *pszTemp = ';';
- pszBegin = pszTemp + 1;
-
- // check for a comma in the string
- pszTemp = strchr(szLogPort, ',');
- if (pszTemp != NULL)
- *pszTemp = '\0';
- }
- else {
- return(FALSE);
- }
-
- *lpszDriver = _fmalloc(sizeof(char) * (strlen(szDriver)+1));
- strcpy(*lpszDriver, szDriver);
-
- *lpszLogicalPort = _fmalloc(sizeof(char) * (strlen(szLogPort)+1));
- strcpy(*lpszLogicalPort, szLogPort);
-
- return(TRUE);
- }
-
-
- /*
- ******************************************************************************
- ** FUNCTION: GetPrinterHPS
- ** PURPOSE : Gets the presentation space for a printer, and starts the doc
- ** PARAMS : lpdos
- ** : lphDC - the printer's hdc
- ** : pszDocName - the name of the document
- ** : lWidth - the width of the document
- ** : lHeight - the height of the document
- ** RETURN : hPS
- ** DATE : 11-Dec-1992
- ** AUTHOR : Carl Samos
- ******************************************************************************
- ** Modified: Date: Description of changes
- ** CNS : 11-Dec-1992 Initial version
- ******************************************************************************
- */
- HPS GetPrinterHPS(DEVOPENSTRUC FAR *lpdos, HDC FAR* lphDC, PSZ pszDocName,
- LONG lWidth, LONG lHeight)
- {
- LONG lReturn;
- SIZEL sizl;
- HPS hPS;
-
- if (lpdops->pszLogAddress == NULL) { // get the default settings
- char szPrinter[32]; /* The printer name */
- PSZ pszDriver; /* The driver name */
- PSZ pszLogicalPort; /* The logical port */
- char szDeviceName[32];/* The printer's name */
-
- // GetPrinterInformation allocates space for pszDriver and pszLogicalPort
- if (!GetPrinterInformation(szPrinter, &pszDriver, szDeviceName,
- &pszLogicalPort))
- return(GPI_ERROR);
-
- lpdops->pszLogAddress = pszLogicalPort;
- lpdops->pszDriverName = pszDriver;
- lpdops->pszDataType = NULL;
- lpdops->pdriv = NULL;
- }
-
- // open the printer DC
- *lphDC = DevOpenDC (habMain, OD_QUEUED, "*", 4L, lpdops, (HDC) NULL);
- if (*lphDC == DEV_ERROR) {
- return(GPI_ERROR);
- }
-
- // start the document
- lReturn = DevEscape(*lphDC, DEVESC_STARTDOC, strlen(pszDocName), pszDocName,
- NULL, NULL);
-
- // get the PS for the printer
- if (lReturn == DEV_OK) {
- sizl.cx = lWidth;
- sizl.cy = lHeight;
-
- if (lWidth == 0) {
- hPS = GpiCreatePS (habMain, *lphDC, &sizl,
- PU_LOENGLISH | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
- return(hPS);
- }
- else {
- hPS = GpiCreatePS (habMain, *lphDC, &sizl,
- PU_ARBITRARY | PU_LOENGLISH | GPIF_DEFAULT | GPIT_NORMAL |
- GPIA_ASSOC);
- return(hPS);
- }
- }
-
- return(GPI_ERROR);
- }
-
-
- /*
- ******************************************************************************
- ** FUNCTION: EndPrint
- ** PURPOSE : To close the hdc and end the document
- ** PARAMS : hpsPrinter - the printer's presentation space
- ** : hdcPrinter - the printer's device context
- ** : pszDocName - the name of the document
- ** RETURN : nothing
- ** DATE : 11-Dec-1992
- ** AUTHOR : Carl Samos
- ******************************************************************************
- ** Modified: Date: Description of changes
- ** CNS : 11-Dec-1992 Initial version
- ******************************************************************************
- */
- void EndPrint(HPS hpsPrinter, HDC hdcPrinter, PSZ pszDocName)
- {
- DevEscape(hdcPrinter, DEVESC_ENDDOC, strlen(pszDocName),
- pszDocName, NULL,NULL);
- GpiAssociate(hpsPrinter, (HDC) NULL);
- DevCloseDC(hdcPrinter);
- GpiDestroyPS(hpsPrinter);
- }
-
- Credit: Carl Samos
-
-
- ΓòÉΓòÉΓòÉ 9.1.2. Is there an easy way to get printer output (another opinion)? ΓòÉΓòÉΓòÉ
-
- A reader who desires to remain anonymous writes:
-
- Generally: My understanding was that OS/2 would handle printing for me. That
- is to say that I wouldn't have to create separate printer drivers for every
- printer under the sun (or any for that matter). Since I am creating an image
- on the screen that is device independent (well, mostly anyway), is there an
- easy way to get printer output?
-
- PM achieves a level of device independence by defining a logical output space.
- This logical output space is then bound to a physical output space, which
- creates a mapping of logical characteristics to their physical counterparts.
- The logical and physical output spaces are referred to as the presentation
- space and the device context (HPS and HDC) and are bound to one another by
- using either the GpiAssociate function or by specifying GPIA_ASSOC to the
- GpiCreatePS function.
-
- The easiest way to accomplish what you desire is to organize your drawing code
- into one or more functions with a single entrypoint that accepts an HPS as a
- parameter. Then, when you want to draw to the screen, you can call
- WinGetPS/WinBeginPaint to get an HPS and call the function. When you want
- hardcopy, you call DevOpenDC to get an HDC and GpiCreatePS to get an HPS and
- call the function.
-
- Note that to get hardcopy, you need to perform some additional setup to get
- things to work properly. The two most important things are that you initialize
- the DEVOPENSTRUC structure properly before calling DevOpenDC and that you send
- the following escape codes (via DevEscape) at the following times:
-
- hdcPrn=DevOpenDC(...);
- hpsPrn=GpiCreatePS(...);
-
- DevEscape(...,DEVESC_STARTDOC,...);
-
- if (!doDraw(hpsPrn)) {
- DevEscape(...,DEVESC_ABORTDOC,...);
- } /* endif */
-
- DevEscape(...,DEVESC_ENDDOC,...);
-
- GpiDestroyPS(hpsPrn);
- DevCloseDC(hdcPrn);
-
- I'm not sure because I can't seem to find my copy anywhere, but I belive that
- the book by Graham Winn (entitled something to the effect of "Building
- applications using the OS/2 Presentation Manager") dedicates a chapter to the
- nuances of printing.
-
- (Quoted almost directly from EDMI/2 Edition 1)
-
-
- Related Information:
-
- What are good reference books for programming in OS/2 and PM?
-
-
- ΓòÉΓòÉΓòÉ 9.1.3. How do I print a bitmap? ΓòÉΓòÉΓòÉ
-
- Here's my code for sending a bitmap to the printer I'm leaving out the part
- where I maintain an aspect ratio between the screen and the printer page.
-
- SIZEL sizl = {0,0};
- // Get DC/PS for printer
- hdcPrinter = GetPrinterDC( hab, PM_Q_STD );
- hpsPrinter = GpiCreatePS( hab, hdcPrinter, &sizl,
- PU_PELS | GPIF_DEFAULT |
- GPIT_NORMAL | GPIA_ASSOC);
-
- // Get DC/PS for memory DC compatible with printer
- hdcPrtMem = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, hdcPrinter );
- hpsPrtMem = GpiCreatePS( hab, hdcPrtMem, &sizl,
- PU_PELS | GPIF_DEFAULT |
- GPIT_MICRO | GPIA_ASSOC );
-
- // Get DC/PS for memory DC compatible with display
- hdcMemory = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE );
- hpsMemory = GpiCreatePS( hab, hdcMemory, &sizl,
- PU_PELS | GPIF_DEFAULT |
- GPIT_MICRO | GPIA_ASSOC );
-
- // Get PS for a window to be printed
- hpsToPrint = WinGetPS( hwndToPrint );
-
- // Set up memory BitBlt
- BITMAPINFOHEADER2 bmih;
- LONG alBitmapStuff[ 2 ];
- WinQueryWindowPos( hwndToPrint, &swp );
- bmih.cbFix = sizeof( BITMAPINFOHEADER2 );
- bmih.cx = swp.cx;
- bmih.cy = swp.cy;
- GpiQueryDeviceBitmapFormats( hpsToPrint, 2L, alBitmapStuff );
- bmih.cPlanes = (USHORT) alBitmapStuff[ 0 ];
- bmih.cBitCount = (USHORT) alBitmapStuff[ 1 ];
-
- // ....Set up aptl[0],[1],[2],[3] for the memory BitBlt
-
- // Do BitBlt from Display memory PS to Printer memory PS
- hbmToPrint = GpiCreateBitmap( hpsMemory, &bmih, 0, NULL, NULL );
- GpiSetBitmap( hpsMemory, hbmToPrint );
- GpiBitBlt( hpsMemory, hpsToPrint, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE );
- GpiSetBitmap( hpsMemory, NULLHANDLE );
-
- GpiSetBitmap( hpsPrtMem, hbmToPrint );
-
- // ....Set up aptl[0],[1],[2],[3] for the printer BitBlt
-
- // BitBlt to printer PS from Printer memory PS
- DevEscape( hdcPrinter, DEVESC_STARTDOC,strlen( szDocName ), szDocName,
- &lBytes, NULL );
- GpiBitBlt( hpsPrinter, hpsPrtMem, 4L, aptl, ROP_SRCCOPY,BBO_IGNORE );
- DevEscape( hdcPrinter, DEVESC_ENDDOC, 0, NULL, &lBytes, NULL );
- GpiSetBitmap( hpsPrtMem, NULLHANDLE );
- GpiDeleteBitmap( hbmToPrint );
-
- // Release all hdc's and hps's
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.1.4. How do I do my own Print Screen? ΓòÉΓòÉΓòÉ
-
- The following code segments are drawn from a much larger system that I manage
- at work. The intent is to show how to provide a graphical print screen
- capability in a PM program. We install a hook to watch for the print screen
- key and then take a bit map snapshot of the screen. This bit map is then sent
- to the printer. Forgive me if I don't go into all the details about the
- non-related data structures -- it's late and my mind is a bit foggy.
-
- Feel free to use anything here. Please add some kind of acknowledgement, if
- you use them as is, like:
-
- "Print routines (c) 1990, 1991 Applied Signal Technology, Inc."
-
- Comment, questions, ridicule should be directed to:
-
- Jeff Hitchcock
- CompuServe 71601,260
-
- or U.S. Mail to
-
- Applied Signal Technology, Inc.
- 470 Spring Park Place, Suite 700
- Herndon, VA 22070
-
- or phone to
-
- 703/478-5619
-
- /*****************************************************************************/
-
- 1. During the WM_CREATE message processing, add the following:
-
- // Set the print screen hook
-
- WinSetHook (hab, HMQ_CURRENT, HK_INPUT, (PFN) PrintScreenHook,
- (HMODULE) NULL);
-
- /*****************************************************************************/
-
- 2. Somewhere, have this function:
-
- BOOL CALLBACK PrintScreenHook (HAB hab, PQMSG pQmsg, USHORT fs)
- {
- if ( pQmsg->msg == WM_CHAR )
- if ( ( SHORT1FROMMP(pQmsg->mp1) & KC_KEYUP) &&
- ( SHORT1FROMMP(pQmsg->mp1) & KC_VIRTUALKEY ) &&
- ( SHORT2FROMMP(pQmsg->mp2) == VK_PRINTSCRN) )
- PrintScreen (hab);
- return FALSE;
- }
-
- /*****************************************************************************/
-
- 3. Here's the "driver:"
-
- VOID EXPENTRY PrintScreen (HAB hab)
- {
- HBITMAP hbm;
-
- hbm = ScreenToBitmap (hab);
- PrintBitMap(hbm);
- }
-
- /*****************************************************************************/
-
- 4. Here's a general print-related structure we use. We often have many print
- threads running concurrently, but we only allow one to "run" at a time. We use
- a semaphore to show availability of the printer (so to speak), and only one
- thread at a time gets it. If we didn't do this, and more than a few print
- threads are running (especially graphical prints), even a 486/33 with 16 MB of
- RAM begins to C-R-A-W-L. So, for what it's worth, these are the structures
- that we use:
-
- /**************************************************************
- * *
- * PRINTTHREADPARAMS structure *
- * *
- * Parameters that are used to manage separate print threads *
- * *
- * Item Contents/Use *
- * -------------- ---------------------------------------- *
- * *
- * sJobNumber Print job number, used for cancelling *
- * aiThreadStack Thread's stack *
- * hwndNotify Window to which notif. msgs are sent *
- * tidPrint System task id *
- * hssmPrinter... Semaphore for printer available *
- * fSemSet TRUE if semaphore was made and cleared *
- * szSummary Print summary (e.g., fax printout) *
- * fStart Can't start until TRUE (default FALSE) *
- * fContinue Quit if FALSE (default is TRUE) *
- * fHold Hold if TRUE (default is FALSE) *
- * sStartingPage For multipage, start here *
- * sEndingPage For multipage, end here *
- * usParam Module-dependent USHORT *
- * ulParam Module-dependent ULONG *
- * pPrintData PVOID to the print data *
- * *
- * PAGESETUP structure *
- * *
- * Parameters used to describe the appearance *
- * *
- * Item Contents/Use *
- * -------------- ---------------------------------------- *
- * *
- * szFont The name of the font to use *
- * sLinesPerPage Used to scale font *
- * sCharsPerLine Used to scale font *
- * sLeft Used to position on page, in chars *
- * sRight Used to position on page, in char *
- * sTop Used to position on page, in lines *
- * sBottom Used to position on page, in lines *
- * szHeader Text to place on top of each page *
- * fIncludeSummary If TRUE, include SRI summary on page 1 *
- * fHeaderEveryPage TRUE for every page, false for pg 1 *
- * fHeaderUnderline TRUE for underline *
- * szFooter Text to place at bottom of each page *
- * fFooterEveryPage TRUE for every page, false for pg 1 *
- * fOverlineFooter TRUE for overline *
- * *
- * HEADER AND FOOTER OPTIONS: *
- * *
- * Special Flags that should be supported in each module: *
- * *
- * &l Left justify *
- * &c Center *
- * &r Right justify *
- * &d Date *
- * &t Time *
- * &p Page number *
- * *
- **************************************************************/
-
- typedef struct
- {
- CHAR szFont[FACESIZE] ;
- SHORT sLinesPerPage ;
- SHORT sCharsPerLine ;
- SHORT sLeft ;
- SHORT sRight ;
- SHORT sTop ;
- SHORT sBottom ;
- BOOL fIncludeSummary ;
- CHAR szHeader[HEADERFOOTERLENGTH] ;
- BOOL fHeaderEveryPage ;
- BOOL fUnderlineHeader ;
- CHAR szFooter[HEADERFOOTERLENGTH] ;
- BOOL fFooterEveryPage ;
- BOOL fOverlineFooter ;
- }
- PAGESETUP ;
-
- typedef PAGESETUP FAR *PPAGESETUP ;
-
- typedef struct
- {
- SHORT sJobNumber ;
- int aiThreadStack[STACKSIZE / sizeof (int)] ;
- HWND hwndNotify ;
- HSYSSEM hssmPrinterAvailable ;
- BOOL fSemSet ;
- CHAR szSummary[HEADERFOOTERLENGTH] ;
- BOOL fStart ;
- BOOL fRunning ;
- BOOL fContinue ;
- BOOL fHold ;
- SHORT sStartingPage ;
- SHORT sEndingPage ;
- PAGESETUP page ;
- USHORT usParam ;
- ULONG ulParam ;
- VOID huge *pPrintData ;
- }
- PRINTTHREADPARAMS ;
-
- typedef PRINTTHREADPARAMS FAR *PPRINTTHREADPARAMS ;
-
- /*****************************************************************************/
-
- 5. This function saves the screen display to a bitmap.
-
- HBITMAP ScreenToBitmap (HAB hab)
-
- {
- BITMAPINFOHEADER bmp ;
- HBITMAP hbm ;
- HDC hdcMemory ;
- HPS hpsScreen, hpsMemory ;
- LONG alBitmapFormats [2] ;
- POINTL aptl[3] ;
- SIZEL sizl ;
- SHORT cxScreen;
- SHORT cyScreen;
- BOOL fMonochrome = FALSE;
- // Create memory DC and PS
-
- cxScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
- cyScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
-
- hdcMemory = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ;
-
- sizl.cx = sizl.cy = 0 ;
- hpsMemory = GpiCreatePS (hab, hdcMemory, &sizl,
- PU_PELS | GPIF_DEFAULT |
- GPIT_MICRO | GPIA_ASSOC) ;
-
- // Create bitmap for destination
-
- bmp.cbFix = sizeof bmp ;
-
- if (fMonochrome)
- {
- bmp.cPlanes = 1 ;
- bmp.cBitCount = 1 ;
- }
- else
- {
- GpiQueryDeviceBitmapFormats (hpsMemory, 2L, alBitmapFormats) ;
-
- bmp.cPlanes = (USHORT) alBitmapFormats[0] ;
- bmp.cBitCount = (USHORT) alBitmapFormats[1] ;
- }
-
- bmp.cx = cxScreen ;
- bmp.cy = cyScreen ;
-
- hbm = GpiCreateBitmap (hpsMemory, &bmp, 0L, NULL, NULL) ;
-
- // Copy from screen to bitmap
-
- if (hbm != NULL)
- {
- GpiSetBitmap (hpsMemory, hbm) ;
- hpsScreen = WinGetScreenPS (HWND_DESKTOP) ;
-
- aptl[0].x = 0 ;
- aptl[0].y = 0 ;
- aptl[1].x = cxScreen ;
- aptl[1].y = cyScreen ;
- aptl[2].x = 0 ;
- aptl[2].y = 0 ;
-
- WinLockVisRegions (HWND_DESKTOP, TRUE) ;
-
- GpiBitBlt (hpsMemory, hpsScreen, 3L, aptl,
- fMonochrome ? ROP_NOTSRCCOPY : ROP_SRCCOPY, BBO_IGNORE) ;
-
- WinLockVisRegions (HWND_DESKTOP, FALSE) ;
-
- WinReleasePS (hpsScreen) ;
- GpiDestroyPS (hpsMemory) ;
- DevCloseDC (hdcMemory) ;
- }
-
- return hbm ;
- }
-
- /*****************************************************************************
-
- 6. The "core" function:
-
- This function prints a bitmap to the printer. The bitmap is scaled according
- to the size of the printer. No distortion is allowed of the bitmap image.
-
- Returns False : if an error occurrs
- Returns True : no Error occurred
-
- Known bug(s):
-
- Areas on the screen that have a black forground and a gray background are
- completely black when printed. For example, when a window does not have the
- focus it's title bar becomes black lettering on a gray background. When this
- window is printed the entire title bar is black and no title can be read. This
- is using the Hewlett Packard LaserJet Series II printer.
-
- According to microsoft online help this is a know bug with the printer device
- driver. To fix the bug you must go to the control panel and change the colors
- of the inactive window.
-
- ************************************************************************/
-
- SHORT sBitmapToPrinter(PPRINTTHREADPARAMS pptp,
- HPS hpsPrinter,
- HDC hdcPrinter,
- HAB habPrinter,
- SIZEL *psizlPage,
- SIZEL *psizlChar)
- {
-
- HDC hdcPrinterMemory;
- HPS hpsPrinterMemory;
- POINTL ptl;
- SHORT sPage = 1;
- RECTL rcl; // Coordinates of region
-
- long lCapsHRes;
- long lCapsVRes;
- float fYAspectRatio;
- float fXAspectRatio;
- SIZEL sizl;
-
- HBITMAP hbm;
- POINTL aptl [4] ;
- SHORT cxScreen;
- SHORT cyScreen;
- float fltScale;
-
- // Skip down top margin, ...
-
- ptl.x = pptp->page.sLeft * psizlChar->cx ;
- ptl.y = psizlPage->cy - (pptp->page.sTop * psizlChar->cy) ;
-
- // Print header, if requested
-
- if (pptp->page.szHeader[0] != '\0')
- {
- PrintHeaderFooter (hpsPrinter, &ptl, pptp,
- psizlPage, psizlChar,
- pptp->page.szHeader,
- sPage, PRINT_HEADER) ;
- }
-
- hbm = pptp->pPrintData;
-
- // Find the aspect ratio of the printer
-
- DevQueryCaps(hdcPrinter,CAPS_HORIZONTAL_RESOLUTION,1L,&lCapsHRes);
- DevQueryCaps(hdcPrinter,CAPS_VERTICAL_RESOLUTION,1L,&lCapsVRes);
-
- if ( (lCapsVRes == 0) || (lCapsHRes == 0) ) {
- fXAspectRatio = (float) 1;
- fYAspectRatio = (float) 1;
- }
- else {
- fXAspectRatio = (float) ((float) lCapsVRes / (float) lCapsHRes);
- fYAspectRatio = (float) ((float) lCapsHRes / (float) lCapsVRes);
- }
-
- // determine coordinates to print on printer
-
- rcl.xLeft = pptp->page.sLeft * psizlChar->cx; // Printer left
-
- rcl.xRight = psizlPage->cx -
- (pptp->page.sRight * psizlChar->cx); // Printer right
-
- rcl.yBottom = (pptp->page.sBottom + 1) * psizlChar->cy; // Printer bottom
-
- rcl.yTop = psizlPage->cy -
- ( (pptp->page.sTop + 1) * psizlChar->cy); // Printer top
-
-
- cxScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN);
- cyScreen = (SHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN);
-
- ScaleToWindowSize ((SHORT) (rcl.xRight - rcl.xLeft), // sXtarget
- (SHORT) (rcl.yTop - rcl.yBottom), // sYTarget
- cxScreen, // sXSource
- cyScreen, // sYSource
- &fltScale) ;
-
-
- // Create a memory device context
- // Memory device contexts are used to contain bitmaps
-
- hdcPrinterMemory = DevOpenDC (habPrinter, OD_MEMORY, "*", 0L,
- NULL, hdcPrinter);
-
- if ( hdcPrinterMemory == DEV_ERROR )
- return FALSE;
-
- sizl.cx = 0;
- sizl.cy = 0;
-
- // Create a presentation space and associate it the memory device context
-
- hpsPrinterMemory = GpiCreatePS (habPrinter, hdcPrinterMemory, &sizl,
- PU_PELS | GPIF_DEFAULT |
- GPIT_NORMAL | GPIA_ASSOC);
-
- if( ! hpsPrinterMemory) {
- DevCloseDC (hdcPrinterMemory);
- return FALSE;
- }
-
-
- GpiSetBitmap(hpsPrinterMemory,hbm);
-
-
- aptl [0].x = rcl.xRight - (long) ((float) cxScreen * fltScale);
- aptl [0].y = rcl.yTop - (long) ((float) cyScreen * fltScale *
- fYAspectRatio);
- aptl [1].x = rcl.xRight;
- aptl [1].y = rcl.yTop;
- aptl [2].x = 0;
- aptl [2].y = 0;
- aptl [3].x = cxScreen;
- aptl [3].y = cyScreen;
-
- GpiBitBlt(hpsPrinter,hpsPrinterMemory,4L,aptl,ROP_SRCCOPY,BBO_IGNORE);
-
- GpiAssociate (hpsPrinterMemory, NULL) ;
- GpiDestroyPS (hpsPrinterMemory);
- DevCloseDC (hdcPrinterMemory);
-
- // If a footer is defined, ...
-
- if (pptp->page.szFooter[0] != '\0')
- {
- // ... compute its position ...
-
- ptl.x = pptp->page.sLeft * psizlChar->cx ;
- ptl.y = pptp->page.sBottom * psizlChar->cy ;
-
- // ... and print it.
-
- PrintHeaderFooter (hpsPrinter, &ptl, pptp,
- psizlPage, psizlChar,
- pptp->page.szFooter,
- sPage, PRINT_FOOTER) ;
- }
- return( TRUE);
- }
-
-
- ΓòÉΓòÉΓòÉ 9.2. Menus ΓòÉΓòÉΓòÉ
-
- This section covers Presentation Manager menus.
-
-
- ΓòÉΓòÉΓòÉ 9.2.1. How do I add a menu to a dialog box? ΓòÉΓòÉΓòÉ
-
- Do a WinLoadMenu and then WM_UPDATEFRAME.
-
-
- ΓòÉΓòÉΓòÉ 9.2.2. How do I make a dynamically changing menu? ΓòÉΓòÉΓòÉ
-
- Create the menu with all the items that it will ever contain, then dynamically
- remove and insert the items as required. After loading menu, Query and maintain
- a copy of the menuitem(s) that will be removed.
-
- // Obtain and keep a copy of the convert submenuitem
- if (!WinSendMsg (pwd->hwndAB, MM_QUERYITEM,
- MPFROM2SHORT (IDM_KanCnvMnu, TRUE), MPFROMP (&pwd->miCnvMnu))) {
-
- // And the convert submenu text
- if (!WinSendMsg (pwd->hwndAB, MM_QUERYITEMTEXT,
- MPFROM2SHORT (IDM_KanCnvMnu, sizeof (pwd->szCnvMnuTxt)),
- MPFROMP (&pwd->szCnvMnuTxt)) ){
-
- When menu is to updated, insert/remove as necessary
-
- // This is layout, is the submenu already in place?
- if (!pwd->fCnvMenu) {
-
- // The submenu is not installed, so insert the submenu
- WinSendMsg (pwd->hwndAction, MM_INSERTITEM,
- MPFROMP (&pwd->miCnvMnu), MPFROMP (pwd->szCnvMnuTxt));
-
- // And remove the convert menuitem
- WinSendMsg (pwd->hwndAB, MM_REMOVEITEM,
- MPFROM2SHORT (IDM_KanCnv, TRUE), 0L);
-
- // Set the submenu flag
- pwd->fCnvMenu = TRUE;
- }
-
- Credit: Matthew S. Osborn
-
-
- ΓòÉΓòÉΓòÉ 9.2.3. How do I create a conditional cascade menu? ΓòÉΓòÉΓòÉ
-
- The following works for me to set a submenu as a conditional-cascade menu, then
- set it's default id (hwndMenu is the hwnd of the top-level menu):
-
- MENUITEM mi;
-
- WinSendMsg( hwndMenu, MM_QUERYITEM,
- MPFROM2SHORT( idSubMenu, TRUE ), &mi );
-
- // Set the MS_CONDITIONALCASCADE bit for the submenu.
-
- WinSetWindowBits( mi.hwndSubMenu, QWL_STYLE, MS_CONDITIONALCASCADE,
- MS_CONDITIONALCASCADE );
-
- // Set cascade menu default
-
- WinSendMsg( mi.hwndSubMenu, MM_SETDEFAULTITEMID,
- MPFROMSHORT( idDefaultItem ), NULL );
-
- Then I do this to query the default item:
-
- MENUITEM mi;
-
- WinSendMsg( hwndMenu, MM_QUERYITEM, MPFROM2SHORT( idSubMenu, TRUE ),
- &mi );
-
- id = (USHORT) WinSendMsg( mi.hwndSubMenu,
- MM_QUERYDEFAULTITEMID, NULL, NULL );
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.2.4. How do I remove a separator from a menu? ΓòÉΓòÉΓòÉ
-
- Here are two methods of doing that. The first is from the PMHINTS file, and
- the second is from Gpf. PMHINTS takes the approach of removing SC_CLOSE and
- the nearby separator. The Gpf solution takes the approach of deleting
- everything that it doesn't explicitly want. I've extended it to, among other
- things, conditionally delete the "Window List" menu item as well.
-
- The deletion problems get messier in application menus when there are multiple
- separaters in different pull-downs. That is when assigning the separators an
- id really pays off.
-
- Both examples are 16-bit OS/2 1.x code.
-
- PMHINTS:
-
- VOID DelClose(HWND hwnd)
- {
- HWND hSysMenu,
- hSysSubMenu;
- MENUITEM SysMenu;
- SHORT idItem,
- idSep,
- idSysMenu;
-
- hSysMenu = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT, FALSE),
- FID_SYSMENU);
-
- idSysMenu = SHORT1FROMMR(WinSendMsg(hSysMenu, MM_ITEMIDFROMPOSITION,
- NULL, NULL));
-
- WinSendMsg(hSysMenu, MM_QUERYITEM, MPFROM2SHORT(idSysMenu, FALSE),
- MPFROMP(&SysMenu));
-
- hSysSubMenu = SysMenu.hwndSubMenu;
-
- idItem = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMPOSITIONFROMID,
- MPFROM2SHORT(SC_CLOSE, FALSE), NULL));
- if (idItem != MIT_ERROR)
- {
- idSep = idItem + 1; // Get separator ID
-
- idSep = SHORT1FROMMR(WinSendMsg(hSysSubMenu, MM_ITEMIDFROMPOSITION,
- MPFROMSHORT(idSep), NULL));
-
- WinSendMsg(hSysMenu, MM_DELETEITEM, MPFROM2SHORT(SC_CLOSE, TRUE),
- MPFROMSHORT(NULL));
-
- WinSendMsg(hSysSubMenu, MM_DELETEITEM, MPFROM2SHORT(idSep, FALSE), NULL);
- }
- }
-
- Derived from Gpf, adapted for a client, with some of my changes expurgated (so
- it won't compile as is):
-
- /*****
- *
- * UtilDlgSysMenu
- *
- * Remove unavailable items from system menu of dialog box.
- *
- * History:
- * 8/31/92 gts Adapted from Gpf's GpfSetDialogBoxSysMenu
- * with slight modifications.
- *
- *****/
-
- void _export UtilDlgSysMenu ( /* Remove unwanted system menu items */
- HWND hwndFrame) /* I - Handle to dialog window */
- {
- HWND hwndSubMenu; /* sys menu pull-down handle */
- MENUITEM miTemp; /* menu item template */
- SHORT sItemId; /* system menu item ID */
- SHORT sItemIndex; /* system menu item index */
- MRESULT mresult;
-
- /********************************************************************/
- /* Get the handle of the system menu pull-down. */
- /********************************************************************/
- hwndSubMenu = WinWindowFromID( hwndFrame, FID_SYSMENU );
- WinSendMsg( hwndSubMenu,
- MM_QUERYITEM,
- MPFROM2SHORT( SC_SYSMENU, FALSE ),
- MPFROMP( (PSZ)&miTemp ) );
- hwndSubMenu = miTemp.hwndSubMenu;
-
- /********************************************************************/
- /* Remove all items from the system menu pull-down that are no */
- /* longer wanted. */
- /********************************************************************/
- mresult = WinSendMsg( hwndSubMenu,
- MM_QUERYITEMCOUNT,
- MPFROMSHORT(0),
- MPFROMSHORT(0) );
- sItemIndex = SHORT1FROMMR(mresult);
- for (sItemId = 0; sItemIndex != -1; sItemIndex--)
- {
- mresult = WinSendMsg( hwndSubMenu,
- MM_ITEMIDFROMPOSITION,
- MPFROMSHORT(sItemIndex),
- MPFROMSHORT(0) );
- sItemId = SHORT1FROMMR(mresult);
- if ( sItemId != MIT_ERROR
- && sItemId != SC_MOVE
- && sItemId != SC_CLOSE
- && (sItemId != SC_TASKMANAGER
- || (flFlags & MAXONLY)) ) // <- application controls
- {
- WinSendMsg( hwndSubMenu,
- MM_DELETEITEM,
- MPFROM2SHORT(sItemId,FALSE),
- MPFROMSHORT(0) );
- }
- }
- }
-
- Credit: Guy Scharf
-
-
- ΓòÉΓòÉΓòÉ 9.3. Container Controls ΓòÉΓòÉΓòÉ
-
- This section covers Presentation Manager container controls.
-
-
- ΓòÉΓòÉΓòÉ 9.3.1. How do I stop a container from flashing every time I add a record? ΓòÉΓòÉΓòÉ
-
- Disable/Enable the container window before and after the insertion/deletion.
-
-
- ΓòÉΓòÉΓòÉ 9.3.2. How do I get my containers to use Mini-icons? ΓòÉΓòÉΓòÉ
-
- Here is some sample code that displays mini icons. First, supply a missing
- #define:
-
- #ifndef CCS_MINIICONS
- #define CCS_MINIICONS 0x0800
- #endif // not CCS_MINIICONS
-
- Use CCS_MINIICONS as part of your container style (when you create the
- container). Now, fill in the RECORDCORE structure pointed to by 'pRecordCore';
- 'pUserRecord' also points to 'pRecordCore', which is part of a "user data"
- structure:
-
- // Fill in fields of container record.
- #ifdef USE_MINIRECORDCORE
- pRecordCore->cb = sizeof (MINIRECORDCORE) ;
- #else
- pRecordCore->cb = sizeof (RECORDCORE) ;
- #endif // USE_MINIRECORDCORE
- pRecordCore->flRecordAttr = 0 ; // CRA_DROPONABLE ;
- // pRecordCore->ptlIcon is left to zeros.
- pRecordCore->pszIcon = pUserRecord->szName ;
- if (*DDirRecord.szIconName)
- LoadIcon (pUserRecord) ;
- // pRecordCore->hptrMiniIcon is left to zeros.
- // pRecordCore->hbmBitmap is left to zeros.
- // pRecordCore->hbmMiniBitmap is left to zeros.
- // pRecordCore->pTreeItemDesc is left to zeros.
-
- #ifndef USE_MINIRECORDCORE
- pRecordCore->pszText = pUserRecord->szName ;
- pRecordCore->pszName = pUserRecord->szName ;
- pRecordCore->pszTree = pUserRecord->szName ;
- #endif // not USE_MINIRECORDCORE
-
- Now, if your user asks for mini-icons (via a popup menu, presumably), you send
- a CM_SETCNRINFO message to your container, after ORing in the CV_MINI style to
- CnrInfo.flWindowAttr, or removing it to restore full-size icons. Hope this
- helps.
-
- Credit: Wayne Kovsky
-
-
- ΓòÉΓòÉΓòÉ 9.3.3. How do I sort a container control? ΓòÉΓòÉΓòÉ
-
- /*
- * Note that PSESSION is my own instance data structure.
- * I use it here to retrieve the type of field comparison I should do.
- */
-
- static SHORT APIENTRY Compare (PMINIRECORDCORE pmrc1,
- PMINIRECORDCORE pmrc2,
- PVOID pvStorage)
- {
- PSESSION pSession = (PSESSION) pvStorage ;
- PFIELDINFO pFieldInfo = pSession->pFieldInfoSort ;
- PPVOID pField1 = (PPVOID) ((PBYTE) pmrc1 +
- pFieldInfo->offStruct) ;
- PPVOID pField2 = (PPVOID) ((PBYTE) pmrc2 +
- pFieldInfo->offStruct) ;
- SHORT sResult = 0 ;
-
- if (pFieldInfo->flData & CFA_STRING) {
- sResult = strcmp ((PCHAR) *pField1, (PCHAR) *pField2) ;
- }
- else if (pFieldInfo->flData & CFA_ULONG) {
- if ((ULONG) *pField1 < (ULONG) *pField2)
- sResult = -1 ;
- else if ((ULONG) *pField1 > (ULONG) *pField2)
- sResult = 1 ;
- else
- sResult = 0 ;
- }
- else if (pFieldInfo->flData & CFA_DATE) {
- sResult = CompareDate ((PCDATE) (PVOID) pField1,
- (PCDATE) (PVOID) pField2) ;
- }
- else if (pFieldInfo->flData & CFA_TIME) {
- sResult = CompareTime ((PCTIME) (PVOID) pField1,
- (PCTIME) (PVOID) pField2) ;
- }
-
- // Any other data type gets treated as equal;
- // no sorting can be done. Now handle reverse sequence.
- if (pSession->fSortReverse && sResult)
- sResult = -sResult ;
- return sResult ;
- }
-
- Here is how I invoke the sort:
-
- // Send container a sort message.
- ulRC = LONGFROMMR (WinSendMsg (
- pSession->hwndContainer,
- CM_SORTRECORD,
- MPFROMP (Compare), MPFROMP (pSession))) ;
- if (!ulRC) {
- // Report error.
- }
-
- Credit: Wayne Kovsky
-
-
- ΓòÉΓòÉΓòÉ 9.3.4. How do I query all records in a container - tree view? ΓòÉΓòÉΓòÉ
-
- The following code works for querying all records in a tree structure but
-
- USHORT usParentCmd = CMA_FIRST, usChildCmd;
- PUSERREC purParent = NULL, purChild;
-
- for( ; ; )
- {
- purParent = (PUSERREC) WinSendMsg( hwndCnr, CM_QUERYRECORD,
- MPFROMP( purParent ),
- MPFROM2SHORT( usParentCmd, CMA_ITEMORDER ) );
- if( !purParent )
- break;
-
- DoWhatever( purParent );
-
- usChildCmd = CMA_FIRSTCHILD;
- purChild = NULL;
- for( ; ; )
- {
- purChild = (PUSERREC) WinSendMsg( hwndCnr, CM_QUERYRECORD,
- MPFROMP( purChild ),
- MPFROM2SHORT( usChildCmd, CMA_ITEMORDER ));
- if( !purChild )
- break;
-
- DoWhatever( purChild );
- usChildCmd = CMA_NEXT;
- }
-
- usCmdParent = CMA_NEXT;
- }
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.4. I can't get different colors in text control windows ΓòÉΓòÉΓòÉ
-
- I've finally got static text control windows (WS_STATIC, SS_TEXT) working with
- a different color pres. parameter set ! Thanks, Rick, Dan and Wayne. Code as
- follows:
-
- RGB2 rgb2 ; // RGB2 structure
- HWND hwnd ; // window handle
-
- // Set RGB values for a SYSCLR_BACKGROUND (light gray) color
- rgb2.bred = 204 ; // Found these in 'WinSetSysColors' API
- rgb2.bgreen = 204 ;
- rgb2.bblue = 204 ;
- rgb2.fcOptions = 0 ;
- // Set background color
- WinSetPresParam (hwnd, PP_BACKGROUNDCOLOR, (ULONG) sizeof (RGB2),
- &rgb2) ;
- // Set RGB values for black
- rgb2.bred = 0 ;
- rgb2.bgreen = 0 ;
- rgb2.bblue = 0 ;
- rgb2.fcOptions = 0 ;
- // Set text foreground color
- WinSetPresParam (hwnd, PP_FOREGROUNDCOLOR, (ULONG) sizeof (RGB2),
- &rgb2) ;
- // Set text border color (important for outline fonts)
- WinSetPresParam (hwnd, PP_BORDERCOLOR, (ULONG) sizeof (RGB2), &rgb2) ;
-
- Three big caveats here:
-
- 1. The OS/2 internal code for static text control windows is *definitely*
- using RGB colors, not index colors when it draws the text string. Thus, the
- PP_*INDEX presentation parameter values will *not* work.
- 2. You *must* use a set of colors that are already loaded in the color table.
- If the RGB color is not found, the background will be dithered affecting
- the text appearance (washed out). If you are not sure the RGB color is
- loaded do a GpiQueryNearestColor to get the nearest color.
- 3. You *must* use the RGB2 structure and *not* the RGB structure. This is
- *NOT* documented, but it appears in general that all OS/2 2.0 APIs should
- use RGB2 *instead* of RGB.
-
- Credit: Bill Kenning
-
-
- ΓòÉΓòÉΓòÉ 9.5. How can I toggle my titlebar on and off? ΓòÉΓòÉΓòÉ
-
- Basically, move frame window controls from being children of the frame to being
- children of the background HWND_OBJECT. You can then reverse the process to
- bring them back into view. Following function implements this code.
-
- /* --------------------------------------------------------------
- -- Function: ToggleFrame
- --
- -- Description: Toggles frame control visible/invisible
- --
- -- Notes: Code stolen from someone who stole it from an MS sample
- ----------------------------------------------------------------- */
- void ToggleFrame(HWND hwndFrame) {
-
- if (! Hidden) { /* hide contorls */
- hwndTitle = WinWindowFromID( hwndFrame, FID_TITLEBAR );
- hwndSys = WinWindowFromID( hwndFrame, FID_SYSMENU );
- ... repeat for FID_MINMAX, etc ...
- WinSetParent(hwndTitle, HWND_OBJECT, FALSE );
- WinSetParent(hwndSys, HWND_OBJECT, FALSE );
- ... repeat for FID_MINMAX, etc ...
- } else { /* restore controls */
- WinSetParent( hwndTitle, hwndFrame, FALSE );
- WinSetParent( hwndSys, hwndFrame, FALSE );
- ... basically reverse of above ...
- }
- WinSendMsg( hwndFrame, WM_UPDATEFRAME,
- (MPARAM)(FCF_TITLEBAR | FCF_SYSMENU | ...), NULL);
- SizeTheWindow( hwndFrame );
- Hidden = ! Hidden;
- return;
- }
-
- Credit: Mike Thompson
-
-
- ΓòÉΓòÉΓòÉ 9.6. How can I get transparent regions in bitmaps? ΓòÉΓòÉΓòÉ
-
- Currently, you can get the same effect with PM if you use the method used with
- icons:
-
- 1. Use a monochrome mask to prep the destination area. The mask would define
- which areas would be transparent and which would show the bitmap. The bits
- would be defined as 1=transparent,0=bitmap. You would blit the mask to the
- destination using ROP_SRCAND. This would blacken out the area that would
- display the non-transparent bits of the bitmap.
- 2. Now blit the bitmap to the destination using ROP_SRCPAINT. Note that the
- "transparent" areas of the bitmap must have the color black (i.e. bits=0).
- This ORs the bitmap onto the prep area. Viola - "transparent" bitmap.
-
- Credit: John Webb
-
-
- ΓòÉΓòÉΓòÉ 9.7. How do I create a status bar at the bottom of my window? ΓòÉΓòÉΓòÉ
-
- You need to intercept several frame messages:
-
- WM_CALCFRAMERECT to calculate the new location of the client. You should send
- it to the frame superclass then modify the result. This message is invoked
- during frame formatting and whenever WinCalcFrameRect is called against your
- frame window handle.
-
- WM_FRAMECTLCOUNT to tell the frame superclass the number of frame controls you
- expect to format. If you're adding a status line as a child of the frame
- (below the client, I suspect), you would add 1 to the result returned by your
- frame superclass.
-
- WM_FORMATFRAME is where you actually position/size the frame controls. The
- message gives you an array of SWP's. Call your frame superclass and modify the
- result (in your case, I would expect only FID_CLIENT and your status line).
-
- Sample follows...
-
- /*
- * FYI, WinDefFrameProc is just a macro I defined to
- * call my superclass frame window procedure, ie,
- * (*vpfnFrameWndProc) (h,m,p1,p2).
- *
- * This example splits the client area space 1/3
- * and 2/3 horizontally with the old client area
- * and a new sibling.
- */
-
- case WM_CALCFRAMERECT:
- mr = WinDefFrameProc(hwnd, msg, mp1, mp2);
-
- /*
- * Calculate the position of the client rectangle
- * Otherwise, we'll see a lot of redraw when we move the
- * client during WM_FORMATFRAME.
- */
-
- if (mr && mp2)
- {
- prectl = (PRECTL) mp1;
- prectl->xLeft += ((prectl->xRight - prectl->xLeft) / 3);
- }
- break;
-
- case WM_FORMATFRAME:
- sCount = (SHORT) WinDefFrameProc(hwnd, msg, mp1, mp2);
-
- /*
- * Reformat the frame to move the client
- * over and make room for the his/her sibling.
- */
-
- pswp = (PSWP) mp1;
- pswpClient = pswp + sCount - 1;
- pswpNew = pswpClient + 1;
-
- *pswpNew = *pswpClient;
- swpClient = *pswpClient;
-
- pswpNew->hwnd = WinWindowFromID(hwnd, ID_SIBLING);
- pswpNew->cx = pswpClient->cx / 3;
-
- pswpClient->x = pswpNew->x + pswpNew->cx - 1;
- pswpClient->cx = swpClient.cx - pswpNew->cx + 1;
-
- sCount++;
- mr = MRFROMSHORT(sCount);
- break;
-
- case WM_QUERYFRAMECTLCOUNT:
- sCount = (SHORT) WinDefFrameProc(hwnd, msg, mp1, mp2);
- sCount++;
- mr = MRFROMSHORT(sCount);
- break;
-
- Credit: Dan Kehn
-
-
- ΓòÉΓòÉΓòÉ 9.8. How to have a frame/client and still have a std window? ΓòÉΓòÉΓòÉ
-
- FRAMECDATA fcdata;
-
- fcdata.cb = sizeof( FRAMECDATA );
- fcdata.flCreateFlags = FCF_TASKLIST | FCF_MENU, etc.;
- fcdata.hmodResources = 0; // or the hmod of the DLL containing the resources
- fcdata.idResources = ID_RESOURCES; // ID of the resources, as usual
-
- hwndFrame = WinCreateWindow( HWND_DESKTOP, WC_FRAME, NULL, 0, 0, 0, 0, 0,
- NULLHANDLE, HWND_TOP, ID_RESOURCES,
- &fcdata, NULL);
-
- hwndClient = WinCreateWindow( hwndFrame, szClientClass, NULL, 0, 0, 0, 0, 0,
- NULLHANDLE, HWND_TOP, FID_CLIENT, NULL, NULL );
-
- WinSetWindowPos( hwndFrame, HWND_TOP, x, y, cx, cy,
- SWP_ZORDER | SWP_SIZE | SWP_MOVE |
- SWP_SHOW | SWP_ACTIVATE );
-
- If you want to then add new controls, like the system menu, you would do this:
-
- fcdata.flCreateFlags = FCF_SYSMENU;
- WinCreateFrameControls( hwndFrame, &fcdata, NULL );
- WinSendMsg( hwndFrame, WM_UPDATEFRAME,
- MPFROMLONG( FCF_SYSMENU ), NULL );
-
- The same thing applies to all the other controls like FCF_SIZEBORDER,
- FCF_TITLEBAR, FCF_HORZSCROLL, FCF_MINMAX, etc. You could also OR more than one
- together if you wanted to add more than one frame control in the same shot. On
- the titlebar, you need to also send this message:
-
- WinSendMsg( WinWindowFromID( hwndFrame, FID_TITLEBAR ),
- TBM_SETHILITE, MPFROMSHORT( TRUE ), NULL );
-
- If you want to delete frame controls, you would do this (assuming system menu):
-
- WinDestroyWindow( WinWindowFromID( hwndFrame, FID_SYSMENU ) );
- WinSendMsg( hwndFrame, WM_UPDATEFRAME,
- MPFROMLONG( FCF_SYSMENU ), NULL );
-
- Unfortunately this doesn't fit completely well with OOP, since the controls
- really are not themselves objects independent of the frame window. One of the
- problems here is that in order to make them independent objects, you need to
- know the internals of the frame window proc. For instance, you would think that
- the MIN and MAX are two WC_BUTTON controls, but they are really one menu with
- two bitmap menuitems (at least in 1.x they were). So if you were to do a
- WinCreateWindow for either, you'd have to know where to get the bitmaps, and
- hope that doesn't change.
-
- Similarly you'd have to be able to construct the system menu after creating a
- WC_MENU window. This isn't a tough feat, but if a later version of OS/2 adds a
- new menu item to the system menu, you'd have to become aware of it.
-
- The titlebar and the scrollbars aren't a problem since they have their own
- public window classes - WC_TITLEBAR and WC_SCROLLBAR respectively. You can, for
- instance, do a WinCreateWindow( ..., WC_SCROLLBAR,..., FID_HORZSCROLL, ..),
- then send the frame a WM_UPDATEFRAME message for FCF_HORZSCROLL and this would
- work. But there is no WC_SIZEBORDER so you couldn't use this method to add the
- sizing border later. So for the sizing border you need to use the method I
- first posted above.
-
- I spoke too soon about the sizing border. If you want to add or remove it from
- a frame window, you need to add or remove the FS_SIZEBORDER style from the
- frame, then send the frame an UPDATEFRAME message for FCF_SIZEBORDER.
-
- To change the style, here is a technique that John Webb just turned me on to.
- To add the style:
-
- WinSetWindowBits( hwndFrame, QWL_STYLE, FS_SIZEBORDER, FS_SIZEBORDER );
-
- To remove it:
-
- WinSetWindowBits( hwndFrame QWL_STYLE, 0, FS_SIZEBORDER );
-
- Also, if you want to add or remove just one of the MIN or the MAX, you
- basically need to get the window handle of the MINMAX menu, then do a
- MM_REMOVEITEM for the one you want to remove. I did this in 1.x but haven't yet
- in 2.0.
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.9. How do I use printf() in a PM program? ΓòÉΓòÉΓòÉ
-
- Use PMPRINTF, check your local BBS's, CIS, BIX or cdrom.com or redirect stdout
- and stderr to files.
-
- // Redirect 'stderr'.
- (void) freopen ("stderr.txt", "w", stderr) ;
-
- // Redirect 'stdout'.
- (void) freopen ("stdout.txt", "w", stdout) ;
-
-
- ΓòÉΓòÉΓòÉ 9.10. I have a SOM DLL. How do I register it? ΓòÉΓòÉΓòÉ
-
- Here's an example I use for registering. It checks if the DLL is valid before
- continuing:
-
- #define INCL_WPCLASS
- #define INCL_WIN
- #define INCL_DOS
- #include <os2.h>
- #include <string.h>
- #include <stdio.h>
-
- int main(int argc, char *argv[]) {
- HMQ hmq;
- HAB hab;
- CHAR szText[256];
- USHORT usResponse;
- CHAR szLoadError[128];
- HMODULE hmod;
- APIRET rc;
-
- if (argc != 3)
- return 0;
-
- hab = WinInitialize(0);
- hmq = WinCreateMsgQueue(hab, 0);
-
- WinDeregisterObjectClass(argv[1]);
-
- sprintf(szText, "Register %s DLL '%s'?", argv[1], argv[2]);
- usResponse = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szText,
- "Register WPS Class", 0, MB_YESNO | MB_MOVEABLE | MB_ICONQUESTION);
-
- if (usResponse != MBID_YES)
- return 0;
-
- rc = DosLoadModule(szLoadError, sizeof(szLoadError), argv[2], &hmod);
-
- if (rc != 0)
- {
- sprintf(szText, "Return code = %u, error module = '%s'.",
- rc, szLoadError);
- WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szText,
- "DosLoadModule Failed", 0,
- MB_ENTER | MB_MOVEABLE | MB_ERROR);
-
- return 0;
- }
-
-
- if (WinRegisterObjectClass(argv[1], argv[2]))
- {
- if (WinCreateObject(argv[1], argv[1], " ",
- "<WP_DESKTOP>", CO_REPLACEIFEXISTS))
- WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Created.",
- argv[1], 0,
- MB_ENTER | MB_MOVEABLE | MB_INFORMATION);
- else
- {
- DosFreeModule(hmod);
- WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Failed.",
- argv[1], 0,
- MB_ENTER | MB_MOVEABLE | MB_ERROR);
- }
- }
- else
- {
- DosFreeModule(hmod);
- WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, "Registration failed.",
- argv[1], 0,
- MB_ENTER | MB_MOVEABLE | MB_ERROR);
- }
-
- return 0; }
-
- FYI, when WPS registers your DLL with SOM, SOM checks if your DLL has a module
- entry point called SOMInitModule. If it does, it is called (most use
- SOMInitModule for registering DLLs that have more than one class). Otherwise,
- it checks for YourClassNewClass, and tries to call it (where 'YourClass' is the
- parameter you specified on the WinRegisterObjectClass). SOM generates
- 'YourClassNewClass' in the .IH file; if you're still stuck, verify it is being
- called and that it doesn't fail (eg, because of version number check).
-
- I suggest registering with a full DLL filespec, eg, C:\MYSTUFF\MYCAR.DLL. Saves
- on the length of the LIBPATH.
-
- Credit: Dan Kehn
-
-
- ΓòÉΓòÉΓòÉ 9.11. How do I save and restore my window size and position? ΓòÉΓòÉΓòÉ
-
- Here is code I use to restore a saved window position, which includes checks to
- make sure the user hasn't saved a window position at one screen resolution and
- then restored it at a different screen resolution (which might cause the
- window's frame controls to be completely off the display -- we've all seen
- that, right???):
-
- BOOL SetWindowPosition (const HAB hab, const HWND hwndFrame,
- const SWP swpConfig)
- {
- SWP swp ;
- APIRET ulRC ;
-
- // Initialize the window positioning flags.
- swp.fl = SWP_ACTIVATE | SWP_MOVE | SWP_SIZE | SWP_SHOW ;
-
- /* Check for saved user preferences for screen width/height in
- * config file. Did user want to start maximized?
- */
- if (swpConfig.fl & SWP_MAXIMIZE)
- {
- // Get maximized frame window position and size.
- ulRC = WinGetMaxPosition (hwndFrame, &swp) ;
- if (!ulRC)
- {
- // Report error, and then ...
- return TRUE ;
- }
- swp.fl |= SWP_MAXIMIZE ;
- }
-
- // Did user want to start minimized?
- else if (swpConfig.fl & SWP_MINIMIZE)
- {
- // Get minimized frame window position and size.
- ulRC = WinGetMinPosition (hwndFrame, &swp, (PPOINTL) NULL) ;
- if (!ulRC)
- {
- // Report error, and then ...
- return TRUE ;
- }
- swp.fl |= SWP_MINIMIZE ;
- }
-
- // Did user have a saved starting position and size?
- else if (swpConfig.cy || swpConfig.cx || swpConfig.x || swpConfig.y)
- {
- LONG cxClientMax ;
- LONG cyClientMax ;
- LONG cyTitleBar ;
- LONG cxSizeBorder ;
- LONG cySizeBorder ;
-
- // Get maximum client window size.
- cxClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CXFULLSCREEN) ;
- cyClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CYFULLSCREEN) ;
- cyTitleBar = WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR) ;
- cxSizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER) ;
- cySizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER) ;
-
- // Maximum client window size excludes title bar.
- cyClientMax += cyTitleBar ;
-
- // Make sure x origin is within display boundaries.
- swp.x = swpConfig.x ;
- if (swp.x < -cxSizeBorder)
- swp.x = 0 ;
-
- // Make sure window isn't too wide, or negative value.
- swp.cx = swpConfig.cx ;
- if (swp.cx >= cxClientMax || swp.cx < 0)
- {
- swp.cx = cxClientMax ;
- swp.x = 0 ;
- }
-
- if ((swp.x + swp.cx) > (cxClientMax + cxSizeBorder))
- swp.x = cxClientMax + cxSizeBorder - swp.cx ;
-
- // Make sure y origin is within display boundaries.
- swp.y = swpConfig.y ;
- if (swp.y < -cySizeBorder)
- swp.y = 0 ;
-
- // Make sure window isn't too high, or negative value.
- swp.cy = swpConfig.cy ;
- if (swp.cy > cyClientMax || swp.cy < 0)
- {
- swp.cy = cyClientMax ;
- swp.y = 0 ;
- }
-
- if ((swp.y + swp.cy) > (cyClientMax + cySizeBorder))
- swp.y = cyClientMax + cySizeBorder - swp.cy ;
- }
-
- // No saved position -- move window to FCF_SHELLPOSITION location.
- else
- {
- // Get default window size and position.
- ulRC = WinQueryTaskSizePos (hab, 0, &swp) ;
- if (ulRC)
- {
- // Report error, and then ...
- return TRUE ;
- }
- swp.fl = SWP_ACTIVATE | SWP_MOVE | SWP_SIZE | SWP_SHOW ;
- }
-
- // Position and size this frame window.
- ulRC = WinSetWindowPos (hwndFrame, HWND_TOP,
- swp.x, swp.y, swp.cx, swp.cy, swp.fl) ;
- if (!ulRC)
- {
- // Report error, and then ...
- return TRUE ;
- }
-
- return FALSE ;
- }
-
- Credit: Wayne Kovsky
-
-
- ΓòÉΓòÉΓòÉ 9.12. How do you make a window float above all other? ΓòÉΓòÉΓòÉ
-
- Here's how it's done. Assume you have a generic program in place that just
- creates a window with no menu's. Add the following to it.
-
- ================ Setup Code
-
- // Put the window where it belongs
-
- WinSetWindowPos (hwndFrame, NULL, (SHORT) rcl.xLeft, (SHORT) rcl.yBottom,
- (SHORT) (rcl.xRight ),
- (SHORT) (rcl.yTop ), SWP_SIZE | SWP_MOVE) ;
-
- // Make the controls all disappear behind the client
-
- hwndTitleBar = WinWindowFromID ( hwndFrame , FID_TITLEBAR ) ;
- hwndSysMenu = WinWindowFromID ( hwndFrame , FID_SYSMENU ) ;
- hwndMinMax = WinWindowFromID ( hwndFrame , FID_MINMAX ) ;
- hwndMenu = WinWindowFromID ( hwndFrame , FID_MENU ) ;
-
- WinSetParent ( hwndTitleBar , HWND_OBJECT , FALSE ) ;
- WinSetParent ( hwndSysMenu , HWND_OBJECT , FALSE ) ;
- WinSetParent ( hwndMinMax , HWND_OBJECT , FALSE ) ;
- WinSetParent ( hwndMenu , HWND_OBJECT , FALSE ) ;
-
- WinSendMsg ( hwndFrame , WM_UPDATEFRAME ,
- ( MPARAM ) ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX | FCF_MENU ) ,
- NULL ) ;
-
-
- if (WinStartTimer (hab, hwndClient, ID_TIMER, 1000))
- {
- while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
- WinDispatchMsg (hab, &qmsg) ;
-
- WinStopTimer (hab, hwndClient, ID_TIMER) ;
- }
- else
- WinMessageBox (HWND_DESKTOP, hwndClient,
- "Too many clocks or timers",
- szClientClass, 0, MB_OK | MB_ICONEXCLAMATION) ;
-
- ========= Message Loop
-
- case WM_TIMER:
-
- // Force the window to 'float' to the top of the stack again
-
- WinSetWindowPos (hwndFrame, HWND_TOP,....., SWP_ZORDER) ;
- break;
-
- case WM_BUTTON1DOWN :
- return WinSendMsg ( hwndFrame , WM_TRACKFRAME ,
- ( MPARAM ) ( LOUSHORT ( mp2 ) | TF_MOVE ) , NULL ) ;
-
- ========================================
-
- The first stuff gets you a client window that has invisible frame and controls.
- There may be better ways to do this, but this works for me. You need the frame
- to drag it aroound. the toughie was figuring out how to drag the client, and
- that's done by sending wm_trackframe messages to the frame. On the timer you
- set the position to the place it's already at, but set the z alignment to
- HWND_TOP. It effectively floats into position. It's great for setting a clock
- or freemem display into the empty portion of another titlebar.
-
- Credit: Gerry Rozema
-
-
- ΓòÉΓòÉΓòÉ 9.13. How to ensure the sizing's correct so the dlg "fits" in the notebook...? ΓòÉΓòÉΓòÉ
-
- Override wpclsQuerySettingsPageSize (or some such verbage, I don't have docs at
- home). I don't know if this API made it into the on-line docs, but it is
- definitely public (see \TOOLKT20\C\OS2H\WPOBJECT.H). There you are given the
- opportunity to adjust the size up to accomodate your dialog, if necessary.
-
- The PAGEINFO structure is used by the Settings page code to delay the loading
- of the dialog required for a page until the user turns to it for the first
- time. It has the resource ID, module handle (which is incorrectly named in the
- structure, 'resid' or some nonsense, grr-r), dialog procedure, and pointer of
- your choice to receive on WM_INITDLG (most choose the object pointer, somSelf).
- When the user selects the notebook tab, WPS calls WinLoadDlg based on the
- parameters in PAGEINFO.
-
-
- ΓòÉΓòÉΓòÉ 9.14. How do I prevent Shutdown from stopping my app? ΓòÉΓòÉΓòÉ
-
- In our application, the WM_CLOSE message processor determines the state of the
- application, issues all the "Are you sure?" questions, etc. If the close is to
- be continued, a WM_QUIT message is posted and a value of FALSE is returned.
- Otherwise a value of TRUE is returned.
-
- The window receiving the WMU_EndTask message handles it by posting a WM_CLOSE
- message to itself, and letting the WM_CLOSE processing handle it. The only
- reason it is not translated to a WM_CLOSE within the message loop is allow
- future use. This message requires no special handling.
-
- The window receiving the WMU_ShutDown message handles it by sending (not
- posting) a WM_CLOSE message to itself. If the WM_CLOSE message returns TRUE,
- then a WinCancelShutdown (hmq, FALSE) call is issued to cancel this instance of
- the shutdown.
-
- If you issue a WinCancelShutdown (hmq, TRUE), a WM_QUIT message will never be
- sent to your message queue, so will not have an opportunity to stop the
- shutdown. This is intended for secondary message queues that do not have a
- message loop.
-
- while (1) {
-
- HWND hwndClient;
-
- // Get next message from queue
- if (!WinGetMsg (hab, &qmsg, NULLHANDLE, 0, 0)) {
-
- // The WM_QUIT message has three sources:
- // 1. The task manager 'End task' pulldown
- // 2. System shutdown from desktop manager
- // 3. Posted by the application
-
- // This is a WM_QUIT message. Check the window handle, if the
- // handle matches mp2, it is from switch list close
- if (qmsg.hwnd == HWNDFROMMP (qmsg.mp2)) {
-
- // This is from close on the task list, convert to our message
- qmsg.msg = WMU_EndTask;
-
- // Get the intended client's window handle
- if (!(hwndClient = WinWindowFromID (qmsg.hwnd, FID_CLIENT))) {
-
- // Failed to find client. No idea who this belongs to,
- // give it to default window for processing
- hwndClient = hwndDefault
- }
-
- // Otherwise, readdress the message to the appropriate client
- qmsg.hwnd = hwndClient;
-
- // We can use mp1 and mp2 for anything we want.
- // Currently, just clear both
- qmsg.mp1 = qmsg.mp2 = 0L;
-
- } else if (qmsg.hwnd == NULLHANDLE) {
-
- // This message is from shutdown,
- // Address it to default window for processing
- qmsg.hwnd = hwndDefault;
-
- // And set the message to our shutdown message,
- qmsg.msg = WMU_SysShutdown;
-
- } else {
-
- // If here, we posted the WM_QUIT message, so break out of
- // the message loop
- break;
- }
- }
-
- // This is not a WM_QUIT message, intercept all other
- // messages intended for the NULL window
- if (qmsg.hwnd == NULLHANDLE) {
-
- // Pass all NULL window messages to the NULL window handler
- NullMsg (qmsg.hwnd, qmsg.msg, qmsg.mp1, qmsg.mp2);
-
- } else {
-
- // This is not a WM_QUIT message, nor is it intended for the NULL
- // window. Pass this message to the message filter hook for
- // processing.
- if (!WinCallMsgFilter (hab, (PQMSG) &qmsg, 0)) {
-
- // Filter hook has not cancelled the message, so dispatch
- // the message to the proper window
- WinDispatchMsg (hab, &qmsg);
- }
- }
- }
-
- Credit: Matt Osborn
-
-
- ΓòÉΓòÉΓòÉ 9.15. When I pass a structure to WinCreateWindow, sometimes it doesn't work! ΓòÉΓòÉΓòÉ
-
- Put the size of the structure as the first word.
-
-
- ΓòÉΓòÉΓòÉ 9.16. How do I use type filtering in 2.0's open dlg? ΓòÉΓòÉΓòÉ
-
- It's broken in 2.0GA, fixed in 2.0's service pak.
-
-
- ΓòÉΓòÉΓòÉ 9.17. When minimizing, my dialog box is overwriting my icon! ΓòÉΓòÉΓòÉ
-
- In the WM_MINMAXFRAME message hide the offending control.
-
- case WM_MINMAXFRAME:
- {
- PSWP pswp; /* pos change structure */
-
- /* hide list box when minimized so it doesn't overwrite icon */
- pswp = PVOIDFROMMP( mp1 );
- WinShowWindow(
- WinWindowFromID( hwnd, IDD_FILES ),
- !(pswp->fs & SWP_MINIMIZE)
- );
- }
- break;
-
-
- ΓòÉΓòÉΓòÉ 9.18. How do I make a multi-column listbox? ΓòÉΓòÉΓòÉ
-
- Use the container in details view. If you just have to use a list box:
-
- Here is an extract from my dialog box procedure that produces a two-column list
- box.
-
- In this example there is only one list box, so I don't have to worry about
- which control is involved. In this example, a blank is used to separate the
- first and second column. You could use tabs or any other sort of separator
- character. You could also draw anything you wanted in the list box item,
- including bit maps, colors, other fonts, etc.
-
- This is not a complete program, of course, but does show the details of
- handling a multi-column list box.
-
- /******************** Dialog Box Procedure ******************************/
-
- MRESULT EXPENTRY SelectDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
- {
- HPS hPS; /* Handle to the presentation space */
- FONTMETRICS FontMetrics; /* Metrics of default font */
- CHAR pszItemText[MAX_ITEM_TEXT_LENGTH];
- CHAR *s;
- OWNERITEM FAR *poi; /* Pointer to owner item structure */
- RECTL rcl; /* Rectangle for writing */
- COLOR clrForeGround;
- COLOR clrBackGround;
-
- switch (msg)
- {
- case WM_INITDLG: /* Initialize the list box */
-
- FillCfgListBox (hwnd); /* Fill the list box */
-
- return (FALSE);
-
-
- case WM_MEASUREITEM: /* Measure text height */
-
- hPS = WinGetPS (hwnd); /* Get handle to presentation space */
- GpiQueryFontMetrics (hPS, (LONG) sizeof (FONTMETRICS),
- &FontMetrics);
- WinReleasePS (hPS); /* Release the presentation space */
-
- return (FontMetrics.lMaxBaselineExt);
-
-
- case WM_DRAWITEM: /* Draw a list box entry */
-
- poi = mp2; /* Get address of owner item */
-
- if (poi->fsState == TRUE) /* Is this cell to be highlighted? */
- { /* Yes, use highlight attributes */
- clrForeGround = SYSCLR_HILITEFOREGROUND;
- clrBackGround = SYSCLR_HILITEBACKGROUND;
- }
- else /* No, use normal attributes */
- {
- clrForeGround = CLR_NEUTRAL;
- clrBackGround = CLR_BACKGROUND;
- }
-
- WinSendMsg (poi->hwnd, /* Get item text */
- LM_QUERYITEMTEXT,
- (MPARAM) MAKEULONG (poi->idItem,
- MAX_ITEM_TEXT_LENGTH),
- (MPARAM) pszItemText);
-
- rcl.xLeft = poi->rclItem.xLeft; /* Set co-ordinates */
- rcl.xRight = poi->rclItem.xRight; /* of rectangle */
- rcl.yTop = poi->rclItem.yTop;
- rcl.yBottom = poi->rclItem.yBottom;
-
- s = strchr (pszItemText, ' '); /* Find first blank */
- if (s)
- *s = '\0'; /* Terminate first column here */
-
- WinDrawText (poi->hps, /* Draw the first column */
- -1, /* Null-terminated string */
- pszItemText, /* File name is here */
- &rcl, /* Rectangle to draw in */
- clrForeGround,/* Foreground color */
- clrBackGround,/* Background color */
- DT_LEFT | DT_VCENTER | DT_ERASERECT);
-
- if (s) /* If there is a second column */
- {
- rcl.xLeft = 100; /* It starts out here */
- /* Spacing calculations could be */
- /* much cleverer than this very */
- /* crude use of an absolute position */
- /* (which is not transportable */
- /* to different display types, as */
- /* between 8514 and VGA) */
- s++; /* Point to beginning of text */
- WinDrawText (poi->hps, /* Draw the second column */
- -1, /* Also a null-terminated string */
- s, /* File Description */
- &rcl, /* Rectangle to draw in */
- clrForeGround, /* Colors are same as */
- clrBackGround, /* before */
- DT_LEFT | DT_VCENTER);
- }
-
- /* If fsState || fsStateOld and return TRUE, then */
- /* control will invert the rectangle -- not what */
- /* we want. Tell control not do do anything like that! */
-
- poi->fsState = poi->fsStateOld = FALSE;
-
- return (TRUE); /* Say we did it */
-
- ... case statements for rest of program ...
-
- Credit: Guy Scharf
-
-
- ΓòÉΓòÉΓòÉ 9.19. How do I create my own Master Help Index? ΓòÉΓòÉΓòÉ
-
- I talked with the owner of the Master Index, and she said there is no problem
- with using a like index to view online documentation for your application.
- There are just a few catches:
-
- 1. The documentation must be compiled as an .HLP file and not an .INF file.
- Note that this is the default for IPFC.
-
- 2. The tagged indexed entries must have the "global" attribute. For example:
-
- :i1 global.giving examples
-
- or:
-
- :i1 id=examp global.giving examples
-
- 3. The Index executable is a WPS object, not a standalone application. You
- will need to create your own copy of the object (instance) of class Mindex,
- either by using a REXX script (e.g. SysCreateObject()) or within your app
- (e.g. WinCreateObject()).
-
- For a REXX example:
-
- CALL SysCreateObject "Mindex", "Title", "<WP_DESKTOP>",
- "INDEX=MYFILE;OBJECTID=<MY_INDEX>"
-
- where MYFILE can be an environmental variable set to the path or filespec
- of your .HLP files, or it can be the actual filespec itself (e.g.
- INDEX=c:\myapp\myfile.hlp ). Note too that files can be concatenated (e.g.
- INDEX=c:\myapp\myfile.hlp+c:\yourapp\yourfile.hlp).
-
- 4. Objects of Mindex class CAN NOT be subclassed. There are no public methods
- in this class and it must be used as is.
-
- Credit: John Webb
-
-
- ΓòÉΓòÉΓòÉ 9.20. How do I change the font in an MLE? ΓòÉΓòÉΓòÉ
-
- How do I change the font in an MLE? WinSetPresParms doesn't work.
-
- This is a function I used in 1.x to set the font for an MLE (haven't ported it
- yet but it should be the same). I pass it the parent hwnd of the MLE, the MLE's
- id, a facename, a pointsize, the maximum height for an outline font, and
- fsSelection (FATTR_SEL_BOLD, etc). It first tries to match on pointsize and
- facename. If it can't it uses an outline font with the height requested.
-
- VOID EXPENTRY UtlSetMleFont( HWND hwndParent, USHORT usMleId, PSZ szFacename,
- USHORT usPointSize, LONG lMaxHeight,
- USHORT fsSelection )
- {
- PFONTMETRICS pfm;
- HDC hdc;
- HPS hps;
- HWND hwndMle;
- LONG lHorzRes, lVertRes, lRequestFonts = 0, lNumberFonts;
- FATTRS fat;
- SHORT sOutlineIndex = -1;
- INT i;
-
- (void) memset( &fat, 0, sizeof( FATTRS ) );
- fat.usRecordLength = sizeof( FATTRS );
- fat.fsSelection = fsSelection;
- strcpy( fat.szFacename, szFacename );
- hwndMle = WinWindowFromID( hwndParent, usMleId );
- hps = WinGetPS( hwndMle );
- hdc = GpiQueryDevice( hps );
- DevQueryCaps( hdc, CAPS_HORIZONTAL_FONT_RES, 1L, &lHorzRes );
- DevQueryCaps( hdc, CAPS_VERTICAL_FONT_RES, 1L, &lVertRes );
- lNumberFonts = GpiQueryFonts( hps, QF_PUBLIC, szFacename,
- &lRequestFonts, 0L, NULL);
- pfm = malloc( (SHORT) lNumberFonts * sizeof( FONTMETRICS ) );
- GpiQueryFonts( hps, QF_PUBLIC, szFacename,
- &lNumberFonts, (LONG) sizeof( FONTMETRICS ), pfm );
- for( i = 0; i < (USHORT) lNumberFonts; i++ )
- {
- if( pfm[ i ].fsDefn & 1 )
- {
- sOutlineIndex = (SHORT) i;
- continue;
- }
-
- if (pfm[ i ].sXDeviceRes == (SHORT) lHorzRes &&
- pfm[ i ].sYDeviceRes == (SHORT) lVertRes &&
- pfm[ i ].sNominalPointSize == (SHORT) (usPointSize * 10) )
- {
- fat.lMatch = pfm[ i ].lMatch;
- fat.lMaxBaselineExt = pfm[ i ].lMaxBaselineExt;
- fat.lAveCharWidth = pfm[ i ].lAveCharWidth;
- break;
- }
- }
-
- if( i >= (USHORT) lNumberFonts )
- if( sOutlineIndex >= 0 )
- if( lMaxHeight )
- {
- fat.fsFontUse = FATTR_FONTUSE_OUTLINE;
- if( !(fat.usCodePage = pfm[ sOutlineIndex ].usCodePage) )
- fat.usCodePage = 850;
- fat.lMaxBaselineExt = lMaxHeight;
- WinSendMsg( hwndMle, MLM_SETFONT, MPFROMP( &fat ), 0 );
- }
- WinSendMsg( hwndMle, MLM_SETFONT, MPFROMP( &fat ), 0 );
- WinReleasePS( hps );
- free( pfm );
- }
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.21. How do I attach Instance data to window created with WinCreateStdWindow? ΓòÉΓòÉΓòÉ
-
- I always use the two call to WinCreateWindow() method, instead of the
- WinCreateStdWindow() method, because the latter does not allow you to set
- instance data before your winproc is called for the first time.
-
- Here's a cset/2 program (icc /Ss+ /W3 /Se /B"/pm:pm" foo.c):
-
- #define INCL_PM
- #include <os2.h>
-
- typedef struct _mydata {
- HWND hwndFrame;
- HWND hwndClient;
- char whatever[100];
- }MYDATA;
-
- static MRESULT EXPENTRY WinProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
- {
- MYDATA *mine;
-
- mine = (MYDATA *)WinQueryWindowPtr(hwnd, 0); // will be null for WM_CREATE
- switch(msg){
- case WM_CREATE:
- mine = (MYDATA *)mp1;
- WinSetWindowPtr(hwnd, 0, mine);
- break;
- case WM_ERASEBACKGROUND:
- return (MRESULT)TRUE;
- default:
- return WinDefWindowProc(hwnd, msg, mp1, mp2);
- }
- return 0;
- }
-
- void main(void)
- {
- HAB hab;
- HMQ hmq;
- QMSG qmsg;
- char *class = "foo";
- FRAMECDATA fcdata; /* frame creation data */
- MYDATA mydat;
-
- hab = WinInitialize(0);
- hmq = WinCreateMsgQueue(hab, hmq);
-
- WinRegisterClass(hab, class, WinProc, 0, sizeof(MYDATA *));
-
- /* create frame window (WC_FRAME) */
- fcdata.cb = sizeof(FRAMECDATA);
- fcdata.flCreateFlags = FCF_TITLEBAR | FCF_SYSMENU |
- FCF_SHELLPOSITION | FCF_TASKLIST |
- FCF_SIZEBORDER | FCF_MINMAX ;
-
- fcdata.hmodResources = 0;
- fcdata.idResources = 1; /* resource id */
- mydat.hwndFrame = WinCreateWindow(HWND_DESKTOP, WC_FRAME, "Title",
- 0, 0, 0, 0, 0,
- 0, /* no owner */
- HWND_TOP, fcdata.idResources, &fcdata, NULL);
-
- if(!mydat.hwndFrame)
- exit(3);
-
- /* WinProc() has not been called yet */
-
- /* Create Client window: */
- mydat.hwndClient = WinCreateWindow(mydat.hwndFrame, class, "text",
- 0, 0, 0, 0, 0,
- mydat.hwndFrame, /* frame is owner */
- HWND_TOP, FID_CLIENT,
- &mydat, /* passed as mp1 to wm_create */
- NULL);
-
- WinShowWindow(mydat.hwndFrame, TRUE);
-
- while(WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0))
- WinDispatchMsg(hab, &qmsg);
-
- }
-
- Credit: Peter Fitzsimmons
-
-
- ΓòÉΓòÉΓòÉ 9.22. How do I get a list of fonts? ΓòÉΓòÉΓòÉ
-
- Shown is code for For v1.3. Petzold has had a nice series on fonts in PC MAG
- from about Nov 92-present.
-
- #define INCL_DEV
- #define INCL_DOSMEMMGR
- #define INCL_GPILCIDS
- #define INCL_WINWINDOWMGR
- #define INCL_WINLISTBOXES
- #include <os2.h>
- #include <stdio.h>
-
- VOID EXPENTRY FntQueryList(hwnd)
- HWND hwnd; // listbox handle
- {
- PFONTMETRICS pfm;
- HDC hdc;
- HPS hps;
- LONG alDevInfo[2];
- LONG lFonts;
- LONG lFontCnt = 0L;
- CHAR pch[64];
- SEL sel;
- USHORT i;
-
- hdc = WinOpenWindowDC(hwnd);
- DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 2L, alDevInfo);
- hps = WinGetPS(hwnd);
- lFonts = GpiQueryFonts(hps, QF_PUBLIC, (PSZ)0, &lFontCnt,
- (LONG)sizeof(FONTMETRICS), (PFONTMETRICS)0 );
- DosAllocSeg((USHORT)lFonts * sizeof(FONTMETRICS), &sel, SEG_NONSHARED);
- pfm = (PFONTMETRICS)MAKEP(sel, 0);
- GpiQueryFonts(hps, QF_PUBLIC, (PSZ)0, &lFonts,
- (LONG)sizeof(FONTMETRICS), pfm );
- for (i = 0; i < (USHORT)lFonts; i++) {
- if (!(pfm[i].fsDefn & FM_DEFN_OUTLINE)) {
- if ((pfm[i].sXDeviceRes == (SHORT)alDevInfo[0]) &&
- (pfm[i].sYDeviceRes == (SHORT)alDevInfo[1]) ) {
- sprintf(pch, "%2d.%s",
- pfm[i].sNominalPointSize / 10,
- pfm[i].szFacename );
- WinSendMsg(hwnd, LM_INSERTITEM,
- MPFROMSHORT(LIT_END), MPFROMP(pch) );
- }
- }
- }
- DosFreeSeg(sel);
- WinReleasePS(hps);
- return;
- }
-
-
- ΓòÉΓòÉΓòÉ 9.23. How do I create a folder in C and put my pgm in it? ΓòÉΓòÉΓòÉ
-
- /* Create our folder on the desktop */
-
- HOBJECT hFolder, hObject;
-
- hFolder = WinCreateObject ("wpFolder", "My Folder",
- "OBJECTID=<MY_FOLDER>", "<WP_DESKTOP>",
- CO_REPLACEIFEXISTS);
-
- /* Now, put our object into the folder. */
-
- hObject = WinCreateObject ("wpProgram", "My Online Book",
- "EXENAME=VIEW.EXE;PARAMETERS=MYBOOK.INF;\
- OBJECTID=<MY_BOOK>", "<MY_FOLDER>",
- CO_REPLACEIFEXISTS);
-
- What that little code snippet does is create a folder called "My Folder"
- on the desktop, and puts a program object for an online book in it.
- Check out the documentation on the following functions for more
- information:
-
- WinCreateObject
- wpSetup (for information on the setup string parameter to WinCreateObj)
- WPFolder (for information on the setup strings of folders)
- WPProgram programs
- etc.
-
-
- ΓòÉΓòÉΓòÉ 9.24. How do I do it in REXX? ΓòÉΓòÉΓòÉ
-
- You may have seen the Paradox 4.0 install script, which uses SysCreateObject to
- make a WPS object
-
- Hope they don't mind me posting a fragment of the script by:
-
- /* Rob Gordon Borland International 6/8/92 */
-
- title = "Paradox 4.0"
- classname = 'WPProgram'
- location = '<WP_DESKTOP>'
- setup = 'PROGTYPE=WINDOWEDVDM;EXENAME='pdoxpath'paradox.exe;
- STARTUPDIR='pdoxpath';SET DPMI_DOS_API=ENABLED;
- SET DPMI_MEMORY_LIMIT=4;ICONFILE 'pdoxpath'pdoxos2.ico;'
-
- BldObj:
- call charout , 'Building : 'title
- result = SysCreateObject(classname, title, location, setup)
-
-
- ΓòÉΓòÉΓòÉ 9.25. How do I use the Font dialog (WinFontDlg)? ΓòÉΓòÉΓòÉ
-
- FIRST: make your stack huge (>32K) It is sparsely allocated and you only use
- what you need. Here's some code:
-
- FONTDLG fontdlg ;
- FONTMETRICS fm ;
- CHAR szBuf [200] ;
- CHAR szFamily [CCHMAXPATH] ;
- static CHAR szTitle [] = "Fonts Dialog" ;
- static CHAR szMsgBoxTitle [] = "Result from 'WinFontDlg ()'" ;
- static CHAR szPreview [] = "We hold these truths to be self-evident ..." ;
-
- // Here, get an HPS and then do a WinQueryFontMetrics.
- // Continuing ...
-
- memset ((void *) &fontdlg, 0, sizeof (FONTDLG)) ;
- fontdlg.cbSize = sizeof (FONTDLG) ;
- fontdlg.hpsScreen = WinGetScreenPS (HWND_DESKTOP) ;
- fontdlg.hpsPrinter = NULLHANDLE ;
- fontdlg.pszTitle = szTitle ;
- fontdlg.pszPreview = szPreview ;
- fontdlg.pfnDlgProc = NULL ;
- strcpy (szFamily, fm.szFamilyname) ;
- fontdlg.pszFamilyname = szFamily ;
- fontdlg.usFamilyBufLen = sizeof (szFamily) ;
- fontdlg.fxPointSize = MAKEFIXED (fm.sNominalPointSize / 10, 0) ;
- fontdlg.fl = FNTS_CENTER | FNTS_HELPBUTTON |
- FNTS_INITFROMFATTRS | FNTS_NOSYNTHESIZEDFONTS |
- FNTS_RESETBUTTON ;
- fontdlg.sNominalPointSize = fm.sNominalPointSize ;
- fontdlg.flType = (LONG) fm.fsType ;
- fontdlg.clrFore = CLR_NEUTRAL ;
- fontdlg.clrBack = CLR_BACKGROUND ;
- fontdlg.usWeight = fm.usWeightClass ;
- fontdlg.usWidth = fm.usWidthClass ;
-
- hwndDlg = WinFontDlg (HWND_DESKTOP, hwnd, &fontdlg) ;
-
- Credit: Wayne Kovsky
-
-
- ΓòÉΓòÉΓòÉ 9.26. How do I take control of frame sizing? ΓòÉΓòÉΓòÉ
-
- I want to "subclass" the Window Frame Class to allow me to control the size of
- my main window when it's resized by the mouse. I want to control the steps it
- take to resize too, (ie: by 8x8 steps).
-
- --- CUT --- CUT ---- .H file --- CUT ---
-
- HWND APIENTRY WinCreateMBWindow(
-
- HWND hwndParent,
- ULONG flStyle,
- PULONG pflCreateFlags,
- PSZ pszClientClass,
- PSZ pszTitle,
- ULONG styleClient,
- HMODULE hmod,
- USHORT idResources,
- PHWND phwndClient);
-
-
- #define HMODFROMMP(mp) ((USHORT)(ULONG)(mp))
-
- #define MB_CHILD_SIZE WM_USER+204
- //Sent from child to frame indicating the new
- //requested size of the child area. (high&width in MP1)
- //If ChildMax is shrinking below current size,
- // frame is redused, and evt scroll bars is hidden.
- //If Child is growing
- // MP2=True -> grows frame to contain maximized child
- // MP2=False-> enables scroll bars, keeps size.
-
- #define MB_FIX_N 0x1 //Fix north border when sizing
- #define MB_FIX_E 0x2 //Fix east border when sizing
-
- #define MB_FIX_NE 0x3 //Fix north east corner when sizing
- #define MB_FIX_SE 0x2 //Fix south east corner when sizing
- #define MB_FIX_NW 0x1 //Fix north west corner when sizing
- #define MB_FIX_SW 0x0 //Fix south west corner when sizing
-
- #define MB_QCHILD_SIZE_MAX WM_USER+205
- //Sent from frame to child to queryw
- //max size of the child area. (h&w in MR)
- //Used when sizing to determin if scroll bars are ness.
-
- #define MB_QCHILD_GRID WM_USER+206
- //Sent from frame to child before tracking
- //Child supposed to return x&y granularity in MR
-
- #define MB_CREATE WM_USER+207 //Internally shipped command.
-
- typedef struct _FRM_DTA { /* Fram data */
- PFNWP oldProc;
- SHORT nTrkCnr,nYSclHor,nXSclVer,nTitle;
- SHORT xMax,yMax; //Max size of Client in PIX
- SHORT ScrMaxX,ScrMaxY;
- POINTL ptlBdr;
- HWND hVert,hHori;
- SHORT xCur,yCur; //Current size of Client in PIX
- SHORT nCorner; //Which corner is to be stable
- } FRM_DTA;
- typedef FRM_DTA FAR * PFRM_DTA;
-
- --- CUT --- CUT --- .C file --- CUT --- CUT ---
-
- HWND APIENTRY WinCreateMBWindow(HWND hParent, ULONG flStyle,
- PULONG pflCreate, PSZ pszClientClass,
- PSZ pszTitle, ULONG styleClient,
- HMODULE hmod,
- USHORT idResources, PHWND phClient)
- {
- HWND hFrame;
- PFRM_DTA pFrm;
-
- hFrame = WinCreateStdWindow(hParent,flStyle,pflCreate,pszClientClass,
- pszTitle,styleClient,hmod,idResources,phClient);
-
-
- //Allocate some storage for local parameters, and initialize it
- pFrm=malloc(sizeof( FRM_DTA));
- memset(pFrm,0,sizeof( FRM_DTA));
-
- WinSetWindowPtr(hFrame,QWL_USER,(PVOID) pFrm);
-
- pFrm->oldProc= WinSubclassWindow(hFrame,newFrameProc);
-
- //Now window is setup:
-
- WinSendMsg(hFrame,MB_CREATE,MP0,MP0); //My own WM_CREATE
-
- WinShowWindow(hFrame,TRUE);
-
- WinUpdateWindow(hFrame);
- return hFrame;
- }
-
- VOID GetChildMax(HWND hFrame, PFRM_DTA pFrm)
- { MRESULT mr;
- mr = WinSendMsg(WinWindowFromID(hFrame,FID_CLIENT),
- MB_QCHILD_SIZE_MAX,MP0,MP0);
- pFrm->xMax=SHORT1FROMMR(mr);
- pFrm->yMax=SHORT2FROMMR(mr);
- }
-
- #define CLIENT_PROVIDED FALSE
- #define FRAME_PROVIDED TRUE
-
- BOOL WinCalcFrameSWP(HWND hwnd, PSWP pSWP, BOOL bFrame)
- { // TRUE Frame rectangle provided
- // FALSE Client-area rectangle provided.
- RECTL rcl;
- BOOL bSuccess;
-
- rcl.xLeft = pSWP->x;
- rcl.yBottom = pSWP->y;
- rcl.xRight = pSWP->x+pSWP->cx;
- rcl.yTop = pSWP->y+pSWP->cy;
-
- bSuccess = WinCalcFrameRect(hwnd, &rcl, bFrame );
-
- pSWP->x =(SHORT) rcl.xLeft;
- pSWP->y =(SHORT) rcl.yBottom;
- pSWP->cx =(SHORT) (rcl.xRight-rcl.xLeft);
- pSWP->cy =(SHORT) (rcl.yTop -rcl.yBottom);
-
- return(bSuccess);
- }
-
-
- VOID SclBarEnable(HWND hwnd, PSWP pSWP, PFRM_DTA pFrm)
- {
-
- .....
-
- Your routines to determine and en/disable scroll bars
-
- .....
- /* Part of my code */
- swpClient = *(pSWP);
- WinCalcFrameSWP(hwnd, &swpClient, FRAME_PROVIDED);
- if (swpClient.cx >= pFrm->xMax-1)
- { //Turn off horisontal scroll bar
- WinSetParent(pFrm->hHori,HWND_OBJECT ,FALSE);
- nUpdt = FCF_HORZSCROLL;
- } /* code for enabling left out..... */
-
- if (nUpdt != 0)
- {
- WinSendMsg (hwnd, WM_UPDATEFRAME, MPFROMSHORT(nUpdt), MP0);
- }
- */
- }
-
- /***************** Start of frame subclass procedure *****************/
-
- MRESULT EXPENTRY newFrameProc( HWND hwnd, USHORT msg,
- MPARAM mp1, MPARAM mp2 )
-
- { PSWP pSWP;
- PFNWP oldProc;
- PFRM_DTA pFrm;
-
- pFrm=(PFRM_DTA)WinQueryWindowPtr(hwnd,QWL_USER);
- oldProc=pFrm->oldProc;
-
- switch(msg)
- {
- case MB_CREATE:
- //Start hiding scroll bars
- pFrm->hVert = WinWindowFromID(hwnd,FID_VERTSCROLL);
- WinSetParent(pFrm->hVert,HWND_OBJECT ,FALSE);
- pFrm->nYSclHor = 0;
- break;
-
- case WM_MINMAXFRAME:
- { SWP swpClient;
- pSWP=(PSWP) PVOIDFROMMP(mp1);
- pSWP->fs |= SWP_SIZE;
-
- GetChildMax(hwnd, pFrm);
-
- if (pSWP->fs & SWP_MAXIMIZE) //MaxiMizeing Operation
- {
- //tprintf("WM_MINMAXFRAME SWP_MAXIMIZE FS: %X ",pSWP->fs);
- if ((0!=pFrm->xMax) && (0!=pFrm->yMax))
- { //I have no data for all of screen, so act as Windowed OS/2
-
- memset(&swpClient,0,sizeof(swpClient));
- swpClient.cx=pFrm->xMax;
- swpClient.cy=pFrm->yMax;
- WinCalcFrameSWP(hwnd, &swpClient,CLIENT_PROVIDED);
-
- pSWP->cx = swpClient.cx;
- pSWP->cy = swpClient.cy;
-
- pSWP->y = pFrm->ScrMaxY - swpClient.cy + (SHORT)pFrm->ptlBdr.y;
-
-
- SclBarEnable(hwnd, pSWP, pFrm);
-
- return MRFROMSHORT(FALSE);
- }
- }
-
- if (pSWP->fs & SWP_RESTORE) //MiniMizeing Operation
-
- ??? (restore i guess)
-
- {
- //tprintf("WM_MINMAXFRAME SWP_RESTORE FS: %X ",pSWP->fs);
- if ((0!=pFrm->xMax) && (0!=pFrm->yMax)) //Why do I need this?
- {
- return MRFROMSHORT(FALSE);
- }
- }
- }
- return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
-
-
- case WM_QUERYTRACKINFO:
- {
- PTRACKINFO pTI;
- LONG i;
-
- if (TF_MOVE <= SHORT1FROMMP(mp1))
- {
- pFrm->nTrkCnr= 0;
- return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
- }
-
- pTI = (PTRACKINFO) PVOIDFROMMP (mp2); //Get structure pointer;
- //tprintf("@+WM_QUERYTRACKINFO FS: %X ",pTI->fs);
- if ((*oldProc)(hwnd, msg, mp1, mp2)==0) return MRFROMSHORT(FALSE);
-
- GetChildMax(hwnd, pFrm);
- if ((0!=pFrm->xMax) && (0!=pFrm->yMax))
- { //Setup track info structure
- pTI->ptlMaxTrackSize.x = (LONG) pFrm->xMax;
- pTI->ptlMaxTrackSize.y = (LONG) pFrm->yMax;
-
- WinCalcFrameRect(hwnd, &(pTI->rclTrack), FRAME_PROVIDED );
-
- { MRESULT mr;
- mr = WinSendMsg(WinWindowFromID(hwnd,FID_CLIENT),
- MB_QCHILD_GRID,MP0,MP0);
- if (NULL!=mr)
- {
- pTI->cxGrid = SHORT1FROMMR(mr);
- pTI->cyGrid = SHORT2FROMMR(mr);
-
-
- //Setting height of client to integral cyGrid
- i = (pTI->rclTrack.yTop - pTI->rclTrack.yBottom)/pTI->cyGrid;
- pTI->rclTrack.yTop = i * pTI->cyGrid + pTI->rclTrack.yBottom;
-
- pTI->fs |= TF_GRID;
- pFrm->nTrkCnr= WM_QUERYTRACKINFO;
- //Used in WM_ADJUSTWINODWPOS
- }
- }
- }
- return MRFROMSHORT(TRUE);
- }
- break;
-
- case WM_ADJUSTWINDOWPOS:
- { RECTL rcl;
- pSWP=(PSWP) PVOIDFROMMP(mp1);
-
- if (pSWP->fs & (SWP_SIZE | SWP_MOVE | SWP_MAXIMIZE))
- {
- GetChildMax(hwnd, pFrm);
- if (WM_QUERYTRACKINFO==pFrm->nTrkCnr)
- //As a result of tracking
- {
- //Go from client to frame values
- WinCalcFrameSWP(hwnd, pSWP, CLIENT_PROVIDED);
- }
-
- pFrm->nTrkCnr = 0;
-
- SclBarEnable(hwnd, pSWP, pFrm);
- }
- return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
- }
- break;
-
- case MB_CHILD_SIZE: //xCur,yCur
- { SWP swp;
-
- ............. do your actions as responce to client resize request (Change of
- fontsize for instance)
-
-
- return (MRESULT)TRUE;
- }
- break;
-
- default:
- break;
- }
- return (MRESULT)(*oldProc)(hwnd, msg, mp1, mp2);
- }
-
- A lot is deleted (Som is very application specific), but i hope you get the
- general picture.
-
- Credit: Henrik Wahlberg
-
-
- ΓòÉΓòÉΓòÉ 9.27. How do I use the 16-bit EPM toolkit? ΓòÉΓòÉΓòÉ
-
- Since there were a few requests, here are the changes I made to get the ESIMPLE
- example from the EPM Toolkit to work with the C Set/2 compiler. The ETK DLLs
- are 16-bit and need to be thunked to be called from a 32-bit app. Since I was
- playing around, some of the changes were not necessary to get the program to
- run. Changes are in DIFF format.
-
- **** Changes to EDLL.H ****
- 254a255
- > #pragma pack(2)
- 259,263c260,264
- < PSWP pswp; // positioning of edit window
- < PSZ filename; // file to be edited (with wildcard)
- < PVOID hEditPtr; // handle to editor pointer icon.
- < PVOID hMarkPtr; // handle to mark pointer icon.
- < PVOID hEditorIcon; // editor ICON.
- > PSWP _Seg16 pswp; // positioning of edit window
- > PSZ _Seg16 filename; // file to be edited (with wildcard)
- > HPOINTER hEditPtr; // handle to editor pointer icon.
- > HPOINTER hMarkPtr; // handle to mark pointer icon.
- > PVOID _Seg16 hEditorIcon; // editor ICON.
- 267,269c268,270
- < PSZ exfile; // pre-compiled macro code file (EPM.EX)
- < PSZ topmkr; // top and bottom of file marker
- < PSZ botmkr; //
- ---
- > PSZ _Seg16 exfile; // pre-compiled macro code file (EPM.EX)
- > PSZ _Seg16 topmkr; // top and bottom of file marker
- > PSZ _Seg16 botmkr; //
- 271,272c272,273
- < PSZ exsearchpath; // a set of paths to search for ex's files
- < PSZ exe_path; // path where the application started
- ---
- > PSZ _Seg16 exsearchpath; // a set of paths to search for ex's files
- > PSZ _Seg16 exe_path; // path where the application started
- 275c276,277
- < typedef EDITORINFO far *PEDITORINFO;
- ---
- > typedef EDITORINFO * PEDITORINFO;
- > #pragma pack()
- 280c282
- < #define ETKENTRY _loadds
- ---
- > #define ETKENTRY CDECL16
- 285,286c287,288
- < PSZ ETKENTRY EtkRegister( HAB hab, ULONG class_style );
- < USHORT ETKENTRY EtkCreate( PEDITORINFO epm_p, PHWND hEwnd_p);
- ---
- > PSZ _Seg16 ETKENTRY EtkRegister( HAB hab, ULONG class_style );
- > USHORT ETKENTRY EtkCreate( PEDITORINFO _Seg16 epm_p, PHWND _Seg16 hEwnd_p);
- 304c306,307
- < SHORT ETKENTRY EtkSetSelection( HWND hwndClient, LINE_INDEX_G firstline,
- ---
- > SHORT ETKENTRY EtkSetSelection( HWND hwndClient, LINE_INDEX_G firstline,
- > FIDType fileid);
-
- **** Changes to ESIMPLE.C ****
- 28a29,30
- >
- > #include "thunk.h"
- 47a50
- > HWND hwndEditFrame;
- 52c55
- <
- ---
- > swp.fl = SWP_MOVE | SWP_SIZE;
- 58c61
- < epm.filename = (PSZ)Fname; // file to be edited (with wildca
- ---
- > epm.filename = Fname; // file to be
- > edited (with wildca
- 64,65c67,70
- < epm.editorstyle = EDIT_STYLE_ACTIVATEFOCUS | EDIT_STYLE_DISABLEOWNERAFFECT
- < EDIT_STYLE_CURSORON;
- ---
- > epm.editorstyle = EDIT_STYLE_ACTIVATEFOCUS |
- > EDIT_STYLE_CURSORON |
- > EDIT_STYLE_STATUSLINE |
- > EDIT_STYLE_MESSAGELINE;
- 67,68c72,73
- < epm.pmstyle = FCF_TITLEBAR | FCF_SIZEBORDER | FCF_VERTSCROLL;
- <
- ---
- > epm.pmstyle = FCF_TITLEBAR | FCF_SIZEBORDER |
- > FCF_VERTSCROLL | FCF_MIN
- > epm.font = TRUE; // large font
- 70,71c75,76
- < epm.topmkr = // top and bottom file indicator
- < epm.botmkr = (PSZ)" ўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўўў";
- ---
- > epm.topmkr = (PSZ)"<Top>";
- > // top and bottom fi
- > epm.botmkr = (PSZ)"<Bottom>";
- 75c80
- <
- ---
- > epm.hini = NULLHANDLE;
- 77,79c82,86
- < EtkCreate( (EDITORINFO far *)&epm, (PHWND)&hwndEdit );
- <
- < return( (HWND)hwndEdit );
- ---
- > EtkCreate( &epm, &hwndEdit );
- > hwndEditFrame = WinQueryWindow(hwndEdit, QW_PARENT);
- > WinSetWindowPos(hwndEditFrame, NULLHANDLE, swp.x, swp.y,
- > swp.cx, swp.cy, SWP_MOVE | SWP_SIZE);
- > return( hwndEdit );
- 95c102
- < MRESULT FAR PASCAL TestWndProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2
- ---
- > MRESULT EXPENTRY TestWndProc( HWND hwnd, USHORT msg,
- > MPARAM mp1, MPARAM mp2 )
- 144,146c151,155
- < case EPM_EDIT_ACTIVEHWND:
- < WinSetActiveWindow(HWND_DESKTOP,(HWND)mp1 );
- < break;
- ---
- > case EPM_EDIT_ACTIVEHWND:
- > {
- > WinSetActiveWindow(HWND_DESKTOP,(HWND)mp1 );
- > }
- > break;
- 160c169
- < (PSZ)mp1,
- ---
- > (PSZ)_DosSelToFlat(mp1),
- 162c171
- < NULL,
- ---
- > NULLHANDLE,
- 235c244
- < hab = WinInitialize(NULL); // Initialize app as a PM app
- ---
- > hab = WinInitialize(NULLHANDLE); // Initialize app as a PM app
- 247c256
- <
-
- Credit: Mat Kramer
-
-
- ΓòÉΓòÉΓòÉ 9.28. How do I get error info after using WinGetLastError()? ΓòÉΓòÉΓòÉ
-
- ShowError Function:
-
- /*
- * ShowError -- for debugging: outputs (via printf) the last error;
- * to use this, redirect the output of this program to a file and
- * check the results in that file.
- * Updated to display the error text in a MESSAGE BOX; ID_MSGBOX must be
- * defined.
- */
- void ShowError(void)
- {
- PERRINFO p;
- char *cp;
- extern HAB hab; /* kinda kludgy, should be a parameter */
-
- printf("ShowError: ");
- if((p = WinGetErrorInfo(hab)) == NULL)
- printf("NO ERROR\n");
- else
- {
- printf("idError = %#X\n", p->idError);
- cp = (char *)((ULONG)p + *(ULONG *)((ULONG)p + p->offaoffszMsg));
- printf("\"%s\"\n", cp);
- WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (PSZ)cp, (PSZ)"Show Error",
- ID_MSGBOX, MB_OK | MB_ICONEXCLAMATION);
- WinFreeErrorInfo(p);
- }
- }
-
- Credit: Justin V Frank
-
-
- ΓòÉΓòÉΓòÉ 9.29. Do you have code to save/restore the clipboard? ΓòÉΓòÉΓòÉ
-
- typedef struct _CLPBRDDATA // INFORMATION ABOUT A CLIPBOARD FORMAT
- {
- ULONG ulFormat; // The format type
- PVOID pvData; // Pointer to the data for this format
- } CLPBRDDATA, *PCLPBRDDATA;
-
- //***************
- // Save formats
- //***************
- INT SaveClipboardData( HAB hab, PCLPBRDDATA *ppcd )
- {
- INT iFmtCount = 0;
-
- if( WinOpenClipbrd( hab ) )
- {
- ULONG ulNextFmt, ulPrevFmt = 0;
-
- ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
- while( ulNextFmt )
- {
- iFmtCount++;
- ulPrevFmt = ulNextFmt;
- ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
- }
-
- if( iFmtCount )
- {
- *ppcd =
- (PCLPBRDDATA) malloc( sizeof( CLPBRDDATA ) * iFmtCount );
- if( *ppcd )
- {
- memset( *ppcd, 0, sizeof( CLPBRDDATA ) * iFmtCount );
- if( !GetClipboardFmts( hab, *ppcd ) )
- iFmtCount = 0;
- }
- else
- {
- iFmtCount = 0;
- Msg( "Out of memory in SaveClipboardData" );
- }
- }
- WinCloseClipbrd( hab );
- }
- else
- Msg( "SaveClipboardData could not open the clipboard" );
-
- return iFmtCount;
- }
-
- BOOL GetClipboardFmts( HAB hab, PCLPBRDDATA pcd )
- {
- BOOL fSuccess = TRUE;
- ULONG ulNextFmt, ulPrevFmt = 0;
-
- ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
- while( ulNextFmt )
- {
- pcd->ulFormat = ulNextFmt;
- switch( ulNextFmt )
- {
- case CF_TEXT:
- StoreClipboardText( hab, pcd );
- break;
- case CF_BITMAP:
- StoreClipboardBmp( hab, pcd );
- break;
- case CF_METAFILE:
- StoreClipboardMeta( hab, pcd );
- break;
- default:
- break;
- }
- pcd++;
- ulPrevFmt = ulNextFmt;
- ulNextFmt = WinEnumClipbrdFmts( hab, ulPrevFmt );
- }
- return fSuccess;
- }
-
- VOID StoreClipboardText( HAB hab, PCLPBRDDATA pcd )
- {
- PSZ szClipText = (PSZ) WinQueryClipbrdData( hab, CF_TEXT );
- if( szClipText )
- {
- pcd->pvData = malloc( strlen( szClipText ) + 1 );
- if( pcd->pvData )
- strcpy( pcd->pvData, szClipText );
- else
- Msg( "Out of memory in StoreClipboardText" );
- }
- else
- Msg( "StoreClipboardText found no TEXT in the clipboard" );
- }
-
- VOID StoreClipboardBmp( HAB hab, PCLPBRDDATA pcd )
- {
- HBITMAP hbmClip = WinQueryClipbrdData( hab, CF_BITMAP );
- if( hbmClip )
- pcd->pvData = (PVOID) CopyBitmap( hab, hbmClip );
- else
- Msg( "StoreClipboardBmp found no BITMAP in the clipboard" );
- }
-
- VOID StoreClipboardMeta( HAB hab, PCLPBRDDATA pcd )
- {
- HMF hmfClip = WinQueryClipbrdData( hab, CF_METAFILE );
- if( hmfClip )
- {
- HMF hmfNew = GpiCopyMetaFile( hmfClip );
- if( hmfNew == GPI_ERROR )
- Msg( "StoreClipboardMeta GpiCopyMetaFile RC = %x",
- (USHORT) WinGetLastError( hab ) );
- else
- pcd->pvData = (PVOID) hmfNew;
- }
- else
- Msg( "StoreClipboardMeta found no METAFILE in the clipboard" );
- }
-
- //******************
- // Restore formats
- //******************
- VOID RestClipboardData( HAB hab, INT iFmtCount, PCLPBRDDATA pcd )
- {
- PCLPBRDDATA pcdSave = pcd;
- INT i;
- BOOL fFormatsExist = FALSE;
-
- for( i = 0; i < iFmtCount; i++, pcd++ )
- {
- if( pcd->ulFormat && pcd->pvData )
- {
- fFormatsExist = TRUE;
- break;
- }
- }
-
- pcd = pcdSave;
- if( fFormatsExist )
- if( WinOpenClipbrd( hab ) )
- {
- WinEmptyClipbrd( hab );
- for( i = 0; i < iFmtCount; i++, pcd++ )
- {
- switch( pcd->ulFormat )
- {
- case 0:
- break;
- case CF_TEXT:
- if( pcd->pvData )
- {
- RestClipboardText( hab, pcd->pvData );
- free( pcd->pvData );
- }
- break;
- case CF_BITMAP:
- if( pcd->pvData )
- RestClipboardBmp( hab, (HBITMAP) pcd->pvData );
- break;
- case CF_METAFILE:
- if( pcd->pvData )
- RestClipboardMeta( hab, (HMF) pcd->pvData );
- break;
- default:
- break;
- }
- }
- WinCloseClipbrd( hab );
- }
- else
- Msg( "RestClipboardData could not open the clipboard" );
- free( pcdSave );
- }
-
- VOID RestClipboardText( HAB hab, PSZ szTextIn )
- {
- PSZ szTextOut = NULL;
- ULONG ulRC =
- DosAllocSharedMem( (PVOID) &szTextOut, NULL,
- strlen( szTextIn ) + 1,
- PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE );
- if( !ulRC )
- {
- strcpy( szTextOut, szTextIn );
- if( !WinSetClipbrdData( hab, (ULONG) szTextOut, CF_TEXT,
- CFI_POINTER ) )
- Msg( "RestClipboardText WinSetClipbrdData failed" );
- }
- else
- Msg( "RestClipboardText DosAllocSharedMem RC: %u", ulRC );
- }
-
- VOID RestClipboardBmp( HAB hab, HBITMAP hbm )
- {
- if( !WinSetClipbrdData( hab, (ULONG) hbm, CF_BITMAP, CFI_HANDLE ) )
- Msg( "RestClipboardBmp WinSetClipbrdData failed" );
- }
-
- VOID RestClipboardMeta( HAB hab, HMF hmf )
- {
- if( !WinSetClipbrdData( hab, (ULONG) hmf, CF_METAFILE, CFI_HANDLE ) )
- Msg( "RestClipboardMeta WinSetClipbrdData failed" );
- }
-
- HBITMAP CopyBitmap( HAB hab, HBITMAP hbmIn )
- {
- BITMAPINFOHEADER2 bmih;
- HBITMAP hbmOut = NULLHANDLE;
- HDC hdcIn = NULLHANDLE, hdcOut = NULLHANDLE;
- HPS hpsIn = NULLHANDLE, hpsOut = NULLHANDLE;
- POINTL aptl[ 3 ];
- SIZEL sizel = {0,0};
-
- hdcIn = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE );
- if( !hdcIn )
- {
- Msg( "CopyBitmap DevOpenDC for hdcIn RC = %x",
- (USHORT) WinGetLastError( hab ) );
- goto BYEBYE;
- }
-
- hdcOut = DevOpenDC( hab, OD_MEMORY, "*", 0, NULL, NULLHANDLE );
- if( !hdcOut )
- {
- Msg( "CopyBitmap DevOpenDC for hdcOut RC = %x",
- (USHORT) WinGetLastError( hab ) );
- goto BYEBYE;
- }
-
- hpsIn = GpiCreatePS( hab, hdcIn, &sizel,
- PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
- if( !hpsIn )
- {
- Msg( "CopyBitmap GpiCreatePS for hpsIn RC = %x",
- (USHORT) WinGetLastError( hab ) );
- goto BYEBYE;
- }
-
- hpsOut = GpiCreatePS( hab, hdcOut, &sizel,
- PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
- if( !hpsOut )
- {
- Msg( "CopyBitmap GpiCreatePS for hpsOut RC = %x",
- (USHORT) WinGetLastError( hab ) );
- goto BYEBYE;
- }
-
- bmih.cbFix = sizeof( BITMAPINFOHEADER2 );
- if( !GpiQueryBitmapInfoHeader( hbmIn, &bmih ) )
- {
- Msg( "CopyBitmap GpiQueryBitmapInfoHeader for hbmIn RC = %x",
- (USHORT) WinGetLastError( hab ) );
- goto BYEBYE;
- }
-
- hbmOut = GpiCreateBitmap( hpsOut, &bmih, 0, NULL, NULL );
- if( hbmOut )
- {
- if( HBM_ERROR == GpiSetBitmap( hpsIn, hbmIn ) )
- {
- Msg( "CopyBitmap GpiSetBitmap for hpsIn RC = %x",
- (USHORT) WinGetLastError( hab ) );
- hbmOut = NULLHANDLE;
- goto BYEBYE;
- }
-
- if( HBM_ERROR == GpiSetBitmap( hpsOut, hbmOut ) )
- {
- Msg( "CopyBitmap GpiSetBitmap for hpsOut RC = %x",
- (USHORT) WinGetLastError( hab ) );
- hbmOut = NULLHANDLE;
- goto BYEBYE;
- }
-
- aptl[ 0 ].x = 0;
- aptl[ 0 ].y = 0;
- aptl[ 1 ].x = bmih.cx;
- aptl[ 1 ].y = bmih.cy;
- aptl[ 2 ].x = 0;
- aptl[ 2 ].y = 0;
-
- if( GPI_ERROR == GpiBitBlt( hpsOut, hpsIn, 3, aptl, ROP_SRCCOPY,
- BBO_IGNORE ) )
- {
- Msg( "CopyBitmap GpiBitBlt for hpsOut RC = %x",
- (USHORT) WinGetLastError( hab ) );
- hbmOut = NULLHANDLE;
- }
- }
- else
- Msg( "CopyBitmap GpiCreateBitmap for hbmOut RC = %x",
- (USHORT) WinGetLastError( hab ) );
-
- BYEBYE:
-
- if( hpsIn )
- GpiDestroyPS( hpsIn );
- if( hpsOut )
- GpiDestroyPS( hpsOut );
- if( hdcIn )
- DevCloseDC( hdcIn );
- if( hdcOut )
- DevCloseDC( hdcOut );
- return hbmOut;
- }
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.30. How do I know what item was selected in a Combo box? ΓòÉΓòÉΓòÉ
-
- Catch the LN_SELECT message from the combo box, then send an LM_QUERYSELECTION
- to get the index of the selection, then a LM_QUERYITEMTEXT to get the selected
- text.
-
- Credit: Pete Norloff
-
-
- ΓòÉΓòÉΓòÉ 9.31. How do I get a bitmap into a dialog in a DLL? ΓòÉΓòÉΓòÉ
-
- You've hit on a known problem with bitmaps in dialogs in dlls. This also used
- to be a problem for icons but that appears to be working now.
-
- First, define your bitmap in your dialog like this (notice no mention of
- SS_BITMAP). It is strictly text at this point. PM can handle this when loading
- the dialog:
-
- Below are all the files necessary to create dllbitmp.exe and dlgdll.dll. Dlgdll
- has the dialog box and bitmap. Dllbitmp.exe calls DllDialog() in dlgdll.dll to
- bring up the dialog box from the dll's resource file...
-
- DLLBITMP.C:
-
- #define INCL_GPI
- #define INCL_WIN
- #include <os2.h>
- #include "dllbitmp.h"
-
-
- #define FRAME_FLAGS (FCF_TASKLIST | FCF_TITLEBAR |
- FCF_MENU | FCF_SYSMENU |
- FCF_MINMAX | FCF_SIZEBORDER |
- FCF_SHELLPOSITION)
- #define CLIENT_CLASS "DllBitmp"
-
-
- INT main( VOID );
- VOID EXPENTRY DllDialog( HWND );
- FNWP wpClient;
-
-
- INT main( VOID )
- {
- HAB hab;
- HMQ hmq;
- QMSG qmsg;
- HWND hwndFrame, hwndClient;
- ULONG flFrame = FRAME_FLAGS;
-
- hab = WinInitialize( 0 );
- hmq = WinCreateMsgQueue( hab, 0 );
- WinRegisterClass( hab, CLIENT_CLASS, wpClient, 0, 0 );
- hwndFrame =
- WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE, &flFrame,
- CLIENT_CLASS, NULL, 0,
- NULLHANDLE, ID_RESOURCES, &hwndClient );
- while( WinGetMsg( hab, &qmsg, NULLHANDLE, 0, 0 ) )
- WinDispatchMsg( hab, &qmsg );
- WinDestroyWindow( hwndFrame );
- WinDestroyMsgQueue( hmq );
- WinTerminate( hab );
- return 0;
- }
-
-
- MRESULT EXPENTRY wpClient( HWND hwnd, ULONG msg,
- MPARAM mp1, MPARAM mp2 )
- {
- switch( msg )
- {
- case WM_ERASEBACKGROUND:
- return (MRESULT) TRUE;
- case WM_COMMAND:
- switch( SHORT1FROMMP( mp1 ) )
- {
- case IDM_DOIT:
- {
- DllDialog( hwnd );
- return 0;
- }
- }
-
- break;
- }
- return WinDefWindowProc( hwnd, msg, mp1, mp2 );
- }
-
- DLLBITMP.H:
-
- #define ID_RESOURCES 1
- #define IDD_DOIT 100
- #define IDM_DOIT 110
- #define ID_BITMAP 1100
- #define ID_BITMAPID 1200
-
- DLLBITMP.DEF:
-
- NAME DLLBITMP WINDOWAPI
- PROTMODE
- HEAPSIZE 16384
- STACKSIZE 16384
-
- DLLBITMP.RC:
-
- #include <os2.h>
- #include "dllbitmp.h"
-
-
- MENU ID_RESOURCES
- {
- MENUITEM "!~DoIt", IDM_DOIT
- }
-
- DLGDLL.C:
-
- #define INCL_DOS
- #define INCL_GPI
- #define INCL_WIN
- #include <os2.h>
- #include "dllbitmp.h"
-
-
- FNWP wpDlg;
-
-
- VOID EXPENTRY DllDialog( HWND hwnd )
- {
- HMODULE hmod;
-
- DosQueryModuleHandle( "DLGDLL", &hmod );
- WinDlgBox( HWND_DESKTOP, hwnd, wpDlg, hmod, IDD_DOIT, NULL );
- }
-
-
- MRESULT EXPENTRY wpDlg( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2 )
- {
- switch (msg)
- {
- case WM_INITDLG:
- {
- HWND hwndBmp = WinWindowFromID( hwndDlg, ID_BITMAPID );
- HPS hps = WinGetPS( hwndDlg );
- HBITMAP hbm;
- HMODULE hmod;
- DosQuieryModuleHandle( "DLGDLL", &hmod );
- hbm = GpiLoadBitmap( hps, hmod, ID_BITMAP, 0, 0 );
- WinSetWindowBits(hwndBmp,QWL_STYLE,SS_BITMAP,SS_BITMAP | 0x7f);
- WinSendMsg( hwndBmp, SM_SETHANDLE, MPFROMP( hbm ), NULL );
- WinSetWindowULong( hwndDlg, QWL_USER, (ULONG) hbm );
- WinReleasePS( hps );
- break;
- }
- case WM_DESTROY:
- {
- HBITMAP hbm = (HBITMAP) WinQueryWindowULong( hwndDlg,
- QWL_USER );
- GpiDeleteBitmap( hbm );
- break;
- }
- }
- return WinDefDlgProc( hwndDlg, msg, mp1, mp2 );
- }
-
- DLGDLL.DLG:
-
- DLGTEMPLATE IDD_DOIT LOADONCALL MOVEABLE DISCARDABLE
- BEGIN
- DIALOG "", IDD_DOIT, 0, 0, 210, 154, FS_NOBYTEALIGN | FS_DLGBORDER |
- WS_VISIBLE | WS_CLIPSIBLINGS | WS_SAVEBITS, FCF_TITLEBAR
- BEGIN
- CONTROL "foo", ID_BITMAPID, 98, 56, 32, 32, WC_STATIC,
- SS_TEXT | DT_LEFT | DT_TOP | WS_VISIBLE
- END
- END
-
- DLGDLL.DEF:
-
- LIBRARY DLGDLL INITINSTANCE TERMINSTANCE
- PROTMODE
- CODE LOADONCALL
- DATA LOADONCALL MULTIPLE NONSHARED
- EXPORTS DllDialog
-
- DLGDLL.RC:
-
- #include <os2.h>
- #include "dllbitmp.h"
-
-
- BITMAP ID_BITMAP "dlgdll.bmp"
-
-
- rcinclude dlgdll.dlg
-
- MAKEFILE:
-
- all: dlgdll.dll dllbitmp.exe
-
- dlgdll.dll: $*.obj $*.res
- link386 /NOI /NOE /MAP /DE /NOL $*, $*.dll,, os2386, $*
- rc $*.res $*.dll
- implib $*.lib $*.def
-
- dllbitmp.exe: $*.obj $*.def $*.res
- link386 /NOI /NOE /MAP /DE /NOL $*,,, os2386 dlgdll, $*
- rc $*.res $*.exe
-
- dllbitmp.obj: $*.c
- icc /Q+ /Ss /W3 /Kbcepr /Gm- /Gd- /Ge+ /Ti+ /O- /C $*.c
-
- dllbitmp.res: $*.rc
- rc -r $*
-
- dlgdll.obj: $*.c
- icc /Q+ /Ss /W3 /Kbcepr /Gm- /Gd- /Ge- /Ti+ /O- /C $*.c
-
- dlgdll.res: $*.rc $*.dlg
- rc -r $*
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 9.32. How does programming PM compare to programming X? ΓòÉΓòÉΓòÉ
-
- Many people have said "PM is much cleaner." Until I hear from someone I trust
- with extensive experience with both (I only know X), however, this FAQ will
- take no position.
-
- There was an unsubstantiated rumor that someone was porting an X library to
- OS/2 (X-Windows, not X-Mode or any other X), I dunno whether this has been
- substantiated or not.
-
- IBM and a few other manufacturers have built their own X servers for OS/2.
- [details?]
-
- [Colin Jensen...]
-
- I have some limited experience with X and PM. Raw Xlib is harder to program
- than PM. However most, if not all, of the X11 Toolkits are *easier* to use
- than PM. I have experience comparing XView to PM. A friend of mine has
- experience with Windows versus Xt, and has the same opinion (Windows isn't that
- far off conceptually from PM).
-
-
- ΓòÉΓòÉΓòÉ 9.33. How do I put bitmaps on buttons? ΓòÉΓòÉΓòÉ
-
- Stefan Gruendal (Stefan_Gruendel@wue.maus.de) writes:
-
- But to my question: How do I build my own "smart icons", i.e. bitmaps on
- pushbuttons, that optically "move into the screen"? I didn't find any way to
- achieve this with the Toolkit's Dialog Editor. But as mentioned above, I know
- there's a way.
-
- Starting with OS/2 2.x, a new button style was added - BS_ICON - which allows
- you to do what you are trying to accomplish. It works, as far as I know, only
- for pushbuttons, and the icon or bitmap is taken from the resource file, whose
- resource id is specified in the pushbutton text.
-
- For example:
-
- In FOO.H:
-
- #define IDBM_BUTTON 256
- #define IDPB_BUTTON 257
-
- In FOO.RC:
-
- BITMAP IDBM_BUTTON BUTTON.BMP
-
- In FOO.C:
-
- sprintf(achText,"#%d",IDBM_BUTTON);
-
- hwndButton=WinCreateWindow(hwndClient,
- WC_BUTTON,
- achText,
- WS_VISIBLE|BS_PUSHBUTTON|BS_ICON,
- 10,
- 10,
- 32,
- 32,
- hwndClient,
- HWND_TOP,
- IDPB_BUTTON,
- NULL,
- NULL);
-
- The bitmap is stretched or compressed to fill the button.
-
- (Quoted almost directly from EDMI/2 Edition 1)
-
-
- ΓòÉΓòÉΓòÉ 9.34. Can a PM program tell if there's a previous instance of itself running? ΓòÉΓòÉΓòÉ
-
- Raja Thiagarajan (sthiagar@bronze.ucs.indiana.edu) writes:
-
- Can a PM program tell if there's a previous instance of itself running? In
- Win3.x (but apparently NOT Win32), there's a hPrevInst handle; is there an OS/2
- 2.x equivalent? Basically, I'm thinking in terms of a program that would try
- to borrow resources from a previous instance if a previous instance is running.
- (Specifically, if my palette animation program gets started twice, the second
- instance oughta share palettes with the first instance!)
-
- What you're really asking is two questions:
-
- 1. How can I determine if a previous instance of my application is already
- running?
- 2. How can I share resources between multiple instances of my application?
-
- To answer your first question, you need to enumerate all of the main windows
- present on the desktop, and figure out if any of them are yours. This is
- achieved using the following code:
-
- HWND queryAppInstance(PCHAR pchClassWanted)
- {
- HENUM heEnum;
- HWND hwndTop;
- HWND hwndClient;
- CHAR achClass[256];
-
- heEnum=WinBeginEnumWindows(HWND_DESKTOP);
-
- hwndTop=WinGetNextWindow(heEnum);
- while (hwndTop!=NULLHANDLE) {
- hwndClient=WinWindowFromID(hwndTop,FID_CLIENT);
- if (hwndClient!=NULLHANDLE) {
- WinQueryClassName(hwndClient,sizeof(achClass),achClass);
- if (strcmp(achClass,pchClassWanted)==0) {
- WinEndEnumWindows(heEnum);
- return hwndClient;
- } /* endif */
- } /* endif */
-
- hwndTop=WinGetNextWindow(heEnum);
- } /* endwhile */
-
- WinEndEnumWindows(heEnum);
- return NULLHANDLE;
- }
-
- To answer your second question, the only way that I know of to share resources
- is to place them in a DLL. The procedure to do this is as follows:
-
- o Create a dummy source file with an empty procedure in it.
- o Compile the source file and link as a DLL.
- o Add your resources to the DLL in the same manner as you would to an
- executable.
-
- Then, when your application starts, you simply call WinLoadLibrary (the
- preferred way) or DosLoadModule to load the DLL. These functions return a
- handle to the DLL which must then be used in any function which loads resources
- (e.g. GpiLoadBitmap, WinLoadPointer, etc.).
-
- Note that this procedure does not require knowing the window handle of any
- previous instance of your application because OS/2 implements DLLs in a shared
- fashion (which I suspect is one of the reasons they were created in the first
- place). All you need to know is the name of the DLL. This technique can also
- be used to share resources between different applications.
-
- (Quoted almost directly from EDMI/2 Edition 1)
-
-
- ΓòÉΓòÉΓòÉ 10. Miscellaneous Programming ΓòÉΓòÉΓòÉ
-
- This section covers non-Presentation Manager programming.
-
-
- ΓòÉΓòÉΓòÉ 10.1. Explain the SYS_DLL keywords. ΓòÉΓòÉΓòÉ
-
- Actually there are three key names that exist for the app name SYS_DLL.
-
- They are:
-
- LOAD
- DLL loaded and ordinal 1 entry point called for every msg queue
- created in the system
-
- LOADPERPROCESS
- DLL loaded and ordinal 1 entry point called for only the first
- message queue created on a process
-
- LOADONETIME
- DLL loaded and ordinal 1 entry point called for only the shell's
- message queue (the first PM queue in the system)
-
- You would use one over another depending on the type of initialization that you
- require. Most DLL's only need to be initialized once for the system and are
- thus LOADONETIME, some DLLs like PMCTLS have per process initialization and
- thus are LOADPERPROCESS, and then there is the very rare case of DLLs that need
- to perform some function every time a message queue is created and these are
- specified as LOAD. Note: that anything other than LOADONETIME is a significant
- performance hit on the system. Note: also that in addition to your
- INITIALIZATION/TERMINATION function specified in the DEF file for your DLL
- (which is a new feature in 2.0), your ORDINAL 1 entry point in your DLL is also
- called. Be careful with this as I have seen some pretty strange results if you
- have an ordinal 1 entry point that has nothing to do with initialization. In
- addition, remember to never ever create a message queue inside of your
- initialization routine. Always call WinQueryAnchorBlock if you need a HAB for
- some API.
-
- As for shared resources, if you need resources on multiple processes then they
- need to be created on multiple processes as they won't be valid on any process
- other than the one you loaded. I believe that this is the reason PMCTLS is
- LOADPERPROCESS. You have a few options here, 1) you can store your resources
- in shared memory, and 2) for icons you can call WinSetPoinerOwner to make your
- icons shared across the entire system.
-
-
- ΓòÉΓòÉΓòÉ 10.2. How do I start another session? ΓòÉΓòÉΓòÉ
-
- This small program will start any program synchronously using
- DosStartSession(). The important thing is the queue. When you specify
- SSF_RELATED_CHILD and a TermQ name, OS/2 will write the return code to the
- specified queue when the session terminates. I use this in an event scheduler
- by creating a separate thread that does reads from the queue but you can just
- as easily block on the main thread to catch the return code. That will, in
- effect, provide for synchronous execution. Note that one problem with
- SSF_RELATED_CHILD is that if the program that started the child dies, so does
- the child.
-
- #define INCL_DOSERRORS
- #define INCL_DOSPROCESS
- #define INCL_DOSQUEUES
- #define INCL_DOSSESMGR
- #include <os2.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define QUEUE_NAME "\\QUEUES\\STRTSYNC.QUE"
-
- int main( int argc, char *argv[] );
-
- int main( int argc, char *argv[] )
- {
- APIRET rc;
- HQUEUE hque;
-
- if( argc < 2 )
- return 1;
-
- rc = DosCreateQueue( &hque, QUE_FIFO | QUE_CONVERT_ADDRESS, QUEUE_NAME );
- if( !rc )
- {
- STARTDATA stdata;
- PID pidSession;
- CHAR szObjFail[ 50 ];
- ULONG ulLength, idSession;
- REQUESTDATA rd;
- PUSHORT pusInfo = NULL;
- BYTE bPriority;
-
- (void) memset( &stdata, 0, sizeof( stdata ) );
-
- stdata.Length = sizeof( STARTDATA );
- stdata.FgBg = SSF_FGBG_FORE;
- stdata.TraceOpt = SSF_TRACEOPT_NONE;
- stdata.PgmTitle = "Rick's Program";
- stdata.InheritOpt = SSF_INHERTOPT_SHELL;
- stdata.SessionType = SSF_TYPE_DEFAULT;
- stdata.PgmControl = SSF_CONTROL_VISIBLE;
- stdata.ObjectBuffer = szObjFail;
- stdata.ObjectBuffLen= sizeof( szObjFail );
- stdata.Related = SSF_RELATED_CHILD;
- stdata.TermQ = QUEUE_NAME;
- stdata.PgmName = argv[ 1 ];
-
- rc = DosStartSession( &stdata, &idSession, &pidSession );
-
- if( rc && rc != ERROR_SMG_START_IN_BACKGROUND )
- {
- printf( "DosStartSession RC(%u)\n", rc );
- return (INT) rc;
- }
-
- rc = DosReadQueue( hque, &rd, &ulLength, (PPVOID) &pusInfo, 0,
- DCWW_WAIT, &bPriority, 0 );
-
- if( rc && rc != ERROR_QUE_EMPTY )
- {
- printf( "DosReadQueue RC(%u)\n", rc );
- return (INT) rc;
- }
-
- printf( "RetCode from Session %u: %u\n",
- pusInfo[ 0 ], pusInfo[ 1 ]);
-
- DosCloseQueue( hque );
- }
- else
- {
- printf( "DosCreateQueue RC(%u)\n", rc );
- return (INT) rc;
- }
-
- return 0;
- }
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 10.3. How do I check if a filename is valid? ΓòÉΓòÉΓòÉ
-
- Here's some code that should help. I found that you have to look at each
- return code to see if it's really an error. This routine does do syntax
- checking, it's just a little more complicated than before :^)
-
- #define INCL_DOSFILEMGR
- #define INCL_DOSERRORS
- #include <os2.h>
- #include <stdio.h>
-
- int main( int argc, char **argv )
- {
- int rc;
- FILESTATUS3 piBuffer;
-
- if ( argc !=2 )
- {
- printf( "Must pass filename on command line!\n");
- return( -1 );
- }
- else
- {
- printf( "Checking on %s, ", argv[ 1 ] );
- rc = DosQueryPathInfo( (PSZ)argv[1], FIL_STANDARD, &piBuffer,
- sizeof(FILESTATUS3));
-
- if ( rc == 0 )
- printf( "syntax valid and file exists\n" );
- else
- if ( rc == ERROR_FILE_NOT_FOUND )
- printf( "syntax valid and file doesn't exist.\n");
- else
- if ( rc == ERROR_PATH_NOT_FOUND )
- printf( "syntax valid, somthing in path was not found\n");
- else
- {
- printf( "bad, rc=%d, ",rc );
- switch( rc )
- {
- case ERROR_INVALID_DRIVE:
- printf( "drive name does not exist\n");
- break;
-
- case ERROR_INVALID_NAME:
- printf( "invalid syntax for drive name\n");
- break;
-
- case ERROR_FILENAME_EXCED_RANGE:
- printf( "dir name and/or filename too long\n");
- break;
-
- case ERROR_SHARING_VIOLATION:
- printf( "sharing violation\n");
- break;
-
- case ERROR_BUFFER_OVERFLOW:
- printf( "buffer overflow\n");
- break;
-
- case ERROR_INVALID_LEVEL:
- printf( "invalid level requested\n");
- break;
-
- case ERROR_INVALID_EA_NAME:
- printf( "invalid EA name\n");
- break;
-
- case ERROR_EA_LIST_INCONSISTENT:
- printf( "EA list inconsistent\n");
- break;
-
- default:
- printf("Undocumented return value.\n");
- }
- return( -1 );
- }
- return( 0 );
- }
- }
-
- Credit: Mike Brown
-
-
- ΓòÉΓòÉΓòÉ 10.4. Why should I use _beginthread instead of DosCreateThread? ΓòÉΓòÉΓòÉ
-
- You must if you want to use the C runtime library.
-
-
- ΓòÉΓòÉΓòÉ 10.5. How do I open a file that is already in use? ΓòÉΓòÉΓòÉ
-
- Use DosOpen with OPEN_SHARE_DENYNONE.
-
- /* this will copy an open program */
-
- #define INCL_NOPM
- #define INCL_DOS
- #include <os2.h>
- #include <stdio.h>
- #include <string.h>
-
- void usage(void)
- {
- printf("USAGE: CopyOpen <source file> <dest file>\n\n");
- printf(" This program, unlike the normal copy and xcopy commands,\n");
- printf(" will copy an open file.\n");
- printf("NOTE: Wildcards are not supported\n");
- }
-
- int cdecl main(int argc, char **argv)
- {
- HFILE hf, hfOut;
- USHORT usAction, rc, bytesRead, bytesWriten ;
- static BYTE buf[4096];
- long total=0l;
- int error = FALSE;
-
- if(argc!=3){
- usage();
- return 1;
- }
- rc = DosOpen(strupr(argv[1]),
- &hf,
- &usAction,
- 0L,
- FILE_NORMAL,
- FILE_OPEN,
- OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE,
- 0L);
- if(rc){
- printf("SYS%04u: Could not open %s for read.\n", rc, argv[1]);
- return 3;
- }
- rc = DosOpen(strupr(argv[2]),
- &hfOut,
- &usAction,
- 0L,
- FILE_NORMAL,
- FILE_CREATE | FILE_TRUNCATE,
- OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE,
- 0L);
- if(rc){
- printf("SYS%04u: Could not open %s for write.\n", rc, argv[2]);
- return 3;
- }
- else{
- do{
- rc = DosRead(hf, buf, sizeof(buf), &bytesRead);
- if(!rc){
- rc = DosWrite(hfOut, buf, bytesRead, &bytesWriten);
- if(!rc) total += bytesWriten;
- }
- }while(!rc &&
- sizeof(buf) == bytesRead &&
- bytesRead == bytesWriten);
- if(rc){
- printf("SYS%04u: while copying.\n", rc);
- error = TRUE;
- }
- if(bytesRead != bytesWriten){
- printf("Disk full?\n");
- error = TRUE;
- }
- DosClose(hf);
- if(!error)
- printf("%lu bytes copied.\n", total);
- }
- return( error? 3 : 0);
- }
-
- Credit: Peter Fitzsimmons
-
-
- ΓòÉΓòÉΓòÉ 10.6. Can we use Vio in v2.0? Where are the docs for it? ΓòÉΓòÉΓòÉ
-
- Yes; check cdrom.com for PRCP.ZIP.
-
-
- ΓòÉΓòÉΓòÉ 10.7. Can I redirect stdin and stdout in a child process? ΓòÉΓòÉΓòÉ
-
- This is what I use to redirect stderr, stdout to a file from a program I start
- using DosStartSession. You could do the same type of thing using a pipe.
-
- ULONG ulAction;
- ULONG ulNew;
- HFILE hfFile, hfNewStdOut = -1, hfNewStdErr = -1,
- hfStdOut = 1, hfStdErr = 2;
-
- // Open output file
- DosOpen( szOutputFile, &hfFile, &ulAction, 1, 0,
- FILE_OPEN | FILE_CREATE,
- OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE, 0L );
- // Duplicate handles
- DosDupHandle( hfStdOut, phfNewStdOut );
- DosDupHandle( hfStdErr, phfNewStdErr );
- // Close existing handles for current process
- DosClose( hfStdOut );
- DosClose( hfStdErr );
- // Redirect existing handles to new file
- DosDupHandle( hfFile, &hfStdOut );
- DosDupHandle( hfFile, &hfStdErr );
- // Let started program inherit handles from parent
- stdata.InheritOpt = SSF_INHERITOPT_PARENT;
- // Start new session
- DosStartSession( &stdata, &ulSessionID, &pidSession );
- // Get back original handles
- DosDupHandle( hfNewStdOut, &hfStdOut );
- DosDupHandle( hfNewStdErr, &hfStdErr );
- // Close the duplicated handles - no longer needed
- DosClose( hfNewStdOut );
- DosClose( hfNewStdErr );
-
- Credit: Rick Fishman
-
-
- ΓòÉΓòÉΓòÉ 10.8. How do I use DosMon*() to stuff the kbd buf? ΓòÉΓòÉΓòÉ
-
- Here's a mini app (all error handling, comments, etc. removed.)
-
- (also all this stuff to avoid compile warnings !!!!!).
-
- compile with: icc -Sm -Kabgioprx+ -Ss+ -W3 -Gs+ -Gf+ -O+ KEY.C
- start with: detach key
- stop with: F11 or CTRL-F10
- test envir: OS/2 2.0GA+SP, C-SET/2 CSD 22.
- no other functionality.
-
- orginal src part of my glorious DOS/OS2 1.x/OS2 2.0 keyboard roboter which
- inserts keys into the keyboard monitor queue controlled by an source file (mini
- language).
-
- (C) Mario Semo 1777,1832,1967-92.
-
- ========= TOP OF FILE KEY.C ================
-
- #define INCL_DOS
- #define INCL_KBD
- #define INCL_NOPM
-
- #include<os2.h>
- #include<stdio.h>
- #include<conio.h>
- #include<process.h>
- #include<stdlib.h>
- #include<string.h>
-
- #define DosMonOpen DOS16MONOPEN
- #define DosMonClose DOS16MONCLOSE
- #define DosMonReg DOS16MONREG
- #define DosMonRead DOS16MONREAD
- #define DosMonWrite DOS16MONWRITE
-
- #define MONITOR_DEFAULT 0x0000
- #define MONITOR_BEGIN 0x0001
- #define MONITOR_END 0x0002
-
- typedef SHANDLE HMONITOR; /* hmon */
- typedef HMONITOR *PHMONITOR;
-
- #pragma pack(2)
- typedef struct _MONIN { /* mnin */
- USHORT cb;
- BYTE abReserved[18];
- BYTE abBuffer[108];
- } MONIN;
- typedef MONIN *PMONIN;
-
- #pragma pack(2)
- typedef struct _MONOUT { /* mnout */
- USHORT cb;
- UCHAR buffer[18];
- BYTE abBuf[108];
- } MONOUT;
- typedef MONOUT *PMONOUT;
-
- APIRET16 APIENTRY16 DosMonOpen(PSZ pszDevName, PHMONITOR phmon);
- APIRET16 APIENTRY16 DosMonClose(HMONITOR hmon);
- APIRET16 APIENTRY16 DosMonReg(HMONITOR hmon, PBYTE pbInBuf,
- PBYTE pbOutBuf, USHORT fPosition, USHORT usIndex);
- APIRET16 APIENTRY16 DosMonRead(PBYTE pbInBuf, USHORT fWait,
- PBYTE pbDataBuf,
- PUSHORT pcbData);
- APIRET16 APIENTRY16 DosMonWrite(PBYTE pbOutBuf, PBYTE pbDataBuf,
- USHORT cbData);
-
- #define DosGetInfoSeg DOS16GETINFOSEG
- APIRET16 APIENTRY16 DosGetInfoSeg(PSEL pselGlobal, PSEL pselLocal);
-
- #pragma pack(2)
- typedef struct _GINFOSEG { /* gis */
- ULONG time; ULONG msecs; UCHAR hour;
- UCHAR minutes; UCHAR seconds; UCHAR hundredths;
- USHORT timezone; USHORT cusecTimerInterval; UCHAR day;
- UCHAR month; USHORT year; UCHAR weekday;
- UCHAR uchMajorVersion; UCHAR uchMinorVersion;
- UCHAR chRevisionLetter; UCHAR sgCurrent;
- UCHAR sgMax; UCHAR cHugeShift;
- UCHAR fProtectModeOnly; USHORT pidForeground;
- UCHAR fDynamicSched; UCHAR csecMaxWait;
- USHORT cmsecMinSlice; USHORT cmsecMaxSlice;
- USHORT bootdrive; UCHAR amecRAS[32];
- UCHAR csgWindowableVioMax; UCHAR csgPMMax;
- } GINFOSEG;
- typedef GINFOSEG *PGINFOSEG;
-
- static PGINFOSEG gdt;
-
- #define MAKEPGINFOSEG(sel) ((PGINFOSEG)MAKEP(sel, 0))
- #define MAKEPLINFOSEG(sel) ((PLINFOSEG)MAKEP(sel, 0))
-
- #pragma pack(2)
- typedef struct _keypacket
- {
- USHORT mnflags;
- KBDKEYINFO cp;
- USHORT ddflags;
- } KEYPACKET;
-
-
- #define RELEASE 0x40
- #define CTL_F10_KEY 103
- #define F11_KEY 133
-
- #pragma stack16(8192)
- #pragma seg16(HKBD)
- #pragma seg16(MONIN)
- #pragma seg16(MONOUT)
- #pragma seg16(KEYPACKET)
-
- static HKBD KBDHandle = (HKBD)0;
- static PGINFOSEG _Seg16 gdt;
- static MONIN monInbuf = {0};
- static MONOUT monOutbuf = {0};
- static HEV hevThreadDone = (HEV)0;
-
- static void _System keyboard_monitor(ULONG Dummy);
-
- int main(int argc, char *argv[], char *envp[])
- {
- SEL gdt_descriptor, ldt_descriptor;
- PID pidKeybrd;
-
- monInbuf.cb = sizeof(MONIN);
- monOutbuf.cb = sizeof(MONOUT);
-
- DosGetInfoSeg(&gdt_descriptor, &ldt_descriptor);
-
- gdt = MAKEPGINFOSEG(gdt_descriptor);
-
- DosMonOpen ( "KBD$", &KBDHandle );
-
- DosCreateEventSem(NULL, &hevThreadDone,0,FALSE);
-
- if (DosCreateThread(&pidKeybrd, &keyboard_monitor, 0L, 2L, 12000L))
- DosExit(EXIT_PROCESS,0);
-
- DosWaitEventSem(hevThreadDone, (ULONG)SEM_INDEFINITE_WAIT);
- DosMonClose(KBDHandle);
-
- DosBeep(100,100);
-
- DosExit(EXIT_PROCESS,0);
- return(0);
- }
-
-
- static void _System keyboard_monitor(ULONG Dummy)
- {
- KEYPACKET keybuff;
- USHORT count;
-
- DosSetPrty(PRTYS_THREAD, PRTYC_TIMECRITICAL,0, 0);
-
- DosMonReg( KBDHandle, (PBYTE)&monInbuf, (PBYTE)&monOutbuf,
- MONITOR_BEGIN, gdt->sgCurrent);
-
- DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR,0, 0);
-
- for(keybuff.cp.chChar = 0; ; )
- {
- count = sizeof(keybuff);
- DosMonRead( (PBYTE)&monInbuf, IO_WAIT, (PBYTE)&keybuff, &count);
- if (!(keybuff.ddflags & RELEASE))
- {
- if(keybuff.cp.chChar == 0)
- {
- switch (keybuff.cp.chScan)
- {
- case CTL_F10_KEY :
- case F11_KEY :
- DosPostEventSem(hevThreadDone);
- DosExit(EXIT_THREAD,0);
- break;
- }
- }
- }
- DosMonWrite((PBYTE)&monOutbuf,(PBYTE)&keybuff,count);
- }
- }
-
- Credit: Mario Semo
-
-
- ΓòÉΓòÉΓòÉ 10.9. How do I determine what file system a drive uses? ΓòÉΓòÉΓòÉ
-
- 16 bit: DosQFsInfo().
- 32 but: DosQueryFSInfo()
-
- The folling little 16 bit program produces the following output on my computer:
-
- LOCAL C: FAT
- LOCAL D: HPFS
- LOCAL E: HPFS
- LOCAL F: FAT
- REMOTE P: LAN \\SERV1\C$
- REMOTE Q: LAN \\SERV1\D$
- REMOTE R: LAN \\SERV1\E$
-
- Code....
-
- /* qdisk.c */
- #define INCL_NOPM
- #define INCL_DOS
- #include <os2.h>
- #include <stdio.h>
- #include <stdlib.h>
-
-
- void errorRC(USHORT rc)
- {
- char msg[256];
- USHORT bc;
- if(0 != (rc=DosGetMessage(NULL, 0, msg, sizeof(msg), rc,
- "OSO001.MSG", &bc))) {
- printf("SYS%04u: Unable to access OSO001.MSG\n", rc);
- }
- else DosWrite(2, msg, bc, &bc);
- }
-
- void qdisk(char drv)
- {
- USHORT rc, len;
- char dev[3];
- void *buf;
- char *p;
-
- if(drv < 'C')
- return;
- sprintf(dev, "%c:", drv);
- buf = malloc(2048);
- len = 2048;
- rc = DosQFSAttach(dev, 0, FSAIL_QUERYNAME, buf, &len, 0L);
- if(rc){
- errorRC(rc);
- return;
- }
- switch((*(PUSHORT)buf)){
- case FSAT_CHARDEV : printf("CHAR "); break;
- case FSAT_PSEUDODEV: printf("DEV "); break;
- case FSAT_LOCALDRV : printf("LOCAL "); break;
- case FSAT_REMOTEDRV: printf("REMOTE "); break;
- default: printf("Unknown "); break;
- }
- p = buf;
- p += sizeof(USHORT); /* itype */
- printf("%-3s ", p+sizeof(USHORT));
- p += (sizeof(USHORT) + (*(USHORT *)p) + 1); /* cbName */
- printf("%-8s ", p+sizeof(USHORT));
- p += (sizeof(USHORT) + (*(USHORT *)p) + 1); /* cbFSDName */
- if((*(USHORT *)p)) /* cbFSAData */
- printf("%s", p+sizeof(USHORT));
- printf("\n");
- free(buf);
- }
-
- void cdecl main(void)
- {
- char drv;
- USHORT usDisk;
- ULONG ulDrives;
- DosQCurDisk(&usDisk, &ulDrives); /* gets current drive */
- for (drv = 'A'; drv <= 'Z'; drv++) {
- if (ulDrives & 1) /* if the drive bit is set, */
- qdisk(drv);
- ulDrives >>= 1;
- }
- }
-
- ps: DosQSysInfo() will return the max path length that your version of OS/2
- supports. But since this API is specific to OS/2, and not to a particular
- drive, it does not answer your original question.
-
- Credit: Peter Fitzsimmons
-
-
- ΓòÉΓòÉΓòÉ 10.10. How do I get the error message from a DOS API call? ΓòÉΓòÉΓòÉ
-
- For DOSAPI calls, you can issue a DosGetMessage as follows:
-
- RC = DosXXXX(...);
- DosGetMessage(NULL,0,Msg,sizeof(Msg),RC,"OSO001.MSG",&Msg_Length);
-
- Credit: Ken Kahn
-
-
- ΓòÉΓòÉΓòÉ 10.11. How do I set an exception handler? ΓòÉΓòÉΓòÉ
-
- /*
- * Simple example of an exception handler
- */
-
- #define INCL_DOS
- #include <os2.h>
- #include <setjmp.h>
- #include <stdio.h>
- #include <string.h>
-
- extern int main(void);
-
- /*
- * Exception registration record. Stored on stack, with first
- * pointer to next registeration record, second pointer to
- * exception handler, and the rest defined by the author of
- * the exception handler.
- */
-
- typedef struct {
- struct _EXCEPTIONREGISTRATIONRECORD * volatile prev_structure;
- _ERR * volatile ExceptionHandler;
- jmp_buf env;
- } MYEXCEPTIONREGISTRATIONRECORD, *PMYEXCEPTIONREGISTRATIONRECORD;
-
- /*
- * Exception handler that returns traps via longjmp().
- */
-
- extern ULONG APIENTRY MyExceptionHandler
- (PEXCEPTIONREPORTRECORD pReportRecord,
- PEXCEPTIONREGISTRATIONRECORD pRegRecord,
- PCONTEXTRECORD pContextRecord, PVOID pReserved)
- {
- ULONG rc = XCPT_CONTINUE_SEARCH;
-
- if (pReportRecord->ExceptionNum == XCPT_ACCESS_VIOLATION)
- longjmp(((PMYEXCEPTIONREGISTRATIONRECORD) pRegRecord)->env, -1);
-
- /*
- * If we return to here then we could not handle the exception.
- */
-
- return rc;
- }
-
- extern BOOL Trapper(PSZ psz)
- {
- MYEXCEPTIONREGISTRATIONRECORD myExceptionRegRecord;
-
- /*
- * Insert my exception handler into the chain.
- */
-
- myExceptionRegRecord.prev_structure = NULL;
- myExceptionRegRecord.ExceptionHandler = MyExceptionHandler;
- DosSetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD) &myExceptionRegRecord);
-
- if (setjmp(myExceptionRegRecord.env))
- goto OnException;
-
- /*
- * Now go about my business in safety.
- */
-
- if (strlen(psz))
- printf("Trapper says okay to '%s'\n", psz);
- else
- printf("Trapper says it is empty\n");
-
- /*
- * I'm done, so unchain my exception handler.
- */
-
- DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&myExceptionRegRecord)
-
- return TRUE;
-
- /*
- * The code below is only executed if a trap occurs.
- */
-
- OnException:
- printf("Trapper says 'ouch!'\n");
-
- DosUnsetExceptionHandler((PEXCEPTIONREGISTRATIONRECORD)&myExceptionRegRecord)
-
- return FALSE;
- }
-
- extern int main()
- {
- Trapper("Hello");
- Trapper(NULL);
- Trapper("");
- Trapper((PSZ) 42);
- Trapper("Goodbye");
-
- return 0;
- }
-
- Credit: Dan Kehn
-
-
- ΓòÉΓòÉΓòÉ 10.12. How can I determine a diskette format and if a disk is in a drive? ΓòÉΓòÉΓòÉ
-
- Let's have a snippet from one of my functions:
-
- The 'ifdef M_I386's mean CSet/2
-
- --- snip ---
-
- EXPORT int GetFileSysAttach ( char cDrv, PVOID pInfo, UnsInt cbInfo )
- {
- CHAR szFileSys [4];
-
- szFileSys [0] = (CHAR) toupper ( cDrv );
- szFileSys [1] = ':';
- szFileSys [2] = '\0';
-
- DosError ( EXCEPTION_DISABLE );
-
- #ifdef M_I386
- Errno = DosQueryFSAttach ( szFileSys, 0, FSAIL_QUERYNAME, pInfo, &cbInfo );
- #else
- Errno = DosQFSAttach ( szFileSys, 0, FSAIL_QUERYNAME, pInfo, &cbInfo, 0L );
- #endif
-
- DosError ( EXCEPTION_ENABLE );
- return Errno ? -1 : 0;
- }
-
-
- EXPORT int GetFileSysInfo ( PSZ pszFileSys, PFSysInfo pfsi )
- {
- USHORT idDrv;
- FSALLOCATE fsal;
- FSINFO fsinfo;
- #ifdef M_I386
- PFSQBUFFER2 fsq = NULL;
- #else
- PFSQBUFFER fsq = NULL;
- PUSHORT pus;
- #endif
- CHAR hbuf [L_FILENAME];
- PCHAR pch;
- #ifndef _MT
- BOOL fProt = ProtectedMode ();
- #else
- #define fProt TRUE
- #endif
-
- idDrv = tolower ( *pszFileSys ) - ('a' - 1);
-
- DosError ( EXCEPTION_DISABLE );
-
- if ( ! (Errno = DosQFSInfo ( idDrv, 1, (PBYTE) &fsal, sizeof ( fsal ) )) )
- Errno = DosQFSInfo ( idDrv, 2, (PBYTE) &fsinfo, sizeof ( fsinfo ) );
-
- DosError ( EXCEPTION_ENABLE );
-
- if ( Errno )
- {
- if ( Errno == ERROR_NO_VOLUME_LABEL )
- memset ( &fsinfo, 0, sizeof (fsinfo) );
- else
- return -1; // No disk inserted
- }
-
- if ( fProt )
- {
- if ( GetFileSysAttach ( (CHAR) (idDrv + 'a' - 1), hbuf, L_FILENAME ) )
- return -1;
-
- #ifdef M_I386
- fsq = (PFSQBUFFER2) hbuf;
- #else
- fsq = (PFSQBUFFER) hbuf;
- #endif
- }
-
- DosError ( EXCEPTION_ENABLE );
-
- ...
-
- --- snap ---
-
- I think it's more than you want, the fsal-struct contains the size information,
- but I think if you want to retrieve ALL information about a logical drive
- that's what you need.
-
- Credit: Rainer Prem
-
-
- ΓòÉΓòÉΓòÉ 10.13. What do all those keywords mean when making a DLL? ΓòÉΓòÉΓòÉ
-
- Okay, with the help of some of my peers, I've solved the mystery surrounding
- the seemingly redundant SINGLE/MULTIPLE and SHARED/NONSHARED attributes.
-
- First, some prep up work...
-
- Every DLL needs and gets a data segment ("automatic data segment"). It is the
- place where the DLL stores all its STATIC data--basically the data declared in
- the DLL module but declared outside any function AND (I venture) variables
- declared STATIC within a DLL function as well. The STACK is NOT!! part of a
- DLL's automatic data segment (thoug it seems to be for an EXE). The stack that
- is used when 'running' a DLL function is that of the calling thread.
-
- Now here's the clincher...
-
- DLLs CAN ALSO HAVE ADDITIONAL DATA SEGMENTS!! (as can EXEs, I imagine)
-
- Bingo! Now we understand why there are two different sets of
- attributes--specifically, NONE/SINGLE/MULTIPLE and SHARED/NONSHARED. Though
- they basically do the same thing, they APPLY to different things.
-
- NONE/SINGLE/MULTIPLE
- applies to the one and only default data segment. This is the data
- segment that is "automatically" created for your DLL (or EXE). I
- imagine that for 90% of the DLLs written, this is the only type of
- data segment that exists. Whether or not this data segment is shared
- or whether a private copy is created for each linking application is
- A DIRECT FUNCTION OF THIS ATTRIBUTE--'SINGLE'=it's shared,
- 'MULTIPLE'=everyone get's his own copy.
-
- SHARED/NONSHARED
- This SETS THE DEFAULT!! FOR ALL DATA SEGMENTS other than the
- "automatic" data segment. DEFAULT is the key word, because you can
- specify, through the SEGMENTS statement, the characteristics of these
- additional segments on an individual basis (which in all certainty,
- override this value.)
-
- So...to answer my own question
-
- >could {someone} explain what the following statements would
- >produce:
- >
- > DATA MULTIPLE SHARED
-
- Every application which links to the DLL will have it's own private copy of the
- automatic data segment. If the DLL has no additional data segments, the SHARED
- keyword is meaningless and can be omitted. If there are additional data
- segments, only one copy of each will exist and they will be shared by all
- applications (unless a SEGMENTS statement follows which overrides this default
- for a specific segment)
-
- > or
- > DATA SINGLE NONSHARED
-
- Every application which links to the DLL will share a single automatic data
- segment (hence, each app that affects the DLL STATIC data will affect it for
- all apps). If there are no additional data segments, the NONSHARED keyword is
- meaningless and can be omitted. If there are, a private copy will be created
- for each app (unless overriden by a SEGMENTS statement).
-
- Note that in the absence of BOTH a SINGLE/MUTLIPLE and SHARED/NONSHARED
- keyword, the default is for ALL data segments (automatic and additional ones)
- to be shared (i.e., only one copy). In the absence of one OR the other, but not
- both, the property of ALL data segments are mandated by the single keyword. In
- other words,
-
- DATA SINGLE
- and
- DATA SHARED
-
- do the same exact thing.
-
- Credit: John Cortell
-
-
- ΓòÉΓòÉΓòÉ 10.14. Where can I find serial port sample code? ΓòÉΓòÉΓòÉ
-
- Q) Does anyone have any C sample code showing how to use the serial port under
- OS/2 using DosOpen() and DosDevIoCtl()?
-
- A) As a matter of fact, yes. :-)
-
- =-=-=-=-= extracted from a silly & specialized program =-=-=-=-=
-
- /* dtp.c -- D-dial Terminal Program: the first hack */
-
- //-- an annoying detail
-
- #define INCL_BASE
- #define INCL_DOSDEVIOCTL /* docs lie, this is NOT included by BASE */
- #include <os2.h>
-
- //-- initialization (in main() as written)
-
- HFILE portFd;
- ULONG action;
-
- if (DosOpen("COM1", &portFd, &action, 0, FILE_NORMAL, FILE_OPEN,
- OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, 0) != 0) {
- fprintf(stderr, "Open of COM1 failed\n");
- goto error0;
- }
-
- { DCBINFO di;
- ULONG dummy;
-
- dummy = sizeof(di);
- if (DosDevIOCtl(portFd, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0,
- &di, sizeof(di), &dummy) != 0)
- fprintf(stderr, "DosDevIOCtl failed\n");
- else {
- fprintf(stderr, "Timeouts: read = %u, write = %u\n",
- di.usWriteTimeout, di.usReadTimeout);
- fprintf(stderr, "Flag bytes: %02x, %02x, %02x\n",
- di.fbCtlHndShake, di.fbFlowReplace, di.fbTimeout);
- }
- di.fbTimeout = (di.fbTimeout & ~(3 << 1)) | (2 << 1);
- /* rcv = wait-for-something */
- di.usReadTimeout = 250;
- dummy = sizeof(di);
- if (DosDevIOCtl(portFd, IOCTL_ASYNC, ASYNC_SETDCBINFO,
- &di, sizeof(di), &dummy, 0, 0, 0) != 0)
- fprintf(stderr, "DosDevIOCtl failed to set parameters!\a\n");
- }
-
- if (initSerialOutput(portFd) != 0)
- goto error1;
-
- //-- the "running" variable is sort of a relic, I think
-
- running = 1;
- if (_beginthread(serialInputThread, 0, 8192, (void *)portFd) < 0) {
- fprintf(stderr, "can't start serial input thread\n");
- goto error2;
- }
-
- if (_beginthread(serialOutputThread, 0, 8192, (void *)portFd) < 0) {
- fprintf(stderr, "can't start serial output thread\n");
- goto error2;
- }
-
- //-- wrapup code
-
- shutdownSerialOutput();
- DosClose(portFd);
-
- //-- the rest of this lives outside of main()...
-
- //-- input side: gory details omitted
-
- //-- the port has been setup in "wait for something" mode, so we can request
- //-- more than one character at a time without blocking until the buffer is
- //-- full. At least, I *think* that's working now: this is used with 300 baud
- //-- systems, so it's hard to tell <g>. At least it isn't blocking until the
- //-- buffer is filled...
-
- /* serialInputThread -- reads port, writes to text window
- *
- * arg is the port's handle for reading
- */
- void serialInputThread(void *arg)
- {
- HFILE inFd = (long)arg;
- FILE *logFile;
- UCHAR buf[10];
-
- ParserState ps = {0};
-
- logFile = fopen("dtp.log", "ab");
-
- for ( ; ; )
- {
- ULONG n;
- if (DosRead(inFd, buf, 10, &n) == 0)
- {
- ULONG i;
- for (i = 0; i <n; ++i)
- {
- if (logFile != 0)
- putc(buf[i], logFile);
- if (runParser(&ps, buf[i]) != 0)
- postChar(buf[i]);
- }
- }
- }
- }
-
- /* output side: I rather like this arrangement using queues
- except that I'd prefer an anonymous queue.
- For this, having the queue named in the
- filesystem's name space is at best a minor annoyance. */
-
- /* * * * SerialOutput subsystem
- */
-
- #define MAX_CHUNK_SIZE 50
-
- typedef struct
- {
- USHORT nUsed;
- UCHAR buf[MAX_CHUNK_SIZE];
- } SO_CHUNK;
-
- #define NUM_SO_CHUNKS 6
-
-
- HQUEUE soQueue, freeQueue;
-
-
- int initSerialOutput (HFILE outFd)
- {
- (void) outFd; /* reserved for more general version */
-
- if (DosCreateQueue
- (&soQueue, QUE_FIFO, "\\queues\\dtp\\soQueue") != 0)
- {
- fprintf(stderr, "Failed to create serial output queue\n");
- goto error0;
- }
- if (DosCreateQueue
- (&freeQueue, QUE_FIFO, "\\queues\\dtp\\freeQueue") != 0)
- {
- fprintf(stderr, "Failed to create serial free queue\n");
- goto error1;
- }
- { SO_CHUNK *p = malloc(sizeof(SO_CHUNK) * NUM_SO_CHUNKS);
- int i;
- if (p == 0)
- {
- fprintf(stderr,
- "Failed to allocate memory for serial chunks\n");
- goto error1;
- }
- for (i = NUM_SO_CHUNKS; 0 < i; --i)
- if (DosWriteQueue(freeQueue, 0, sizeof(SO_CHUNK), p++, 0)
- != 0)
- {
- fprintf(stderr, "Failed to initialize free queue\n");
- goto error1;
- }
- }
-
- return 0;
-
- error1:
- DosCloseQueue(soQueue);
- error0:
- return -1;
- }
-
-
- void shutdownSerialOutput(void)
- {
- DosCloseQueue(freeQueue);
- DosCloseQueue(soQueue);
- }
-
-
- void writeSerial(UCHAR const *buf, USHORT n)
- {
-
- while (0 < n)
- {
- REQUESTDATA rd;
- ULONG dataLength;
- PVOID data;
- BYTE priority;
-
- if (DosReadQueue(freeQueue, &rd, &dataLength, &data,
- 0, DCWW_WAIT, &priority, 0) == 0)
- {
- SO_CHUNK *sc = data;
- USHORT m = MAX_CHUNK_SIZE;
- if (n < m)
- m = n;
- memcpy(sc->buf, buf, m);
- sc->nUsed = m;
- DosWriteQueue(soQueue, 0, sizeof(SO_CHUNK), sc, 0);
- buf += m;
- n -= m;
- }
- }
- }
-
-
- void writeSerialString(UCHAR const *buf)
- {
- writeSerial(buf, strlen(buf));
- }
-
-
- void serialOutputThread(void *arg)
- {
- HFILE outFd = (long)arg;
- REQUESTDATA rd;
- ULONG dataLength;
- PVOID data;
- BYTE priority;
-
- for ( ; ; )
- {
- if (DosReadQueue(soQueue, &rd, &dataLength, &data,
- 0, DCWW_WAIT, &priority, 0) == 0)
- {
- if (rd.ulData == 0) { /* simple data block */
- ULONG dummy;
- SO_CHUNK *sc = data;
- DosWrite(outFd, sc->buf, sc->nUsed, &dummy);
- DosWriteQueue(freeQueue, 0, sizeof(SO_CHUNK), sc, 0);
- }
- else
- ; /* anything else is a test, ignore it */
- }
- }
- }
-
- The intention was that control messages could be posted to the queue using null
- data packets (passing the actual message in the REQUESTDATA.ulData field);
- these would allow for controlling the port's baud rate and other settings.
- This seems to work under 2.0, and even appears to be intended to work (Deitel &
- Kogan's description), but I haven't done anything with it yet, as you can see.
- Haven't needed the facility yet...
-
- Credit: Martin Maney
-
-
- ΓòÉΓòÉΓòÉ 10.15. How do I disable <Ctrl><Alt><Del>? ΓòÉΓòÉΓòÉ
-
- You need to do a DosDevIOCtl with Category 4, Function 56. Use a 0xFFFF for the
- Hot Key ID. Set the other values to 0. This will toggle <Ctrl><Alt><Del> and
- <Ctrl><Esc> and <Alt><Esc> on then off on the next call. Note that this does a
- little more than what you want since it also disables <Ctrl><Esc> and
- <Alt><Esc> so you may run into problems getting around your different sessions
- when you've got it disabled. Other than this there is NO WAY to disable
- <Ctrl><Alt><Del> under OS/2 and believe me, people have tried!
-
- Credit: Mike Brown
-
-
- ΓòÉΓòÉΓòÉ 10.16. Why doesn't printf() produce output when I expect it to? ΓòÉΓòÉΓòÉ
-
- For historical reasons, most Unix C libraries' stdio default to using line
- buffered streams, whereas most DOS and OS/2 C libraries' stdio default to using
- fully buffered streams. ANSI C species that standard output should be line
- buffered when connected to an interactive device, but not all libraries are
- ANSI compliant. You can control the buffering algorithm used for a particular
- stream with the setvbuf() function.
-
- If you didn't understand that paragraph, read on.
-
- printf() is part of the Standard I/O (stdio) library, which uses buffered
- streams for file IO. ANSI C specifies three algorithms for deciding when to
- flush the buffer (i.e. when to print buffered data to the file):
-
- o not buffered. Data is flushed to the file as soon as possible, usually
- immediately after being received.
- o line buffered. Data is flushed to the file when a newline is received (and
- the newline is also flushed).
- o fully buffered. Data is flushed to the file when the buffer is full.
-
- Buffered data is always flushed when the stream is closed or when fflush() is
- called. Since standard output is flushed when main() exits, all data printed
- with printf() will appear at that time, if it has not already. However, ANSI C
- does not require that a stream be flushed when scanf() is called on it.
- Therefore, if you print to a fully buffered stream and then request input on
- it, it is likely that the input will be read before the printed data appears.
-
- You can control the buffering algorithm used for a particular stream with the
- setvbuf() function. For example, the statement setvbuf(stdout, NULL, _IOLBF,
- BUFSIZ) sets standard output to be line-buffered, which is what most Unix
- programmers expect. Any decent C reference will cover all of this material.
-
- [Colin Jensen...]
-
- After reading one too many bug reports about this phenomena, the gcc/2
- maintainer changed its stdout to not-buffered whenever stdout is interactive.
- When stdout is sent to a pipe or file, stdout is still fully-buffered.
-
-
- ΓòÉΓòÉΓòÉ 10.17. How do I write an OS/2 device driver? ΓòÉΓòÉΓòÉ
-
- There's a book called Writing OS/2 2.0 Device Drivers in C from
- Van Nostrand-Reinhold. There's also IBM's flood of printed material.
-
-
- Related Information:
-
- What are good reference books for programming in OS/2 and PM?
-
-
- ΓòÉΓòÉΓòÉ 10.18. How do I change the master environment? ΓòÉΓòÉΓòÉ
-
- Quick and simple answer: you don't.
-
- In OS/2 it is literally impossible for you to change the master environment
- from one of your programs. Do be able to do so would fatally disrupt the
- programming paradigm that has existed for ages: Your program does not alter
- the master environment. Your program is the slave, not the master. Therefore,
- no capability was built into OS/2 to facilitate this.
-
- There is, however, a kludge.
-
- As you know, a .CMD file can alter the master environment. This is the nature
- of batch files (ok, so I'm a MS-DOG dinosaur and still call them batch files
- instead of command files or scripts). Therefore, you can place a sequence of
- commands in the batch file that will take your program's output and alter the
- environment of your current shell.
-
- That's as close as you are gonna get to the master environment. You can always
- create your own sort of environment variables, in the form of shared memory or
- named pipes.
-
-
- ΓòÉΓòÉΓòÉ 10.19. What is the best way to communicate between processes? ΓòÉΓòÉΓòÉ
-
- There is more than one way - and you get to decide which is right for you!
-
- Shared Memory
-
- Shared memory is pretty self-explanatory. It is a memory segment that is
- allocated by one program, and then made available to other programs. When all
- the programs are done with it, then it is disposed of. You can name shared
- memory. So if you want two programs to communicate, then let them look for
- memory with the same name and communicate that way.
-
- Named Pipes
-
- Named pipes are a lot like shared memory, but think of a named pipe as a file
- instead of a single block of memory. Each process can create, read, write, and
- destroy a named pipe, much like you can a file.
-
- The difference between named pipes and shared memory is that a named pipe link
- is hot; With shared memory, data can be left in (as a sleeper, if you will),
- process 1 exits, process 2 accesses the data in memory, then deallocates the
- memory. With shared memory, a process doesn't even have to exist to leave a
- message for another process.
-
- Queues
-
- Nevertheless, an OS/2 queue is a standard First-In First-Out (FIFO) queue
- data/operation structure. However, OS/2 makes it really special because more
- than one process (or thread) can write to this queue. They are sometimes
- useful as an IPC mechanism.
-
-
- Related Information:
-
- What is the best way to communicate between threads?
-
-
- ΓòÉΓòÉΓòÉ 10.20. What is the best way to communicate between threads? ΓòÉΓòÉΓòÉ
-
- The best way to communicate between threads is sometimes also the best way to
- communicate between processes. However, when communicating between threads you
- can utilize two (very important) techniques:
-
- Semaphores
-
- In order to share application resources, and not write to the same space at the
- same time, you have to have some kind of flags that tell the thread when it
- should stop, when it should keep on going, and so on. Semaphores provide this
- capability. Semaphores are not for passing data. They merely exist as simple
- flags between threads and you should treat them as such. (It would be nice
- sometimes if semaphores worked across processes, but they don't.)
-
- Global Variables
-
- "Hey Jeff - I thought this was supposed to be about nifty OS/2-specific
- tricks!" It is! You can now use those old nasty things, global variables, in
- new ways. In conjunction with semaphores, you can pass data very easily
- between threads with global variables. Here's a simple example:
-
- 1. Create a global variable called PassData.
- 2. Create a semaphore called OkToPassData.
- 3. Create a semaphore called DataPassed.
- 4. Have two threads work at the same time:
-
- a. If the semaphore DataPassed is true:
-
- 1. Set the semaphore OkToPassData to false.
- 2. Read the data in the global.
- 3. Set the semaphore DataPassed to false.
- 4. Set the semaphore OkToPassData to true.
-
- b. When a thread wants to pass data, wait for the semaphore to be clear.
- c. Set the semaphore OkToPassData to false.
- d. Put the data in the global.
- e. Set the semaphore DataPassed to true.
- f. Set the semaphore OkToPassData to true.
-
- Of course, there are issues of deadlock and other such nonsense that corporate
- chaps get paid to consider, but that's beyond the scope of this document.
-
-
- Related Information:
-
- What is the best way to communicate between processes?
-
-
- ΓòÉΓòÉΓòÉ 11. Porting ΓòÉΓòÉΓòÉ
-
- This section covers all aspects of porting programs.
-
-
- ΓòÉΓòÉΓòÉ 11.1. How do I port my DOS keyboard TSR to OS/2? ΓòÉΓòÉΓòÉ
-
- Use keyboard monitors (for fullscreen sessions) or hooks for the PM session.
-
-
- ΓòÉΓòÉΓòÉ 11.2. How can I simulate (Unix feature) under OS/2? ΓòÉΓòÉΓòÉ
-
- 1. fork
- 2. fork/exec
- 3. select
- 4. job control
-
- In general, you can't. select() depends heavily on the fact that all sources
- and sinks of data originate in the filesystem and are identified by a coherent
- set of file descriptors; these assumptions are not true under OS/2. For
- (almost) any particular kind of data source/sink (files, sockets, pipes) you
- can achieve most of select()'s semantics. A decent solution to this problem
- requires a C library that maintains its own array of file descriptors and
- information on each one such that it can dispatch to the appropriate module in
- response to library calls. The C libraries delivered with emx/gcc will have
- such functionality in the (possibly near) future, but don't yet. The current
- maintainer of GCC/2 says that there are no plans to add select() into GCC/2's
- library.
-
- A working version of fork() comes with the emx/gcc libraries. The author
- cautions that this is not the way to multitask, though, because it eats up a
- lot of resources (since it literally duplicates the current process, leaving
- everything but the PID unchanged). _beginthread() is the suggested solution if
- at all possible.
-
-
- ΓòÉΓòÉΓòÉ 11.3. How can I recompile public domain/shareware source code for OS/2? ΓòÉΓòÉΓòÉ
-
- Most publicly available OS/2 programs come with binaries (since there is
- currently only one OS/2 architecture). If you are porting source code from
- another system (for example, Unix), you will first need to acquire a compiler.
- See section 1 for information on compilers; in particular, note that the GNU C
- compiler is available.
-
- You should realize that many publicly available programs have already been
- ported to OS/2. Check the many FTP sites carrying OS/2 programs before you
- reinvent any wheels (the OS/2 User's FAQ contains information on FTP site).
-
- Most Unix applications (through the use of emx/gcc) port with extreme ease; DOS
- and Windows applications are a tougher problem, and require many changes before
- they can be recompiled as a native OS/2 program.
-
- (It is interesting to note that MicroSoft C v6.0 will compile bound OS/2
- programs, which will run under DOS and OS/2 without modification.)
-
-
- Related Information:
-
- How can I port my DOS program to OS/2?
- How can I port my Windows program to OS/2?
-
-
- ΓòÉΓòÉΓòÉ 11.4. How can I port my DOS program to OS/2? ΓòÉΓòÉΓòÉ
-
- To the first approximation, you don't have to --- OS/2 2.x's DOS support is
- excellent, and your DOS program will probably just work; similarly, OS/2 2.x
- supports Windows 3.0 (and soon 3.1) programs. See the OS/2 User's FAQ for
- details.
-
- [That was Barry Jaspan's opinion. I believe that you should make every effort
- to recompile your existing DOS programs for OS/2 2.x. They will run faster in
- many cases, and both (a) use less memory and (b) be able to use more memory
- than their DOS counterparts. - Jeff]
-
- If you truly want to port your DOS program over to OS/2, then study the
- libraries available to you. The core code (if you wrote it correctly) will
- probably not change much. You will just have to change the user interface
- stuff.
-
- If your program is a real simple one that uses standard input and output, then
- you will probably not make very many changes to your program when converting it
- to OS/2.
-
- You should also realize that neato and nifty DOS tricks (like grabbing an
- interrupt whenever you feel like it, or writing directly to almost anywhere)
- are completely out of the question.
-
-
- Related Information:
-
- How can I port my Windows program to OS/2?
-
-
- ΓòÉΓòÉΓòÉ 11.5. How can I port my Windows program to OS/2? ΓòÉΓòÉΓòÉ
-
- IBM Workset/2 includes Mirrors, a toolkit designed to help port Windows
- applications to OS/2. [Details?]
-
- There are also several toolkits available that allow you to make calls to a
- common API library, and your source will work across the two platforms without
- any changes at all.
-
- However, if you want to bite the bullet and port it, then be prepared to make a
- lot of changes. Just like porting regular DOS programs, you will have to scrap
- most, if not all, of your user interface. Your core code, if modular and
- abstract enough, should come through the port relatively unscathed.
-
-
- Related Information:
-
- How can I port my DOS program to OS/2?
-
-
- ΓòÉΓòÉΓòÉ 12. Miscellaneous ΓòÉΓòÉΓòÉ
-
- This section covers questions not covered in previous sections.
-
-
- ΓòÉΓòÉΓòÉ 12.1. Is OS/2 suitable for real time programs? ΓòÉΓòÉΓòÉ
-
- Yes! There is a special priority you can assign your programs
- (ForegroundServer Mode) via DosSetPriority() which will give your process
- (note, not thread, but process) the maximum allowable CPU time.
-
- Another route is to use DosEnterCritSec()/DosExitCritSec(). Calling the former
- will disable thread switching (hopefully for a short period of time), and
- calling the latter will enable thread switching again.
-
-
- ΓòÉΓòÉΓòÉ 12.2. What is available for multimedia programming under OS/2? ΓòÉΓòÉΓòÉ
-
- The OS/2 2.x Multimedia package is now available. Call the IBM Multimedia
- office at (800) 426-9402 ext. 150.
-
-
- ΓòÉΓòÉΓòÉ 12.3. What is available for AI/neural net programming under OS/2? ΓòÉΓòÉΓòÉ
-
- LISP and XScheme are available from cdrom.com. There are also some AI/neural
- net tools listed in tinf31.zip.
-
-
- Related Information:
-
- What other programming languages are available for OS/2?
-
-
- ΓòÉΓòÉΓòÉ 12.4. Special software offers ΓòÉΓòÉΓòÉ
-
- Here are some of the OS/2 software products that represent particularly good
- values. Most prices do not include shipping and handling.
-
- o Borland C++ for OS/2. Available from Below Zero in Calgary (phone
- 800-461-2777, 403-547-0669, or FAX 403-547-1018) for about $136 U.S.,
- including shipping. Add GST in Canada. Below Zero will export outside North
- America.
-
- o IBM PL/I. Not everyone is a PL/I programmer, but IBM is offering free copies
- of Workframe/2 with every purchase and free product videos. Phone
- 800-426-3346 ext. STL10 for more information on the two packages available.
-
- (Quoted almost directly from OS/2 General FAQ)
-
-
- ΓòÉΓòÉΓòÉ 12.5. Technical Support ΓòÉΓòÉΓòÉ
-
- How can I get answers to my OS/2 questions?
-
- If your question is not answered in this List, post a note to the appropriate
- Usenet conference:
-
- Newsgroup Description
- comp.os.os2.apps carries discussions related to finding or
- using any application running under OS/2
- comp.os.os2.networking looks at networking issues
- comp.os.os2.advocacy deals with opinions and speculation
- comp.os.os2.programmer.porting helps programmers move applications over to
- OS/2 from other operating systems and
- environments
- comp.os.os2.programmer.misc addresses anything else related to OS/2
- programming
- comp.os.os2.beta explores beta releases of OS/2
- comp.os.os2.ver1x supports all releases of OS/2 prior to
- Version 2.0
- comp.os.os2.announce carries important OS/2 announcements
- comp.os.os2.bugs discusses possible bugs found in released
- versions of the operating system
- comp.os.os2.multimedia fosters conversation about OS/2 multimedia
- (including MMPM/2),
- comp.os.os2.setup offers a place to talk about setup and
- installation issues
- comp.os.os2.misc is for any other OS/2-related discussion
- comp.lang.rexx discusses REXX programming
-
- These groups are also watched closely by OS/2 experts from IBM.
-
- A LISTSERVer distributes its own OS/2 conference by mail; send a single line
- message with the word HELP to listserv@cc1.kuleuven.ac.be for full
- instructions; or send the same message to listserv@frors12.circe.fr for
- information on an unedited mailing list. To subscribe to the Multimedia
- Presentation Manager/2, send a single line message with the phrase SUBSCRIBE
- MMOS2-L (Your Name) to mail-server@knex.via.mind.org.
-
- Your local FidoNet BBS may carry OS/2 echo conferences and/or OS2NET. If not,
- ask your system operator to join them. CompuServe (FIND OS/2) and Prodigy are
- also excellent resources.
-
- The IBM PC Co. BBS's (modem 404-835-6600) message areas, product database, and
- PS/2 Assistant file(s) are invaluable resources. Information on the new OS/2
- BBS is included in the OS/2 2.0 package. In the United States IBM has toll free
- technical support (phone 800-237-5511), an OS/2 Hotline (general information,
- orders, upgrades, phone 800-3-IBM-OS2; ask about OS/2 videotapes, T-shirts, and
- other accessories), the HelpWare Center (phone 800-PS2-2227), a software order
- line (phone 800-IBM-CALL), two FAX information services (phone 800-IBM-4FAX
- and/or 800-IBM-3395), and an educational inquiries line (phone 800-222-7257).
- In Canada phone IBM Personal Systems Software at 800-465-1234.
-
- Any of the regular DOS or Windows resources (e.g. books, magazines,
- shareware/freeware sources) will be useful since both environments come with
- OS/2 2.0.
-
- (taken from OS/2 General FAQ)
-
-
- Related Information:
-
- Developer's Assistance Program
-
-
- ΓòÉΓòÉΓòÉ 12.6. Developer's Assistance Program (DAP) ΓòÉΓòÉΓòÉ
-
- OS/2 2.0 developers should contact the IBM Developer Assistance Program (phone
- 407-982-6408); membership is free. (You may also join on CompuServe with GO
- OS2DAP.) The OS/2 Professional Developer's Kit CD-ROM, containing a wide
- selection of development tools and code, and the OS/2 2.1 Beta CD-ROM are both
- available from IBM (phone 800-3-IBM-OS2 to order in the United States for
- between $15 and $20 each, shipping included; in Canada, phone 800-465-1234; in
- Australia, phone Rohaini Cain or Mike Voris at 13-2426 ext. 7684; elsewhere,
- contact the International OS/2 User Group by phoning 285-641175 in the U.K.)
- The OS/2 Device Driver Development Kit CD-ROM is also now available from IBM.
- To order phone 407-982-4239 (FAX 407-982-4218) in North America, 61-2-354-7684
- (FAX 61-2-354-7766) in most of the Far East and Pacific Rim, 81-3-5563-5897
- (FAX 81-3-5563-4957) in Japan, 81-2-528-1548 (FAX 82-2-528-1414) in Korea, or
- 011-52-627-1846 (FAX 011-52-395-7812) in Latin America.
-
- (taken from the OS/2 general FAQ)
-
-
- ΓòÉΓòÉΓòÉ 13. OS/2 Software Sources ΓòÉΓòÉΓòÉ
-
- The following BBSes hold large OS/2 libraries:
-
-
- Name Number
-
- Fernwood (203) 483-0348
-
- OS/2 Shareware (703) 385-4325
-
- Bay Area OS/2 (510) 657-7948
-
- Gateway/2 (314) 554-9313
-
- Greater Chicago Online (708) 895-4042
-
- OS/2 San Diego (619) 558-9475
-
- OS/2 Las Vegas (702) 433-5535
-
- IBM Germany 049-711-785-777
-
- IBM Denmark 45-42-88-72-22
-
- OS/2 UK 0454-633197
-
- IBM UK 0256-336655
-
- IBM Norway 47-66-99-94-50
-
- OS/2 Norway 47-22-38-09-49
-
- OS/2 Australia 61-2-241-2466
-
- (The monthly Worldwide OS/2 BBS Listing, available from these BBSes, lists
- others.) The IBM PC Company BBS (modem 404-835-6600) has some
- shareware/freeware as well, along with CSDs and the PS/2 Assistant (an
- invaluable resource for locating almost any sort of information on OS/2). For
- information on IBM's new OS/2 BBS phone 800-547-1283. IBM Canada maintains
- several support BBSes:
-
- (416) 946-4255
- (514) 938-3022
- (604) 664-6464
- (416) 946-4244
-
- The Usenet conference comp.binaries.os2 carries OS/2 software. And several
- sites are available via anonymous ftp. (No ftp? Send a single line message
- with the word HELP to bitftp@pucc.bitnet or ftpmail@decwrl.dec.com to learn
- about ftp mail servers.) Some are (with Internet node numbers and
- subdirectories):
-
-
- Site IP Address Home OS/2 Directory
-
- cdrom.com ???.???.???.??? os2
-
- ftp-os2.nmsu.edu 128.123.35.151 pub/os2
- hobbes.nmsu.edu
-
- software.watson.ibm.com 129.34.139.5 pub/os2
-
- mtsg.ubc.ca 137.82.27.1 os2
-
- access.usask.ca 128.233.3.1 pub/archives/os2
-
- luga.latrobe.edu.au 131.172.2.2 pub/os2
-
- funic.funet.fi 128.214.6.100 pub/os2
-
- pdsoft.lancs.ac.uk 148.88.64.2 micros/ibmpc/os2
-
- ftp.uni-stuttgart.de 129.69.1.12 soft/os2
-
- src.doc.ic.ac.uk 146.169.2.1 computing/systems/os2
-
- zaphod.cs.uwindsor.ca 137.207.224.3 pub/local/os2
-
- ftp.luth.se 130.240.18.2 pub/pc/os2
-
- The cdrom.com library is available on CD-ROM from Walnut Creek (phone
- 510-947-5996). EMS (phone 301-924-3594) offers an OS/2 shareware/freeware
- library on diskette.
-
- Other sources include CompuServe (FIND OS/2) and archive servers (send a single
- line message with the word HELP to listserv@cc1.kuleuven.ac.be or
- mail-server@rus.uni-stuttgart.de for more information, or use ftp). TRICKLE
- servers are also available outside the United States. For more information on
- TRICKLE services, including automatic file subscription procedures, send a
- single line message with the word HELP to any one of the following sites
- nearest you:
-
- Country Address
- Austria TRICKLE@AWIWUW11.BITNET
- Belgium TRICKLE@BANUFS11.BITNET
- Colombia TRICKLE@UNALCOL.BITNET
- France TRICKLE@FRMOP11.BITNET
- Germany TRICKLE@DEARN.BITNET
- Israel TRICKLE@TAUNIVM.BITNET
- Italy TRICKLE@IMIPOLI.BITNET
- Netherlands TRICKLE@HEARN.BITNET
- Sweden TRICKLE@SEARN.BITNET
- Turkey TRICKLE@TREARN.BITNET
- TRICKLE@TRMETU.BITNET
-
- IBM has been releasing freely distributable employee written software (e.g.
- Visual REXX) and OS/2 patches to these sites.
-
- (The previous was taken almost verbatim from the OS/2 General FAQ)
-
-
- ΓòÉΓòÉΓòÉ 14. Bugs / Obtaining this FAQ / Contacting the Author ΓòÉΓòÉΓòÉ
-
- Reporting Bugs and Errors in the FAQ
-
- With the advent of all this nifty hypertext IPF stuff, there are bound to be
- bugs and errors in this FAQ, simply by Murphy's Law. (Anything that can go
- wrong, will go wrong) If you find an error, however, insignificant, please
- send me a note (through one of the ways listed below) telling me what's wrong
- with the FAQ.
-
- Obtaining this FAQ
-
- This FAQ is distributed on a regular basis to:
-
- 1. cdrom.com on the Internet
- 2. IBM PCC BBS in Atlanta, GA (404-835-6600) 14.4k V.32bis
- 3. Information Overload in Atlanta, GA (1:133/308 FidoNet) (404-471-1549)
- 19.2k ZyXEL V.32bis
-
- All other sites should receive this FAQ on a trickle-down basis from these
- sites.
-
- This FAQ is distributed in two versions, ASCII and INF. The INF version is
- binary and viewable only by the VIEW.EXE program that comes with OS/2. The
- filename is PFAQnnIN.ZIP, where 'nn' is the FAQ version. The ASCII version is
- text and is viewable by any program that can view text (which includes most
- word processors). The filename is PFAQnnAS.ZIP, where 'nn' is the FAQ version.
-
- Contacting the Author
-
- I can be contacted in a multitude of ways:
-
- o Internet. This is the preferred method. E-mail me at jgarzik@nyx.cs.du.edu.
- You may see me posting from one of my two Georgia Tech accounts,
- gtd543a@cc.gatech.edu and gtd543a@prism.gatech.edu. Don't be alarmed. I
- have my mail forwarded. I ask people to e-mail me at nyx because my account
- there is permanent. My account at GT is contingent on my staying at Tech. I
- lose it when I either get kicked out or graduate.
-
- o FidoNet. I check this one at least one or twice a week.
- Jeff Garzik@1:133/103 FidoNet. This account is contingent on my staying in
- Atlanta. Which I plan to for quite some time.
-
- o US Postal Service. This will stay while I am at Tech also.
-
- Jeff Garzik
- 25861 Georgia Tech Station
- Atlanta, GA 30332
-
- o Face to face. This is the toughest, because no one knows what I look like
- and most people reading this FAQ don't hang out at Tech for fun. (I know I
- wouldn't!) But the next time you are in Atlanta, GA, if you see a 6' guy
- with a goatee and a punk rock t-shirt, don't hesitate to ask if it's me...
-
-
- ΓòÉΓòÉΓòÉ 15. Credits ΓòÉΓòÉΓòÉ
-
- The following people have contributed in numerous and not-so-numerous ways to
- this document to make it what it is today, and what it will be tomorrow. Give
- a big round of applause for...
-
- o Barry Jaspan <bjaspan@athena.mit.edu>
- o Jeff Garzik <jgarzik@nyx.cs.du.edu>
- o Byers R E James <zoorejb@nusunix2.nus.sg>
- o Stefan Gruendal <Stefan_Gruendel@wue.maus.de>
- o Raja Thiagarajan <sthiagar@bronze.ucs.indiana.edu>
- o Larry Saloman <os2man@panix.com>
- o Timothy Sipples <sip1@ellis.uchicago.edu>
- o Bob Smith <OECN_SMITH@MEC.OHIO.GOV>
- o Tim Francis <francis@vnet.IBM.COM>
- o Colin Jensen <ljensen@netcom.com>
- o Bill Henning <bhenning@wimsey.com>
- o Axel Uhl <auhl@fzi.de>
- o R. Mahoney <rmahoney@bix.com>
- o Frank Fuchs <ffu@softpro.de>
-
- Ok, so the list is a little short right now. If you contributed to Barry's FAQ
- and you are not listed here, then please send me your name and I'll be glad to
- include you in this list.
-
- I have obtained some information from sources other than people also. Besides
- being credited above, here is another list:
-
- o OS/2 Frequently Asked Questions List v2.1 (Available from cdrom.com in
- os2/all/info/faq/faq21*.zip)
-
- o Electronic Developers' OS/2 Magazine (Available from cdrom.com in
- os2/all/info/edmi/*)
-