Programming Guide


Dynamic Binding

 

The dynamic binding recipes are listed as follows:

Binding

 

The OpenDoc name binding subsystem is responsible for determining what part editor or part viewer, of those installed on user's system, is to be loaded in order to edit or view a given part or document. The binding process uses information gathered from nmap resources found in any installed editors or viewers.

Kind

String (ISO type format) which is used to identify a data format. Examples of kinds:

SurfCorp:SurfText
SurfCorp:Picture:BlackAndWhite
SurfCorp:Picture:Color

Category

Kinds can be grouped together in one or more categories. Examples of categories:

OpenDoc:Category:Text
OpenDoc:Category:Graphics
OpenDoc:Category:Table

Kinds may be in more than one category.

Part editor

Dynamically linked library which has the ability to manipulate (read, Sample, edit, print, write) a number of different kinds of parts. Since the context implies it, editor is often used instead of part editor. An editor is said to exist, or to be, if it has been installed.

Part viewer

Part editor which is not capable of changing the contents of parts.

Binding

Act of taking a part and assigning a part editor to it at run time.

Unbound

Without a binding (to an editor).

Fidelity

Different kinds of data can be said to represent the same information, but some may be qualitatively better or worse than others. A qualitatively better kind is said be of higher Fidelity. There is no universal ordering of kinds by fidelity, therefore fidelity is always determined by a particular context. Part editors support many different kinds, and stored with the part editor is a list of those kinds in fidelity ordering. Parts may contain many different kinds, different representations of their content, and they are fidelity ordered by what the part editor which last wrote out that part considers fidelity.

Installation of OpenDoc Software

   

This section describes the organization of the files that the OpenDoc software installs and creates. When you install OpenDoc, you can select optional features. If you do not select all of the optional features, some of the files described below will not be present on your computer.

Some files are created based on your commands when using OpenDoc. For example, if you do not recompile the samples, you will not have the compiled samples files.

OpenDoc provides a set of runtime files and a developer environment. The runtime files include part handler files, a user desktop area, and tools to install and uninstall parts. The developer environment includes sample code, arranged in a typical development directory structure (or sandbox), and tools that enable you to write and package part handlers so they can be used by OpenDoc.

OpenDoc organizes its files into four independent directories. Generally, the directories have a common structure. Each directory corresponds to the major functional purpose of each set of files. The following environment variables define the different directories for OpenDoc files:
%ODBASE% Directory for the installed OpenDoc runtime files.  
%ODPARTS% Directory for installed OpenDoc part handlers.  
%ODSRC% Directory for developing your OpenDoc part handlers.  
%ODCFG% Directory for your desktop and OpenDoc documents.  

Note:

On the AIX platform, substitute the Korn shell notation for example, $ODBASE for the PC notation %ODBASE%.

The Standard File Directory Structure

   

OpenDoc runtime files and developer files are kept in one of four independent directories. The environment variables named previously describe the four directories, each of which has a common structure. This section provides an overview of the standard structure that applies to all directories. On OS/2 and Windows platforms, the standard directory structure has the following major subdirectories. On the AIX platform, there is no .\dll subdirectory.

.\bin

Executable files.

.\dll

Dynamic (shared) linked libraries. On the Windows platform, the COM type libraries for OpenDoc part handlers are stored in this directory as well.

Note:

On the AIX platform, there is no .\dll subdirectory.

.\doc

OpenDoc data files.

.\include

Programming interfaces (headers) for OpenDoc

.\lib

Binary interfaces for OpenDoc. On the AIX platform, shared libraries are stored in this directory.

.\locale

Language specific message catalog files and the locale management data files. Contains one or more subdirectories for the name of each locale for which OpenDoc support has been installed. For example, the path for U.S. English is .\locale\en_us\*. Under each locale path there are message catalogs, help files, locale and codepage data, and other translatable data. On the AIX platform, the .\locale directory is called .\msg

.\src

OpenDoc debugging source code or OpenDoc part handler source code.

.\pkg

IBM-supplied OpenDoc part handler packages that you selected during installation. Immediately after installation, each of the part handler packages is installed in the OpenDoc part handler file directory. See "The Part Handler File Directory" for more information.

.\work

