Index of Topics
- - A -
- Adding To WPI
- B -
- Bitmaps
- C -
- Colours
Converting Windows Applications
Coordinates and Rectangles
- D -
- Dialogs
Differences in Philosophies
- F -
- Fonts
- G -
- Graphics
- I -
- Instances and Anchor Blocks
- M -
- Menus
- O -
- Open Watcom Windows Programming Interface (WPI)
Other Platform Considerations
Owner-Drawn Controls
- P -
- Palettes
Pens and Brushes
PM Windows
Presentation Spaces and Device Contexts
- R -
- Resources
- U -
- Using WPI to Draw
- W -
- What is WPI?
Window APIs
Window Creation
Window Functions
Window Procedures
Open Watcom Windows Programming Interface (WPI)
Paul Fast, December 23, 1993
Open Watcom Windows Programming Interface (WPI) is a developers tool to aid in porting applications from Microsoft
Windows to IBM Presentation Manager (PM). The goal in the creation of WPI (pronounced wippee) is to supply programmers
with a set of macros and library routines which allow them to quickly convert an application which already exists in Windows
code to PM. It should be mentioned that this will not necessarily give a very efficient PM program; only a working
executable in short period of time. Using WPI also allows the developer the luxury of having only one copy of the source
instead of a Windows version and a PM version. The WPI interface has evolved only as functionality is required; future
projects may use Windows features which require additional enhancements to WPI.
WPI is explicitly designed to port Windows functionality to OS2/PM (not the other way around). Because of this,
converted projects may require additional system dependent code to take advantage of native OS/2 features (such as drag and
drop or notebooks in OS/2).
This document is intended to be used by developers porting applications from Windows to PM as an introduction to using
WPI. It notes situations which are similar to Windows code and some which are quite different from Windows code.
What is WPI?
WPI is a combination of macros and library routines. The WPI project is in ./bld/wpi and contains subdirectories
for source code, header files, and libraries. The header file wpi.h includes the type header file wpitypes.h and either
wpi_win.h or wpi_os2.h depending on the platform for which you wish to compile. The header files wpi_os2.h and wpi_win.h
contain the macros and prototypes for functions which correspond to Windows API calls when compiling under the Windows platform
and PM API calls when compiling for the OS2 platform. It should be noted that these files are not necessarily complete.
These files will constantly be modified and further macros will no doubt be added as their need arises. Therefore,
if a particular function is required by the developer and it does not already exist, it is the job of that developer to add
it to both wpi_win.h and wpi_os2.h. The source code for the library routines are in wpi_win.c and wpi_os2.c.
To distinguish between the Windows and PM platforms, the Open Watcom C compiler provides a __OS2_PM__ macro which
indicates that the program is being compiled for OS2 Presentation Manager. To separate Windows and PM code something
like the following is needed:
#ifdef __OS2_PM__
// PM code
#else
// Windows code
#endif
The file wpitypes.h contains the conversion of types from Windows to PM. There are some cases in which Windows
types have equivalent PM data types, such as HDC and HWND. These obviously are not redefined. In other cases,
a non existent equivalent can easily be added. For example the data type ULONG in PM is defined as unsigned long for
Windows in wpitypes.h. It should be noted that not all data type definitions are as neat and clean as this; however,
an attempt has been made to make this as invisible to the developer as possible.
The files wpi_win.h and wpi_win.c contain macros and routines which translate to Windows API calls under the Windows
platform and wpi_os2.h and wpi_os2.c translate to PM API calls under the PM platform. Some of these routine will have
the same parameter list as the Windows version of the API and others may appear drastically different than their Windows
counterpart. Many of the Windows APIs do not have corresponding PM APIs and in these cases, many lines of code are
required to mimick the Windows call. In cases where more than one line of code is required to convert the Windows code
to PM, the routines have been coded as library functions instead of macros. All WPI functions are prefixed by _wpi_
and contain no uppercase characters. Furthermore, an attempt has been made to keep the macro names as similar to the
Windows functions as possible. Hence, BeginPaint is called _wpi_beginpaint. In cases where the Windows API has
an exact equivalent in PM, the Windows function is defined as is for PM. For example, GetClientRect has an PM equivalent
of WinQueryWindowRect and hence GetClientRect has been defined as WinQueryWindowRect for PM. This means that some Windows
API names can remain the way they are. Even if an API has an exact equivalent and is defined that way for PM, it is
also defined in the form _wpi_functionname for both Windows and PM. It is up to the developer as to whether they wish
to use the Windows name or the WPI name.
Converting Windows Applications
The nature of the application will dictate the amount of code reusability available through WPI (and hence the usefulness
of WPI). If the application deals with elements that are similar on both the Windows and PM platform then perhaps the
developer can reuse 90% or more of their code. In cases where Windows and PM handle things quite differently, reuseability
may only reach 70-80%. The developer should determine places in their Windows application that may differ quite drastically
in PM such as file storage formats or window classes or messages. These will be the most difficult modules of code
to port.
The method the developer uses to port is really up to him or her. The most straightforward way is to (after
reading this document) choose a module in the applications code that is small or has relatively few major Windows/PM differences
and begin there. The file wpi.h will need to be included (it includes the other WPI header files) in every module that
uses WPI macros. Every function call that is a Windows API will need to be replaced with the equivalent _wpi_functionname
macro. The simplest way to determine which macro to use is to search for the API name in wpi.h. It should be
relatively easy to determine the name of the macro and whether or not the parameter list has changed. The OS2 Toolkit
contains on-line help which describes the PM APIs. This will also prove to be very useful since some macros may take
parameters that are required and only used in the PM calls.
The user may find it easier to have separate code for the initialization of their program. While Windows has
a WinMain key word, PM applications simply begin with the normal C main. Moreover, PM requires the user to initialize
the windows and create a message queue. Although _wpi_createwindow and _wpi_registerclass are provided in WPI, the
user may find the code to register and create windows different enough to warrant separate Windows and PM code. It
is safest to look at the WPI code to see if it performs as you wish.
One final word on converting code. Some applications have unique memory allocation functions they use in order
to track memory. Since WPI occassionally allocates memory, users may wish to use their own memory allocation and freeing
routines. They can do so by defining the symbol _wpi_malloc and _wpi_free to be their own routines. If they are
not defined, WPI sets them to the default of malloc and free. All memory allocations and frees are performed with _wpi_malloc
and _wpi_free (the exception is in _wpi_selectobject which uses alloca. This routine is discussed later).
Differences in Philosophies
Before beginning the PM conversion, you should become aquainted with a few differences between the philosophies of Windows
and PM. This document does not cover all of them; only the ones that pertain to WPI.
PM Windows
To begin with, windows are put together slightly differently. A typical Windows window has a title bar with a system
menu and application menu, border and a client area. These are all part of the window indicated by one HWND.
In PM, each of these components has its own HWND and all are considered to be children of the frame window HWND. Hence,
the client area has its own HWND as does the menu bar, the scroll bars, etc. Drawing in the client area should be done
by referencing the HWND of the client; however, visibility, destruction and menu operations need to reference the HWND of
the frame. To overcome some of these problems, the macros _wpi_getclient(hwnd) and _wpi_getframe(hwnd) have been defined
which do nothing in Windows and return the client window handle of the supplied frame handle and the frame handle of the
given client (respectively). Moreover, through WPI, HMENU has been defined as an HWND and routines have been created
which allow the user to use an HMENU as it is in Window.
Instances and Anchor Blocks
Windows programs have the concept of an instance which is required by some functions to differentiate between possibly
numerous instances of the program. PM does not have an instance identifier, however it does have an anchor block.
In WPI, instance handles and anchor blocks are associated in the data type WPI_INST. This type should be used instead
of the INSTANCE type for declaring INSTANCE variables in Windows. For PM, it is defined as a follows:
typedef struct {
HAB
hab;
HMODULE mod_handle;
} WPI_INST;
The hab is the anchor block that is required for many of the function like creating presentation spaces and registering
windows. The mod_handle field is required when working with DLLs. It is particularly required for loading accelerator
tables, menus and other resources. If you are not working with DLLs, you may simply set this field to NULL. PM
functions that require HABs will have macros that accept a WPI_INST and the hab field will be extracted from the structure.
The following routines handle the WPI_INST data type:
- _wpi_setwpiinst( hab, mod_handle, &wpi_instance )
-
Use this function to initialize a WPI_INST. For Windows set hab to the instance and set mod_handle to NULL.
_wpi_issameinst( inst1, inst2 )
-
This compares the two instances and returns whether or not they are the same.
_wpi_setmodhandle( name, inst )
-
This sets the module handle only, of a WPI_INST. This function does nothing in Windows.
_wpi_setanchorblock( hwnd, inst )
-
This sets the anchor block only, of a WPI_INST given a window handle. For Windows, this sets the instance.
Coordinates and Rectangles
Another major difference between Windows and PM is the coordinate system used for the desktop. In Windows the default
for the origin is the top left of the screen with the axes extending positively to the right and down. In PM, the origin
is the bottom left and the axes extend positively to the right and up. Therefore, the coordinates for Windows will
differ from that of PM. In fact, PM has a slightly different definition for their rectangle data type which also reflects
its coordinate origin. Where Windows has:
typedef struct {
int left;
int top;
int right;
int bottom;
} RECT;
PM has
typedef struct {
LONG xLeft;
LONG yBottom;
LONG xRight;
LONG yTop;
} RECTL;
Aside from the different type names the issues that needed resolving through WPI were the differences in field names
and the different types for the fields. The different structure field names make accessing individual fields in the
rectangle structure awkward and the different types of the fields once they are accessed is important to bear in mind.
WPI defines a data type WPI_RECT which is RECT in Windows and RECTL in PM. To get and set the values of the structure,
a call must be made to a routine (see below) supplying the rectangle structure and the values for the fields. A data
type called WPI_RECTDIM has been created which is the type of the fields of the structure. WPI_RECTDIM is defined as
LONG in PM and int in Windows. The following routines handle rectangles and assume that left, top, right, and bottom
are defined as WPI_RECTDIM:
- _wpi_setrectvalues(&r, left, top, right, bottom)
-
In Windows this simply sets the values of the fields. In PM this will set top to yBottom and bottom to yTop.
This function can be useful when you have Windows code which subtracts bottom from top to get window heights.
_wpi_setwrectvalues(&r, left, top, right, bottom)
-
This will set the values of the relative fields in both Windows and PM (ie no switching is performed between top and bottom).
_wpi_getrectvalues(r, &left, &top, &right, &bottom)
-
This will retrieve the values of the rectangle structure in Windows as expected and will assign the value of yBottom to
top and yTop to bottom. Again, this is because of the difference in the coordinate systems.
_wpi_getwrectvalues(r, &left, &top, &right, &bottom)
-
This will retrieve the values of the fields in both Windows and PM as expected (ie no switching is performed between top
and bottom).
Because some developers may wish to work strictly with the int data type, the following equivalent functions have been
created which do the same as the above routines, but accept as parameters int instead of WPI_RECTDIM:
- _wpi_setintrectvalues(&r, left, top, right, bottom)
-
_wpi_setintwrectvalues(&r, left, top, right, bottom)
-
_wpi_getintrectvalues(r, &left, &top, &right, &bottom)
-
_wpi_getintwrectvalues(r, &left, &top, &right, &bottom)
-
Using these macros will at first be annoying; however the need to have a WPI_RECT lies in the fact that many macros will
require a Windows RECT for the Windows API and a PM RECTL for the equivalent PM API. Hence, there is really no getting
around the matter. Note especially the difference between _wpi_setrectvalues and _wpi_setwrectvalues; and _wpi_getrectvalues
and _wpi_getwrectvalues. For Windows, top < bottom is normal for a rectangle. However, for PM bottom <
top is normal for a rectangle. Hence by switching the values of top and bottom in the assignment, we guarantee that
if top < bottom in Windows, then bottom < top in PM. It is recommended that coordinates that are saved be stored
in the windows format and then be converted to PM coordinates before displaying or drawing.
The WPI_RECT structure also has a sister WPI_POINT data type. This is defined as POINT in Windows and POINTL in
PM. This type should be used to replace the POINT structure in the Windows code. This will assure the user that
Windows APIs will use the POINT structure and PM ones, the POINTL structure. The fields of this structure are named
the same (x and y); however, the types for Windows are int and for PM, LONG. While there is a _wpi_setpoint macro in
WPI, it is not essential to use it because of the common field names.
In addition, the following routines work with rectangles, points and coordinates:
- _wpi_getwidthrect( r )
-
This will return the width of the rectangle.
_wpi_getheightrect( r )
-
This will return the height of the rectangle.
_wpi_cvth_y( y, height )
-
This will convert the value of y for a window in Windows coordinates to PM coordinates. Height is the height of
the window and the new value is returned.
_wpi_cvth_pt( &pt, height )
-
This converts the y value of a WPI_POINT in a window from Windows coordinates to PM coordinates. Height is the height
of the window.
_wpi_cvth_rect(&rect, height)
-
This converts the top and bottom values of a WPI_RECT from Windows coordinates to PM coordinates. Height is the
height of the window and is assumed to be a LONG.
_wpi_cvth_wanchor( y, window_cy, parent_cy )
-
This converts an anchor point (y) from Windows to PM coordinates. The anchor point is the coordinates at which a
window is displayed on the desk top (top left for Windows and bottom left for PM). All values are assumed to be LONG.
_wpi_cvts_y( y )
-
This converts a value relative to the desktop in Windows coordinates to that of PM. The new value is returned (ie.
same as _wpi_cvth_y except it is relative to the desktop).
_wpi_cvts_pt( &pt )
-
Same as _wpi_cvth_pt except that the point is assumed to be relative to the screen (desk top window).
_wpi_cvts_rect( &rect )
-
Same as _wpi_cvth_rect except that the values are assumed to be relative to the screen (desk top window).
_wpi_cvts_wanchor( y, window_cy )
-
Same as _wpi_cvth_wanchor except the anchor point is assumed to be relative to the screen (desk top window). Values
are expected to be LONG.
_wpi_cvtc_y( hwnd, y )
-
Same as _wpi_cvth_y except the routine only takes the window handle (it calculates the window height). The new value
is returned and y is expected to be LONG.
_wpi_cvtc_rect( hwnd, &rect )
-
Same as _wpi_cvth_rect except the routine calculates the window height itself.
The _wpi_cvt* macros are used for converting coordinates between the two target systems. For PM, calling the macros
once will convert the y values passed in from Windows coordinates to the equivalent PM coordinates. In some instances,
coordinates may be stored differently for the different platforms (for example when the coordinates are established by a
detection of a WM_MOUSEMOVE). Be sure the _wpi_cvt* routines are only used when the values will be in Windows coordinates.
For example, drawing a rectangle according to the coordinates determined from a WM_MOUSEMOVE would not warrant a _wpi_cvt*
call. For Windows, these macros do not alter the y values. The _wpi_cvt*_wanchor macros can be used to place
a window on the desktop. The point passed in can be in Windows coordinates and the macro will convert the point to
PM coordinates.
Presentation Spaces and Device Contexts
PM has the concept of a presentation space which can be used to display graphics. However, the presentation space
does not replace the notion of a device context, because PM also has device contexts. Since Windows does not have a
presentation space, a WPI_PRES has been introduced to allow the use of presentation spaces. For Windows, a WPI_PRES
is simply an HDC and for PM it is an HPS (presentation space handle). The equivalent of creating a memory device context
in Windows is to create a memory presentation space. In creating a compatible presentation space in PM, an HDC is required
and must be deleted. WPI handles this. Throughout this document the term presentation space (or pres) is used
and will refer to an HPS in PM and an HDC in Windows. Hence when phrases such as "drawing on a pres" arise,
it is implied that drawing is happening on an HPS in PM and an HDC in Windows. Moreover, a compatible pres corresponds
to a compatible HPS in PM and a compatible (memory) HDC in Windows. When HDC is refered to (unless specifically for
Windows) it will imply both HDC for Windows and HDC for PM.
The following are some common macros used with presentation spaces and device contexts:
- _wpi_getpres( hwnd )
-
This returns the presentation space associated with the window handle. For Windows this is simply GetDC. hwnd
can be HWND_DESKTOP (which is the same as NULL).
_wpi_releasepres( hwnd, pres )
-
This releases the presentation space associated with the given window. In Windows this is a ReleaseDC.
_wpi_createcompatiblepres( pres, hab, &hdc )
-
For PM this macro creates and returns a presentation space that is compatible with the one given. It also creates
a device context which is required when deleting the presentation space. For normal drawing, the hdc is not used.
For Windows this simply performs a CreateCompatibleDC.
_wpi_deletecompatiblepres( mempres, hdc )
-
This function deletes the presentation space and for PM, the device context handle.
Creating a compatible presentation space handle may appear a little confusing. First, recall that the Windows steps
to creating a compatible presentation space are as follows:
hdc = GetDC( hwnd );
...
memdc = CreateCompatibleDC( hdc );
/*
* Either draw on the memdc or the hdc
*/
...
ReleaseDC( hwnd, hdc );
...
DeleteDC( memdc );
...
When using WPI, a presentation space handle and a device context appear to be created. In Windows, the compatible
DC is returned by the routine and hdc is simply set to NULL (ie. it is not used). When deleting the compatible
pres in Windows, nothing happens to the hdc parameter since it has been set to NULLonly the compatible DC is deleted (stored
in mempres). In PM, the device context handle is only used when deleting the presentation space handle. Under
both platforms, the pres parameter passed into _wpi_createcompatiblepres must be valid and all drawing must take place on
the returned memory presentation space handle, or pres. The equivalent to the above example would be:
pres = _wpi_getpres( hwnd );
...
mempres = _wpi_createcompatiblepres( pres, Instance, &hdc );
/*
* Either draw on pres or mempres
*/
...
_wpi_releasepres( hwnd, pres );
...
_wpi_deletecompatiblepres( mempres, hdc );
...
Graphics
In Windows, the graphics interface is known as the GDI (Graphics Device Interface). The equivalent in PM is the
GPI (Graphical Programming Interface). The graphics interface includes objects such as pens, brushes, fonts, bitmaps,
palettes and presentation space attributes.
In PM as in Windows, each presentation space has its own set of attributes. When a presentation space is created,
it has a default set of attributes which are used unless they are specifically changed. Among these attributes are
line, area, image, and character attributes. Each of these attribute types has a corresponding structure which contains
fields to describe the type. PM provides APIs to change the values of the individual fields of the attributes.
Also, there is a GpiSetAttrs API in which the attribute type (line, area, etc.) must be specified and can be set.
Colours
There is a slight difference between colours in Windows and PM. In Windows, colours are usually referenced by a
COLORREF variable which contains an RGB value. Moreover, Windows APIs with a COLORREF parameter expect the variable
to be an RGB value. This is not necessarily the case in PM. In PM, a presentation space can either be in index
mode or RGB mode. If a presentation space is in RGB mode, all references are expected to be RGB values. However,
this is NOT the default mode. The default (index mode) implies that all references to colours are indices into a colour
table associated with the presentation space. When in index mode, all API references to colours are expected to contain
indices and when in RGB mode, all APIs expect RGB values. Attempting to use RGB values in index mode will produce unpredictable
results. Furthermore, PM will interpret index values as RGB values when in RGB mode.
Since the user is converting from Windows to PM, their Windows code will contain RGB colour values. Since RGB
is not the default mode, the user will need to switch to RGB mode whenever RGB colour values are used in a newly created
presentation space. The WPI macro _wpi_torgbmode(pres) will set the given presentation space to RGB mode. This
macro does nothing in Windows. A very easy mistake to make when converting code is to forget to set the presentation
space to RGB mode.
WPI defines COLORREF to be ULONG for PM which is how colours are stored in that environment. Hence, the user
can leave Windows COLORREF variables as COLORREF variables (alternatively, they can declare colour variables as WPI_COLOUR)
in their converted code. Moreover, the RGB macro used in Windows to create an RGB value is also available with WPI
in PM. Occurrences like: RGB(red, green, blue) need not change.
Pens and Brushes
Windows includes the data types HPEN and HBRUSH which PM does not. However, through WPI, HPEN and HBRUSH can be
used in PM. In order to create and use an HPEN or HBRUSH, WPI allocates memory for a structure which describes its
attributes. When selecting an HPEN or HBRUSH into a presentation space, space must be allocated to store the old pen
or brush and the attributes of the pen or brush being selected are set for the current pres. Upon deleting an HPEN
or HBRUSH, WPI frees the memory it has allocated. When a WPI routine returns (or accepts as a parameter) an HPEN or
HBRUSH, it is really returning an address to the object structure (this address has been defined as a WPI_HANDLE).
Creating a pen using WPI is the same as creating a pen in Windows. Certain attributes must be set such as the
pen type (solid or dashed), the pen thickness and the pen colour. The _wpi_createpen macro accepts the same parameters
as Windows' CreatePen and returns the newly created pen. The pen type should be specified using the Windows pen type
definitions (these are of the form PS_* and some types may not yet be converted in WPI). After allocating memory for
the object structure, the PM routine sets the field values of the structure as indicated by the parameters to the function
(the structure corresponding to an HPEN in PM is a LINEBUNDLE; however, this should be invisible to the user).
Similarly, brushes are created as they are in Windows. The _wpi_createsolidbrush, for example accepts the colour
of the solid brush and returns the brush being created. Again, the PM version of the function allocates memory for
the object structure and then sets the fields of the structure as indicated by the parameters to the function (the structure
corresponding to an HBRUSH in PM is an AREABUNDLE; again, this is invisible to the user).
Recall that both HPEN and HBRUSH are addresses of a object structures in PM. Hence when a pen or brush is created,
WPI allocates space for the structure before setting the fields of the structure and returning a pointer to the structure.
Naturally, when deleting an object WPI frees the memory associated with the object. Moreover, when selecting
an object into a presentation space, the normal Windows behaviour is to return the old object. So WPI needs to allocate
space for the old object and must know when to free that memory. To accomplish this, WPI uses alloca which allocates
enough space for the old object and the automatically frees the memory when the routine selecting the object is exited.
By employing this method, most Windows code is convertable by simply using the _wpi_selectobject routine. The drawback
to this method is that the old object returned from _wpi_selectobject cannot be a global variable. To accommodate this
problem, WPI also has the following routines:
- _wpi_selectpen( pres, hpen )
-
This routine selects the pen associated with hpen into the presentation space. Space for the old pen is allocated
and returned from the function. The old pen can be global if necessary.
_wpi_getoldpen( pres, holdpen )
-
This routine sets the presentation space attributes for the old pen and frees the memory associated with the old pen.
_wpi_selectbrush( pres, hbrush )
-
This routine is the same as _wpi_selectpen except for brushes.
_wpi_getoldbrush( pres, holdbrush )
-
This routine sets the presentation space attributes for the old brush and frees the memory associeated with the old brush.
The difference between _wpi_selectobject and _wpi_selectpen cannot be over-emphasized! The points to consider when
using _wpi_selectobject are:
it is more generic (the same function selects pens, brushes, bitmaps, old pens, old brushes etc...) and looks more like
windows code
the following code is possible because all old objects will be freed when myproc is exited:
void myproc( void ) {
oldpen = _wpi_selectobject( hpres, hpen1
);
...
_wpi_selectobject( hpres, hpen2 );
...
_wpi_selectobject( hpres, oldpen );
}
if the old object is a global variable, set in one routine and selected back into the pres in another routine, _wpi_selectobject
cannot be used because alloca will free the memory when exiting the routine in which the old object was created.
The points to consider when using _wpi_selectpen or _wpi_selectbrush are:
the old object returned from the select can be used as a global variable because the select does a normal allocate
(using _wpi_malloc) and the memory will not be freed until a _wpi_getold*
each _wpi_selectpen (or _wpi_selectbrush) must have a corresponding _wpi_getoldpen before the next _wpi_selectpen
for that presentation space handle; so the following code is not correct because memory for the second _wpi_selectpen will
never be freed:
void myproc( void ) {
oldpen = _wpi_selectpen( hpres, hpen1 );
...
_wpi_selectpen( hpres, hpen2 );
...
_wpi_getoldpen( hpres, oldpen );
}
One final note about selecting pens and brushes: the routines are not interchangable. So if a pen has
been selected with _wpi_selectobject the old pen should be selected with _wpi_selectobject, not with _wpi_getoldpen!
Similarly, selecting a pen with _wpi_selectpen necessitates _wpi_getoldpen to select the old pen back into the presentation
space.
Finally, deleting a pen or brush is similar to deleting the object in Windows. For PM, the WPI macro frees the
space associated with the pointer to the structure. The following WPI routines handle creating and deleting pens and
brushes:
- _wpi_createpen( type, width, colour )
-
In Windows, this creates a pen with the specified pen style (PS_*), width and colour. In PM this allocates space
for the object structure and sets the type, width and foreground colour for the pen. The pen is returned by the function.
_wpi_createnullpen( )
-
Creates and returns a NULL pen (ie. invisible pen). Windows version simply gets the NULL stock pen.
_wpi_createnullbrush( )
-
Creates and returns a NULL brush. Windows version simply gets the NULL stock brush.
_wpi_createsolidbrush( colour )
-
In Windows this returns a solid brush with colour colour. In PM this allocates space for the object structure and
sets the foreground colour for the brush.
_wpi_createpatternbrush( bitmap )
-
Returns a pattern brush using bitmap as the pattern.
_wpi_deletepen( pen )
-
In Windows this deletes the pen object. In PM this frees the memory associated with pen.
_wpi_deletebrush( brush )
-
In Windows this deletes the brush object. In PM this frees the memory associated with brush.
_wpi_deletenullpen( pen )
-
For PM this deletes the NULL pen. This does nothing in Windows.
_wpi_deletenullbrush( brush )
-
For PM this deletes the NULL brush. This does nothing in Windows.
_wpi_selectobject( pres, hobject )
-
This routine selects a pen, brush or bitmap into the presentation space. The PM version performs an alloca to allocate
space for the old object which is returned.
There may be more functions than are presented here. If the desired routine does not appear in this list, search
for it in wpi_os2.h and if it does not exist, add it. Here is a typical example of selecting pens and brushes into
a presentation space.
Windows code:
pen1 = CreatePen( PS_SOLID, 0, BLACK );
pen2 = CreatePen( PS_SOLID, 0, WHITE );
brush1 = CreateSolidBrush( RED );
...
oldpen = SelectObject( hdc, pen1 );
oldbrush = SelectObject( hdc, brush1 );
...
SelectObject( hdc, pen2 );
...
SelectObject( hdc, oldpen );
SelectObject( hdc, oldbrush );
DeleteObject( pen1 );
DeleteObject( pen2 );
DeleteObject( brush1 );
WPI code:
pen1 = _wpi_createpen( PS_SOLID, 0, BLACK );
pen2 = _wpi_createpen( PS_SOLID, 0, WHITE );
brush1 = _wpi_createsolidbrush( RED );
...
oldpen = _wpi_selectobject( pres, pen1 );
oldbrush = _wpi_selectobject( pres, brush1 );
...
_wpi_selectobject( pres, pen2 );
...
_wpi_selectobject( pres, oldpen );
_wpi_selectobject( pres, oldbrush );
_wpi_deletepen( pen1 );
_wpi_deletepen( pen2 );
_wpi_deletebrush( brush1 );
If the old objects are global:
pen1 = _wpi_createpen( PS_SOLID, 0, BLACK );
pen2 = _wpi_createpen( PS_SOLID, 0, WHITE );
brush1 = _wpi_createsolidbrush( RED );
...
Oldpen = _wpi_selectpen( pres, pen1 );
Oldbrush = _wpi_selectbrush( pres, brush1 );
...
_wpi_getoldpen( pres, Oldpen );
Oldpen = _wpi_selectpen( pres, pen2 );
...
_wpi_getoldpen( pres, Oldpen );
_wpi_getoldbrush( pres, Oldbrush );
_wpi_deletepen( pen1 );
_wpi_deletepen( pen2 );
_wpi_deletebrush( brush1 );
Notice that with a few exceptions, the code looks very similar to that of Windows. In general, pens and brushes
can be used the same way they are in Windows.
Bitmaps
The use of bitmaps is quite similar between Windows and PM. Although both platforms have an HBITMAP data type, WPI
stores bitmaps as object structures similar to HPENs and HBRUSHes. Hence when a bitmap is created and a handle returned,
the returned value should not be used for pure PM code, but only in WPI code. For example, the return value from _wpi_createcompatiblebitmap
is an address to a structure describing the bitmap (this address is defined as a WPI_HANDLE). This return value (the
WPI_HANDLE) can be passed to WPI functions expecting a bitmap handle, but the return value should not be used in PM specific
code (because the return value is a WPI_HANDLE and not an HBITMAP). The bitmap data types declared in WPI are as follows:
WPI Data Type Windows Data Type PM Data Type
------------- ----------------- ------------
WPI_HBITMAP HBITMAP
WPI_HANDLE
Like HPEN and HBRUSH, bitmaps can be selected into memory presentation spaces with the _wpi_selectobject routine and
the old bitmap will be allocated and returned from the routine. For example:
oldbitmap = _wpi_selectobject( mempres, hbitmap );
...
_wpi_selectobject( mempres, oldbitmap );
Again, if the old bitmap is used outside the routine selecting the bitmap into the space, _wpi_selectbitmap and _wpi_getoldbitmap
can be used. Note once again that each _wpi_selectbitmap must have a corresponding _wpi_getoldbitmap before another
bitmap can be selected into the presentation space. So if the old bitmap was global the code would look like:
Oldbitmap = _wpi_selectbitmap( mempres, hbitmap );
...
_wpi_getoldbitmap( mempres, Oldbitmap );
The following WPI routines handle bitmaps:
- _wpi_createcompatiblebitmap( pres, width, height )
-
This routine returns a bitmap compatible with the given presentation space (HDC for Windows) and having the specified
dimensions.
_wpi_createbitmap( width, height, planes, bitcount, &bits )
-
This routine returns a bitmap with the attributes given in the parameter list. Like Windows, if bits is NULL then
the bitmap is left uninitialized.
_wpi_deletebitmap(bmp)
-
Deletes the given bitmap. The bitmap must have been created by a WPI function.
_wpi_getbitmapbits( hbitmap, size, &bits )
-
Performs the same action as the Windows GetBitmapBits. The bitmap must be created by a WPI routine.
_wpi_setbitmapbits( hbitmap, size, &bits )
-
Performs the same action as the Windows SetBitmapBits. The bitmap must be created by a WPI routine.
_wpi_selectobject( hpres, hobj )
-
This will select the bitmap (or pen or brush) into the presentation space. For PM, the old bitmap gets space allocated
for it and is returned. It will be freed when the routine is exited.
_wpi_selectbitmap( hpres, hbitmap )
-
This will select the bitmap into the presentation space. In PM, space is allocated for the old bitmap handle (which
is return) and will not be freed until a call to _wpi_getoldbitmap.
_wpi_getoldbitmap( hpres, holdbitmap )
-
This will select the old bitmap into the presentation space. For PM this frees the memory associated with the old
bitmap.
This again, is merely a subset of the bitmap functions available in WPI. Many other Windows APIs have been converted
to WPI. If the desired function is not present in this list then search wpi_os2.h.
Mention should be made here of how monochrome bitmaps are converted to colour bitmaps. The user should read the
section on BitBlt (Windows) and GpiBitBlt (PM) to find out how the conversion is done for each platform. Unfortunately
Windows and PM perform in the opposite manner. Windows converts all white pixels (1's) in the monochrome bitmap to
the destination DC background colour and all black pixels (0's) in the monochrome bitmap to the destination DC foreground
colour. PM converts all white pixels to the destination presentation space foreground colour and black pixels to the
background colour. Hence in WPI, a macro called _wpi_preparemono can be used to prepare the destination background
and foreground colours to allow the user to copy a monochrome bitmap to a colour bitmap. The macro is used as follows:
_wpi_preparemono( destpres, black_pixel_colour, white_pixel_colour );
This will allow the user to set the presentation space to its proper colours for both platforms. The Windows
default DC attributes should be such that a monochrome bitmap copied to a colour bitmap will in fact be a colour bitmap appearing
the same as the monochrome bitmap. These default settings cannot be assumed for PM. Hence this macro should be
used whenever copying from a monochrome to a colour bitmap.
A few new types have been declared in wpitypes.h that relate to bitmaps. They are as follows and can be used
to pass to some of the macros that require different types for Windows and PM:
WPI Data Type Windows Data
Type PM Data Type
------------- -----------------
------------
WPI_BITMAP
BITMAP PM1632_BITMAPINFOHEADER2
WPI_BITMAPINFO BITMAPINFO
PM1632_BITMAPINFO2
WPI_BITMAPINFOHEADER BITMAPINFOHEADER PM1632_BITMAPINFOHEADER2
WPI_BMPBITS LPSTR
PBYTE
Since the bitmap structures for 16 bit PM are different than that for 32 bit PM, a file called pm1632.h handles the
differences (pm1632.h will be discussed later). There are also functions available to retrieve bitmap information:
- _wpi_getbitmapparms(hbitmap, &cx, &cy, &planes, &bitcount, &bitspixel)
-
Takes the bitmap handle and returns the information about the bitmap. NULL can be passed to any parameters not desired.
The bitspixel parameter will always be set to 0 in PM because that information is not available under PM.
_wpi_getbitmapstruct(hbitmap, &bitmap_info)
-
This routine fills the bitmap_info structure (should be type WPI_BITMAP) according to the attributes of the given bitmap
handle. This routine may be usefull when a structure is needed to pass to another WPI routine.
Using WPI to Draw
Once pens, brushes and bitmaps have been selected into their proper presentation spaces, drawing can begin. Many
of the Windows drawing functions have been converted in WPI to provide functionality for PM. While some of these routine
are quite similar to the Windows versions, others differ dramatically. The following is a list of some of these routines:
- _wpi_moveto(pres, &pt)
-
Moves to the point on pres indicated by pt.
_wpi_lineto(pres, &pt)
-
Draws a line from the current position to the indicated point.
_wpi_setpixel(pres, x, y, colour)
-
Performs the same as the Windows SetPixel routine.
_wpi_getpixel(pres, x, y)
-
Performs the same as the Windows GetPixel.
_wpi_rectangle(pres, left, top, right, bottom)
-
Draws a rectangle. Note that top is both top in Windows and PM (ie not bottom in PM). Hence _wpi_cvt* macros
may prove useful before using this macro.
_wpi_ellipse(pres, left, top, right, bottom)
-
Draws an ellipse inside the box implied by the dimensions. Note again that top < bottom for Windows and top >
bottom for PM is assumed.
_wpi_arc(pres, x1, y1, x2, y2, x3, y3, x4, y4)
-
Draws an arc (as it does in Windows) defined by the given points.
_wpi_bitblt(dest, x1, y1, cx, cy, src, x2, y2, rop)
-
Identical to Windows BitBlt. PM version assumes (x1, y1) is actually the bottom left corner of the area and uses
Windows predefined ROP codes.
_wpi_patblt(dest, x1, y1, cx, cy, rop)
-
Identical to Windows PatBlt. Same comments as _wpi_bitblt.
_wpi_stretchblt(dest, x1, y1, cx1, cy1, src, x2, y2, cx2, cy2, rop)
-
Identical to Windows StretchBlt. Same comments as _wpi_bitblt.
Note the difference in the first two routines listed. They take a WPI_POINT instead of x and y values. It
should also be emphasized that the rectangle and ellipse macros for PM expect top > bottom. This is important because
of the way PM draws these images. Windows draws up to but not including the right and bottom coordinates. PM
actually includes the right and bottom coordinates. WPI attempts to handle this difference and in so doing, requires
that top actually be the top. Note the difference between the Windows code and converted code in this example:
Windows Code:
Rectangle( hdc, 10, 0, 100, 50 );
WPI Code:
top = 0;
bottom = 50;
// Assume height has been set to the height of pres
top = _wpi_cvth_y( 0, height );
bottom = _wpi_cvth_y( 50, height );
_wpi_rectangle( pres, 10, top, 100, bottom );
The user will be required to add the conversion of the height (depending on the circumstances) in order to assure
that top > bottom. Currently, ellipses are not drawn very accurately in PM. This is due to the way in which
PM draws ellipses. The most trouble occurs when the dimensions of the bounding rectangle of the ellipse contain even
values. Work is underway to rectify this problem.
Since the blt functions take only an origin and then the width and height, the origin is assumed to be in PM format
for PM and Windows format for Windows. This is particularly useful in copying bitmaps since the origin (0, 0) can be
used under both platforms.
Palettes
Currently, WPI does not support many palette operations. The macro _wpi_selectpalette(pres, hpal) will select a
palette into the given presentation space. Moreover, the data type HPALETTE in PM is defined to be HPAL. If the
code being converted contains references to palettes, expect to make additions to WPI.
Fonts
Fonts can be complicated objects to deal with in PM. PM does not have an HFONT data type nor a LOGFONT data type.
The font data types declared in WPI are as follows:
WPI Data Type Windows Data Type PM Data Type
------------- ----------------- ------------
HFONT HFONT
LONG
WPI_FONT HFONTF
ATTRS*
WPI_LOGFONT LOGFONT
FONTMETRICS
WPI_TEXTMETRIC TEXTMETRIC FONTMETRICS
In Windows, one can create a font and once a font handle is acquired, use that font handle as a parameter (or any
other kind of variable) to be selected into a device context for text output. However, creating a font in PM requires
a presentation space and once that presentation space is released, the created font is gone. So, a division arises
between the two cases. When a font is desired and a presentation space exists, the following macros can be used:
- _wpi_createfont(pres, &wlfont, &hfont)
-
For Windows this is the same as CreateFontIndirect with wlfont as the logfont. The font handle is returned in hfont.
For PM this creates a font from the specifed WPI_LOGFONT and returns the font handle (the value: 1) in hfont.
The font can only be used in the given presentation space.
_wpi_getdeffm(wlfont)
-
Sets the WPI_LOGFONT to its default values.
_wpi_deletefont(hfont)
-
Deletes the font for Windows and resets the font identifier for PM.
_wpi_getsystemfont()
-
Returns the system font for Windows and the default font identifier for PM.
_wpi_selectfont(pres, hfont, &oldfont)
-
Selects the given font into the given presentation space.
_wpi_getoldfont(pres, oldfont)
-
Selects the old font into the given presentation space.
In addition to these macros, there are macros to set the font to italics, bold, strikeout, and more. Moreover, macros
exist to set the font height, width and pointsize. Due to the number of macros available, they are not all listed here.
To find the proper macro, search for _wpi_setfont in wpi_os2.h until the required macro has been found.
All of the above macros work with the HFONT data type. They all assume that text output will occur with the presentation
space used in the macro calls. However, there may be situations in which the user wishes to create a font and use it
with a presentation space created at a later time. This is the purpose of the WPI_FONT data type. The following
macros handle WPI_FONTs:
- _wpi_createwpifont(&wlfont, wfont)
-
Creates a WPI_FONT. For Windows, this is the same as a normal font creation.
_wpi_selectwpifont(pres, wfont)
-
Windows version selects the font into the DC. PM allocates memory for the old font and sets the font of the given
pres to be that of wfont.
_wpi_getoldwpifont(pres, oldfont)
-
Restores the font of pres to be the old font and frees the old font memory.
_wpi_deletewpifont(wfont)
-
Deletes the font associated with wfont.
A WPI_FONT for PM is actually a pointer. The creation macro allocates space for the structure on the PM platform
and the deletion frees the space. As with pens and brushes, selecting the font into the presentation space allocates
space for the old font structure so it is essential that the old font be selected back into the presentation space to free
the memory associated with it. A quick look at _wpi_selectwpifont for PM will show that the font is actually being
created in this routine. This is because the font is always tied to the presentation space. Once again, before
calling the creation macro, the user may use the _wpi_setfont* macros to set the attributes of the desired font.
Window Functions
There are some similarities between Windows window procedures and PM window procedures and hence converting these is relatively
straightforward. The format and main philosophy of windows procedures is the same on both platforms and much is accomplished
by simply defining a new set of types or function names.
Window APIs
Since many of the windows related functions differ only in name between the two platforms, WPI allows the user to use
the Windows name when calling the API. The following is a list of some of the window related macros and the names available
to the user:
DefWindowProc(hwnd, msg, wp, lp) _wpi_defwindowproc(hwnd, msg, wp,
lp)
Takes default window procedure action.
ShowWindow(hwnd, state)
_wpi_showwindow(hwnd, state)
Shows the window according the given state. Windows predefined states are used.
GetClientRect(hwnd, &wrect) _wpi_getclientrect(hwnd,
&wrect)
Gets the rectangle dimensions of the given window. The function fills the WPI_RECT variable.
DestroyWindow(hwnd)
_wpi_destroywindow(hwnd)
Destroys the given window.
SetWindowText(hwnd, str)
_wpi_setwindowtext(hwnd, str)
Sets the caption of the given window.
MessageBox(hpar, txt, title, style) _wpi_messagebox(hpar, txt, title, style)
Displays a message box as it does in Windows. Most of the MB_* styles have been converted, using the Windows
naming convention.
GetMenu(hwnd)
_wpi_getmenu(hwnd)
Gets the menu of the window. For PM this window handle must be a frame window.
The user may decide whether or not to keep the Windows names or use the available WPI names.
Window Creation
Window creation is somewhat different in PM than Windows. The user may wish to use separate PM code from their Windows
code in order to gain clarity and the flexibility when creating windows. In WPI however, an attempt has been made to
convert the window creation routines. The two main macros are _wpi_registerclass and _wpi_createwindow. The _wpi_createwindow
routine may prove useful for creating a standard window style, however it is limiting in some areas including the fact that
it will not allow initialization data to be passed in the WM_CREATE message. The user should examine this routine to
verify its usefulness for the situation at hand.
Window Procedures
Window procedures are also similar in both Windows and PM. Under the WPI scheme, windows functions should be declared
as follows:
MRESULT CALLBACK WindowsProc( HWND hwnd,
WPI_MSG msg,
WPI_PARAM1 wparam,
WPI_PARAM2 lparam );
Most of the messages are similar in name and where they differ, the Windows convention has been used. The user
should note that messages such as WM_MOUSEMOVE that store coordinates will store the coordinates according to the platform
under which they are running (ie Windows will return the mouse coordinates with the top left as the origin and PM with the
bottom left as the origin).
When creating windows, PM does not specify the background colour of the window. This suggests that no default
painting goes on when a PM window procedure receives a WM_PAINT. The user may be required to add the following to their
WM_PAINT messages:
case WM_PAINT:
_wpi_beginpaint( hps, NULL, &wrect );
...
#ifdef __OS2_PM__
WinFillRect( hps, wrect, background_clr );
#endif
...
_wpi_endpaint( hwnd, pres, &wrect );
Resources
Open Watcom has its own resource compiler, so Open Watcom does not require the use of the OS2 toolkit resource compiler.
RC files in PM look similar to those of Windows. The user should look at the PM help files or an available example
in order to convert their RC files.
Dialogs
Dialogs, like other windows have some definite similarities between Windows and PM. Because of these similarities,
a program has been created to transform Microsoft Dialog Editor DLG files to PM DLG files. This program is called parsedlg.exe
and can be found in r:\cmds. To use this program simply type:
parsedlg infile.dlg outfile.dlg
The user will need to compile their PM application with the newly parsed DLG file. Note that this new dialog
should look the same as the Windows dialog. The user does not need to convert any coordinates. One should also
note that in Windows a dialog can either be referenced by either a unique string name or a unique integer (this gets passed
into the DialogBox API). In PM however, a dialog box can be referenced only by a unique integer. If a string
is currently used, the user will need to change this to an integer.
Once the dialog file is parsed, the user can convert the code generating the dialog procedure. Initializing
a dialog box procedure would look like the following under WPI:
fp = _wpi_makedlgprocinstance( DlgProc, Instance );
ret_val = _wpi_dialogbox( hparent, fp, Instance, DLG_ID, 0L );
_wpi_freedlgprocinstance( fp );
The dialog procedure itself looks much like a Windows dialog procedure excluding the WPI conversion names:
DLG_RESULT CALLBACK DlgProc( HWND hwnd,
WPI_MSG msg,
WPI_PARAM1 wparam,
WPI_PARAM2 lparam );
The user may continue to use the constants IDOK and IDCANCEL since they are defined in WPI to be consistent with the
constants used by the parsedlg.exe program. Unique to PM is the use of a default dialog procedure. Where Windows
usually returns FALSE, PM returns WinDefDlgProc with the same parameters as the procedure from which it is returned.
Hence the user will want to return _wpi_defdlgproc(hwnd, msg, wparam, lparam) for unprocessed dialog messages. This
will simply return FALSE for Windows.
The following is an example of a dialog procedure for which there are a number of tricky points between Windows and
PM. This is done to illustrate some of the differences between Windows and PM as well as where to spot trouble.
WPI_DLGRESULT CALLBACK dlg_sample( HWND dlg_hld,
WPI_MSG
msg,
WPI_PARAM1
parm1,
WPI_PARAM2
parm2 )
{
int
initial_col;
int
tmp;
if( msg == WM_INITDIALOG ) {
/* PM expects a pointer to the data
*/
/* while Windows just expects the data */
#ifdef __OS2_PM__
{
int
*ptr;
ptr = (int *) parm2;
initial_col = *ptr;
}
#else
initial_col = parm2;
#endif
return( (WPI_DLGRESULT) TRUE );
/* The following line is necessary because
for PM */
/* because some messages which are caught
under */
/* WM_COMMAND in PM are not in Windows and
vice */
/* versa. Hence, use this routine to
trap the */
/* WM_COMMAND message.
*/
} else if( _wpi_dlg_command( dlg_hld, &msg, &parm1, &parm2
) ) {
if( _wpi_getid( parm1 ) == IDOK ) {
_wpi_enddialog( dlg_hld,
TRUE );
return( (WPI_DLGRESULT)
TRUE );
} else if( _wpi_getid( parm1 ) == IDCANCEL
) {
_wpi_enddialog( dlg_hld,
FALSE );
return( (WPI_DLGRESULT)
TRUE );
} else if( _wpi_isbuttoncode( parm1,
parm2, LBN_SELCHANGE ) &&
_wpi_getid( parm1 ) == DLG_SAMPLE_BUTTON )
{
/* Many messages
in PM pack the information */
/* in different places
than in Windows */
/* hence the need
for _wpi_getid, and new */
/* parameters for
the following messages */
/* cf. _wpi_getdlgitemlbtext
etc. as well */
tmp = (int) _wpi_senddlgitemmessage(
dlg_hld,
DLG_GPCMN_GROUP, LB_GETCURSEL, LIT_FIRST, NULL );
_wpi_senddlgitemmessage(
dlg_hld, DLG_GPCMN_GROUP,
LB_SETCURSEL, initial_col, LIT_SELECT );
initial_col =
tmp;
}
} else {
return( _wpi_defdlgproc( dlg_hld, msg, parm1,
parm2 ) );
}
return( (WPI_DLGRESULT) FALSE );
}
.
.
.
/* PM expects a pointer to the data */
/* while Windows just expects the data */
#ifdef __OS2_PM__
dlg_ret = _wpi_dialogbox( frame_win_hld,
proc, Inst, tpl, &id );
#else
dlg_ret = _wpi_dialogbox( frame_win_hld,
proc, Inst, tpl, id );
#endif
.
.
.
Owner-Drawn Controls
This section covers only buttons and listboxes since menus have not been researched or tested. There is some fully
functioning code in the datactl library (cf. Dan Pronovost).
To begin with, owner-drawn buttons get drawn by responding to a WM_CONTROL (WM_DLGCOMMAND) message while everything
else should respond to a WM_DRAWITEM message. The following section of code illustrates how to determine what type
to draw:
...
_wpi_getcursorpos( &q_pt );
_wpi_setanchorblock( hwnd, inst );
time = _wpi_getcurrenttime( inst );
_wpi_setqmsgvalues( &qmsg, hwnd, msg, parm1, parm2, time, q_pt
);
/*
* make absolutely sure that any buttons handle the WM_QUERYDLGCODE
* message and return DLGC_BUTTON
*/
is_button = ((int)_wpi_sendmessage(hwnd, WM_QUERYDLGCODE, &qmsg,
0L)
& DLGC_BUTTON);
is_button = is_button &&
( SHORT2FROMMP( parm1 ) == BN_PAINT ) &&
( msg == WM_DLGCOMMAND );
if( is_button ) {
.
.
< draw the button >
.
.
} else if( msg == WM_DRAWITEM ) {
.
.
< draw the listbox >
.
.
}
.
.
Buttons are sent a USERBUTTON structure in the second parameter. The following section of code illustrates how
to obtain information from this structure:
.
.
USERBUTTON
*b2;
b2 = (USERBUTTON *) parm2;
win_hld = b2->hwnd;
pres = b2->hps;
id = SHORT1FROMMP( parm1 );
tmp_word = LOWORD( b2->fsState );
disabled = ( tmp_word == BDS_DISABLED );
selected = ( tmp_word == BDS_HILITED );
tmp_word = LOWORD( b2->fsStateOld );
old_selected = ( tmp_word == BDS_HILITED
);
select_changed = ( selected == old_selected
);
has_focus = ( GetFocus() == win_hld );
_wpi_getclientrect( win_hld, &rect );
.
.
< draw the button based on above information
>
.
.
// tells the system you did the highlighting
b2->fsStateOld = b2->fsState;
// tells the system you drew the item
to_ret = (WPI_DLGRESULT) TRUE;
.
.
Listboxes are sent an OWNERITEM structure in the second parameter. The following section of code illustrates
how to obtain information from this structure:
.
.
poi = (OWNERITEM *) parm2;
win_hld = poi->hwnd;
pres = poi->hps;
id = poi->idItem;
rect = poi->rclItem;
disabled = !WinIsControlEnabled( win_hld,
id );
selected = poi->fsState;
focus_changed = !( poi->fsState == poi->fsStateOld
);
select_changed = !focus_changed;
.
.
< draw the listbox based on above information
>
.
.
// tells the system you did the highlighting
poi->fsState = poi->fsStateOld = 0;
// tells the system you drew the item
to_ret = (WPI_DLGRESULT) TRUE;
.
.
Menus are handled in the WM_DRAWITEM message, similar to listboxes, and also use the OWNERITEM structure but take advantage
of the attribute and old attribute fields (MIA_). The following routines handle menu operations:
- _wpi_getmenu( hwnd )
-
This returns the handle of the menu. Note that for PM, hwnd must be a frame window handle.
_wpi_getcurrentsysmenu( hwnd )
-
Returns the current system menu for the given frame window handle.
_wpi_checkmenuitem( hmenu, id, fchecked, fby_pos )
-
This checks a menu item identified by id. The fchecked variable should be either TRUE or FALSE (whether the item
should be checked or unchecked) and by_pos indicates whether the id indicates the position (TRUE) or the actual identifier.
_wpi_enablemenuitem( hmenu, id, fenabled, fby_pos )
-
Similar to _wpi_checkmenuitem except it indicates whether the item should be enabled (TRUE) or grayed (FALSE).
Once again, this is only a subset of the available menu functions.
There is a good possibility that the Windows program being converted to PM has already been converted to 32 or 64 bit
Windows (or will be converted to 32 or 64 bit Windows). Furthermore, there is the possibility that a PM application
is desired for both 16 and 32 bit platforms. These can produce somewhat precarious situations; however, there should
not be too many problems if the user is careful. To begin with, wpitypes.h includes wi163264.h if compiling for Windows
and pm1632.h if compiling for PM. These header files contain macros which translate between 16 and 32 and 64 bit Windows;
and 16 and 32 bit PM.
Where possible, if adding to WPI the user should be certain that the Windows version will be compatible with wi163264.h
and the PM version with pm1632.h. This means for example, that it may be appropriate for a WPI macro on the Windows
side to refer to another macro defined in wi163264.h.
Adding To WPI
A few considerations should be made when modifying WPI.
Note first of all that all references to malloc should use the _wpi_malloc symbol since the user may decide to define
their own memory allocating routine.
Remember that if a routine is changing there could be several parties affected by the change.
When adding routines, be sure to consider how the code may affect 32 or 64 bit Windows or may be different for 16
and 32 bit PM. Be sure to check wi163264.h and pm1632.h to make sure one of the contained macros is not needed.
It is best after adding a routine to WPI to create the library for all of 16 and 32 and 64 bit Windows, and 16 bit PM, and
32 bit PM, even if you are not using all levels.
One should be certain when adding macros to WPI that no size values are hard coded. Whenever possible the sizeof
operator should be used since structures may be different sizes in 16 and 32 and 64 bit Windows; and 16 and 32 bit PM.
When using macros be generous in the use of parentheses. Bracket pointers and structures in case expressions
are passed to the macros. In general, if the macro requires more than 1 line of code or if the routine needs to return
a value, add the routine to the library.