Programming Guide: Exception Handling

# Programming Guide

## Exception Handling

This version of OpenDoc improves the handling of C++ and SOM exceptions. It provides better cross-platform and cross-compiler functions than the previous versions. It replaces the old header files, `Except.h` and `Except.cpp`, with the new header files, `ODExcept.h` and `ODExcept.cpp`. This version does not provide a DLL, because exception handling is dependent on your compiler. Compile and link the `ODExcept.cpp` code into your parts.

Note:

> The files `Except.h` and `Except.cpp` are no longer shipped and should not be used.

Enhancements in this version of OpenDoc:

- Handle OpenDoc runtimes and OpenDoc parts created on different compilers.

- Simplify coding necessary to implement the exception handling required of the SOM interfaces of a part.

This version of OpenDoc provides support tools to augment the exception handling code. One important set of support tools is the debugging tools shipped as `ODDebug.h`. Include this header file in your code and define the DEBUG macro to use the debugging tools.

### Guidelines for Coding Exception Handling

Using exceptions allows you to implement a useful C++ programming idiom to manage constructors and destructors of stack-based classes. The idiom simplifies the acquisition and release of resources such as memory blocks or references to a ref-counted object. You do not need to remember to code the release calls because it is implicit within the destructor code. When an object goes out of scope and any exceptions are returned, the release will take place on the way out. This is easier than wrapping an exception handler around the block.

The exception handling guidelines for OpenDoc are the same guidelines used to code exception handling in any C++-based SOM interface. OpenDoc adds no additional restrictions. These guidelines consider your part's needs to interoperate with DLLs that use the C++ runtimes from different compilers.

#### Use the New Header Files

All OpenDoc parts, extensions, and objects that implement SOM interfaces should include the `ODExcept.h` file and use the appropriate macros within it. Do not use the deprecated `Except.h` or `Except.cpp` header files. Do not use the deprecated services from the obsolete header. See "Obsolete Macros and Methods" for a list of the obsolete services.

#### Use the Debug Header Files

All OpenDoc parts, extensions, and objects that implement SOM interfaces should include the `ODDebug.h` header file and use the appropriate macros within it. You can disable the debugging messaging by modifying your makefiles. This modification will leave the debugging capabilities in your part's source code if correctly coded. See "Guidelines for Using the Debugging Tools." for additional details on the debugging tools.

#### Define the _NATIVE_EXCEPTIONS_ Macro

All OpenDoc parts, extensions, and objects should have the following macro defined:

              -D_NATIVE_EXCEPTIONS_    // as an nmake or compiler flag

or

        #define _NATIVE_EXCEPTIONS_ = 1  // in a header file

### Never Throw a C++ Exception out of an OpenDoc Part DLL

Because you use SOM methods in an OpenDoc part, you must use SOM-style exceptions instead of C++ exceptions because:

- Different C++ compilers unwrap the stack in different ways.

- SOM provides a standard, cross-compiler technique.

Your part cannot throw a C++ exception outside its DLL. Your part is a compiled SOM object. In OpenDoc, it interoperates with other SOM DLLs. The other DLLs could be compiler with other C++ compilers. If the compiling of the DLLs of SOM objects is on different C++ compilers, there is a chance that exceptions returned by an object compiled in one DLL will be incompatible with an object compiled on a second DLL. When you have incompatible DLL files among objects, an exception returned by one object can be passed to another object causing one of the C++ runtimes to fail and the document shell or the part to crash.

If your code does not handle all the C++ exceptions from within its DLL, then the unhandled ones will pass out of your part across the SOM interface and could crash your system. To resolve possible problems, you can design your code to:

- Change the flow of control within your part to return an error to the caller.
- Handle the C++ exceptions generated in your part.
- Catch the C++ exceptions and generate a SOM exception.

These code designs are to the outermost code of the SOM interface of your part. They serve as preparation in handling all C++ exceptions

For example, to change the flow of control within your part, you can wrap the return with code similar to:

      if (ev->_major) { return my_retcode }

For additional information on the ODSetSOMException macro, see "ODSetSOMException".

Note:

> Never return a C++ exception from a SOM object. Catch the exception within that object, raise a SOM exception to the calling object, or raise a program assert.

#### Check for SOM Exceptions

