1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=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 // NB: This code may be used from non-XPCOM code, in particular, the
8 // Windows Default Browser Agent.
9
10 #ifndef nsWindowsHelpers_h
11 #define nsWindowsHelpers_h
12
13 #include <windows.h>
14 #include <msi.h>
15 #include "nsAutoRef.h"
16 #include "mozilla/Assertions.h"
17 #include "mozilla/UniquePtr.h"
18
19 // ----------------------------------------------------------------------------
20 // Critical Section helper class
21 // ----------------------------------------------------------------------------
22
23 class AutoCriticalSection {
24 public:
AutoCriticalSection(LPCRITICAL_SECTION aSection)25 explicit AutoCriticalSection(LPCRITICAL_SECTION aSection)
26 : mSection(aSection) {
27 ::EnterCriticalSection(mSection);
28 }
~AutoCriticalSection()29 ~AutoCriticalSection() { ::LeaveCriticalSection(mSection); }
30
31 private:
32 LPCRITICAL_SECTION mSection;
33 };
34
35 template <>
36 class nsAutoRefTraits<HKEY> {
37 public:
38 typedef HKEY RawRef;
Void()39 static HKEY Void() { return nullptr; }
40
Release(RawRef aFD)41 static void Release(RawRef aFD) {
42 if (aFD != Void()) {
43 RegCloseKey(aFD);
44 }
45 }
46 };
47
48 template <>
49 class nsAutoRefTraits<HDC> {
50 public:
51 typedef HDC RawRef;
Void()52 static HDC Void() { return nullptr; }
53
Release(RawRef aFD)54 static void Release(RawRef aFD) {
55 if (aFD != Void()) {
56 ::DeleteDC(aFD);
57 }
58 }
59 };
60
61 template <>
62 class nsAutoRefTraits<HFONT> {
63 public:
64 typedef HFONT RawRef;
Void()65 static HFONT Void() { return nullptr; }
66
Release(RawRef aFD)67 static void Release(RawRef aFD) {
68 if (aFD != Void()) {
69 ::DeleteObject(aFD);
70 }
71 }
72 };
73
74 template <>
75 class nsAutoRefTraits<HBRUSH> {
76 public:
77 typedef HBRUSH RawRef;
Void()78 static HBRUSH Void() { return nullptr; }
79
Release(RawRef aFD)80 static void Release(RawRef aFD) {
81 if (aFD != Void()) {
82 ::DeleteObject(aFD);
83 }
84 }
85 };
86
87 template <>
88 class nsAutoRefTraits<HRGN> {
89 public:
90 typedef HRGN RawRef;
Void()91 static HRGN Void() { return nullptr; }
92
Release(RawRef aFD)93 static void Release(RawRef aFD) {
94 if (aFD != Void()) {
95 ::DeleteObject(aFD);
96 }
97 }
98 };
99
100 template <>
101 class nsAutoRefTraits<HBITMAP> {
102 public:
103 typedef HBITMAP RawRef;
Void()104 static HBITMAP Void() { return nullptr; }
105
Release(RawRef aFD)106 static void Release(RawRef aFD) {
107 if (aFD != Void()) {
108 ::DeleteObject(aFD);
109 }
110 }
111 };
112
113 template <>
114 class nsAutoRefTraits<SC_HANDLE> {
115 public:
116 typedef SC_HANDLE RawRef;
Void()117 static SC_HANDLE Void() { return nullptr; }
118
Release(RawRef aFD)119 static void Release(RawRef aFD) {
120 if (aFD != Void()) {
121 CloseServiceHandle(aFD);
122 }
123 }
124 };
125
126 template <>
127 class nsSimpleRef<HANDLE> {
128 protected:
129 typedef HANDLE RawRef;
130
nsSimpleRef()131 nsSimpleRef() : mRawRef(nullptr) {}
132
nsSimpleRef(RawRef aRawRef)133 explicit nsSimpleRef(RawRef aRawRef) : mRawRef(aRawRef) {}
134
HaveResource()135 bool HaveResource() const {
136 return mRawRef && mRawRef != INVALID_HANDLE_VALUE;
137 }
138
139 public:
get()140 RawRef get() const { return mRawRef; }
141
Release(RawRef aRawRef)142 static void Release(RawRef aRawRef) {
143 if (aRawRef && aRawRef != INVALID_HANDLE_VALUE) {
144 CloseHandle(aRawRef);
145 }
146 }
147 RawRef mRawRef;
148 };
149
150 template <>
151 class nsAutoRefTraits<HMODULE> {
152 public:
153 typedef HMODULE RawRef;
Void()154 static RawRef Void() { return nullptr; }
155
Release(RawRef aFD)156 static void Release(RawRef aFD) {
157 if (aFD != Void()) {
158 FreeLibrary(aFD);
159 }
160 }
161 };
162
163 template <>
164 class nsAutoRefTraits<DEVMODEW*> {
165 public:
166 typedef DEVMODEW* RawRef;
Void()167 static RawRef Void() { return nullptr; }
168
Release(RawRef aDevMode)169 static void Release(RawRef aDevMode) {
170 if (aDevMode != Void()) {
171 ::HeapFree(::GetProcessHeap(), 0, aDevMode);
172 }
173 }
174 };
175
176 template <>
177 class nsAutoRefTraits<MSIHANDLE> {
178 public:
179 typedef MSIHANDLE RawRef;
Void()180 static RawRef Void() { return 0; }
181
Release(RawRef aHandle)182 static void Release(RawRef aHandle) {
183 if (aHandle != Void()) {
184 ::MsiCloseHandle(aHandle);
185 }
186 }
187 };
188
189 // HGLOBAL is just a typedef of HANDLE which nsSimpleRef has a specialization
190 // of, that means having a nsAutoRefTraits specialization for HGLOBAL is
191 // useless. Therefore we create a wrapper class for HGLOBAL to make
192 // nsAutoRefTraits and nsAutoRef work as intention.
193 class nsHGLOBAL {
194 public:
nsHGLOBAL(HGLOBAL hGlobal)195 MOZ_IMPLICIT nsHGLOBAL(HGLOBAL hGlobal) : m_hGlobal(hGlobal) {}
196
HGLOBAL()197 operator HGLOBAL() const { return m_hGlobal; }
198
199 private:
200 HGLOBAL m_hGlobal;
201 };
202
203 template <>
204 class nsAutoRefTraits<nsHGLOBAL> {
205 public:
206 typedef nsHGLOBAL RawRef;
Void()207 static RawRef Void() { return nullptr; }
208
Release(RawRef hGlobal)209 static void Release(RawRef hGlobal) { ::GlobalFree(hGlobal); }
210 };
211
212 // Because Printer's HANDLE uses ClosePrinter and we already have
213 // nsAutoRef<HANDLE> which uses CloseHandle so we need to create a wrapper class
214 // for HANDLE to have another specialization for nsAutoRefTraits.
215 class nsHPRINTER {
216 public:
nsHPRINTER(HANDLE hPrinter)217 MOZ_IMPLICIT nsHPRINTER(HANDLE hPrinter) : m_hPrinter(hPrinter) {}
218
HANDLE()219 operator HANDLE() const { return m_hPrinter; }
220
221 HANDLE* operator&() { return &m_hPrinter; }
222
223 private:
224 HANDLE m_hPrinter;
225 };
226
227 // winspool.h header has AddMonitor macro, it conflicts with AddMonitor member
228 // function in TaskbarPreview.cpp and TaskbarTabPreview.cpp. Beside, we only
229 // need ClosePrinter here for Release function, so having its prototype is
230 // enough.
231 extern "C" BOOL WINAPI ClosePrinter(HANDLE hPrinter);
232
233 template <>
234 class nsAutoRefTraits<nsHPRINTER> {
235 public:
236 typedef nsHPRINTER RawRef;
Void()237 static RawRef Void() { return nullptr; }
238
Release(RawRef hPrinter)239 static void Release(RawRef hPrinter) { ::ClosePrinter(hPrinter); }
240 };
241
242 typedef nsAutoRef<HKEY> nsAutoRegKey;
243 typedef nsAutoRef<HDC> nsAutoHDC;
244 typedef nsAutoRef<HFONT> nsAutoFont;
245 typedef nsAutoRef<HBRUSH> nsAutoBrush;
246 typedef nsAutoRef<HRGN> nsAutoRegion;
247 typedef nsAutoRef<HBITMAP> nsAutoBitmap;
248 typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle;
249 typedef nsAutoRef<HANDLE> nsAutoHandle;
250 typedef nsAutoRef<HMODULE> nsModuleHandle;
251 typedef nsAutoRef<DEVMODEW*> nsAutoDevMode;
252 typedef nsAutoRef<nsHGLOBAL> nsAutoGlobalMem;
253 typedef nsAutoRef<nsHPRINTER> nsAutoPrinter;
254 typedef nsAutoRef<MSIHANDLE> nsAutoMsiHandle;
255
256 namespace {
257
258 // Construct a path "<system32>\<aModule>". return false if the output buffer
259 // is too small.
260 // Note: If the system path cannot be found, or doesn't fit in the output buffer
261 // with the module name, we will just ignore the system path and output the
262 // module name alone;
263 // this may mean using a normal search path wherever the output is used.
ConstructSystem32Path(LPCWSTR aModule,WCHAR * aSystemPath,UINT aSize)264 bool inline ConstructSystem32Path(LPCWSTR aModule, WCHAR* aSystemPath,
265 UINT aSize) {
266 MOZ_ASSERT(aSystemPath);
267
268 size_t fileLen = wcslen(aModule);
269 if (fileLen >= aSize) {
270 // The module name alone cannot even fit!
271 return false;
272 }
273
274 size_t systemDirLen = GetSystemDirectoryW(aSystemPath, aSize);
275
276 if (systemDirLen) {
277 if (systemDirLen < aSize - fileLen) {
278 // Make the system directory path terminate with a slash.
279 if (aSystemPath[systemDirLen - 1] != L'\\') {
280 if (systemDirLen + 1 < aSize - fileLen) {
281 aSystemPath[systemDirLen] = L'\\';
282 ++systemDirLen;
283 // No need to re-nullptr terminate.
284 } else {
285 // Couldn't fit the system path with added slash.
286 systemDirLen = 0;
287 }
288 }
289 } else {
290 // Couldn't fit the system path.
291 systemDirLen = 0;
292 }
293 }
294
295 MOZ_ASSERT(systemDirLen + fileLen < aSize);
296
297 wcsncpy(aSystemPath + systemDirLen, aModule, fileLen);
298 aSystemPath[systemDirLen + fileLen] = L'\0';
299 return true;
300 }
301
LoadLibrarySystem32(LPCWSTR aModule)302 HMODULE inline LoadLibrarySystem32(LPCWSTR aModule) {
303 WCHAR systemPath[MAX_PATH + 1];
304 if (!ConstructSystem32Path(aModule, systemPath, MAX_PATH + 1)) {
305 return NULL;
306 }
307 return LoadLibraryW(systemPath);
308 }
309
310 } // namespace
311
312 // for UniquePtr
313 struct LocalFreeDeleter {
operatorLocalFreeDeleter314 void operator()(void* aPtr) { ::LocalFree(aPtr); }
315 };
316
317 struct VirtualFreeDeleter {
operatorVirtualFreeDeleter318 void operator()(void* aPtr) { ::VirtualFree(aPtr, 0, MEM_RELEASE); }
319 };
320
321 // for UniquePtr to store a PSID
322 struct FreeSidDeleter {
operatorFreeSidDeleter323 void operator()(void* aPtr) { ::FreeSid(aPtr); }
324 };
325 // Unfortunately, although SID is a struct, PSID is a void*
326 // This typedef will work for storing a PSID in a UniquePtr and should make
327 // things a bit more readable.
328 typedef mozilla::UniquePtr<void, FreeSidDeleter> UniqueSidPtr;
329 #endif
330