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 https://mozilla.org/MPL/2.0/. */
6
7 #ifndef mozilla_WinHeaderOnlyUtils_h
8 #define mozilla_WinHeaderOnlyUtils_h
9
10 #include <windows.h>
11 #include <winerror.h>
12 #include <winnt.h>
13 #include <winternl.h>
14 #include <objbase.h>
15
16 #include <stdlib.h>
17
18 #include "mozilla/Assertions.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/DynamicallyLinkedFunctionPtr.h"
21 #include "mozilla/Maybe.h"
22 #include "mozilla/Result.h"
23 #include "mozilla/Tuple.h"
24 #include "mozilla/UniquePtr.h"
25 #include "mozilla/WindowsVersion.h"
26 #include "nsWindowsHelpers.h"
27
28 #if defined(MOZILLA_INTERNAL_API)
29 # include "nsIFile.h"
30 # include "nsString.h"
31 #endif // defined(MOZILLA_INTERNAL_API)
32
33 /**
34 * This header is intended for self-contained, header-only, utility code for
35 * Win32. It may be used outside of xul.dll, in places such as firefox.exe or
36 * mozglue.dll. If your code creates dependencies on Mozilla libraries, you
37 * should put it elsewhere.
38 */
39
40 #if _WIN32_WINNT < _WIN32_WINNT_WIN8
41 typedef struct _FILE_ID_INFO {
42 ULONGLONG VolumeSerialNumber;
43 FILE_ID_128 FileId;
44 } FILE_ID_INFO;
45
46 # define FileIdInfo ((FILE_INFO_BY_HANDLE_CLASS)18)
47
48 #endif // _WIN32_WINNT < _WIN32_WINNT_WIN8
49
50 #if !defined(STATUS_SUCCESS)
51 # define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
52 #endif // !defined(STATUS_SUCCESS)
53
54 namespace mozilla {
55
56 class WindowsError final {
57 private:
58 // HRESULT and NTSTATUS are both typedefs of LONG, so we cannot use
59 // overloading to properly differentiate between the two. Instead we'll use
60 // static functions to convert the various error types to HRESULTs before
61 // instantiating.
WindowsError(HRESULT aHResult)62 explicit WindowsError(HRESULT aHResult) : mHResult(aHResult) {}
63
64 public:
65 using UniqueString = UniquePtr<WCHAR[], LocalFreeDeleter>;
66
FromNtStatus(NTSTATUS aNtStatus)67 static WindowsError FromNtStatus(NTSTATUS aNtStatus) {
68 if (aNtStatus == STATUS_SUCCESS) {
69 // Special case: we don't want to set FACILITY_NT_BIT
70 // (HRESULT_FROM_NT does not handle this case, unlike HRESULT_FROM_WIN32)
71 return WindowsError(S_OK);
72 }
73
74 return WindowsError(HRESULT_FROM_NT(aNtStatus));
75 }
76
FromHResult(HRESULT aHResult)77 static WindowsError FromHResult(HRESULT aHResult) {
78 return WindowsError(aHResult);
79 }
80
FromWin32Error(DWORD aWin32Err)81 static WindowsError FromWin32Error(DWORD aWin32Err) {
82 return WindowsError(HRESULT_FROM_WIN32(aWin32Err));
83 }
84
FromLastError()85 static WindowsError FromLastError() {
86 return FromWin32Error(::GetLastError());
87 }
88
CreateSuccess()89 static WindowsError CreateSuccess() { return WindowsError(S_OK); }
90
CreateGeneric()91 static WindowsError CreateGeneric() {
92 return FromWin32Error(ERROR_UNIDENTIFIED_ERROR);
93 }
94
IsSuccess()95 bool IsSuccess() const { return SUCCEEDED(mHResult); }
96
IsFailure()97 bool IsFailure() const { return FAILED(mHResult); }
98
IsAvailableAsWin32Error()99 bool IsAvailableAsWin32Error() const {
100 return IsAvailableAsNtStatus() ||
101 HRESULT_FACILITY(mHResult) == FACILITY_WIN32;
102 }
103
IsAvailableAsNtStatus()104 bool IsAvailableAsNtStatus() const {
105 return mHResult == S_OK || (mHResult & FACILITY_NT_BIT);
106 }
107
IsAvailableAsHResult()108 bool IsAvailableAsHResult() const { return true; }
109
AsString()110 UniqueString AsString() const {
111 LPWSTR rawMsgBuf = nullptr;
112 constexpr DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
113 FORMAT_MESSAGE_FROM_SYSTEM |
114 FORMAT_MESSAGE_IGNORE_INSERTS;
115 DWORD result =
116 ::FormatMessageW(flags, nullptr, mHResult, 0,
117 reinterpret_cast<LPWSTR>(&rawMsgBuf), 0, nullptr);
118 if (!result) {
119 return nullptr;
120 }
121
122 return UniqueString(rawMsgBuf);
123 }
124
AsHResult()125 HRESULT AsHResult() const { return mHResult; }
126
127 // Not all HRESULTs are convertible to Win32 Errors, so we use Maybe
AsWin32Error()128 Maybe<DWORD> AsWin32Error() const {
129 if (mHResult == S_OK) {
130 return Some(static_cast<DWORD>(ERROR_SUCCESS));
131 }
132
133 if (HRESULT_FACILITY(mHResult) == FACILITY_WIN32) {
134 // This is the inverse of HRESULT_FROM_WIN32
135 return Some(static_cast<DWORD>(HRESULT_CODE(mHResult)));
136 }
137
138 // The NTSTATUS facility is a special case and thus does not utilize the
139 // HRESULT_FACILITY and HRESULT_CODE macros.
140 if (mHResult & FACILITY_NT_BIT) {
141 return Some(NtStatusToWin32Error(
142 static_cast<NTSTATUS>(mHResult & ~FACILITY_NT_BIT)));
143 }
144
145 return Nothing();
146 }
147
148 // Not all HRESULTs are convertible to NTSTATUS, so we use Maybe
AsNtStatus()149 Maybe<NTSTATUS> AsNtStatus() const {
150 if (mHResult == S_OK) {
151 return Some(STATUS_SUCCESS);
152 }
153
154 // The NTSTATUS facility is a special case and thus does not utilize the
155 // HRESULT_FACILITY and HRESULT_CODE macros.
156 if (mHResult & FACILITY_NT_BIT) {
157 return Some(static_cast<NTSTATUS>(mHResult & ~FACILITY_NT_BIT));
158 }
159
160 return Nothing();
161 }
162
163 bool operator==(const WindowsError& aOther) const {
164 return mHResult == aOther.mHResult;
165 }
166
167 bool operator!=(const WindowsError& aOther) const {
168 return mHResult != aOther.mHResult;
169 }
170
NtStatusToWin32Error(NTSTATUS aNtStatus)171 static DWORD NtStatusToWin32Error(NTSTATUS aNtStatus) {
172 static const StaticDynamicallyLinkedFunctionPtr<decltype(
173 &RtlNtStatusToDosError)>
174 pRtlNtStatusToDosError(L"ntdll.dll", "RtlNtStatusToDosError");
175
176 MOZ_ASSERT(!!pRtlNtStatusToDosError);
177 if (!pRtlNtStatusToDosError) {
178 return ERROR_UNIDENTIFIED_ERROR;
179 }
180
181 return pRtlNtStatusToDosError(aNtStatus);
182 }
183
184 private:
185 // We store the error code as an HRESULT because they can encode both Win32
186 // error codes and NTSTATUS codes.
187 HRESULT mHResult;
188 };
189
190 template <typename T>
191 using WindowsErrorResult = Result<T, WindowsError>;
192
193 struct LauncherError {
LauncherErrorLauncherError194 LauncherError(const char* aFile, int aLine, WindowsError aWin32Error)
195 : mFile(aFile), mLine(aLine), mError(aWin32Error) {}
196
197 const char* mFile;
198 int mLine;
199 WindowsError mError;
200
201 bool operator==(const LauncherError& aOther) const {
202 return mError == aOther.mError;
203 }
204
205 bool operator!=(const LauncherError& aOther) const {
206 return mError != aOther.mError;
207 }
208
209 bool operator==(const WindowsError& aOther) const { return mError == aOther; }
210
211 bool operator!=(const WindowsError& aOther) const { return mError != aOther; }
212 };
213
214 #if defined(MOZILLA_INTERNAL_API)
215
216 template <typename T>
217 using LauncherResult = WindowsErrorResult<T>;
218
219 template <typename T>
220 using LauncherResultWithLineInfo = Result<T, LauncherError>;
221
222 using WindowsErrorType = WindowsError;
223
224 #else
225
226 template <typename T>
227 using LauncherResult = Result<T, LauncherError>;
228
229 template <typename T>
230 using LauncherResultWithLineInfo = LauncherResult<T>;
231
232 using WindowsErrorType = LauncherError;
233
234 #endif // defined(MOZILLA_INTERNAL_API)
235
236 using LauncherVoidResult = LauncherResult<Ok>;
237
238 using LauncherVoidResultWithLineInfo = LauncherResultWithLineInfo<Ok>;
239
240 #if defined(MOZILLA_INTERNAL_API)
241
242 # define LAUNCHER_ERROR_GENERIC() \
243 ::mozilla::Err(::mozilla::WindowsError::CreateGeneric())
244
245 # define LAUNCHER_ERROR_FROM_WIN32(err) \
246 ::mozilla::Err(::mozilla::WindowsError::FromWin32Error(err))
247
248 # define LAUNCHER_ERROR_FROM_LAST() \
249 ::mozilla::Err(::mozilla::WindowsError::FromLastError())
250
251 # define LAUNCHER_ERROR_FROM_NTSTATUS(ntstatus) \
252 ::mozilla::Err(::mozilla::WindowsError::FromNtStatus(ntstatus))
253
254 # define LAUNCHER_ERROR_FROM_HRESULT(hresult) \
255 ::mozilla::Err(::mozilla::WindowsError::FromHResult(hresult))
256
257 # define LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(err) ::mozilla::Err(err)
258
259 #else
260
261 # define LAUNCHER_ERROR_GENERIC() \
262 ::mozilla::Err(::mozilla::LauncherError( \
263 __FILE__, __LINE__, ::mozilla::WindowsError::CreateGeneric()))
264
265 # define LAUNCHER_ERROR_FROM_WIN32(err) \
266 ::mozilla::Err(::mozilla::LauncherError( \
267 __FILE__, __LINE__, ::mozilla::WindowsError::FromWin32Error(err)))
268
269 # define LAUNCHER_ERROR_FROM_LAST() \
270 ::mozilla::Err(::mozilla::LauncherError( \
271 __FILE__, __LINE__, ::mozilla::WindowsError::FromLastError()))
272
273 # define LAUNCHER_ERROR_FROM_NTSTATUS(ntstatus) \
274 ::mozilla::Err(::mozilla::LauncherError( \
275 __FILE__, __LINE__, ::mozilla::WindowsError::FromNtStatus(ntstatus)))
276
277 # define LAUNCHER_ERROR_FROM_HRESULT(hresult) \
278 ::mozilla::Err(::mozilla::LauncherError( \
279 __FILE__, __LINE__, ::mozilla::WindowsError::FromHResult(hresult)))
280
281 // This macro wraps the supplied WindowsError with a LauncherError
282 # define LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(err) \
283 ::mozilla::Err(::mozilla::LauncherError(__FILE__, __LINE__, err))
284
285 #endif // defined(MOZILLA_INTERNAL_API)
286
287 // This macro enables copying of a mozilla::LauncherError from a
288 // mozilla::LauncherResult<Foo> into a mozilla::LauncherResult<Bar>
289 #define LAUNCHER_ERROR_FROM_RESULT(result) ::mozilla::Err(result.inspectErr())
290
291 // How long to wait for a created process to become available for input,
292 // to prevent that process's windows being forced to the background.
293 // This is used across update, restart, and the launcher.
294 const DWORD kWaitForInputIdleTimeoutMS = 10 * 1000;
295
296 /**
297 * Wait for a child GUI process to become "idle." Idle means that the process
298 * has created its message queue and has begun waiting for user input.
299 *
300 * Note that this must only be used when the child process is going to display
301 * GUI! Otherwise you're going to be waiting for a very long time ;-)
302 *
303 * @return true if we successfully waited for input idle;
304 * false if we timed out or failed to wait.
305 */
306 inline bool WaitForInputIdle(HANDLE aProcess,
307 DWORD aTimeoutMs = kWaitForInputIdleTimeoutMS) {
308 const DWORD kSleepTimeMs = 10;
309 const DWORD waitStart = aTimeoutMs == INFINITE ? 0 : ::GetTickCount();
310 DWORD elapsed = 0;
311
312 while (true) {
313 if (aTimeoutMs != INFINITE) {
314 elapsed = ::GetTickCount() - waitStart;
315 }
316
317 if (elapsed >= aTimeoutMs) {
318 return false;
319 }
320
321 // ::WaitForInputIdle() doesn't always set the last-error code on failure
322 ::SetLastError(ERROR_SUCCESS);
323
324 DWORD waitResult = ::WaitForInputIdle(aProcess, aTimeoutMs - elapsed);
325 if (!waitResult) {
326 return true;
327 }
328
329 if (waitResult == WAIT_FAILED &&
330 ::GetLastError() == ERROR_NOT_GUI_PROCESS) {
331 ::Sleep(kSleepTimeMs);
332 continue;
333 }
334
335 return false;
336 }
337 }
338
339 enum class PathType {
340 eNtPath,
341 eDosPath,
342 };
343
344 class FileUniqueId final {
345 public:
FileUniqueId(const wchar_t * aPath,PathType aPathType)346 explicit FileUniqueId(const wchar_t* aPath, PathType aPathType)
347 : mId(FILE_ID_INFO()) {
348 if (!aPath) {
349 mId = LAUNCHER_ERROR_FROM_HRESULT(E_INVALIDARG);
350 return;
351 }
352
353 nsAutoHandle file;
354
355 switch (aPathType) {
356 default:
357 mId = LAUNCHER_ERROR_FROM_HRESULT(E_INVALIDARG);
358 MOZ_ASSERT_UNREACHABLE("Unhandled PathType");
359 return;
360
361 case PathType::eNtPath: {
362 UNICODE_STRING unicodeString;
363 ::RtlInitUnicodeString(&unicodeString, aPath);
364 OBJECT_ATTRIBUTES objectAttributes;
365 InitializeObjectAttributes(&objectAttributes, &unicodeString,
366 OBJ_CASE_INSENSITIVE, nullptr, nullptr);
367 IO_STATUS_BLOCK ioStatus = {};
368 HANDLE ntHandle;
369 NTSTATUS status = ::NtOpenFile(
370 &ntHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &objectAttributes,
371 &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
372 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
373 // We don't need to check |ntHandle| for INVALID_HANDLE_VALUE here,
374 // as that value is set by the Win32 layer.
375 if (!NT_SUCCESS(status)) {
376 mId = LAUNCHER_ERROR_FROM_NTSTATUS(status);
377 return;
378 }
379
380 file.own(ntHandle);
381 break;
382 }
383
384 case PathType::eDosPath: {
385 file.own(::CreateFileW(
386 aPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
387 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr));
388 if (file == INVALID_HANDLE_VALUE) {
389 mId = LAUNCHER_ERROR_FROM_LAST();
390 return;
391 }
392
393 break;
394 }
395 }
396
397 GetId(file);
398 }
399
FileUniqueId(const nsAutoHandle & aFile)400 explicit FileUniqueId(const nsAutoHandle& aFile) : mId(FILE_ID_INFO()) {
401 GetId(aFile);
402 }
403
FileUniqueId(const FileUniqueId & aOther)404 FileUniqueId(const FileUniqueId& aOther) : mId(aOther.mId) {}
405
406 ~FileUniqueId() = default;
407
IsError()408 bool IsError() const { return mId.isErr(); }
409
GetError()410 const WindowsErrorType& GetError() const { return mId.inspectErr(); }
411
412 FileUniqueId& operator=(const FileUniqueId& aOther) {
413 mId = aOther.mId;
414 return *this;
415 }
416
417 FileUniqueId(FileUniqueId&& aOther) = default;
418 FileUniqueId& operator=(FileUniqueId&& aOther) = delete;
419
420 bool operator==(const FileUniqueId& aOther) const {
421 return mId.isOk() && aOther.mId.isOk() &&
422 !memcmp(&mId.inspect(), &aOther.mId.inspect(), sizeof(FILE_ID_INFO));
423 }
424
425 bool operator!=(const FileUniqueId& aOther) const {
426 return !((*this) == aOther);
427 }
428
429 private:
GetId(const nsAutoHandle & aFile)430 void GetId(const nsAutoHandle& aFile) {
431 FILE_ID_INFO fileIdInfo = {};
432 if (IsWin8OrLater()) {
433 if (::GetFileInformationByHandleEx(aFile.get(), FileIdInfo, &fileIdInfo,
434 sizeof(fileIdInfo))) {
435 mId = fileIdInfo;
436 return;
437 }
438 // Only NTFS and ReFS support FileIdInfo. So we have to fallback if
439 // GetFileInformationByHandleEx failed.
440 }
441
442 BY_HANDLE_FILE_INFORMATION info = {};
443 if (!::GetFileInformationByHandle(aFile.get(), &info)) {
444 mId = LAUNCHER_ERROR_FROM_LAST();
445 return;
446 }
447
448 fileIdInfo.VolumeSerialNumber = info.dwVolumeSerialNumber;
449 memcpy(&fileIdInfo.FileId.Identifier[0], &info.nFileIndexLow,
450 sizeof(DWORD));
451 memcpy(&fileIdInfo.FileId.Identifier[sizeof(DWORD)], &info.nFileIndexHigh,
452 sizeof(DWORD));
453 mId = fileIdInfo;
454 }
455
456 private:
457 LauncherResult<FILE_ID_INFO> mId;
458 };
459
460 class MOZ_RAII AutoVirtualProtect final {
461 public:
462 AutoVirtualProtect(void* aAddress, size_t aLength, DWORD aProtFlags,
463 HANDLE aTargetProcess = ::GetCurrentProcess())
mAddress(aAddress)464 : mAddress(aAddress),
465 mLength(aLength),
466 mTargetProcess(aTargetProcess),
467 mPrevProt(0),
468 mError(WindowsError::CreateSuccess()) {
469 if (!::VirtualProtectEx(aTargetProcess, aAddress, aLength, aProtFlags,
470 &mPrevProt)) {
471 mError = WindowsError::FromLastError();
472 }
473 }
474
~AutoVirtualProtect()475 ~AutoVirtualProtect() {
476 if (mError.IsFailure()) {
477 return;
478 }
479
480 ::VirtualProtectEx(mTargetProcess, mAddress, mLength, mPrevProt,
481 &mPrevProt);
482 }
483
484 explicit operator bool() const { return mError.IsSuccess(); }
485
GetError()486 WindowsError GetError() const { return mError; }
487
PrevProt()488 DWORD PrevProt() const { return mPrevProt; }
489
490 AutoVirtualProtect(const AutoVirtualProtect&) = delete;
491 AutoVirtualProtect(AutoVirtualProtect&&) = delete;
492 AutoVirtualProtect& operator=(const AutoVirtualProtect&) = delete;
493 AutoVirtualProtect& operator=(AutoVirtualProtect&&) = delete;
494
495 private:
496 void* mAddress;
497 size_t mLength;
498 HANDLE mTargetProcess;
499 DWORD mPrevProt;
500 WindowsError mError;
501 };
502
GetFullModulePath(HMODULE aModule)503 inline UniquePtr<wchar_t[]> GetFullModulePath(HMODULE aModule) {
504 DWORD bufLen = MAX_PATH;
505 mozilla::UniquePtr<wchar_t[]> buf;
506 DWORD retLen;
507
508 while (true) {
509 buf = mozilla::MakeUnique<wchar_t[]>(bufLen);
510 retLen = ::GetModuleFileNameW(aModule, buf.get(), bufLen);
511 if (!retLen) {
512 return nullptr;
513 }
514
515 if (retLen == bufLen && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
516 bufLen *= 2;
517 continue;
518 }
519
520 break;
521 }
522
523 // Upon success, retLen *excludes* the null character
524 ++retLen;
525
526 // Since we're likely to have a bunch of unused space in buf, let's
527 // reallocate a string to the actual size of the file name.
528 auto result = mozilla::MakeUnique<wchar_t[]>(retLen);
529 if (wcscpy_s(result.get(), retLen, buf.get())) {
530 return nullptr;
531 }
532
533 return result;
534 }
535
GetFullBinaryPath()536 inline UniquePtr<wchar_t[]> GetFullBinaryPath() {
537 return GetFullModulePath(nullptr);
538 }
539
540 class ModuleVersion final {
541 public:
ModuleVersion()542 constexpr ModuleVersion() : mVersion(0ULL) {}
543
ModuleVersion(const VS_FIXEDFILEINFO & aFixedInfo)544 explicit ModuleVersion(const VS_FIXEDFILEINFO& aFixedInfo)
545 : mVersion((static_cast<uint64_t>(aFixedInfo.dwFileVersionMS) << 32) |
546 static_cast<uint64_t>(aFixedInfo.dwFileVersionLS)) {}
547
ModuleVersion(const uint64_t aVersion)548 explicit ModuleVersion(const uint64_t aVersion) : mVersion(aVersion) {}
549
ModuleVersion(const ModuleVersion & aOther)550 ModuleVersion(const ModuleVersion& aOther) : mVersion(aOther.mVersion) {}
551
AsInteger()552 uint64_t AsInteger() const { return mVersion; }
553
uint64_t()554 operator uint64_t() const { return AsInteger(); }
555
AsTuple()556 Tuple<uint16_t, uint16_t, uint16_t, uint16_t> AsTuple() const {
557 uint16_t major = static_cast<uint16_t>((mVersion >> 48) & 0xFFFFU);
558 uint16_t minor = static_cast<uint16_t>((mVersion >> 32) & 0xFFFFU);
559 uint16_t patch = static_cast<uint16_t>((mVersion >> 16) & 0xFFFFU);
560 uint16_t build = static_cast<uint16_t>(mVersion & 0xFFFFU);
561
562 return MakeTuple(major, minor, patch, build);
563 }
564
565 explicit operator bool() const { return !!mVersion; }
566
567 bool operator<(const ModuleVersion& aOther) const {
568 return mVersion < aOther.mVersion;
569 }
570
571 bool operator<(const uint64_t& aOther) const { return mVersion < aOther; }
572
573 ModuleVersion& operator=(const uint64_t aIntVersion) {
574 mVersion = aIntVersion;
575 return *this;
576 }
577
578 private:
579 uint64_t mVersion;
580 };
581
GetModuleVersion(const wchar_t * aModuleFullPath)582 inline LauncherResult<ModuleVersion> GetModuleVersion(
583 const wchar_t* aModuleFullPath) {
584 DWORD verInfoLen = ::GetFileVersionInfoSizeW(aModuleFullPath, nullptr);
585 if (!verInfoLen) {
586 return LAUNCHER_ERROR_FROM_LAST();
587 }
588
589 auto verInfoBuf = MakeUnique<BYTE[]>(verInfoLen);
590 if (!::GetFileVersionInfoW(aModuleFullPath, 0, verInfoLen,
591 verInfoBuf.get())) {
592 return LAUNCHER_ERROR_FROM_LAST();
593 }
594
595 UINT fixedInfoLen;
596 VS_FIXEDFILEINFO* fixedInfo = nullptr;
597 if (!::VerQueryValueW(verInfoBuf.get(), L"\\",
598 reinterpret_cast<LPVOID*>(&fixedInfo), &fixedInfoLen)) {
599 // VerQueryValue may fail if the resource does not exist. This is not an
600 // error; we'll return 0 in this case.
601 return ModuleVersion(0ULL);
602 }
603
604 return ModuleVersion(*fixedInfo);
605 }
606
GetModuleVersion(HMODULE aModule)607 inline LauncherResult<ModuleVersion> GetModuleVersion(HMODULE aModule) {
608 UniquePtr<wchar_t[]> fullPath(GetFullModulePath(aModule));
609 if (!fullPath) {
610 return LAUNCHER_ERROR_GENERIC();
611 }
612
613 return GetModuleVersion(fullPath.get());
614 }
615
616 #if defined(MOZILLA_INTERNAL_API)
GetModuleVersion(nsIFile * aFile)617 inline LauncherResult<ModuleVersion> GetModuleVersion(nsIFile* aFile) {
618 if (!aFile) {
619 return LAUNCHER_ERROR_FROM_HRESULT(E_INVALIDARG);
620 }
621
622 nsAutoString fullPath;
623 nsresult rv = aFile->GetPath(fullPath);
624 if (NS_FAILED(rv)) {
625 return LAUNCHER_ERROR_GENERIC();
626 }
627
628 return GetModuleVersion(fullPath.get());
629 }
630 #endif // defined(MOZILLA_INTERNAL_API)
631
632 struct CoTaskMemFreeDeleter {
operatorCoTaskMemFreeDeleter633 void operator()(void* aPtr) { ::CoTaskMemFree(aPtr); }
634 };
635
GetElevationType(const nsAutoHandle & aToken)636 inline LauncherResult<TOKEN_ELEVATION_TYPE> GetElevationType(
637 const nsAutoHandle& aToken) {
638 DWORD retLen;
639 TOKEN_ELEVATION_TYPE elevationType;
640 if (!::GetTokenInformation(aToken.get(), TokenElevationType, &elevationType,
641 sizeof(elevationType), &retLen)) {
642 return LAUNCHER_ERROR_FROM_LAST();
643 }
644
645 return elevationType;
646 }
647
648 } // namespace mozilla
649
650 #endif // mozilla_WinHeaderOnlyUtils_h
651