When you call a method of another SOM object, you must prepare for and handle SOM exceptions than can be returned by the SOM object. Normally, the returned exception will be realized as a C++ exception of type ODException in your code. You can catch this exception by wrapping your code with the appropriate try and catch block.

There are times when an exception is not possible. Instead of a C++ exception, the calling object returns the SOM exception in the SOM environment. Your code should poll the SOM exception variable of the SOM environment on every invocation of the method.

#### Use ODSetSOMException

If your code handles an internal exception, C++ or otherwise, and needs to return a SOM exception to the caller, your code must use the ODSetSOMException macro to return immediately to the calling object.

#### Clear the SOM Exception Variable

If your code handles an internal exception, your code must use the SetErrorCode macro to clear the SOM exception value from the SOM environment. For additional information on the SetErrorCode macro, see "SetErrorCode".

#### SOM Compiler Flags

All of the `.idl` files for code that implement SOM interfaces must be processed with the SOM compiler. To handle exceptions correctly, the `sc` compiler flag `-mchkexcept` must be specified when compiling a `.xh` or `.xih` file. This flag constructs the proper linkage between SOM exceptions and the C++ exceptions in the calling program.

This flag places an internal interface to resolve and invoke the correct instance of the called SOM object. The `-m` flag tells the SOM compiler to add return value checking code after each method resolution. The added code tests the SOM environment for a SOM exception. If there is an exception, the code throw a C++ exception using the function named as a part of the flag. With OpenDoc, the function `CHECK_ENV` creates and raises the right type of OpenDoc exception. Because the code is compiled into the calling C++ code, the same C++ runtime that your part uses is used for the exception. Therefore, the C++ exception is handled properly within your part.

#### Using SOMMalloc and SOMFree

Like exceptions, the memory management code of different C++ compiler runtimes use no standards. Programs cannot `malloc()` in a DLL on one compiler, pass the pointer to a DLL of another compiler, and then expect the `free()` to work in the second compiler. Using the SOM memory management code avoids this problem.

### Programming Tools in ODExcept.h

The `ODExcept.h` header file provides programming tools. This section presents these tools by category and provides the syntax and semantics for each tool.

#### Tools to Raise Exceptions

The following tools are useful for raising exceptions. The definitions listed assume the standard OpenDoc C++ settings. The following macros return a C++ exception of type ODException.

- THROW
- THROW_IF_ERROR
- THROW_IF_NULL

The following macros return a C++ exception of type ODException and provide an additional message. The behavior of these macros changes depending on the value of the `ODDebug` debugging macro.

- THROW_M
- THROW_IF_ERROR_M
- THROW_IF_NULL_M

When debugging is disabled, no message is generated.

##### THROW

The syntax for the THROW macro is:

        void THROW (ODError error);

This macro is a function that returns `void`.

Throws a C++ exception of type ODException that holds the value specified in error. There is a list of standard OpenDoc error codes in the `ErrorDef.xh` header file.

Note:

> You can use other values if they do not conflict. The error value must be nonzero.

##### THROW_IF_ERROR

The syntax for the THROW_IF_ERROR macro is:

        void THROW_IF_ERROR (ODError error);

This macro is a function that returns `void`.

Conditionally throws a C++ exception of type ODException that holds the value specified in error. There is a list of standard OpenDoc error codes in the header file `ErrorDef.xh`.

For example:

         THROW_IF_ERROR (myFunc(myParm))

Note:

> You may use other values if they do not conflict. The error value is checked. The C++ exception is thrown if the error is nonzero.

##### THROW_IF_NULL

The syntax for the THROW_IF_NULL macro is one of the following:

        void THROW_IF_NULL (void* value);

or

        void THROW_IF_NULL (void* value,ODError error);

Both versions of this macro are functions that return `void`.

The first version of this macro conditionally throws a C++ exception of type ODException(kODErrOutOfMemory). The value is assumed to be a pointer and is checked for NULL. The C++ exception is returned if the pointer is null.

Note:

> Because the error returned is an out of memory indicator, your code should avoid using this function for validating items other than pointers.

> For example:

>         THROW_IF_NULL (SOMMalloc(myptr))

The second version of this macro conditionally throws a C++ exception of type ODException(error).

Note:

> Use this form of the macro if you are testing an item other than a pointer, because you are providing the type of error.

> For example:

>         THROW_IF_NULL (myFunc(myParm), kODMyError)

##### THROW_M

The syntax for the THROW_M macro is:

        void THROW_M (ODError error, const char* msg);

