HOW TO: How can I generate code to automatically handle a C++ exception?

Reference: Q0054

Article last modified on 8-Jul-2012


The information in this article applies to:

  • XLL+ for Visual Studio 2010 - 6.0, 7.0
  • XLL+ for Visual Studio 2008 - 6.0, 7.0
  • XLL+ for Visual Studio 2005 - 6.0, 7.0

HOW TO: How can I generate code to automatically handle a C++ exception?

Problem

I have an existing library of functions, many of which can throw an exception of a particular type. How can I avoid writing code like this for every add-in function:

try {
    // Call library function, which may throw MyException
} catch (const MyException& e) {
    throw ConvertToCXlRuntimeException(e);
}

Summary

You can write a function extension that will automatically generate the catch block, and you can use the XLL+ Function Wizard to mark the add-in function so that the extension code is generated.

Function Extensions

For an introduction to writing and using function extensions, see the XLL+ User Guide topic "Function Extensions" (http://www.planatechsolutions.com/xllplus7-online/?start_function_extensions.htm) and the "Profiling" sample add-in (http://www.planatechsolutions.com/xllplus7-online/?sample_Profiling.htm).

The Extension file

The XML below is placed into an extension file, "MyException.xpe":

<?xml version="1.0" encoding="utf-16"?>
<Extensions xmlns="http://schemas.planatechsolutions.com/xlp/601/xt">
  <FunctionExtensions>
    <FunctionExtension name="MyExceptionHandler" headerFiles="MyException.h">
      <LocalizedDisplayName text="MyExceptionHandler"/>
      <LocalizedDescription text="Handles exceptions of type MyException"/>
      <Insertions>
        <Insertion insertionPoint="AfterCatchException" priority="1">
          <Code>
            <![CDATA[    catch(const MyException& e) {{
        ConvertException(e, xloResult);
    }}
]]>
          </Code>
        </Insertion>
      </Insertions>
    </FunctionExtension>
  </FunctionExtensions>
</Extensions>

The following points are of interest:

  1. The extension will appear in the XLL+ Function Wizard in the list of available Function Features, with the name "MyExceptionHandler", and the help text "Handles exceptions of type MyException".

  2. The code to be generated contains braces: { and }. These must be inserted into the extension template as double braces, i.e.:

              <Code>
                <![CDATA[    catch(const MyException& e) {{
            ConvertException(e, xloResult);
        }}
    ]]>
              </Code>
    
  3. The code will appear in the generated code of the outer wrapper functions, e.g. MyFunction_4 and MyFunction_12. It will be generated after the standard catch blocks, e.g.:

    LPXLOPER12 MyFunction_12(double x)
    {
        XLL_FIX_STATE;
        CXlOper xloResult;
        try {
            CXlStructuredExceptionHandler _seh_;
            xloResult.HandleResult(MyFunction_Impl(xloResult, x));
        }
        catch(const CXlRuntimeException& ex) {
            CXllApp::Instance()->DisplayException(xloResult, ex);
        }
        XLP_CATCH_CLR_EXCEPTIONS_TO(xloResult)
        catch(const MyException& e) {
            ConvertException(e, xloResult);
        }
        return xloResult.Ret12();
    }
    
  4. The header file MyException.h will automatically be included in any cpp file that contains an add-in function which uses the MyExceptionHandler extension. The contents of the header file are shown below.

  5. If the extension is used, the code written by the developer can forget about catching exceptions of type MyException. See below.

You should load the extension by clicking the Manage Extensions... command on the Tools menu in the XLL AddIns window. Then click on the Add tool-button and select your extension file. See "Extended types introduction" (http://www.planatechsolutions.com/xllplus7-online/?start_scalar_extended_types1.htm) in the User Guide for more details on loading extension files.

The header file

The extension header file contains the exception definition and a conversion function which translates the exception to a CXlOper type:

#pragma once

#include <string>
#include <xlpoper.h>

class MyException
{
public:
    ...
    MyException(const char* errText) : m_errText(errText ? errText : "") { }
    const std::string& getText() const { return m_errText; }
    ...
};

inline void ConvertException(const MyException& e, CXlOper& xloResult)
{
    xloResult = "#ERROR: " + e.getText();
}

Using the extension

A typical add-in function which needs to catch an exception of type MyException is as follows:

CXlOper* MySqrt1_Impl(CXlOper& xloResult, double x)
{
    // End of generated code
//}}XLP_SRC
    try
    {
        xloResult = CalcSquareRoot(x);
    }
    catch(const MyException& e)
    {
        ConvertException(e, xloResult);
    }
    return xloResult.Ret();
}

If the function is marked as using the extension "MyExceptionHandler", then the following code can be used instead:

CXlOper* MySqrt2_Impl(CXlOper& xloResult, double x)
{
    // End of generated code
//}}XLP_SRC
    xloResult = CalcSquareRoot(x);
    return xloResult.Ret();
}

As you can see, the developer can ignore exceptions of type MyException, because they are being dealt with by the outer generated wrapper function.

Building help

When you try to build the Release configuration, you may get an error such as this:

1>  Build help project
1>  ExcepExt.cpp: failed to load 1 of 2
1>   MySqrt2: Function extension 'MyExceptionHandler' is unknown. Are you missing an extension file?

You should make sure that the XLL+ help compiler is aware of the extension file by clicking the command Update Help command line from the Tools menu in the XLL AddIns window.

Making the extension a default extension

If the extension is to be used on most or all of your add-in functions, then you can save time by adding the extension's name to the list of default function extensions.

Open the XLL+/General page in the Tools Options dialog of Visual Studio, and add MyExceptionHandler to the list in DefaultFunctionExtensions (in the Defaults category):

From now on, each new function that you create will have the extension defined automatically.

For existing functions, you will need to set the extension yourself. However, you can save time by selecting multiple functions in the XLL AddIns window and then using the Properties window to check the "MyExceptionHandler" extension for all of them at once:

Example code

You can download the example code above, including the extension file, in this zip file: q0054_sample.zip