Archive

Posts Tagged ‘exception handling’

Mixing SEH and C++ EH

May 9th, 2009

Some people have noticed my use of two classes (SehGuard and SehException) in a lot of my code and became curious. The reason I’m using them is so I can mix C++ exception handling with structured exception handling. Obviously if you enable C++ with SEH Exceptions in your compiler you can catch SEH exceptions with ‘catch(…)’ but unforutunately you don’t get an object with which you can get any useful information. I went searching for a workaround and found this blog post.

The following is my implementation of the two classes, which is based off the code in that original post (tstring, tcout, etc are just preprocessor defines that resolve to either string/cout/etc or wstring/wcout/etc depending on whether Unicode is defined or not).

Seh.h

// Use pragma directive if supported.

#pragma once

// Use preprocessor header guards if pragma once is unavailable

// Required to ensure portability

#ifndef __CERBERUS__SEH_H

#define __CERBERUS__SEH_H

// Cerberus

#include “StringWrap.h”

// Windows API

#include <Windows.h>

// C++ Standard Library

#include <iostream>

// Function-local SEH guard. Proxies SEH to C++ EH

// Catch via SehException

class SehGuard

{

public:

SehGuard();

~SehGuard();

private:

void* m_prev;

};

// SEH proxy exception.

// Catch this to catch structured exceptions as C++ exceptions.

// Must have SehGuard object created for it to work (function-local).

class SehException

{

public:

SehException(int Code, struct _EXCEPTION_POINTERS* pException);

DWORD GetCode() const;

PVOID GetAddress() const;

struct _EXCEPTION_POINTERS* GetExceptionPointers() const;

private:

unsigned int m_Code;

struct _EXCEPTION_POINTERS* m_pException;

};

// Ostream overload for SehException. To make debug output easier.

std::tostream& operator<< ( std::tostream& out, const SehException& x );

// SEH to C++ EH proxy function

extern void SehTranslatorFunction(unsigned int, struct _EXCEPTION_POINTERS*);

// Generic unhandled exception filter

extern LONG WINAPI MyGenericUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo);

#endif // __CERBERUS__SEH_H

Seh.cpp
// Cerberus
#include “Seh.h”
#include “StringWrap.h”
// Windows API
#include <Windows.h>
#include <Dbghelp.h>
#include <eh.h>
#include <tchar.h>
// C++ Standard Library
#include <string>
#include <vector>
// Proxies SEH to C++ EH
void SehTranslatorFunction(unsigned int Code, struct _EXCEPTION_POINTERS* pException)
{
throw SehException(Code,pException);
}
// Constructor
SehGuard::SehGuard()
{
// Set SEH translator
m_prev = _set_se_translator(SehTranslatorFunction);
}
// Destructor
SehGuard::~SehGuard()
{
// Reset SEH translator
_set_se_translator(reinterpret_cast<_se_translator_function>(m_prev));
}
// Proxy exception constructor
SehException::SehException( int Code, struct _EXCEPTION_POINTERS* pException )
: m_Code(Code), m_pException(pException)
{ }
// Get exception code
DWORD SehException::GetCode() const
{
return m_Code;
}
// Get exception address
PVOID SehException::GetAddress() const
{
return m_pException->ExceptionRecord->ExceptionAddress;
}
// Get exception data pointer
struct _EXCEPTION_POINTERS* SehException::GetExceptionPointers() const
{
return m_pException;
}
// Ostream overload for SehException. To make debug output easier.
// TODO: Full output for x86 and x64 with registers, stack trace, etc
std::tostream& operator<<( std::tostream& out, const SehException& x )
{
out << _T(”Code: “) << std::hex << x.GetCode() << _T(”. Address: “)
<<  x.GetAddress() << std::dec << _T(”.”);
return out;
}
// Generic unhandled exception filter
LONG WINAPI MyGenericUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo)
{
// Get the current time
SYSTEMTIME sTime;
GetLocalTime( &sTime );
// Pull out the date
std::vector<TCHAR> Date(10);
GetDateFormat(LOCALE_USER_DEFAULT, 0, &sTime, _T(”yyyyMMdd”), &Date[0],
10);
// Pull out the time
std::vector<TCHAR> Time(10);
GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT, &sTime,
_T(”hhmmss”), &Time[0], 10);
// Create a filename for the crash dump out of the current
// date and time.
std::tstring Path(TEXT(”Crash-”));
Path.append(&Date[0]).append(&Time[0]).append(_T(”.txt”));
// Create file to dump output
HANDLE hFile = CreateFile(Path.c_str(), GENERIC_WRITE, 0, NULL,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
// Create minidump
MINIDUMP_EXCEPTION_INFORMATION aMiniDumpInfo;
aMiniDumpInfo.ThreadId = GetCurrentThreadId();
aMiniDumpInfo.ExceptionPointers = ExceptionInfo;
aMiniDumpInfo.ClientPointers = TRUE;
// Write minidump
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
(MINIDUMP_TYPE) (MiniDumpWithFullMemory|MiniDumpWithHandleData),
&aMiniDumpInfo, NULL, NULL);
// Close file handle
CloseHandle(hFile);
// Execute handler
return EXCEPTION_EXECUTE_HANDLER;
}
Usage is fairly simple. Dump a SehGuard in your try block, and catch the SehException as you would any other. It makes programming for Windows in C++ about a lot easier and more natural.