XLL+ Class Library

C Structured Exception handling

Structured Exception Handling in C++

Note: the full code for this example can be found in the project SafeCode in the Samples sub-directory.

Structured Exception Handling (SEH) is a 'C' language technique, which does not mix well with C++ code. The easiest way to integrate this kind of code into an XLL+ program is by converting the SEH exceptions to C++ exceptions. This conversion means that you an be sure that destructors will be called correctly in your C++ code, after the SEH exception occurs.

The code below shows a pair of classes that handle the integration into C++. One is a C++ exception class, and the other is a handler class that installs (and uninstalls) a C exception handler function, and converts C exceptions to C++ exceptions.

/////////////////////////////////////////////////////////////////////////////
// C++ adapter for Structured Exception Handling

#include <eh.h>

class SE_Exception {
private:
    unsigned long nSE;
public:
    SE_Exception() {}
    SE_Exception(unsigned long n) : nSE(n) {}
    ~SE_Exception() {}
    unsigned long getSeNumber() { return nSE; }
};

class SE_Handler {
private:
    static void seh_trans_func(unsigned int u, EXCEPTION_POINTERS* pExp) {
        DWORD dwCode = (pExp && pExp->ExceptionRecord) ? pExp->ExceptionRecord->ExceptionCode : 0;
        throw SE_Exception((long)dwCode);
    }
    _se_translator_function fnOld;
public:
    SE_Handler() { fnOld = _set_se_translator(seh_trans_func); }
    ~SE_Handler() { _set_se_translator(fnOld); }
};

To use the handler class, you just have to instantiate one before calling dangerous code and ensure that it is destroyed soon afterwards.

Using a structured exception handler

The unsafe version looks something like this:

extern "C" __declspec( dllexport )
LPXLOPER INTAVG(const COper* Input)
{
    CXlOper xloResult;
    BOOL bOk = TRUE;
    std::vector<long> vecInput;
    bOk = bOk && Input->ReadVector(vecInput, "Input", xloResult);
    if (!bOk)
        return xloResult.Ret();
//}}XLP_SRC

    xloResult = (double)IntAverage(vecInput.size(), &vecInput[0]);
    
    return xloResult.Ret();
}

The safe version (shown below) is different in two ways:

  1. An instance of SE_Handler is declared just before the dangerous function is called.
  2. C++ exception handling is used to catch exceptions of type SE_Exception, and pass their description back to Excel.

extern "C" __declspec( dllexport )
LPXLOPER INTAVG(const COper* Input)
{
    CXlOper xloResult;
    BOOL bOk = TRUE;
    std::vector<long> vecInput;
    bOk = bOk && Input->ReadVector(vecInput, "Input", xloResult);
    if (!bOk)
        return xloResult.Ret();
//}}XLP_SRC

    try {
        SE_Handler seh;
        xloResult = (double)IntAverage(vecInput.size(), &vecInput[0]);
    }
    catch(SE_Exception e) {
        xloResult.Format("#ERROR: C exception 0x%lX", e.getSeNumber());
    }

    return xloResult.Ret();
}

Next: Object handles >>