OpenDoc data files, part installation information, and document templates. Contains the following subdirectories:

  • .\editors
  • .\stationery
  • .\documents
  • .\shellplugins

The Runtime File Directory

When you install OpenDoc, the runtime, programming interfaces, and binary interfaces are written to the base directory, known by the environment variable %ODBASE%. The %ODBASE% directory assumes the standard directory structure described previously, with the following modifications:

When you install OpenDoc, the installation program writes files to the %ODBASE% directory. After installation, this file system should be considered read-only. No user data or part files are written to the base runtime directory.

Note:

You should never manually add or remove any files from the %ODBASE% directory. If you need to remove OpenDoc from your computer use the uninstall program provided with OpenDoc.

The Part Handler File Directory

 

An OpenDoc part handler is composed of several constituent files. See "Packaging Your OpenDoc Part Handler" for more information. When an OpenDoc part handler is installed on your computer, the files are written to the part handler directory. The directory is known by the value of the environment variable %ODPARTS% and assumes the standard directory structure with the following modifications:

On the desktop, in the OpenDoc folder, there is a Drag and Drop enabled Installation object. The installation object takes a packaged OpenDoc part handler and installs it in the part handler directory which must have write access when part handlers are being installed. Once all the part handlers have been installed the directory should be considered read-only. No user data files are written to the part handler directory.

The .\work\editors subdirectory contains the table of contents file (.odt) that describes each of the files and registration attributes for an OpenDoc part handler. The list of .odt files in the .\work\editors subdirectory is the inventory of part handlers installed on your system. The .odt files are copied to your %ODCFG%\work\editors folder as well. The editors folder contains a list of all the part handlers that are installed.

Note:

Network mounting of collections of previously installed OpenDoc part handlers is not supported by the command line or desktop installation tools provided with OpenDoc.

The .\work\stationery subdirectory contains the OpenDoc stationery files that are templates for OpenDoc documents, that can be edited by part handlers that you installed. The stationery files are copied to your %ODCFG%\work\stationery folder as well.

The .\work\shellplugins subdirectory contains the OpenDoc standard extension files, which are extensions to OpenDoc supplied by part handlers that you installed. The shell plug-ins files are copied to your %ODCFG%\work\shellplugins folder as well.

You should never manually add or remove any files directly from the %ODPARTS% directory. If you wish to add an OpenDoc part handler, you can either drop the OpenDoc part package file icon onto the OpenDoc part installation tool (using your mouse) or you can issue the OpenDoc part handler installation command with the appropriate part handler package as the parameter to the command (using your keyboard). If you wish to remove the part handler, use the uninstall tool or the command line equivalent.

The Source Sandbox File Directory

         

The installation program for OpenDoc provides an option for installing sample source code. The samples are useful in learning how to write your own OpenDoc part handler. If you install the samples, the source code is written to the source sandbox directory. Source code part handlers are provided with NMAKE makefiles and with a directory organization that is representative of a cross-platform source code environment. The makefiles assume the design of the directory system described in this section.

Note:

On the AIX platform, the standard Make tool is used by the samples. In this section assume that NMAKE is replaced by MAKE for AIX.

The OpenDoc source sandbox assumes the standard subdirectory structure with the following modifications:

The .\pkg directory contains the .odz files that are the product of compiling and packaging your OpenDoc part handler. The .odz file is a compressed collection of all the individual files that form an OpenDoc part handler. It has a standard format known to the OpenDoc NMAKE makefiles and to the OpenDoc part handler installation and part handler removal tools. Only one part handler is contained in a given .odz file. Your sandbox can produce more than one part handler but it must package them one at a time. The samples that are shipped with OpenDoc can be compiled, linked, and packaged into deliverable OpenDoc part handler packages.

The other subdirectories, including the .\work subdirectory, contain the generated files of your OpenDoc part handler. For example, when you produce a .dll file by running an NMAKE makefile in the .\src subdirectory, it is written to the .\include subdirectory of the %ODSRC% sandbox. The source and the makefiles for the part handlers are stored in the .\src subdirectory.

Note:

The source sandbox directory must have write access. No OpenDoc runtime files are written to the source sandbox directory.