This macro is similar to THROW but with the addition of printing a message when the debugging tool is enabled. This message may or may not be in a popup message box, depending on which compiler you use.

##### THROW_IF_ERROR_M

The syntax for the THROW_IF_ERROR_M macro is:

        void THROW_IF_ERROR_M (ODError error, const char* msg);

This macro is similar to THROW_IN_ERROR but with the addition of printing a message when the debugging tool is enabled. This message may or may not be in a popup message box, depending on which compiler you use.

##### THROW_IF_NULL_M

The syntax for the THROW_IF_NULL_M macro is:

        void THROW_ID_NULL_M (void* value, const char* msg);

This macro is similar to THROW_IN_NULL but with the addition of printing a message when the debugging tool is enabled. This message may or may not be in a popup message box, depending on which compiler you use.

Note:

> There is no overloaded version of this macro that takes the ODError parameter.

#### Tools to Manage the SOM Exception Handling Environment

The following tools are useful for managing the SOM environment and the current ODException structure in your code's exception handling blocks.

The basic programming interface is (not normally used by parts writers):

        void ODSetErrorCode (Environment *, ODException &, ODError);

Below are the macros that manage the value of the ODException structure named `_exception` in the current namespace. See the specific macros for additional information.

- ErrorCode
- ErrorMessage
- SetErrorMessage
- SetErrorCode
- SetErrorCodeEv

Note:

> The macros assume the exception caught is called "_exception". Your code should have a catch block similar to the following:

>         try
>          {...}
>         catch(ODException _exception)
>          {...}

##### ErrorCode

The syntax for the ErrorCode macro is:

                ErrorCode ()
        #define ErrorCode (_exception.error)

This macro is a function that returns the value of the error code in the current _exception variable. Use this macro within your catch block.

##### ErrorMessage

The syntax for the ErrorMessage macro is:

                ErrorMessage ()
        #define ErrorMessage (_exception.message)

This macro is a function that returns the value of the error message in the current _exception variable. Use this macro within your catch block.

##### SetErrorMessage

The syntax for the SetErrorMessage macro is:

                SetErrorMessage (msg)
        #define SetErrorMessage (strcpy(_exception.message, (msg)))

This macro sets the value of the error message in the current _exception variable. Use this macro within your catch block.

##### SetErrorCode

The syntax for the SetErrorCode macro is:

                SetErrorCode (err)
        #define SetErrorCode (ODSetErrorCode(kODNULL, _exception.message, (err)))

This macro sets the value of the error code in the current _exception variable. Use this macro within your catch block.

##### SetErrorCodeEv

The syntax for the SetErrorCodeEv macro is:

                SetErrorCodeEv (ev, err)
        #define SetErrorCodeEv (ODSetErrorCode(ev, _exception.message, (err)))

This macro sets the value of the error code in the current _exception variable. Use this macro within your catch block. Works on the on the exception attached to the global SOM environment that is supplied.

#### Tools to Get and Set Exception Values

The following are programming interfaces that get and set the ODError member or the ODException structure.

- ODGetSOMException
- ODSetSOMException

##### ODGetSOMException

The syntax of the ODGetSOMException macro is:

        ODError ODGetSOMException (Environment *ev );

This macro is a function that returns `void`.

The macro gets the value of the error part of the ODException structure and returns it to the caller.

##### ODSetSOMException

The syntax of the ODSetSOMException macro is:

       void ODSetSOMException (Environment*,
                                ODError,
                                const char *msg =kODNULL );

or

       void ODSetSOMException (Environment*, ODException& );

Both versions of this macro are functions that return `void`.

The first version of this macro creates a new exception structure and registers it with the SOM environment. It has default behavior for the value of the message string.

The second version of this macro creates a new exception structure and registers it with the SOM environment. It takes an ODException structure as the input.

For both versions, if you plan to raise a SOM exception, you should call this function first to create the exception you will raise.

### Obsolete Macros and Methods

The following macros and methods are no longer used by OpenDoc. Your code will not work if it uses these deprecated services.

- TRY
- CATCH_ALL
- ENDTRY
- SOM_TRY
- SOM_CATCH_ALL
- SOM_ENDTRY
- RERAISE

Note:

> You should use the C++ keywords `try` and `catch` for the deprecated OpenDoc `TRY` and `CATCH` services.

