/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifdefined(MOZILLA_INTERNAL_API) # include "nsIFile.h" # include "nsString.h" #endif// defined(MOZILLA_INTERNAL_API)
/** * This header is intended for self-contained, header-only, utility code for * Win32. It may be used outside of xul.dll, in places such as firefox.exe or * mozglue.dll. If your code creates dependencies on Mozilla libraries, you * should put it elsewhere.
*/
// Our data indicates a few users of Win7 x86 hit failure to load urlmon.dll // for unknown reasons. Since we don't always require urlmon.dll on Win7, // we delay-load it, which causes a crash if loading urlmon.dll fails. This // macro is to safely load and call urlmon's API graciously without crash. #ifdefined(_X86_) # define SAFECALL_URLMON_FUNC(FuncName, ...) \ do { \ staticconst mozilla::StaticDynamicallyLinkedFunctionPtr< \
decltype(&::FuncName)> \
func(L"urlmon.dll", #FuncName); \
hr = \
func ? func(__VA_ARGS__) : HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); \
} while (0) #else # define SAFECALL_URLMON_FUNC(FuncName, ...) hr = ::FuncName(__VA_ARGS__) #endif
namespace mozilla {
class WindowsError final { private: // HRESULT and NTSTATUS are both typedefs of LONG, so we cannot use // overloading to properly differentiate between the two. Instead we'll use // static functions to convert the various error types to HRESULTs before // instantiating. explicit constexpr WindowsError(HRESULT aHResult) : mHResult(aHResult) {}
public: using UniqueString = UniquePtr<WCHAR[], LocalFreeDeleter>;
static constexpr WindowsError FromNtStatus(NTSTATUS aNtStatus) { if (aNtStatus == STATUS_SUCCESS) { // Special case: we don't want to set FACILITY_NT_BIT // (HRESULT_FROM_NT does not handle this case, unlike HRESULT_FROM_WIN32) return WindowsError(S_OK);
}
// Not all HRESULTs are convertible to Win32 Errors, so we use Maybe
Maybe<DWORD> AsWin32Error() const { if (mHResult == S_OK) { return Some(static_cast<DWORD>(ERROR_SUCCESS));
}
if (HRESULT_FACILITY(mHResult) == FACILITY_WIN32) { // This is the inverse of HRESULT_FROM_WIN32 return Some(static_cast<DWORD>(HRESULT_CODE(mHResult)));
}
// The NTSTATUS facility is a special case and thus does not utilize the // HRESULT_FACILITY and HRESULT_CODE macros. if (mHResult & FACILITY_NT_BIT) { return Some(NtStatusToWin32Error( static_cast<NTSTATUS>(mHResult & ~FACILITY_NT_BIT)));
}
return Nothing();
}
// Not all HRESULTs are convertible to NTSTATUS, so we use Maybe
Maybe<NTSTATUS> AsNtStatus() const { if (mHResult == S_OK) { return Some(STATUS_SUCCESS);
}
// The NTSTATUS facility is a special case and thus does not utilize the // HRESULT_FACILITY and HRESULT_CODE macros. if (mHResult & FACILITY_NT_BIT) { return Some(static_cast<NTSTATUS>(mHResult & ~FACILITY_NT_BIT));
}
// This macro wraps the supplied WindowsError with a LauncherError # define LAUNCHER_ERROR_FROM_MOZ_WINDOWS_ERROR(err) \
::mozilla::Err(::mozilla::LauncherError(__FILE__, __LINE__, err))
// How long to wait for a created process to become available for input, // to prevent that process's windows being forced to the background. // This is used across update, restart, and the launcher. const DWORD kWaitForInputIdleTimeoutMS = 10 * 1000;
/** * Wait for a child GUI process to become "idle." Idle means that the process * has created its message queue and has begun waiting for user input. * * Note that this must only be used when the child process is going to display * GUI! Otherwise you're going to be waiting for a very long time ;-) * * @return true if we successfully waited for input idle; * false if we timed out or failed to wait.
*/ inlinebool WaitForInputIdle(HANDLE aProcess,
DWORD aTimeoutMs = kWaitForInputIdleTimeoutMS) { const DWORD kSleepTimeMs = 10; const DWORD waitStart = aTimeoutMs == INFINITE ? 0 : ::GetTickCount();
DWORD elapsed = 0;
while (true) { if (aTimeoutMs != INFINITE) {
elapsed = ::GetTickCount() - waitStart;
}
if (elapsed >= aTimeoutMs) { returnfalse;
}
// ::WaitForInputIdle() doesn't always set the last-error code on failure
::SetLastError(ERROR_SUCCESS);
case PathType::eNtPath: {
UNICODE_STRING unicodeString;
::RtlInitUnicodeString(&unicodeString, aPath);
OBJECT_ATTRIBUTES objectAttributes;
InitializeObjectAttributes(&objectAttributes, &unicodeString,
OBJ_CASE_INSENSITIVE, nullptr, nullptr);
IO_STATUS_BLOCK ioStatus = {};
HANDLE ntHandle;
NTSTATUS status = ::NtOpenFile(
&ntHandle, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &objectAttributes,
&ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); // We don't need to check |ntHandle| for INVALID_HANDLE_VALUE here, // as that value is set by the Win32 layer. if (!NT_SUCCESS(status)) {
mId = LAUNCHER_ERROR_FROM_NTSTATUS(status); return;
}
private: void GetId(const nsAutoHandle& aFile) {
FILE_ID_INFO fileIdInfo = {}; if (::GetFileInformationByHandleEx(aFile.get(), FileIdInfo, &fileIdInfo, sizeof(fileIdInfo))) {
mId = fileIdInfo; return;
} // Only NTFS and ReFS support FileIdInfo. So we have to fallback if // GetFileInformationByHandleEx failed.
BY_HANDLE_FILE_INFORMATION info = {}; if (!::GetFileInformationByHandle(aFile.get(), &info)) {
mId = LAUNCHER_ERROR_FROM_LAST(); return;
}
// Upon success, retLen *excludes* the null character
++retLen;
// Since we're likely to have a bunch of unused space in buf, let's // reallocate a string to the actual size of the file name. auto result = mozilla::MakeUnique<wchar_t[]>(retLen); if (wcscpy_s(result.get(), retLen, buf.get())) { return nullptr;
}
// Generates the install directory without a trailing path separator. inlinebool GetInstallDirectory(UniquePtr<wchar_t[]>& installPath) {
installPath = GetFullBinaryPath(); // It's not safe to use PathRemoveFileSpecW with strings longer than MAX_PATH // (including null terminator). if (wcslen(installPath.get()) >= MAX_PATH) { returnfalse;
}
::PathRemoveFileSpecW(installPath.get()); returntrue;
}
class ModuleVersion final { public:
constexpr ModuleVersion() : mVersion(0ULL) {}
auto verInfoBuf = MakeUnique<BYTE[]>(verInfoLen); if (!::GetFileVersionInfoW(aModuleFullPath, 0, verInfoLen,
verInfoBuf.get())) { return LAUNCHER_ERROR_FROM_LAST();
}
UINT fixedInfoLen;
VS_FIXEDFILEINFO* fixedInfo = nullptr; if (!::VerQueryValueW(verInfoBuf.get(), L"\\", reinterpret_cast<LPVOID*>(&fixedInfo), &fixedInfoLen)) { // VerQueryValue may fail if the resource does not exist. This is not an // error; we'll return 0 in this case. return ModuleVersion(0ULL);
}
// If there was any package identity to retrieve, we get // ERROR_INSUFFICIENT_BUFFER. If there had been no package identity it // would instead return APPMODEL_ERROR_NO_PACKAGE.
UINT32 packageNameSize = 0; return pGetCurrentPackageId &&
(pGetCurrentPackageId(&packageNameSize, nullptr) ==
ERROR_INSUFFICIENT_BUFFER);
}
// This implementation is equivalent to PathGetDriveNumber[AW]. // We define our own version because using PathGetDriveNumber // delay-loads shlwapi.dll, which may fail when the process is // sandboxed. template <typename T> int MozPathGetDriveNumber(const T* aPath) { constauto ToDriveNumber = [](const T* aPath) -> int { if (*aPath == '\0' || *(aPath + 1) != ':') { return -1;
}
T c = *aPath; return (c >= 'A' && c <= 'Z') ? c - 'A'
: (c >= 'a' && c <= 'z') ? c - 'a'
: -1;
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.