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