PreviousPresentation Manager Applications (16-bit) Microsoft Windows ApplicationsNext"

Chapter 15: Presentation Manager Applications (32-bit)

This chapter explains how to create OS/2 Presentation Manager applications using the 32-bit COBOL system for OS/2 V2. It assumes you have a basic knowledge of the concepts involved in writing a Presentation Manager program.

This chapter assumes you are using the 32-bit Presentation Manager API available with OS/2 V2 and later. For details on the 16-bit Presentation Manager API see the chapter Presentation Manager Applications (16-bit).

15.1 Writing Presentation Manager Applications

Presentation Manager (PM) is a graphical user interface (GUI) for OS/2 which provides functions for creating windowed applications. Presentation Manager implements the Common User Access (CUA) user interface standard, allowing you to create applications with a common style of interface.

Micro Focus offers three approaches to 32-bit Presentation Manager programming in COBOL:

The chapter Comparison of Methods for Creating User Interfaces explains the advantages and disadvantages of each approach. The remainder of this chapter describes how to create applications that use the Presentation Manager API.

15.1.1 Requirements

In addition to the 32-bit COBOL system, you need the OS/2 Programmer's Toolkit available from your operating system supplier. This software package includes the Dialog Editor, Icon Editor, and Resource Compiler, as well as the C header files that contain the type information and constants used by the OS/2 API functions.

The Resource Compiler converts menu definitions, icon declarations, accelerator tables, and other structures from readable ASCII files to a binary format which can be incorporated in an .exe or .dll module. The editors enable you to paint dialog boxes, icons and fonts.

Your OS/2 Programmer's Reference describes the OS/2 API functions used by Presentation Manager applications. However, the function descriptions and examples in the OS/2 Programmer's Reference are in C. This chapter explains those descriptions for programmers unfamiliar with C and describes how to translate them into COBOL. This COBOL system includes the H2cpy utility, which allows you to translate #define and typedef information in the C header files into their COBOL equivalents. See the chapter Header-to-COPY Utility in your Programmer's Guide to Writing Programs for details about converting C header files with H2cpy.

This system includes two sample Presentation Manager programs, Pmhello and Pmcalc2. These are used as examples in this chapter.

15.1.2 Programming for Presentation Manager

OS/2 offers Presentation Manager as a graphical user interface to applications in a multitasking environment. An application running under Presentation Manager shares the display with other tasks by using windows, which it creates for interaction with the user. Presentation Manager manages the screen, so an application does not have to worry about other windows on the screen.

In a traditional environment, the program accepts user input in a predetermined order. This is called procedural logic. In a windowed environment, applications respond to user input events as they occur. This is called message-based or event-driven logic. For example, a window event such as a mouse click can occur at any time; the application must respond to that event immediately.

Presentation Manager puts information from the mouse and keyboard in a standard format called a message. These messages are stored in a queue until they are retrieved by the application - there is a separate queue for each application. Each message in the queue contains information identifying the window that received the message, the message event itself (for example "left button pressed" or "Escape key pressed") and any other applicable information.

Such event driven programming is an integral part of Presentation Manager object oriented programming where events are called messages and recipients of messages are called objects. Examples of Presentation Manager objects are windows, dialog boxes and menus.

A Presentation Manager application must create a message queue and implement a message loop. This loop retrieves messages from the message queue and dispatches them to the message handler (called a Window Procedure or WinProc for short) for the window receiving the message.

Each WinProc implements a window class. Many instances of each window class (or type) can be created, but they all share the same WinProc. Window classes are given a name and must be registered with the Presentation Manager subsystem before they can be used.

15.1.3 Using the Systems Programming Extensions

Extensions have been added to the COBOL syntax to enable the systems programming facilities required to program application programming interfaces like Presentation Manager application programming interface (API). These extensions are grouped under the name Systems Programming Extensions.

The Systems Programming Extensions include:

All of these are described fully in your Language Reference. Examples of their use are given in this chapter.

15.1.3.1 Calling the OS/2 V2 API

The OS/2 V2 API uses the system parameter-passing convention. This means that:

This convention is the same as that used by this COBOL system, so you do not need to use the CALL-CONVENTION clause when accessing the OS/2 V2 API.

15.1.3.2 Passing Parameters by Value

By default, the parameters passed by a COBOL CALL statement are address references, using the address of the parameters in memory. Presentation Manager requires some parameters to be passed by value. The example below shows how to do this.

Remember to specify the size in bytes using the SIZE clause with numeric literals. If you do not specify the SIZE clause, a size of four is assumed.

Example

     call "myprog" using by reference param-1 
                         by value     param-2 
                         by value     27 size 2

15.1.3.3 Return Values

The mechanisms for returning values from a WinProc, and receiving values returned from an API routine are explained in the following sections.

15.1.3.3.1 Receiving Values Returned from API Routines

The RETURNING phrase of a CALL statement stores a value returned by an OS/2 API function.

Example

     call "WinInitialize"
              using by value 0 size 4
              returning hab

This stores the result returned by the API function WinInitialize in the data item hab. Presentation Manager calls return either a two byte or four byte value.

15.1.3.3.2 Returning a Value from a Window Procedure

A Presentation Manager WinProc often needs to return a value to the function that called it. In COBOL, use the RETURNING phrase on the EXIT PROGRAM statement:

Example

     exit program returning mresult

15.1.3.4 Procedure Pointers

A data item declared as PROCEDURE-POINTER passes the address of a WinProc to Presentation Manager so that it can call that procedure with messages for the window.

Example

     03 WndProc       usage procedure-pointer.
        . . .
        . . .
 entry "WndProc"   using by value hwnd
     set WndProc to entry "WndProc"
     call 'WinRegisterClass'
              using by value     hab
                    by reference MyClass
                    by value     WndProc
                    by value     CSClass
                    by value     0 size 4
              returning my-refum-value. 

15.1.3.5 Recursion and the Local-Storage Section

Since a Presentation Manager program can process a new event before the processing of a prior event is complete, recursion is required. That is, a program must be able to call itself. It is important that the processing of data should not hold up the handling of events.

Example

Support for recursion enables you to write a message loop as follows:

     perform until loop-end
         call "WinGetMsg" using ...
         call "WinDispatchMsg" using ...
     end-perform
15.1.3.5.1 Local Data for Recursion

By default, all COBOL variables are global ; that is, any variable defined in the Working-Storage Section can be referenced from any other section of the program.

Since Presentation Manager can call an entry point several times, the local data from one call needs to be protected from another call entering the same code. You can create variables that are local to a particular invocation of a procedure; these variables can be referenced only within that procedure. These variables are created on the stack when a procedure using them is called, then discarded when the procedure terminates. You define these variables in the Local-Storage Section.