### Standard Structure for SOM Methods

Your code should use the standard C++ try and catch syntax. After your try blocks, you should provide as many catch blocks as necessary for the types of exceptions your code handles. If your code is a SOM method, it should always wrap the outermost scope of the method with a try block and it should always provide a complete, untyped catch at the end. The following code illustrates one form your code could take.

    YourSOMType YourSOMMethod (YourSOMClass * somSelf,
                               Environment  * ev,
                               yourParms )
    {
            // your SOM method
            try
            {
                    // your primary logic
            }
            catch( ODException _exception ) // you must provide this one
            {
                    // your SOM exception handling block
                    SetErrorCodeEv(ev,err) // part of the error handling
                    ...
                    ODSetSOMException(ev,err) // to return exception thru SOM
            }
            catch( anothertype foo )       // you also handle this type
            {
                    // your extra exception handling logic
            }
            catch( ... )                   // catches everything else
            {
                    WARNMSG( )             // prints a warning
                    assert(0)              // ANSI assert to really exit
            }
            if (ev->_major)
            {
                    // the ODException error was set up already in a catch
                    return yourError ;     // one way to handle this
            }
            // repeat the same try/catch/catch/catch block as needed
    }

### Basic Try and Catch Model

The following code is a basic example of the exception macros. It ignores some of the interactions with SOM and most of the setup. The focus is on the flow of exception handling. Assume that the principal function is the design as an interface of a SOM object.

This example, in two parts, shows a fail-safe allocation of two pointers. The first part of the example is a service function called `MyAlloc`. This function is C++ code compiled into your DLL. There is no interface from outside of the DLL. `MyAlloc` allocates memory and returns an exception if the memory allocation fails. THROW_IF_NULL is part of the exception handling service of `ODExcept.h`. For additional information, see "THROW_IF_NULL".

    #include <ODExcept.h>
    #include <ODDebug.h>
    //-------------------------------
    // the service function MyAlloc
    // (only called within your own DLL)
    //-------------------------------

    void * MyAlloc(ODSize size)
    {
        // not wrapped in try/catch due to an internal function
        void *    p;
        p = malloc(size);

        THROW_IF_NULL(p);             // creates an ODException
                                      // that is returned by C++

        return p ;                    // only taken if no exception
    }

The second part of the example is a function called `foo`. It uses the internal service function `MyAlloc`. It is designed to serve as a SOM interface. It shows the use of the coding guidelines presented in "Guidelines for Coding Exception Handling".

If the first call to `MyAlloc` fails, `ODFoo` returns to the caller with the error value -1. It handles the C++ exception internally, and then uses the return value rc as the channel of communication with the caller.

If the first call succeeds, control passes to the second call to `MyAlloc`, which is inside a second try and catch block. This block frees the `p1` pointer, preventing a memory leak. After `p1` is freed, the exception is handled, and the same `rc` mechanism is used to return to the caller.

If the second call to `MyAlloc` succeeds, we skip the second catch block. The second if test fails, and we return a zero for success.

If an unexpected C++ exception occurs, it enters the generic catch block at the bottom of the method. This block ensures that the C++ exception is not passed across a SOM object boundary, a DLL boundary, by asserting.

    #include <ODExcept.h>
    #include <ODDebug.h>
    int ODFoo (ODFoo *somSelf, Environment * ev )
    {
        // wrap everything in a big try block, to
        // catch all C++ exceptions
        try
        {
            void * p1 = 0 ;
            void * p2 = 0 ;
            int    rc = 0 ;

            // wrap the calls to a function which
            // can raise exceptions, so we can handle them
            try
            {
                p1 = MyAlloc(10000);
            }
            catch( ODException _exception )
            {
                cout<<"Failed to allocated p1"<<endl;
                SetErrorCodeEv( ev,kODErrOutOfMemory );
                rc=-1;
            }

            if( ev->_major ) { return rc; }
            try
            {
                p2 = MyAlloc(10000);
            }
            catch( ODException _exception )
            {
                cout<<"Failed to allocated p2"<<endl;
                SetErrorCodeEv( ev,kODErrOutOfMemory );
                free(p1);
                rc=-2;
            }

            if( ev->_major )
            {
                ODSetSOMException( ev, _exception );
                return rc;
            }
            return 0;
        }

        // overall catch block
        // this example code does not expect errors
        catch( ... )
        {
            if( p1 ) { free(p1) };
            if( p2 ) { free(p2) };
            // next two lines are workaround for ASSERT macros
            WARNMSG( WARN_INDEX(-1),"Unexpected C++ exception.\n" );
            assert( 0 );
        }
    }