Generally, you edit in the .\src subdirectory of the %ODSRC% sandbox directory. There are advantages to having your OpenDoc project reside in the .\src tree. Your makefiles should write the compiled library and load modules to the appropriate subdirectories of the %ODSRC% directory. The clean rules of your makefiles should remove the compiled files in the subdirectories of the %ODSRC% directory. The packaging rules in your makefiles write the completed OpenDoc part handler packages to the .\pkg subdirectory of the %ODSRC% directory.

The OpenDoc Desktop File Directory

When you install OpenDoc, it creates a desktop file directory that contains the SOM Interface Repository (IR), the OpenDoc part handler registry, and folders that contain the following files:

The desktop directory is known by the value of the environment variable ODCFG. The %ODCFG% directory assumes the standard directory structure with the following modifications:

The %ODCFG% directory contains your version of the IR for the installed OpenDoc parts. It also contains the part handler registry file used by Bento. The .\work subdirectory contains the editors, stationery, and documents folders.

Network mounting of collections of previously installed OpenDoc part handlers is not supported by the command line or desktop installation tools provided with OpenDoc. Tools are not provided to rebuild the links between part handlers installed in the %ODPARTS% directory and the user desktop objects in the %ODCFG% directory.

Note:

The desktop file directory must have write access at all times.

Packaging Your OpenDoc Part Handler

 

If you are a part handler developer, there are several steps that you must take to build a functional OpenDoc part handler package. Begin this work after you are satisfied that your part handler compiles and links, and after it passes the developer checklist. See Appendix B. "Part Developer's Checklist" for details. The following steps assume that you are using makefiles that derive from and that are compatible with the makefiles shipped in the sample code. They also assume that you are using a part handler developer source code sandbox that is similar in structure to the one under %ODSRC%.

The sample source code provided with OpenDoc shows the steps needed to build an OpenDoc part handler package:

  1. Define the table of contents entries for your part handler. See "Defining the Table of Content Entries for Your Part Handler".

  2. Build each of the files that form your part handler package. See "Building the Files That Form Your Part Handler Package".

  3. Build the part handler package. See "Building the Part Handler Package".

Defining the Table of Content Entries for Your Part Handler
     

Define the table of contents for your part handler by adding macro definitions to your makefile. Your makefile should use the same form and the same include files that are in the samples makefiles provided with OpenDoc.

The definition of the table of contents entries for your part handler occurs in your local makefile. There are several local makefile macros that you must set to define your table of contents entries. The macros are used to set property/value pairs in the table of contents file. The makefiles generate the correct properties based on these macros, on the type of platform, and on which locale you are using. The following makefile macros should be defined:

RegMain

Defines the key dynamic load library (or shared library) that forms your OpenDoc part handler. This file is named by the DLL parameter of your part's SOM IDL file. It is a required parameter.

RegIDL

Defines the key SOM IDL file that holds the interface definition for your part handler. It is a required parameter.

RegClassName

Defines the SOM class name of your OpenDoc part handler. It is a required parameter.

FilesDlls

Contains the list of dynamic load libraries (shared libraries) that you provide. Each of the files you name is written to the directory %ODPARTS%\dll when the part handler is installed on a target machine. The file named by the RegMain macro must be a member of this list.

Note:

On the AIX platform, the FilesDlls list is written to the $ODPARTS/lib directory.

FilesIncs

Contains the list of include files that you provide. Include files include IDL, compiled SOM language bindings (.xh, .xih, etc.), and other headers that you wish to provide. Each of the files you name is written to the directory %ODPARTS%\include when the part handler installed on a target machine. The file named by the RegIDL macro must be a member of this list.

FilesLibs

Contains the list of linking interfaces that you provide. Linking interfaces include .def files, .lib files, .exp files, and so on. Each of the files you name will be written to the directory %ODPARTS%\lib when the part handler is installed on a target machine. You must define the macro but it can have a null value.

FilesCats

Contains the name of the message catalog files that you provide. Message catalogs are compiled versions of translated strings. The makefiles compute the value of the locale that you are using to build your part handler. This locale is written in the table of contents file. When your part handler is installed on a target machine, the catalog files are written to the %ODPARTS%\locale\%your_locale% directory. You must define the macro but it can have a null value.