Use local variables when writing recursive procedures (see your Programmer's Guide to Writing Programs). If you use global variables in a recursive procedure, each new procedure invocation references the same storage location for a particular variable-name, overwriting information that should be unique to that invocation. The Local-Storage Section eliminates this problem by creating an individual set of procedure variables for each invocation.

Indirect recursion occurs when a procedure invokes Presentation Manager, which in turn calls that procedure. Although it is indirect, this recursion can still overwrite variables that should remain distinct for each invocation. Therefore, unless you are certain that a variable in a Presentation Manager program is truly global and will not change between invocations of a procedure, you should declare it in the Local-Storage Section.

Example

This section of code illustrates the use of the Local-Storage Section:

 working-storage section. 
 ...
 local-storage section.
 01 hps                pointer.
 01 rcl.
     03 xleft          pic x(4) comp-5.
     03 xbottom        pic x(4) comp-5.
     03 xright         pic x(4) comp-5.
     03 xtop           pic x(4) comp-5.
 01 mresult            pic x(4) comp-5.
 linkage section.
 01 hwnd               pic x(4) comp-5.
 01 msg                pic x(4) comp-5.
 01 mp1                pic x(4) comp-5.
 01 mp2                pic x(4) comp-5.
 procedure division. 
 main-control section. 
 entry "ClientWndProc" using by value hwnd
                             by value msg
                             by value mp1
                             by value mp2.
    ...

15.2 Structuring a Presentation Manager Program

All Presentation Manager programs must perform the same basic steps:

15.2.1 Initializing Presentation Manager

The first action in your Presentation Manager application is to call the WinInitialize function. Calling this function declares that this program or thread is going to use Presentation Manager. WinInitialize returns the handle of an anchor block (hab ). The anchor block handle is a value that identifies the application to Presentation Manager.

     call 'WinInitialize'
              using by value 0 size 4
              returning hab.

In this example, the first parameter passed to the function is an initialization option and must be set to 0. The returned parameter, hab, is the handle to the anchor block for the application.

15.2.2 Creating a Message Queue

The next step in your program is to set up a message queue for this thread. The message queue receives messages sent to all of the windows which were created by the current program or thread. Your application must create a message queue before it can create a window. The returned parameter, hmq , is the handle to the message queue. This message queue handle is saved so it can later be passed to the function that terminates the message queue.

     call 'WinCreateMsgQueue'
              using by value hab
                    by value 0 size 4
              returning hmq

15.2.3 Registering a Window Class

Next your program calls WinRegisterClass to create a window class. Every window that is created under Presentation Manager must belong to a window class. The window class defines a WinProc and other information, such as default window styles.

     set WndProc to entry 'WndProc'
     call 'WinRegisterClass'
         using by value       hab
               by reference   MyClass
               by value       WndProc
               by value       CSClass
               by value       0     size 4
         returning bool

15.2.4 Creating a Window

After you have created the window class you can create a window. A Presentation Manager window is the main method of interacting with the user.

Your program creates a standard window by calling the WinCreateWindow or the WinCreateStdWindow function:

     call 'WinCreateStdWindow'
         using by value        Hwnd-Desktop size 4
               by value        WSWindow
               by reference    ctldata
               by reference    Myclass
               by reference    'mytitle' & x'00'
               by value        0     size 4
               by value        0     size 4
               by value        0     size 4
               by reference    hwndClient
         returning hwndFrame

15.2.5 Processing the Message Loop

Presentation Manager sends many messages to each window to convey important information and to inform them of a wide variety of events. To receive these, your application includes a message loop. This loop collects messages from your message queue and dispatches them, via Presentation Manager, to the window specified by the window handle contained in the message.

The function WinGetMsg reads the next available message from the queue. The WinDispatchMsg function dispatches this message throughout the system so the message can be processed.

Example

Processing the message loop:

     perform until loop-end
         call 'WinGetMsg'
             using by value           hab
                   by reference       qmsg
                   by value           0     size 4
                   by value           0     size 4
                   by value           0     size 4
             returning bool
         if boolfalse
             set loop-end to true
         else
             call 'WinDispatchMsg'
                 using by value          hab
                       by reference      qmsg
         end-if
     end-perform

15.2.6 Processing Client Window Procedure

When your program dispatches a message to Presentation Manager using WinDispatchMsg, Presentation Manager evaluates the message and, if appropriate, sends it to your client window. The link between the window and the WinProc is established by the WinRegisterClass call.

Example

This section of code shows how to process the WM-PAINT message.

 entry 'ClientWndProc' using    by value hwnd
                                by value msg
                                by value mp1
                                by value mp2.
         ...
     evaluate msg
        ...
      when wm-paint
         call 'WinBeginPaint'
             using by value hwnd
                   by value 0 size 4
                   by value 0 size 4
             returning hps
        ...
         call 'WinEndPaint'
             using by value hps
        ...
      when other
         call 'WinDefWindowProc'
             using by value hwnd
                   by value msg
                   by value mp1
                   by value mp2
             returning mresult
       ...
     end-evaluate
     exit program returning mresult.

15.2.7 Terminating Presentation Manager

Before your program exits, it should release the resources it got from Presentation Manager. First you call WinDestroyWindow to close any windows created by WinCreateStdWindow or WinCreateWindow. Then you call WinDestroyMsgQueue to dispose of the message queue created in the WinCreateMsgQueue call. Finally, your program must call WinTerminate to tell the system that you have finished with Presentation Manager.

Example

     call 'WinDestroyWindow'
         using by value hwndFrame
     call 'WinDestroyMsgQueue
         using by value hmq
     call 'WinTerminate'
         using by value hab

15.3 Translating C Definitions

The OS/2 Programmer's Reference describes all the OS/2 API functions in terms of the C programming language. For those programmers unfamiliar with C, this section explains how to translate these descriptions into COBOL.

Your OS/2 Programmer's Toolkit includes definitions of many of the Presentation Manager function parameters in C header (.h) files. This COBOL system includes the H2cpy utility to convert typedef and #define statements in .h files to COBOL copyfile form. H2cpy does not translate function declarations or macro definitions; these have no equivalents in COBOL. See the chapter Header-to-COPY Utility in your Programmer's Guide to Writing Programs for instructions on using H2cpy.

15.3.1 H2Cpy - C Header File Conversion

This COBOL system contains a utility, H2cpy, to convert C header files into COBOL copyfiles. The utility converts C header files, including those supplied with the OS/2 Programmer's Toolkit into COBOL data definitions. It is especially useful if you want to write Presentation Manager applications in COBOL using the System Programming Extensions.

H2cpy converts the following C language constructs:

Before you can compile any of the sample programs (or your own Presentation Manager software), you must run H2cpy to translate the C header files into COBOL, using this command line:

h2cpy os2.h os2.cpy /m /dincl_pm /dincl_base

This translates the os2.h file and all its included files into the following files:

H2cpy creates a separate COBOL copyfile (.cpy) for each structure defined in the C files. Use the COPY statement to include these files in your program.

15.3.2 Translating C Function Declarations

The C definition of the WinCreateStdWindow API function is shown in the following example (the rest of this section explains how to translate this C definition into COBOL):

HWND WinCreateStdWindow
                     (HWND     hwndParent,
                       ULONG   flStyle,
                       PULONG  pflCreateFlags,
                       PSZ     pszClientClass,
                       PSZ     pszTitle,
                       ULONG   styleClient,
                       HMODULE hmod,
                       ULONG   idResources,
                       PHWND   phwndClient);

The following list defines each of the words in the example:

Word
Meaning
HWND Function returns data of type HWND
WinCreateStdWindow Function-name
HWND The data type of the parameter hwndParent
hwndParent Possible name for the parameter (optional in the definition, but required in any use of the function)
ULONG The data-type of the parameter flStyle
flStyle Possible name for the parameter
. . . Remaining data types and names
); End of the function definition

