OSDN Git Service

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