Note:

On the AIX platform, the .\locale subdirectory is called the .\msg subdirectory.

FilesStationery

Contains the name of the stationery template files that are associated with your OpenDoc part handler. OpenDoc builds a default stationery document that is a part of your type and is devoid of content. However, you can supply additional stationery that provides content. Each of your files is written to the directory %ODPARTS%\work\stationery when the part handler is installed on a target machine. Each of the files is copied to the user's %ODCFG%\work\stationery desktop folder during the installation process. You must define the macro but it can have a null value.

FilesHelps

Contains the name of the part handler help files that are associated with your OpenDoc part handler. Each of the files that you specify is written to the directory %ODPARTS%\locale\%your_locale%\help when the part is installed on a target machine. You must define the macro but it can have a null value.

FilesTypeLibs

Contains the name of the Win32 type library files that are used to register your OpenDoc part handler with the OpenDoc\OLE interoperability runtime code. This parameter does not apply unless the platform is Win32. Each of the type files that you specify is written to the directory %ODPARTS%\dll. You must define the macro, but it can have a null value.

Building the Files That Form Your Part Handler Package
     

The makefiles shipped with OpenDoc provide a standard set of top level makefile verbs. Your project should use these verbs when building. Packaging an OpenDoc part handler requires the ZIP tool and the ZIP2EXE tool on the OS\2 and Windows platforms, and the TAR tool and the COMPRESS tool on the AIX platform. For all three platforms, if you plan to build packages, a 32-bit compression tool must be installed. You can use the Info-ZIP tool. It is freely available from Compuserve in the IBMPRO forum and by anonymous ftp from the Internet site ftp.uu.net:/pub/archiving.zip. The default build sequence is defined in the platform.mak file that OpenDoc writes to your %ODSRC% file directory. The sequence is:

  1. Interface definition language files (.idl)
  2. Header files (.hdr)
  3. Library files (.lib)
  4. Dynamic link library files (.dll)
This sequence can be obtained by issuing the following commands:
  cd %ODSRC%\src
  nmake -f makefile Default > make.out 2>&1

If you have stationery files create them and place them in the correct location in the %ODSRC% directory.

Building the Part Handler Package
     

After you build a working OpenDoc part handler in your %ODSRC% directory, run the additional makefile verb Pkgs. This command can be obtained by issuing the following commands:

  cd %ODSRC%\src
  nmake -f makefile Pkgs > make.out 2>&1

This rule causes the table of contents file to be created. It then causes the constituent pieces of the OpenDoc part handler to be assembled together in the .odz file. It writes the .odz file to the %ODSRC%\pkg directory.

If you are building OpenDoc part handler packages for more than one platform, you must create a separate part handler package for each platform. If you are building OpenDoc part handler packages for more than one locale, you must create a separate part package for each locale.

Parts Naming Guidelines
       

All of the part handlers that are installed on a target machine are placed in the %ODPARTS% file directory. There is no explicit mechanism that prevents a part handler from using the same filename that some other part handler uses.

IBM-supplied OpenDoc part handlers provide files that start with the prefixes iod or IOD. Choose a prefix meaningful to your project when naming your files. This prefix should be designed not to conflict with IBM-supplied files or with files from other suppliers.

The Part Handler Package File Format

             

Use the techniques described previously, based on the makefiles provided by IBM, to package your part handler. This section provides information about the makeup of the table of contents files and the .odz file.

A part handler package file has the .odz suffix. On OS/2 and Windows platforms this file is produced by the ZIP command followed by the ZIP2EXE command. On the AIX platform, this file is produced by the TAR command followed by the COMPRESS command. If your project has a number of files that form a part handler, then the part handler package file contains that number plus two more files. The two additional files are a bootstrap file and a table of contents file.

The bootstrap file is always named PARTS.LST. It contains a list of table of contents file, one file name per line, with no comments or white space (that is any combination of blanks, spaces, or tabs). OpenDoc allows one table of contents file to be named in the PARTS.LST bootstrap file.

The table of contents file holds the property/value pairs that define the makeup of the part handler. The pairs are placed one per line in the file, in the form property=value,value,value. All properties used by OpenDoc start with the characters IOD and are reserved for future use by OpenDoc. White space is not acceptable in the file. Other properties can be placed in the file providing they follow the basic syntax. The OpenDoc code does not use other properties.