### Automatic Environment Checking

Including the `ODExcept.h` header file defines a special preprocessor symbol that modifies the way SOM messages are sent. Any SOM headers (`.xh` files, for C++) compiled with the `-mchkexcept` flag of the SOM compiler included after the header file has been included will be modified. After the message is sent and control returns to the caller, the SOM environment is checked and an exception of the type ODException return if the method returned an error.

Note:

> The `.xih` and `.xh` header files shipped with OpenDoc were compiled with the `-mchkexcept` option.

The following example does not use autochecking.

    #include <ODFoo.xh>
      ...
    void AFunction(Environment *ev, ODFoo *foo)
    {
      long result = foo->Bazz(ev);
      if( ev->_major )
      {
        // Oops, ODFoo::Bazz returned an error
        result = 0;
        goto handle_error;
      }
      ...
      handle_error:
      return result;
    }

This code does not include `ODExcept.h`, leaving the automated exception checking disabled. `AFunction` must check the environment directly after each call.

The following example uses autochecking.

    // Enables automatic ev checking for ODFoo
    #include <ODExcept.h>
    #include <ODFoo.xh>
      ...
    long AFunction(Environment *ev, ODFoo *foo)
    {
      long result;
      try
      {
        long result = foo->Bazz(ev);
      }
      catch( ODException _exception )
      {
        SetErrorCodeEv( ev , kODNoError );  // clear the error since we handled
        result = kODNULL;
      }
      ...
      return result;
    }

Because `ODExcept.h` is included before `ODFoo.xh`, the environment checking code is added to the call to `Bazz` method. If `Bazz` encounters an error and returns error status in ev, a C++ exception with that same error code is returned. The error code is caught by the exception handler and is returned in the ev parameter.

Consider the following guidelines:

- You must include the `ODExcept.h` header file before including any header file that declares SOM classes (`.xh` files in C++) if you want to use automatic environment checking. If you include a SOM class header file before the exception handling code, it has no effect on the SOM class.

- When using automatic environment checking, any SOM method call could return an exception. Therefore, any SOM method that calls another SOM method must be prepared to handle these exceptions. The point to remember is your code must clear the ODException error for any exception that you catch. You can clear the ODException error with the following statement:

        SetErrorCodeEv (ev, kODNoError);

### Guidelines for Using the Debugging Tools.

You can access the debugging tools by including the `ODDebug.h` and `ODDebug.cpp` files. The tools provide the macro categories:

- Display warnings
- Exceptions and warnings based on conditions
- Printing messages

#### Display Warnings

The following macros enable warnings from your OpenDoc code:

- WARNMSG
- WARNMSG_DEBUG
- WARN_CATALOG
- WARN_INDEX

##### WARNMSG

This macro invokes a function that returns `void`.

The syntax of WARNMSG is:

    WARNMSG (void *   catalogHandler,   // handle to an open catalog
                   int      setIndex,   // set index in the catalog
                   int      catalogIndex,     // message index in the catalog
             const char *   fileName,         // file name where warning is issued
             const int      lineNbr,          // line number in the file where
                                              //   warning was issued
                   char *   defaultMsg,       // default message is not available
                                              //   from the catalog
                   ...      /* per-message var args */ );

The catalog index accesses the IBM-supplied translated message catalog. The default message are used if problems occur with the catalog or index. WARNMSG is not affected by the DEBUG macro.

WARNMSG and WARNMSG_DEBUG macros use the catalogIndex and defaultmsg parameters for user-defined warning messages. If you do not have a message catalog, you can pass a value of -1 as the catalog index. Passing a -1 value forces the defaultMsg to be displayed as the message text.

##### WARNMSG_DEBUG

This macro has the same syntax as WARNMSG. The difference between the two macros is that code generated by the WARNMSG_DEBUG macro will not be compiled when DEBUG is not defined.

##### WARN_CATALOG

This macro supplies the standard parameters for the WARNMSG and WARNMSG_DEBUG macros. The definition of the WARN_CATALOG macro is:

        #define WARN_CATALOG (A,B,C) (void*) A,B,C, __FILE__ , __LINE__