All OS/2 API function definitions appear in at least one of the OS/2 header files.

You now need to find the definitions of the data types and other constructs and decide how to code them in COBOL. This information is in the files produced by H2cpy.

The first data-type you need to translate in the WinCreateStdWindow example above is HWND. Looking up HWND in the file os2.cpy, you find this definition:

  03 HWND                 pointer.

The C data-type HWND is, therefore, equivalent to the COBOL type, POINTER. Since WinCreateStdWindow returns a value of type HWND, you need to define a storage location for that value, say hwndResult. The procedure should include a line of code to place the return value in this variable:

  03 hwndResult           pointer.

Next consider the parameters to the function call. The first parameter has type HWND, which has already been defined as a POINTER type. This results in the line:

  03 hwndParent           pointer.

Next is data-type ULONG. From os2.cpy you get:

  03 ULONG                pic 9(9) comp-5.

This gives the following definition for flStyle:

  03 flStyle              pic 9(9) comp-5.

Using the same method for all the parameters, you end up with the following definitions:

        03 hwndParent                   pointer.
        03 flStyle                      pic 9(9) comp-5.
        03 pflCreateFlags               pointer.
        03 pszClientClass               pointer.
        03 pszTitle                     pointer.
        03 styleClient                  pic 9(9) comp-5.
        03 hmod                         pic 9(9) comp-5.
        03 idResources                  pic 9(9) comp-5.
        03 phwndClient                  pointer.

Although these definitions are correct, they can be simplified. C normally passes parameters by value, not by reference. Therefore, if the value of the parameter needs to be changed, a pointer to the variable must be passed instead. In COBOL, parameters can also be passed by reference, so a pointer might not be needed. In the above example, some of the pointer definitions can be replaced by the definition of the item pointed to by the pointer. Those items can be passed as parameters by reference.

