Bug 1563336: Add a common implementation of module version info extraction to WinHeaderOnlyUtils; r=mhowell

Differential Revision: https://phabricator.services.mozilla.com/D36817

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Aaron Klotz 2019-07-04 21:30:30 +00:00
Родитель 960e4c47d4
Коммит 7acf7a06ca
3 изменённых файлов: 132 добавлений и 34 удалений

Просмотреть файл

@ -21,6 +21,7 @@
# include "mozilla/Move.h"
# include "mozilla/UniquePtr.h"
# include "mozilla/Vector.h"
# include "mozilla/WinHeaderOnlyUtils.h"
# include <wchar.h>
# include <windows.h>
@ -359,39 +360,6 @@ inline UniquePtr<wchar_t[]> MakeCommandLine(int argc, wchar_t** argv,
return s;
}
inline UniquePtr<wchar_t[]> GetFullBinaryPath() {
DWORD bufLen = MAX_PATH;
mozilla::UniquePtr<wchar_t[]> buf;
DWORD retLen;
while (true) {
buf = mozilla::MakeUnique<wchar_t[]>(bufLen);
retLen = ::GetModuleFileNameW(nullptr, buf.get(), bufLen);
if (!retLen) {
return nullptr;
}
if (retLen == bufLen && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
bufLen *= 2;
continue;
}
break;
}
// 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;
}
return result;
}
inline bool SetArgv0ToFullBinaryPath(wchar_t* aArgv[]) {
if (!aArgv) {
return false;

Просмотреть файл

@ -7,10 +7,10 @@
#ifndef mozilla_LauncherRegistryInfo_h
#define mozilla_LauncherRegistryInfo_h
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/LauncherResult.h"
#include "mozilla/Maybe.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WinHeaderOnlyUtils.h"
#include "nsWindowsHelpers.h"
#include <string>

Просмотреть файл

@ -12,15 +12,23 @@
#include <winnt.h>
#include <winternl.h>
#include <stdlib.h>
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/DynamicallyLinkedFunctionPtr.h"
#include "mozilla/Maybe.h"
#include "mozilla/Result.h"
#include "mozilla/Tuple.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WindowsVersion.h"
#include "nsWindowsHelpers.h"
#if defined(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
@ -402,6 +410,128 @@ class MOZ_RAII AutoVirtualProtect final {
WindowsError mError;
};
inline UniquePtr<wchar_t[]> GetFullModulePath(HMODULE aModule) {
DWORD bufLen = MAX_PATH;
mozilla::UniquePtr<wchar_t[]> buf;
DWORD retLen;
while (true) {
buf = mozilla::MakeUnique<wchar_t[]>(bufLen);
retLen = ::GetModuleFileNameW(aModule, buf.get(), bufLen);
if (!retLen) {
return nullptr;
}
if (retLen == bufLen && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
bufLen *= 2;
continue;
}
break;
}
// 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;
}
return result;
}
inline UniquePtr<wchar_t[]> GetFullBinaryPath() {
return GetFullModulePath(nullptr);
}
class ModuleVersion final {
public:
explicit ModuleVersion(const VS_FIXEDFILEINFO& aFixedInfo)
: mVersion((static_cast<uint64_t>(aFixedInfo.dwFileVersionMS) << 32) |
static_cast<uint64_t>(aFixedInfo.dwFileVersionLS)) {}
explicit ModuleVersion(const uint64_t aVersion) : mVersion(aVersion) {}
ModuleVersion(const ModuleVersion& aOther) : mVersion(aOther.mVersion) {}
uint64_t AsInteger() const { return mVersion; }
operator uint64_t() const { return AsInteger(); }
Tuple<uint16_t, uint16_t, uint16_t, uint16_t> AsTuple() const {
uint16_t major = static_cast<uint16_t>((mVersion >> 48) & 0xFFFFU);
uint16_t minor = static_cast<uint16_t>((mVersion >> 32) & 0xFFFFU);
uint16_t patch = static_cast<uint16_t>((mVersion >> 16) & 0xFFFFU);
uint16_t build = static_cast<uint16_t>(mVersion & 0xFFFFU);
return MakeTuple(major, minor, patch, build);
}
explicit operator bool() const { return !!mVersion; }
bool operator<(const ModuleVersion& aOther) const {
return mVersion < aOther.mVersion;
}
bool operator<(const uint64_t& aOther) const { return mVersion < aOther; }
private:
const uint64_t mVersion;
};
inline WindowsErrorResult<ModuleVersion> GetModuleVersion(
const wchar_t* aModuleFullPath) {
DWORD verInfoLen = ::GetFileVersionInfoSizeW(aModuleFullPath, nullptr);
if (!verInfoLen) {
return Err(WindowsError::FromLastError());
}
auto verInfoBuf = MakeUnique<BYTE[]>(verInfoLen);
if (!::GetFileVersionInfoW(aModuleFullPath, 0, verInfoLen,
verInfoBuf.get())) {
return Err(WindowsError::FromLastError());
}
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);
}
return ModuleVersion(*fixedInfo);
}
inline WindowsErrorResult<ModuleVersion> GetModuleVersion(HMODULE aModule) {
UniquePtr<wchar_t[]> fullPath(GetFullModulePath(aModule));
if (!fullPath) {
return Err(WindowsError::CreateGeneric());
}
return GetModuleVersion(fullPath.get());
}
#if defined(MOZILLA_INTERNAL_API)
inline WindowsErrorResult<ModuleVersion> GetModuleVersion(nsIFile* aFile) {
if (!aFile) {
return Err(WindowsError::FromHResult(E_INVALIDARG));
}
nsAutoString fullPath;
nsresult rv = aFile->GetPath(fullPath);
if (NS_FAILED(rv)) {
return Err(WindowsError::CreateGeneric());
}
return GetModuleVersion(fullPath.get());
}
#endif // defined(MOZILLA_INTERNAL_API)
} // namespace mozilla
#endif // mozilla_WinHeaderOnlyUtils_h