WARN_CATALOG can be used with WARNMSG and WARN_DEBUG to produce the following code:

    WARNMSG (
             WARN_CATALOG (catalogHandle, setIndex, catalogIndex),
             my_default_msg);

##### WARN_INDEX

This macro supplies the standard parameters for the WARNMSG and WARNMSG_DEBUG macros. The definition of the WARN_INDEX is:

        #define WARN_INDEX(A) NULL, NULL, (A), __FILE__, __LINE__

This macro is used chiefly by the OpenDoc runtime. It assumes your WARNMSG should use the ODMessage catalog, and the AMSG_SET in that catalog. However, if you do not have the ability to build a catalog, you may find using `WARNMSG_INDEX (-1)` the easiest way to put text in a message box.

Because WARNMSG and WARNMSG_DEBUG use the WARN_INDEX, you could use the following code:

        WARNMSG (                              // example with no parameters
                WARN_INDEX (kMyMsgNum),
                my_default_msg
                );
        WARNMSG (                         // example with parameters
                WARN_INDEX (kAnotherNum),
                my_default_msg,
                fMyVar1,
                fMyVar2
                );
        WARNMSG (                         // example with no message catalog
                 WARN_INDEX (-1),
                 my_default_msg
                );

#### Exceptions and Warning Based on Conditions

The following macros enable assertions from your OpenDoc code:

- ASSERT and ASSERT_DEBUG
- ASSERTMSG, ASSERTCATALOG, and ASSERTMSG_DEBUG
- WASSERT and WASSERT_DEBUG
- WASSERTMSG, WASSERTCATALOG, and WASSERTMSG_DEBUG
- ASSERT_NOT_NULL

The macros ending with "_DEBUG" perform the same function, but they only generate code if you define the DEBUG macro.

ASSERTMSG and WASSERTMSG macros use the defaultMsg and index parameters for user-defined assertion messages. If you do not have a message catalog, use a value of -1 for the message index and place the message text in the default string.

Note:

> The ASSERT macros use a built-in catalog of messages that is indexed by the ODError value supplied.

The ASSERT macros do not assert. These macros return C++ exceptions of type ODException. For a true assertion, your code must use the WARN* macros to generate a message, and then use the ANSI assert() of your C++ compiler as follows:

        WARNMSG (WARN_INDEX(-1), fmt, ... );    // your message
         assert (failing_condition );              // a real assert

##### ASSERT

The syntax of the ASSERT macro is :

        ASSERT (condition, ODError)

If the condition is false, a C++ exception is generated. The value of ODError is written to the thrown ODException structure. The OpenDoc code generates a popup that holds the translated message based on the value of the ODError.

##### ASSERTCATALOG

The syntax of the ASSERTCATALOG macro is:

        ASSERTCATALOG (condition, ODError, char *defaultMsg, catalogIndex,
                       catalogHandle, setIndex)

This macro is the same as ASSERT, but the additional message you supply comes from your message catalog.

##### ASSERTMSG

The syntax of the ASSERTMSG macro is :

        ASSERTMSG (condition, ODError, char *defaultMsg, index)

This macro is the same as ASSERT, but your code can supply an additional message accessed by the index. A default message will be used if the index or message catalog access fails. A C++ exception is returned.

##### WASSERT

The syntax of the WASSERT macro is :

        WASSERT (condition)

If the condition is false, the standard assertion message is printed without generating a C++ exception.

##### WASSERTCATALOG

The syntax of the WASSERTCATALOG macro is:

        WASSERTCATALOG (condition, char *defaultMsg, catalogIndex,
                        catalogHandle, setIndex)

The macro is the same as WASSERT, but the additional message you supply comes from your message catalog.

##### WASSERTMSG

The syntax of the WASSERTMSG macro is :

        WASSERTMSG (condition, char *defaultmsg, index)

This macro is the same as WASSERT, but you can supply and additional massage as described in ASSERTMSG.

##### ASSERT_NOT_NULL

The syntax of the ASSERT_NOT_NULL macro is :

        ASSERT_NOT_NULL (parm)

This special form of ASSERT tests the parm parameter against kODNULL and always generates the error kODErrIllegalNullInput.

#### Printing Messages

The PRINT macro enables printing and logging in your OpenDoc code. PRINT has the same syntax and semantics as somPrintf. PRINT is not affected by the DEBUG macro.

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