1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. *
6  */
7 
8 #ifndef mozilla_a11y_IUnknownImpl_h_
9 #define mozilla_a11y_IUnknownImpl_h_
10 
11 #include <windows.h>
12 #undef CreateEvent // thank you windows you're such a helper
13 #include "nsError.h"
14 
15 // Avoid warning C4509 like "nonstandard extension used:
16 // 'AccessibleWrap::[acc_getName]' uses SEH and 'name' has destructor.
17 // At this point we're catching a crash which is of much greater
18 // importance than the missing dereference for the nsCOMPtr<>
19 #ifdef _MSC_VER
20 #pragma warning( disable : 4509 )
21 #endif
22 
23 #ifdef __GNUC__
24 #define ATTRIBUTE_UNUSED __attribute__((unused))
25 #else
26 #define ATTRIBUTE_UNUSED
27 #endif
28 
29 namespace mozilla {
30 namespace a11y {
31 
32 class AutoRefCnt
33 {
34 public:
AutoRefCnt()35   AutoRefCnt() : mValue(0) {}
36 
37   ULONG operator++() { return ++mValue; }
38   ULONG operator--() { return --mValue; }
39   ULONG operator++(int) { return ++mValue; }
40   ULONG operator--(int) { return --mValue; }
41 
ULONG()42   operator ULONG() const { return mValue; }
43 
44 private:
45   ULONG mValue;
46 };
47 
48 } // namespace a11y
49 } // namespace mozilla
50 
51 #define DECL_IUNKNOWN                                                          \
52 public:                                                                        \
53   virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);            \
54   virtual ULONG STDMETHODCALLTYPE AddRef() final                               \
55   {                                                                            \
56     MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");                       \
57     ++mRefCnt;                                                                 \
58     return mRefCnt;                                                            \
59   }                                                                            \
60   virtual ULONG STDMETHODCALLTYPE Release() final                              \
61   {                                                                            \
62      MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");                          \
63      --mRefCnt;                                                                \
64      if (mRefCnt)                                                              \
65        return mRefCnt;                                                         \
66                                                                                \
67      delete this;                                                              \
68      return 0;                                                                 \
69   }                                                                            \
70 private:                                                                       \
71   mozilla::a11y::AutoRefCnt mRefCnt;                                           \
72 public:
73 
74 #define DECL_IUNKNOWN_INHERITED                                                \
75 public:                                                                        \
76 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**);              \
77 
78 #define IMPL_IUNKNOWN_QUERY_HEAD(Class)                                        \
79 STDMETHODIMP                                                                   \
80 Class::QueryInterface(REFIID aIID, void** aInstancePtr)                        \
81 {                                                                              \
82   A11Y_TRYBLOCK_BEGIN                                                          \
83   if (!aInstancePtr)                                                           \
84     return E_INVALIDARG;                                                       \
85   *aInstancePtr = nullptr;                                                     \
86                                                                                \
87   HRESULT hr ATTRIBUTE_UNUSED = E_NOINTERFACE;
88 
89 #define IMPL_IUNKNOWN_QUERY_TAIL                                               \
90   return hr;                                                                   \
91   A11Y_TRYBLOCK_END                                                            \
92 }
93 
94 #define IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(Member)                            \
95   return Member->QueryInterface(aIID, aInstancePtr);                           \
96   A11Y_TRYBLOCK_END                                                            \
97 }
98 
99 #define IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(BaseClass)                          \
100   return BaseClass::QueryInterface(aIID, aInstancePtr);                        \
101   A11Y_TRYBLOCK_END                                                            \
102 }
103 
104 #define IMPL_IUNKNOWN_QUERY_IFACE(Iface)                                       \
105   if (aIID == IID_##Iface) {                                                   \
106     *aInstancePtr = static_cast<Iface*>(this);                                 \
107     AddRef();                                                                  \
108     return S_OK;                                                               \
109   }
110 
111 #define IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(Iface, aResolveIface)              \
112   if (aIID == IID_##Iface) {                                                   \
113     *aInstancePtr = static_cast<Iface*>(static_cast<aResolveIface*>(this));    \
114     AddRef();                                                                  \
115     return S_OK;                                                               \
116   }
117 
118 #define IMPL_IUNKNOWN_QUERY_CLASS(Class)                                       \
119   hr = Class::QueryInterface(aIID, aInstancePtr);                              \
120   if (SUCCEEDED(hr))                                                           \
121     return hr;
122 
123 #define IMPL_IUNKNOWN_QUERY_CLASS_COND(Class, Cond)                            \
124   if (Cond) {                                                                  \
125     hr = Class::QueryInterface(aIID, aInstancePtr);                            \
126     if (SUCCEEDED(hr))                                                         \
127       return hr;                                                               \
128   }
129 
130 #define IMPL_IUNKNOWN_QUERY_AGGR_COND(Member, Cond)                            \
131   if (Cond) {                                                                  \
132     hr = Member->QueryInterface(aIID, aInstancePtr);                           \
133     if (SUCCEEDED(hr))                                                         \
134       return hr;                                                               \
135   }
136 
137 #define IMPL_IUNKNOWN1(Class, I1)                                              \
138   IMPL_IUNKNOWN_QUERY_HEAD(Class)                                              \
139   IMPL_IUNKNOWN_QUERY_IFACE(I1);                                               \
140   IMPL_IUNKNOWN_QUERY_IFACE(IUnknown);                                         \
141   IMPL_IUNKNOWN_QUERY_TAIL                                                     \
142 
143 #define IMPL_IUNKNOWN2(Class, I1, I2)                                          \
144   IMPL_IUNKNOWN_QUERY_HEAD(Class)                                              \
145   IMPL_IUNKNOWN_QUERY_IFACE(I1);                                               \
146   IMPL_IUNKNOWN_QUERY_IFACE(I2);                                               \
147   IMPL_IUNKNOWN_QUERY_IFACE_AMBIGIOUS(IUnknown, I1);                           \
148   IMPL_IUNKNOWN_QUERY_TAIL                                                     \
149 
150 #define IMPL_IUNKNOWN_INHERITED1(Class, Super0, Super1)                        \
151   IMPL_IUNKNOWN_QUERY_HEAD(Class)                                              \
152   IMPL_IUNKNOWN_QUERY_CLASS(Super1);                                           \
153   IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(Super0)
154 
155 #define IMPL_IUNKNOWN_INHERITED2(Class, Super0, Super1, Super2)                \
156   IMPL_IUNKNOWN_QUERY_HEAD(Class)                                              \
157   IMPL_IUNKNOWN_QUERY_CLASS(Super1);                                           \
158   IMPL_IUNKNOWN_QUERY_CLASS(Super2);                                           \
159   IMPL_IUNKNOWN_QUERY_TAIL_INHERITED(Super0)
160 
161 
162 /**
163  * Wrap every method body by these macroses to pass exception to the crash
164  * reporter.
165  */
166 #define A11Y_TRYBLOCK_BEGIN                                                    \
167   MOZ_SEH_TRY {
168 
169 #define A11Y_TRYBLOCK_END                                                      \
170   } MOZ_SEH_EXCEPT(mozilla::a11y::FilterExceptions(::GetExceptionCode(),       \
171                                                    GetExceptionInformation())) \
172   { }                                                                          \
173   return E_FAIL;
174 
175 
176 namespace mozilla {
177 namespace a11y {
178 
179 /**
180  * Converts nsresult to HRESULT.
181  */
182 HRESULT GetHRESULT(nsresult aResult);
183 
184 /**
185  * Used to pass an exception to the crash reporter.
186  */
187 int FilterExceptions(unsigned int aCode, EXCEPTION_POINTERS* aExceptionInfo);
188 
189 } // namespace a11y;
190 } //namespace mozilla;
191 
192 #endif
193