Using C++ Objects in SOM

From EDM2
Jump to: navigation, search

Written by Gordon Zeglinski

Introduction

Having a large collection of C++ objects, I was motivated to see if and how I could use these objects within a SOM object. To keep things nice and familiar, let's use the profile (INI) file manipulation objects as our test case.

Using C++ Objects in SOM

In the second SOM article, we compared SOM and C++ versions of objects designed to manipulate profile files. In each of these objects we went to the OS/2 API to access the profile file. This time, the SOM object will use the C++ object to manipulate the profile file.

The hardest part of this task is determining how to define things in a manner that SOM will accept. Utilizing structures from other languages in SOM seems somewhat cumbersome to me. Pointer types are not supported by CORBA, which makes sense given the cross platform nature of CORBA. Ideally, we want some way of storing a pointer to the instance of the C++ object within our SOM object. Recall that in the IDL file, when you declare an instance of a SOM object within another object, that instance is accessed through a pointer in the C/C++ bindings. Also in SOM, you can declare an object "type" without defining it's body. What if we declared an object type and then later included C++ headers that defined a C++ object as the formentioned "object type"?

Using this idea, we create the following IDL file.

interface ProfileFile;

interface SOM_CPPini : SOMObject
{
   typedef unsigned long ULONG;
   typedef sequence buffType;

   void OpenFile(in string FileName);
   ULONG GetError();

   unsigned long GetHandle();
   void SetHandle(in unsigned long H);

   void  WriteString(in string App,in string Key,
                     in string String);
         // write a string

   void  WriteData(in string App, in string Key,
                   in buffType Buff,in ULONG BLen);

         // write the Buffer

   void  WriteInt(in string App,in string Key,in long Num);
         // write an "int"

   ULONG GetDataSize(in string App,in string Key);
         // return the lenght of the data

   void  GetData(in string App,in string Key,
                 in buffType Buff, inout ULONG BufMax);

         // return the data in Buff

   ULONG GetString(in string App,in string Key,in buffType Buff,
                   in ULONG BufMax, \in string DefArg);

         // return the String in Buff, defaults to DefArg
            if App/Key not present

   ULONG GetStringNoDef(in string App,in string Key,in buffType Buff,
                        in ULONG BufMax);

         // return the String in Buff

   long  GetInt(in string App,in string Key,in long DefArg);

         // return the "int" in App/Key or the DefArg
            if App/Key not present

   long  GetIntNoDef(in string App,in string Key);

         // return the "int" in App/Key

#ifdef __SOMIDL__
implementation
{
    ProfileFile INIFile;

    releaseorder: GetHandle,SetHandle,GetError,OpenFile,
                  \WriteString,WriteData,WriteInt,GetDataSize,
                  GetData,GetString,GetStringNoDef,
                  \GetInt,GetIntNoDef;

    callstyle=oidl;
    filestem = somcpp;
    somInit: override;  // initialize instance variables to 0
    somUninit: override; // just for fun

    passthru C_xh_after=   "#define INCL_WINSHELLDATA" \
                           "#include " \
                           "#include \"iniflobj.h\"";

};
#endif /* __SOMIDL__ */
}

The line interface ProfileFile; declares a "SOM object" with the same name as the "C++ Object" which manipulates the profile files. This object name is then used within the SOM object definition to declare an instance of ProfileFile. The passthru section of the SOM object definition, is used to include the C++ header files that declare the C++ object, ProfileFile. The C++ SOM bindings allow SOM and C++ objects to be intermixed without any major syntax differences. Following is the source code for MAIN.CPP.

void main(){
   int i;

   SOM_CPPini *Prf=new SOM_CPPini;

   Prf->OpenFile("Test.ini");

   Prf->WriteInt("App","Key",10);
   i=Prf->GetIntNoDef("App","Key");

   printf("i= %i\r\n",i);

   delete Prf;
}

The new operator is used to create an instance of the SOM object, SOM_CPPini. Thereafter, the -> operator is used to access its member functions. Following is a snippet of code from the file SOMCPP.CPP.

SOM_Scope void  SOMLINK OpenFile(SOM_CPPini *somSelf, string FileName)
{
    SOM_CPPiniData *somThis = SOM_CPPiniGetData(somSelf);
    SOM_CPPiniMethodDebug("SOM_CPPini","OpenFile");

   if(somThis->INIFile)
	delete somThis->INIFile;

   somThis->INIFile=new ProfileFile(FileName,0);

}

SOM_Scope SOM_CPPini_ULONG  SOMLINK GetError(SOM_CPPini *somSelf)
{
    SOM_CPPiniData *somThis = SOM_CPPiniGetData(somSelf);
    SOM_CPPiniMethodDebug("SOM_CPPini","GetError");

    /* Return statement to be customized: */
    { SOM_CPPini_ULONG retVal;
	if(somThis->INIFile)
	   retVal=somThis->INIFile->GetError();
	else
	   retVal=1;

	return (retVal); }
}

Remember that somThis->INIFile is a pointer to an instance of a C++ object. Outside of the new ProfileFile(FileName,0); statement, the instantizing the C++ and SOM objects is the same. This difference is due to the different way SOM and C++ handle constructors. Methods are called using the same syntax. This allows for a fairly consistent style when mixing C++ and SOM objects.

Wrapping Things Up

Although a fairly simple example was presented here, we have seen that C++ and SOM objects can be intermixed within a program and still maintain good readability. C++ objects can be used as data members of SOM objects to provide lower level support for the SOM methods. This type of interoperability allows one to exploit each OOP model for it's unique features. C++ is still faster than SOM, but SOM provides a much richer environment. In future articles, we will look at DSOM and the new 2.1 SOM toolkit.