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:
-
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".
-
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>
-
The code will appear in the generated code of the outer wrapper functions, e.g.
MyFunction_4
andMyFunction_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(); }
-
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. -
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