The standard naming convention used in the C header files uses a type name prefixed by the letter P to indicate a far pointer to that type. For example, PULONG indicates a far pointer to a variable of type ULONG.

Returning to the example above, pflCreateFlags was actually defined as type PULONG. Therefore, you can replace the previous definition with:

     03 flCreateFlags     pic 9(9) comp-5.

and pass this parameter by reference, which is the same as passing a far pointer to flCreateFlags.

The other parameters that can be replaced are those defined as type PSZ. The PSZ type differs from the standard naming convention used in C header files (described above) in that SZ denotes a null-terminated (C- format) string and type PSZ is a far pointer to a string. Therefore, it can be replaced in the COBOL program with a string of the appropriate length.

COBOL and C strings have different formats. OS/2 expects strings to be null-terminated, so the last character in the string must have the ASCII value of x"00" (null). This is different from COBOL strings, which have a fixed length. Therefore, you must append a byte of x"00" when you pass a COBOL string to an OS/2 API function. For example, you can define the strings as:

     03 szClientClass      pic x(9) value "MY-CLASS" & x"00".
     03 szTitle            pic x(9) value "MY-TITLE" & x"00".

Note the use of the & operator to concatenate the string and the x"00" byte to form a null-terminated string.

After you have performed all these conversions, the COBOL call to the API function WinCreateStdWindow becomes:

call 'WinCreateStdWindow'
        using   by value    hwndParent
                by value        flStyle
                by reference    flCreateFlags
                by reference    szClientClass
                by reference szTitle
                by value        styleClient
                by value        hmod
                by value        idResources
                by reference    hwndClient
        returning hwndResult

If the values you pass to the function are constants, you can use the:

BY VALUE literal

construct as long as you specify the size of the literal. Therefore, if the values you specify for styleClient, hmod, and idResources are all 0, you can replace the parameters by literals, giving the following call:

call 'WinCreateStdWindow'
        using   by value        hwndParent
                by value        lStyle
                by reference    flCreateFlags
                by reference    szClientClass
                by reference    szTitle
                by value        0 size 4
                by value        0 size 4
                by value        0 size 4
                by reference    hwndClient
        returning hwndResult

Constants defined at level-78 do not have any size associated with them. When they are used as parameters in a CALL statement, they default to a size of four bytes. The SIZE phrase of the USING clause can be used specifically to set the number of bytes passed as the parameter.

For example, the constant CS_SIZEREDRAW is defined in the C header files as:

#define CS_SIZEREDRAW 0x00000004L

The L denotes that it is a type LONG. The corresponding level-78 would be defined in os2.78 by H2cpy as:

 78 CS-SIZEREDRAW  value H"04".

If you use this as a parameter, you would have to add a SIZE 4 clause to specify the correct size.

       ... by value CS-SIZEREDRAW size 4


Note: C uses the underscore character ( _ ) to split long names or prefixes. The underscore cannot be used in COBOL. Therefore, H2cpy replaces all underscores in names with hyphens (-) .


15.3.3 Message Parameters and Macros

H2cpy does not convert C macros defined in the header files, because COBOL has no equivalent feature. However, in COBOL, the REDEFINES statement can often be used to achieve the same effect.

Example

The message parameters used by Presentation Manager are defined as type MPARAM. H2cpy produces the following definition for this type:

    03 MPARAM           pointer.

The message parameters are actually used in different ways, depending on the message being sent. Therefore, C macros are provided in the header files to access parts of the message parameter. To access them in COBOL, you can use the mechanism shown below.

A variable mp1 of type MPARAM would be defined this way:

 01 mp1pointer.
 01 mp1-9 redefines mp1    pic S9(9) comp-5.
 01 redefines mp1.
    03 mp1w1               pic S9(4) comp-5.
    03 mp1w2               pic S9(4) comp-5.
 01 redefines mp1.
    03 mp1b1               pic S9(2) comp-5.
    03 mp1b2               pic S9(2) comp-5.
    03 mp1b3               pic S9(2) comp-5.
    03 mp1b4               pic S9(2) comp-5.

