Using the OS/2 Workplace Shell and DirectToSOM C++

From EDM2
Jump to: navigation, search

by Robert Warren

Now is the time to ease your way into Workplace Shell (WPS) programming with the new DirectToSOM C++ technology! The DirectToSOM C++ technology has simply made Workplace Shell (WPS) programming much easier and a lot more fun. You now can create SOM WPS applications directly from C++ code. In the past, these have been a bit difficult to program because programming in SOM required learning about the SOM toolkit bindings for C or C++, as well as expressing the interfaces to new classes in IDL (CORBA's Interface Definition Language). Now, with DirectToSOM C++, you can define new classes of Workplace Shell objects directly in C++. You do this by simply subclassing from DirectToSOM C++ header files for the WPS classes.

What is even more exciting is that the first DirectToSOM C++ compiler is now available on Volume 6 of The Developer Connection for OS/2. MetaWare Incorporated has included a full running version for OS/2 developers to see how easy SOM programming can be with DirectToSOM. Now, you have no excuse not to get on the SOM bandwagon and fully integrate your application to the WPS.

Because the OS/2 WPS is built with SOM objects, you can communicate with it through DirectToSOM (DTS) High C/C++ and derive your own customized subclasses from WPS classes, just as you would with any C++ class.

The best way to describe how easy programming WPS objects is with the C++ DirectToSOM compiler is to go through an example. In this example, we will subclass the color palette, show what steps are required to add custom functions to the existing class, and demonstrate how to subclass the color palette metaclass to provide additional functions. The program also shows how to save and restore instance data persistently, so it will not be lost even if you shut down your machine.

Customizing a WPS Class

The subclass derived from WPColorPalette is named MyPalette. It has its own customized metaclass M_MyPalette, derived from the WPColorPalette metaclass M_WPColorPalette.

The behavior of MyPalette differs from that of WPColorPalette in two ways:

  • Instead of displaying Edit color..., the Edit button displays one of three different message strings in sequence; that is, each time you open an instance of MyPalette in WPS, you get the next string in the sequence. The sequence of strings is specified in the metaclass M_MyPalette, so it is shared across all instances of MyPalette. If you open three instances of MyPalette one after the other, each displays a different edit button string, from first to third in the sequence.
  • Every time you click on the Edit button, you get one of three beeps. The selection rotates through beeps of three different frequencies. The beep state is local to the instance, so each instance of MyPalette has its own copy of the beep data. MyPalette is persistent; that is, the instance data governing the beep frequency to be used is saved across shutdown and restart of OS/2.

The DTS Program PALETTE.CPP

The MyPalette class and its metaclass are defined in a DTS High C/C++ program named PALETTE.CPP. Here is the complete text of PALETTE.CPP:

#define INCL_DOSPROCESS
#include <os2.h>
#include <stdlib.h>
#include <som.hh>

// Do not mangle class names:
#pragma Off(Case_insensitive_class_names);

// Do not generate your own assignment operator,
// constructor, or destructor; inherit them from SOM:
#pragma On(SOMObject_assignment_operators);
#pragma On(SOMObject_constructors);
#pragma On(SOMObject_destructor);

#include "wppalet.hh"
#include "wpclrpal.hh"

// Force definition of classes, because all methods are inline:
#pragma On(SOM_define_class)

// Define metaClass M_MyPalette:
class M_MyPalette : public M_WPColorPalette {
   static int i;
   PSZ wpclsQueryEditString() {
      // Customize messages on the edit button:
      static char * msgs[] = {"CHANGE me!",
                              "Edit, please!",
                              "Say WHAAT?"};

      return msgs[(i++)%3];
      }
   #pragma SOM_version(1,2);
   };
int M_MyPalette::i = 0;

// Declare class MyPallette:
class MyPalette : public WPColorPalette {
   #pragma SOM_metaclass(M_MyPalette);
   #pragma SOM_version(1,2);
   int freq;
   typedef WPColorPalette Parent;
   void beep() {
      for (int j = 0; j <= freq; j++)
         DosBeep(freq*200+400,200);
      freq = (freq+1)%3;
      }
   BOOL wpSetup(PSZ pszSetupString) {
      freq = 0;
      return Parent::wpSetup(pszSetupString);
      }
   BOOL wpEditCell(PCELL pCell, HWND hwndPal) {
      beep();         // Beep when edit button is pushed.
      return Parent::wpEditCell (pCell,hwndPal);
   #define Unique_id "Unique_id"
   BOOL wpSaveState() {
      wpSaveLong(Unique_id, 1, freq);
      DosBeep(1800,200);
      DosBeep(2700,200);
      DosBeep(3500,200);
      return Parent::wpSaveState();
      }
   BOOL wpRestoreState(ULONG ulReserved) {
      wpRestoreLong(Unique_id, 1, (PULONG)&freq);
      DosBeep(1100,200); DosBeep(2100,200);
      return Parent::wpRestoreState(ulReserved);
      }
   };

PALETTE.CPP makes use of several compiler controls designed for working with legacy (non-DTS) classes, such as those that make up the WPS, as follows:

  • Toggle Case_insensitive_class_names to off to keep the class names M_MyPalette and MyPalette from being mangled (to remove the uppercase). You could also avoid mangling by using the lowercase form of the names m_mypalette and mypalette, but preserving the uppercase conforms to the naming style of WPS.
  • Toggle SOMObject_assignment_operators, SOMObject_constructors, and SOMObject_destructor to on to specify that neither M_MyPalette nor MyPalette has a compiler-generated default constructor, destructor, or assignment operator. None of these are needed to work with legacy classes; omitting them saves code space.
  • The functions WPSaveLong() and WPRestoreLong() are methods inherited by MyPalette from WPS classes. They are defined in the header file WPOBJECT.HH, in the \HCOS2\INCC\OS2 directory. The .HH extension indicates a DirectToSOM header file.
  • DosBeep() is a regular OS/2 system function that is available to any application that runs in Presentation Manager.
  • The two methods wpSaveState() and wpRestoreState() in MyPalette are used to save and restore the state of an instance across boots of OS/2. They emit beeps whenever they are called; wpSaveState() produces three beeps, and wpRestoreState() produces two, so you can tell whenever the state is saved or restored.

Compiling and Linking PALETTE.CPP

A WPS class must reside in a dynamic link library (DLL). This example creates a DLL, PALETTE.DLL, from PALETTE.CPP, puts it in a directory along the OS/2 LIBPATH, and executes a REXX script to register the subclass DLL with WPS and bring up the first instance of MyPalette.

Compile PALETTE.CPP to generate a .OBJ file:

hc palette.cpp -c

To link this .OBJ file, you need a module-definition file, PALETTE.DEF, to export from the DLL the names for each class that are important for operation with SOM:

 LIBRARY palette                EXPORTS

 M_MyPaletteClassData          ; Palette.OBJ
 M_MyPaletteCClassData         ; Palette.OBJ
 M_MyPaletteNewClass           ; Palette.OBJ
 MyPaletteClassData            ; Palette.OBJ
 MyPaletteCClassData           ; Palette.OBJ
 MyPaletteNewClass             ; Palette.OBJ

Link the .OBJ file with the following command:

hc palette.obj -Hldopt=/stack:16384 -Hsom -Hdll -Hdef

So the WPS can access PALETTE.DLL, place the DLL in one of the directories in your OS/2 LIBPATH. For example, if C:\LIBTEST is in your LIBPATH, you might copy PALETTE.DLL there:

copy palette.dll c:\libtest

Then, you must register the DLL with the WPS. You can do this with a REXX script; the following example not only registers PALETTE.DLL, but also creates one instance of MyPalette:

/**/
call RxFuncAdd "SysLoadFuncs","RexxUtil","SysLoadFuncs"
call SysLoadFuncs
if SysRegisterObjectClass( "MyPalette" , "palette" );
   then say 'Class registered.'
else
   say 'Class registration failed.'
class = "MyPalette"
title = "My Palette"
location = "<WP_DESKTOP>"
setup = "OBJECTID=<MYPAL>"
replace = 'REPLACE'
rc = SysCreateObject(class, title, location, setup, replace);
if rc then
   say "Object Created"
else
   do
   say rc;
   call SysDeregisterObjectClass("MyPalette");
   say "Class deregistered"
   end

Save this REXX script as a .CMD file, and execute it. After that, you will have a new palette object on the desktop. (Be sure the /**/ line is the first line.)

Create two more instances of MyPalette by right-clicking on the palette icon, and choosing Create another...; when the Create Another dialog appears, type a name in the New name text box and click on Create.

When you finish exploring the new palette objects, deregister the palette class with WPS by using a different REXX script:

/**/
call RxFuncAdd "SysLoadFuncs","RexxUtil","SysLoadFuncs"
call SysLoadFuncs
call SysDeregisterObjectClass( "MyPalette" );
say "Class deregistered"

Class deregistration still leaves any palette instances you have created on the desktop; delete each instance by right-clicking on its icon and choosing Delete... from the pop-up menu, then clicking on the Delete button in the dialog box that opens.

Summary

DirectToSOM is simply the easiest way to create Workplace Shell C++ applications. Other compiler vendors have committed to supporting SOM, as well as DirectToSOM in the future. A standard is in place for DirectToSOM compiler support.

DirecToSOM is the wave of the future for SOM programming; get on the band-wagon!

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation