PreviousWindowing Support for Text-based Systems Presentation Manager Applications (32-bit)Next"

Chapter 14: Presentation Manager Applications (16-bit)

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

This chapter assumes that you are using the 16-bit Presentation Manager API. The 32-bit API available with OS/2 V2.0 and later uses different parameters in some calls; it is described in the chapter Presentation Manager Applications (32-bit).

14.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 16-bit Presentation Manager programming in COBOL:

The chapter Comparison of Methods for Creating User Interfaces explains the advantages and disadvantages of each approach.

14.1.1 Requirements

In addition to this 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 application programming interface (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 within 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 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.

14.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 procedure 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.

14.1.3 Using the Systems Programming Extensions

Extensions have been added to the COBOL syntax to enable the systems programming facilities required to use API's like the Presentation Manager API. These extensions are grouped under the name Systems Programming Extensions.

The Systems Programming Extensions include:

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

14.1.3.1 Calling Conventions

The OS/2 API uses a different parameter-passing convention to COBOL. Usually, COBOL pushes parameters onto the stack by processing the items in CALL statements from right to left. OS/2 API routines, however, expect them in the reverse order; that is, from left to right. Also, COBOL normally expects the calling program to tidy the stack of used parameters after a call whereas OS/2 API routines do this work themselves. You must therefore define the appropriate convention and specify it when calling OS/2 API routines.

To define a calling convention in COBOL, use the CALL-CONVENTION clause in the Special-Names paragraph (see your Language Reference). This clause associates a name with a particular calling convention. You use the name in each call for which the defined convention is to apply.

The calling convention is set with a 16-bit number, where each bit is assigned a particular meaning. This is described in the chapter The COBOL Interfacing Environment in your Programmer's Guide to Writing Programs.

The OS/2 API routines can be treated as a special case of a subprogram that can be called directly from COBOL. The API routines should always be called using a calling convention that includes the Pascal conventions (bits 1 and 2 set in the value, for example CALL-CONVENTION 3) and, since these routines are always resolved at link time, all calls to API routines should be static linked. This must be done either by the recommended method of using CALL-CONVENTION 11 (combining conventions 8 and 3) or by the obsolete method of preceding the API routine name with a double-underscore prefix.

Example

 special-names.
     call-convention 11 is os2api
     call-convention 3  is os2apiold.
        . . .
     call os2api "WinInitialize" using ...
        . . .
     call os2apiold "_ _WinInitialize" using ...

If the COBOL program is to be called by an OS/2 API routine, you will need to specify the calling convention in the PROCEDURE DIVISION header:

 procedure division os2api.

14.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

14.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.

14.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 os2api "WinInitialize"
                   using by value 0 size 2
                   returning hab

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

14.1.3.3.2 Returning a Value from a Window Procedure

A Presentation Manager window procedure 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

14.1.3.4 Procedure Pointers

A data item declared as PROCEDURE-POINTER passes the address of a window procedure to the 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 os2api "WinRegisterClass"
               using by value     hab
                     by reference MyClass
                     by value     WndProc
                     by value     CSClass
                     by value     0 size 2
               returning my-refum-value. 

14.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 os2api "WinGetMsg" using ...
         call os2api "WinDispatchMsg" using ...
     end-perform
14.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 by another call entering the same code. This COBOL system lets you 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                pic x(4) comp-5.
 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 xx   comp-5.
 01 mp1                pic x(4) comp-5.
 01 mp2                pic x(4) comp-5.
 procedure division os2api. 
 main-control section. 
 entry os2api "ClientWndProc" 
                 using by value hwnd
                       by value msg
                       by value mp1
                       by value mp2.
    ...

14.2 Structuring a Presentation Manager Program

All Presentation Manager programs must perform the same basic steps:

14.2.1 Initializing the 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 os2api "WinInitialize"
                 using by value 0 size 2
                 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.

14.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 os2api "WinCreateMsgQueue"
                 using by value hab
                       by value 0 size 2
                 returning hmq.

14.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 window procedure and other information, such as default window styles.

     set WndProc to entry "WndProc"
     call os2api "WinRegisterClass"
         using by value       hab
               by reference   MyClass
               by value       WndProc
               by value       CSClass
               by value       zerobytes size 2
         returning bool

14.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 os2api "WinCreateStdWindow"
         using by value        Hwnd-Desktop
               by value        WSWindow
               by reference    ctldata
               by reference    MyClass
               by reference    "mytitle" & x"00"
               by value        0     size 4
               by value        0     size 2
               by value        0     size 2
               by reference    hwndClient
         returning hwndFrame

14.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 os2api "WinGetMsg"
             using by value           hab
                   by reference       qmsg
                   by value           0     size 4
                   by value           0     size 2
                   by value           0     size 2
             returning bool
         if boolfalse
             set loop-end to true
         else
             call os2api "WinDispatchMsg"
                 using by value          hab
                       by reference      qmsg
         end-if
     end-perform

14.2.6 Process 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 window procedure is established by the WinRegisterClass call.

Example

This section of code outlines how to process the WM-PAINT message in a window procedure.

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

14.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

Terminating Presentation Manager:

     call os2api "WinDestroyWindow"
         using by value hwndFrame
     call os2api "WinDestroyMsgQueue"
         using by value hmq
     call os2api "WinTerminate"
         using by value hab

14.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, function prototype and #define statements in .h files to COBOL copyfile form. See your Programmer's Guide to Writing Programs for instructions on using H2cpy and for details on typedefs and CALL prototypes.

14.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 type definitions and COBOL CALL prototypes. It is especially useful if you want to write Presentation Manager applications in COBOL using the System Programming Extensions.

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

h2cpy os2.h /D incl_pm  /D incl_base /I \incdir /X 

This translates the os2.h file and all its included files (in this example assumed to be located in the directory \incdir) into the COBOL copyfile os2.cpy. You may use the COPY statement to include this file in your program. The Compiler will then validate any function calls that you make to ensure that the parameters conform to the COBOL CALL prototype in os2.cpy. H2cpy will automatically generate useful CALL prototypes from the C function prototypes. However, it may be that you find the validation inappropriate in some cases. You have the choice of either modifying os2.cpy or of running H2cpy with the option to suppress the generation of CALL prototypes.

14.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,
                   USHORT   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. The names used for the parameters are not significant and may differ between the documented function definition and the equivalent definition in the header file.

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. Coding is fairly straightforward but instead of passing fully typed pointer parameters by value, as described in the C function definition, COBOL can often pass them more conveniently using the BY REFERENCE clause as may be shown in the COBOL prototype.

The first thing you need to determine is the calling convention required by the WinCreateStdWindow routine.

Look this routine-name up in os2.cpy and you will find a CALL prototype definition such as:

 entry "WinCreateStdWindow" using
               by value      data-pointer
               by value      uns-long
               by reference  uns-long
               by reference  any
               by reference  any
               by value      uns-long
               by value      uns-short
               by value      uns-short
               by reference  data-pointer
           returning         data-pointer

The parameters are specified in terms of COBOL type definitions data-pointer, uns-long, and others, which are defined at the beginning of the os2.cpy file. The parameter any signifies that any data-type can be used. All COBOL CALL statements referencing WinCreateStdWindow must use parameters that conform with the corresponding data-type otherwise the Compiler will give an error. Wherever possible it is preferable to use the type definition when defining data items rather than the explicit COBOL PICTURE so that your program will be more portable between different OS/2 API environments.

The calling convention that the routine WinCreateStdWindow requires is given in the Special-Names paragraph of the program in which it is defined. Look in os2.cpy for the program-id preceding the call prototype and you will find a declaration such as:

 program-id. "c_typedefs" is external.
 special-names. call-convention 3 is pascal-convention.

This tells you that the routine WinCreateStdWindow must be called with a calling convention of 3. This means that you must define a calling convention for calls to the OS/2 API routines. To combine the Pascal calling convention with the static-link call convention, add the following line to the Special-Names paragraph:

     call-convention 11 is os2api

Returning to the C definition of the WinCreateStdWindow example above, the first data-type you need to translate is HWND. Since WinCreateStdWindow returns a value of type HWND, you need to define a storage location for that value, say hwndResult. Looking up HWND in the file os2.cpy, you find this definition:

 01  HWND  is typedef  usage data-pointer.

The word TYPEDEF indicates that the data-type HWND is a type definition and so can be used to define the type (usage) of the variable hwndResult. HWND is defined as having the data-type data-pointer, which is defined at the beginning of the os2.cpy file as:

 77  data-pointer  pointer is typedef.

The data types HWND and data-pointer are, therefore, both equivalent to the COBOL USAGE POINTER and they can all be used interchangeably. The COBOL CALL prototype found earlier indicates that the routine returns a value of type data-pointer and so you can define hwndResult in terms of HWND. However, as a COBOL programmer you may find the definition more convenient with the equivalent line:

 01  hwndResult  usage data-pointer.

Next consider the parameters to the function call. The first parameter has type HWND, which has already been determined as type data-pointer. The CALL prototype says that the first parameter must be passed BY VALUE and have a type data-pointer and so you can write the line:

 01  hwndParent  usage data-pointer.

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

 01  ULONG  is typedef  usage uns-long.

The CALL prototype says that the second parameter must have a type uns-long and so you can write the line:

 01  flStyle  usage uns-long.

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

 01  PULONG  is typedef  usage data-pointer.

The CALL prototype says that the third parameter must have a type uns-long, so PULONG cannot be used directly. The C definition for PULONG indicates that it is a pointer to a data item of type ULONG, so you can write the line:

 01  flCreateFlags  usage uns-long.

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

 01  PSZ  is typedef  usage data-pointer.

The CALL prototype says that the fourth and fifth parameters must be passed BY REFERENCE but can be of any type. The BY REFERENCE clause is a convenient COBOL way of avoiding direct use of parameter pointers and of permitting type checking. It is otherwise equivalent to passing a parameter as an untyped pointer BY VALUE.

The C header file declares the parameter pszClientClass as a char pointer. In C, a char pointer references a char datatype which represents both a one-byte numeric item or the start of a multi-byte text string. In contrast, COBOL recognizes a one-byte numeric item and a multi-byte alphanumeric item as distinct data types. For this reason, when H2cpy translates a C function prototype parameter that is a char pointer it cannot specify a specific data type and so generates any.

The API function description indicates that the parameter pszClientClass is a pointer to a C string which is a multi-byte text item that is terminated by a C null character. The closest COBOL equivalent is either an alphanumeric data item that includes a C null character within its value or a concatenation of an alphanumeric data item with an explicit C null character. (You can use the DELIMITED clause if you are prepared to modify your CALL prototype; see your Language Reference for details.)

It is generally convenient to use the COBOL concatenation operator. For example you can define the BY REFERENCE parameters for pszClientClass and pszTitle as:

 01  szClientClass     pic x(9) value "My-Class" & x"00".
 01  szTitle           pic x(9) value "My-Title" & x"00".

Where a literal such as x"00" is used many times, it is important that the correct value is coded each time. This can be done in a simple way by declaring the literal as a level-78 item and thereafter using the level-78 name:

 78  c-null            value x"00".
 01  szClientClass     pic x(9) value "My-Class" & c-null.
 01  szTitle           pic x(9) value "My-Title" & c-null.

After defining the complete list of parameters using similar methods, you end up with the following source lines:

 copy "os2.cpy" replacing ==call-convention 3==
                by        ==call-convention 11==.
 program-id. pmdemo.
 special-names.
         call-convention 11 is os2api.
 working-storage section.
 78  c-null            value x"00".
 01  hwndParent        usage data-pointer.
 01  flStyle           usage uns-long.
 01  flCreateFlags     usage uns-long.
 01  szClientClass     pic x(9) value "My-Class" & c-null.
 01  szTitle           pic x(9) value "My-Title" & c-null.
 01  styleClient       usage uns-long.
 01  hmod              usage uns-short.
 01  idResources       usage uns-short.
 01  hwndClient        usage data-pointer.
 01  hwndResult        usage data-pointer.


Note: 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.


When calling an OS/2 API routine, you must either use CALL-CONVENTION 11 or if you use CALL-CONVENTION 3 you must precede each name by two underscore characters ( _ _ ). This ensures that the call is static (resolved at link time).

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

     call os2api "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 numeric constants, you can use the:

     by value literal size n

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. Constant alphanumeric literals can also be used, to give the following call:

     call os2api "WinCreateStdWindow"
                   using by value     hwndParent
                         by value     flStyle
                         by reference flCreateFlags
                         by reference "My-Class" & c-null
                         by reference "My-Title" & c-null
                         by value     0 size 4
                         by value     0 size 2
                         by value     0 size 2
                         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 and generates a COBOL statement in os2.cpy:

 78  CS-SIZEREDRAW     value h"00000004".

If you use this literal value 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 (-) .


14.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:

 01  MPARAM  is typedef  usage data-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 mp1                    pointer.
 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) move 0 to mp1-9
