OSDN Git Service

refactor
[winmerge-jp/winmerge-jp.git] / Src / Exceptions.h
1 /////////////////////////////////////////////////////////////////////////////
2 //    WinMerge:  an interactive diff/merge utility
3 //    Copyright (C) 1997-2000  Thingamahoochie Software
4 //    Author: Dean Grimm
5 //    SPDX-License-Identifier: GPL-2.0-or-later
6 /////////////////////////////////////////////////////////////////////////////
7 /**
8  *  @file Exceptions.h
9  *
10  *  @brief Exceptions handlers (currently, only SE handler for try/catch)
11  */ 
12 #pragma once
13
14 #ifdef _MSC_VER
15
16 #include <windows.h>
17 #include <strsafe.h>
18
19 #endif
20
21 #include "utils/ctchar.h"
22
23
24 /**
25  * @brief C exception "wrapper" class for C++ try/catch
26  *
27  * @note : for the original idea, see MSDN help about _set_se_translator
28  *   derive from CException::CException
29  *     creator needs a flag bAutoDelete
30  *     (when flag is set, exception is reserved on heap, avoid to use the stack as it may be wrecked)
31  *     one single interface to catch SE_Exception and CException
32  *   GetErrorMessage : avoid using CString during exception processing
33  */
34 class SE_Exception
35 {
36 private:
37         unsigned long nSE;
38 public:
39         explicit SE_Exception(unsigned long n) : nSE(n) {}
40         ~SE_Exception() = default;
41
42         unsigned long getSeNumber() { return nSE; }
43 #ifdef _MSC_VER
44         const tchar_t *getSeMessage()
45         {
46                 // known exceptions (from WINNT.H)
47                 #define EXCEPTION( x ) case EXCEPTION_##x: return _T(#x);
48
49           switch ( nSE )
50           {
51                         EXCEPTION( ACCESS_VIOLATION )
52                         EXCEPTION( DATATYPE_MISALIGNMENT )
53                         EXCEPTION( BREAKPOINT )
54                         EXCEPTION( SINGLE_STEP )
55                         EXCEPTION( ARRAY_BOUNDS_EXCEEDED )
56                         EXCEPTION( FLT_DENORMAL_OPERAND )
57                         EXCEPTION( FLT_DIVIDE_BY_ZERO )
58                         EXCEPTION( FLT_INEXACT_RESULT )
59                         EXCEPTION( FLT_INVALID_OPERATION )
60                         EXCEPTION( FLT_OVERFLOW )
61                         EXCEPTION( FLT_STACK_CHECK )
62                         EXCEPTION( FLT_UNDERFLOW )
63                         EXCEPTION( INT_DIVIDE_BY_ZERO )
64                         EXCEPTION( INT_OVERFLOW )
65                         EXCEPTION( PRIV_INSTRUCTION )
66                         EXCEPTION( IN_PAGE_ERROR )
67                         EXCEPTION( ILLEGAL_INSTRUCTION )
68                         EXCEPTION( NONCONTINUABLE_EXCEPTION )
69                         EXCEPTION( STACK_OVERFLOW )
70                         EXCEPTION( INVALID_DISPOSITION )
71                         EXCEPTION( GUARD_PAGE )
72                         EXCEPTION( INVALID_HANDLE )
73                 }
74
75                 // don't localize this as we do not localize the known exceptions
76                 return _T("Unknown structured exception");
77         }
78         virtual bool GetErrorMessage(tchar_t *lpszError, unsigned nMaxError, unsigned *pnHelpContext = nullptr)
79         {
80                 StringCchPrintf(lpszError, nMaxError, _T("Exception %s (0x%.8x)"), getSeMessage(), static_cast<unsigned>(getSeNumber()));
81                 return true;
82         }
83 #else
84         virtual bool GetErrorMessage(tchar_t *lpszError, unsigned nMaxError, unsigned *pnHelpContext = nullptr)
85         {
86                 return true;
87         }
88 #endif
89 };
90
91
92 /**
93  * @brief Set the structured exception translator during the life of the object.
94  * Just add 'SE_Handler seh;' at the beginning of the function.
95  *
96  * @note May be created as a global variable. In fact, you need one instance
97  * for each thread.
98  */
99 class SE_Handler {
100 #ifdef _MSC_VER
101 private:
102         _se_translator_function fnOld;
103         static void seh_trans_func(unsigned u, EXCEPTION_POINTERS* pExp) 
104         {
105                 unsigned dwCode = (pExp && pExp->ExceptionRecord) ? pExp->ExceptionRecord->ExceptionCode : 0;
106                 throw SE_Exception((long)dwCode);
107         }
108 public:
109         SE_Handler() : fnOld{_set_se_translator(seh_trans_func)} {}
110         ~SE_Handler() { _set_se_translator(fnOld); }
111 #else
112 public:
113         SE_Handler() {}
114 #endif
115 };