The following are the properties used by OpenDoc. Each of them must be specified in the table of contents file.

The enumeration types for IODPartPlatform are win32, os2, and aix. The install code uses the table of contents to copy files from a temporary expanded version of the .odz file into the correct destination in the %ODPARTS% directory. Each file named in the table of contents in a property of type IODPartFiles* must be found in the expanded set of files. There is no checking for additional files not named in the table of contents.

The uninstall code uses the table of contents file to remove each file named in a property of type IODPartFiles* from the %ODPARTS% directory.

Registering a Part Handler

   

All part handlers are now required to register themselves.

The changes to the part handler's IDL are simple additions that can be plugged in from the sample code given below. The following steps need to be done:

  1. Add a metaclass definition
  2. Add a interface prototype for the metaclass
  3. Set the part handler's metaclass

Start by adding the new metaclass for the part. In order to register a part handler with OpenDoc, the part handler must respond to several method calls during the registration process. These method calls are defined in an ODPart metaclass called M_ODPart. The M_ODPart's methods are used in the part handler so that the part handler can respond to the registration processes requests for information particular to the part handler.

Add the following code after the part handler's implementation definition:

// Added for Part Registration
interface M_YourPart : M_ODPart
{
  #ifdef __SOMIDL__
  implementation
  {
    functionprefix = M_YourPart;
    override:
    clsGetODPartHandlerName,
    clsGetODPartHandlerDisplayName,
    clsGetODPartKinds,
    clsGetOLE2ClassId,
    clsGetWindowsIconFileName;
  };
  #endif
};

From the sample code above, the text YourPart should be replaced with your part handler's class name. This code sets the metaclass to inherit from M_ODPart and overrides the specified five methods.

The next change is to add the metaclass's interface prototype. Place the following code after all INTERFACE prototype lines in the IDL. If there are no INTERFACE prototypes, place this code before the part handler's interface definition:

interface M_YourPart;

The final addition is in the part handler's implementation definition. Add this line between the FUNCTIONPREFIX and MAJORVERSION lines of the implementation definition:

metaclass = M_YourPart;

Now, save the .IDL file, backup the .CPP file, delete the .XH and .XIH files and recompile.

After updating the .CPP file with the latest SOM headers for the overridden metaclass methods (SOM compiler does this), the following code can be added to the .CPP file. There are five methods that need to be altered and placed at the bottom of the .CPP file. In addition, there are five new CONST definitions used with the following code that need to be placed at the top of the .CPP file after all the #INCLUDE statements:

const ODType   kPartHandlerName             = "YourPart";
const ODType   kPartHandlerDisplayName      = "One's Part";
const ODType   kKindTestYourPart            = "YourPart:yourdll";
const ODType   kYourPartKindDisplayName     = "One's Part Kind";
const ODType   kYourPartCategory            = "Test Part";
const ODType   kYourPartCategoryDisplayName = "Category Name";
  .
  .
  .