move x to mp1b1
MPFROMSHORT(x)

MPFROM2SHORT(x,y)
move x to mp1w1
move 0 to mp1w2
move x to mp1w1
move y to mp1w2
CHAR1FROMMP
CHAR2FROMMP
CHAR3FROMMP
mp1b1
mp1b2
mp1b3
CHAR4FROMMP
SHORT1FROMMP
SHORT2FROMMP
mp1b4
mp1w1
mp1w2

14.4 Compiling, Linking and Debugging

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

14.4.1 Compiling

Compiling a program for Presentation Manager is no different from compiling any other program. Since OS/2 runs only on machines using an 80286 (or more advanced) processor, you can use the TARGET"286" directive to produce slightly faster and more compact code. However, this is not required.

For running under Animator or Animator V2, the compiler normally creates a .def file. 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.

14.4.2 Linking

When linking Presentation Manager applications, 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 window procedure.

For example, the commands to compile and link Pmcalc2 are:

cobol pmcalc2.cbl target(286);
link pmcalc2+cobintfn,,,lcobol+cobfp87o+os2,pmcalc2.def/nod;
rc pmcalc2.res pmcalc2.exe

pmcalc2.def contains these lines:

NAME PMCALC2 WINDOWAPI
PROTMODE
STACKSIZE    16384
EXPORTS
   MWndProc    @1
   BWndProc    @2
   DlgProc     @3 