The bytes and words of mp1 can now be accessed individually. The equivalents of the principal C macros are as follows:

C Macro
COBOL
MPFROMCHAR(x)

MPFROMSHORT(x)

MPFROM2SHORT(x,y)

CHAR1FROMMP
CHAR2FROMMP
CHAR3FROMMP
CHAR4FROMMP
SHORT1FROMMP
SHORT2FROMMP
move 0 to mp1-9
move x to mp1b1
move x to mp1w1
move 0 to mp1w2
move x to mp1w1
move y to mp1w2
mp1b1
mp1b2
mp1b3
mp1b4
mp1w1
mp1w2

15.4 Compiling, Linking and Debugging

The following sections explain how to compile, link and debug your Presentation Manager application.

15.4.1 Compiling

Compiling a program for Presentation Manager is no different from compiling any other program.

Note that the compiler normally creates a .def file (for use with Animator). If you have already created a .def file for the Presentation Manager .exe file, you should specify one of these directives:

Option
Action
NODEFFILE Prevents creation of a .def file. In this case, you need to create your own .def file.
DEFFILE"filename" Creates a .def file, where filename is a different name from that of the .def file used to create the .exe file.

15.4.2 Linking

Use the Cbllink utility to compile and link your Presentation Manager COBOL applications. For example, to compile and link Pmcalc2 using Cbllink, use the command:

cbllink -g pmcalc2.cbl

See your Object COBOL User Guide for more details on Cbllink.

When linking Presentation Manager applications with Link386, you must create a .def file with the WINDOWAPI attribute in the NAME statement, or the resulting executable file will not be able to run in a window. The .def file must also include an EXPORTS statement to tell the operating system the starting address of the WinProc. For example, to compile and link Pmcalc2 using Link386, use the commands:

cobol pmcalc2.cbl obj"pmcalc2.obj" litlink;
cblnames -v -mpmcalc2 cobintfn
link386 /noi/nod pmcalc2,,,mfrts32+mfcmlib+os2386,pmcalc2.def;
rc pmcalc2.res pmcalc2.exe

The Presentation Manager definition file, pmcalc2.def, contains these lines:

name pmcalc2 windowapi
stacksize    250000
exports
   mWndProc    @1
   BWndProc    @2
   DlgProc     @3 

If the application includes icons , dialog boxes, or other resources, you must use the Resource Compiler (RC) to add the compiled resource to the linked executable file. The OS/2 Programmer's Toolkit manuals explain how to use the Resource Compiler.

15.4.3 Debugging

Use Animator V2 in the 32-bit COBOL system to debug Presentation Manager COBOL applications. The environment variable COBANIM_2 must be set to ANIMGUI.

15.4.4 Resource Compiler and Editor

The OS/2 Programmer's Toolkit contains the Resource Compiler and Editor. These utilities, with documentation, are available from your operating system supplier. The Resource Compiler converts items such as menu definitions, icon declarations and accelerator tables from ASCII text to a binary format that can be incorporated in an .exe or .dll module.

The OS/2 Programmer's Toolkit Editor enables you to paint dialog boxes, icons, and fonts.

15.5 32-bit Library Routines

There are some printer handling routines that are portable between the 32-bit COBOL systems running on OS/2 and Windows. These routines are:

PC_PRINT_FILE Print a file
PC_PRINTER_CLOSE Close a printer channel
PC_PRINTER_CONTROL Send a printer command to a printer
PC_PRINTER_FREE_BMP Free bitmap from memory
PC_PRINTER_INFO Get printer information
PC_PRINTER_LOAD_BMP Load bitmap into memory
PC_PRINTER_OPEN Open a printer channel
PC_PRINTER_SET_COLOR Set printer color
PC_PRINTER_SET_FONT Set printer font
PC_PRINTER_WRITE Write text to a printer
PC_PRINTER_WRITE_BMP Write bitmap to a printer

These routines are described in the Library Routines chapter of the Programming Guide to Writing Programs.

15.6 Sample Programs

Two sample programs included with this system provide examples of Presentation Manager programs written in COBOL. The programs are:


Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.

PreviousPresentation Manager Applications (16-bit) Microsoft Windows ApplicationsNext"