SOM_Scope ISOString SOMLINK
M_YourPartclsGetODPartHandlerName(M_YourPart *somSelf,
                                  Environment *ev)
{
  /* M_YourPartData *somThis = M_YourPartGetData(somSelf); */
  M_YourPartMethodDebug("M_YourPart",
                        "M_YourPartclsGetODPartHandlerName");
  string handlerName = (string) SOMMalloc(strlen(kPartHandlerName)+1);
  strcpy (handlerName,kPartHandlerName);;
  return (ISOString) handlerName;
}
SOM_Scope string SOMLINK
M_YourPartclsGetODPartHandlerDisplayName(M_YourPart *somSelf,
                                         Environment *ev)
{
  /* M_YourPartData *somThis = M_YourPartGetData(somSelf); */
  M_YourPartMethodDebug("M_YourPart",
                        "M_YourPartclsGetODPartHandlerDisplayName");
  string displayName = (string) SOMMalloc(strlen(kPartHandlerDisplayName)+1);
  strcpy(displayName,kPartHandlerDisplayName);
  return displayName;
}
SOM_Scope _IDL_SEQUENCE_PartKindInfo SOMLINK
M_YourPartclsGetODPartKinds(M_YourPart *somSelf,
                            Environment *ev)
{
  /* M_YourPartData *somThis = M_YourPartGetData(somSelf); */
  M_YourPartMethodDebug("M_YourPart",
                        "M_YourPartclsGetODPartKinds");
  _IDL_SEQUENCE_PartKindInfo YourPartInfo;

  // Create structure PartKindInfo  and allocate memory for variable
  PartKindInfo * info = (PartKindInfo *)SOMMalloc(sizeof(PartKindInfo));
  info->partKindName  = (ISOString) SOMMalloc(strlen(kKindTestYour)+1);
  info->partKindDisplayName = (string)SOMMalloc(strlen
                                      (kYourPartKindDisplayName)+1);
  info->filenameFilters =  (string)SOMMalloc(strlen("")+1);
  info->categories    = (string)SOMMalloc(strlen(kYourPartCategory)+1);
  info->categoryDisplayName = (string)SOMMalloc(strlen
                                      (kYourPartCategoryDisplayName)+1);

  // New part stationery support
  info->filenameTypes = (string)SOMMalloc(strlen("")+1);
  info->objectID = (string)SOMMalloc(strlen("")+1);

  // Copy the information into the structure
  strcpy(info->partKindName , kKindTestYour);
  strcpy(info->partKindDisplayName, kYourPartKindDisplayName);
  strcpy(info->filenameFilters, "");
  strcpy(info->categories, kYourPartCategory);
  strcpy(info->categoryDisplayName, kYourPartCategoryDisplayName);

  // New part stationery support
  strcpy(info->filenameTypes, "");
  strcpy(info->objectID, "");
  YourPartInfo._maximum = 1;
  YourPartInfo._length = 1;
  YourPartInfo._buffer = info;
  return YourPartInfo;
}
/*
  In the following method: M-YourPartclsGetOLE2ClassId(),
  the OLE2 Class ID is determined by running the tool uuidgen.exe
  or guidgen.exe in the IBM VAC++ sdk\bin directory.  This tool
  will generate a unique ID based on your network access and the time
  of the day (DCE standard).
*/
SOM_Scope string  SOMLINK
M_YourPartclsGetOLE2ClassId(M_YourPart *somSelf,
                            Environment *ev)
{
  /* M_YourPartData *somThis = M_YourPartGetData(somSelf); */
  M_YourPartMethodDebug("M_YourPart",
                        "M_YourPartclsGetOLE2ClassId");
  string tempID = (string) SOMalloc(strlen("")+1);
/* Insert the OLE2 Class ID you generated with UIDGEN or GUIDGEN here.
The ID will be in the following format:
 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.  Add braces inside the quotes. */
  string tempID = "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}";
  string classID = (string) SOMMalloc(strlen(tempID)+1);
  strcpy(classID,tempID);
  return classID;
}
SOM_Scope string  SOMLINK
M_YourPartclsGetWindowsIconFileName(M_YourPart *somSelf,
                                        Environment *ev)
{
  /* M_YourPartData *somThis = M_YourPartGetData(somSelf); */
  M_YourPartMethodDebug("M_YourPart",
                        "M_YourPartclsGetWindowsIconFileName");
  string kWindowsIcon = "my_part.ico";
  string fileName = (string) SOMMalloc(strlen(kWindowsIcon)+1);
  string(fileName,kWindowsIcon);
  return fileName;
}

Throughout this sample code, the YourPart should be replaced with the name of the part handler. All of the pertinent information that is going into the registry is stored in the CONST definitions defined earlier, so once those definitions have been configured to the part handler, the rest of the code changes are simply name changes, with the exception of the filenameFilters data in the PartInfo structure, which can change to match any file types associated with the part handler. For example, a part that edits tunes might create and handle files with the .TUN extension, so *.TUN would be placed between the quotes in the 'strcpy(info->filenameFilters, "")' statement of the clsGetODPartKinds method.

After the part is registered, the part handler's DLL can be replaced as many times as needed without having to reregister unless the code in the five registration methods has been changed.


[ Top | Previous | Next | Contents | Index | Documentation Homepage ]