Applications for Presentation Manager must be linked with os2.lib rather than doscalls.lib, since the latter supports only the kernel OS/2 API calls. For OS/2 V2.0 or later use the library os2286.lib .

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.

14.4.3 Debugging

You can use Xilerator, Animator or Animator V2 to debug a Presentation Manager application.

14.4.3.1 Debugging with Xilerator

Xilerator, part of the add-on product Toolset, is a text-based COBOL debugger. It works in a similar way to Animator but, whereas Animator debugs programs at the intermediate code level, Xilerator debugs programs at the generated code level.

When debugging a Presentation Manager application on OS/2 V2, Xilerator uses hard mode debugging. This means that Xilerator runs in a text window on the Presentation Manager screen but, while your program is stopped in Xilerator, you cannot access any other window. If you move or resize the Xilerator window, any parts of your application's windows that are exposed are not repainted until the next time that you allow your application to run.

To use Xilerator, compile with the GANIM directive and link in the usual way to give an .exe file. For example, the commands to prepare Pmcalc2 are:

cobol pmcalc2.cbl target(286) ganim;
link pmcalc2+cobintfn,,,lcobol+cobfp87o+os2,pmcalc.def/nod;

Then to xilerate pmcalc2.exe, type:

xil pmcalc2.exe

14.4.4 Debugging with Animator

It is possible to use Animator to debug Presentation Manager applications by using cross-session mode, but there are two disadvantages:

For Presentation Manager programming, compile with the ANIM and OPT"0" (to prevent the automatic link) directives and manually link with the Coblib and OS/2 run-time support libraries (coblib.dll and os2286 on OS/2 V2.0 or later) and an appropriate .def file to create a .dll file. If you specify the directive DEFFILE"filename" where filename is the name of the .def file, the Compiler produces a suitable .def file for you.

Before starting the animation, any Presentation Manager resources needed by the application must be made available. These can be linked into the .dll file with the Resource Compiler before animating, provided the program contains code to get its module handle. An example of code to do this is given below:

 01 filler.
     03 modname     pic x(7) value "pmcalc2" & x"00".
     03 modhandle   pic xx.
        . . .
        . . .

     call os2api "DosGetModHandle"
                   using modname
                         modhandle
     if return-code not = 0
         move x"0000" to modhandle
     end-if

In any call that requires a module handle (for example, DosGetResource), the modhandle variable obtained is used. To ensure that the call executes correctly, the program being animated must be in the current directory.

To prepare the Pmcalc2 sample program for Animator debugging, use these commands:

cobol pmcalc2.cbl target"286" anim opt"0" deffile"pmcalc2.dfa";
link pmcalc2+cobintfn,,,coblib+cobfp87o+os2,pmcalc2.dfa/nod;
rc pmcalc2.res pmcalc2.dll

Then to animate the program in cross-session mode, type:

animate pmcalc2.dll user-session(pm)

14.4.4.1 Debugging with Animator V2

It is possible to use Animator V2 to debug Presentation Manager applications using cross-session mode. This has the disadvantage that your application's user interface will run very slowly, as it would under Animator, but it can use hard mode debugging which does not cause Presentation Manager to fail when your application is stopped under Animator V2.

To use Animator V2 with hard mode debugging, prepare a .dll file in the same way as for Animator, and ensure that the environment variable COBANIM_2 is set to ANIMGUI.

14.4.5 Resource Compiler and Editor

The OS/2 Programmer's Toolkit contains the Resource Compiler and Editor. These utilities, together 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.

14.5 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.

PreviousWindowing Support for Text-based Systems Presentation Manager Applications (32-bit)Next"