From 91677166d13595387fa6c61f3b100f7e292195dd Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 22 Jul 2021 11:16:27 -0700 Subject: [PATCH] Windows: add Swift installer custom action This adds the custom action that is needed for the Swift Installer. This is responsible for automating the deployment of the support files for the Windows SDK and Visual C++ SDK. --- .../SwiftInstaller/Headers/logging.hh | 62 + .../SwiftInstaller/Headers/scoped_raii.hh | 51 + .../SwiftInstaller/Headers/swift_installer.hh | 34 + .../SwiftInstaller/Sources/dllmain.cc | 19 + .../SwiftInstaller/Sources/logging.cc | 72 ++ .../SwiftInstaller/Sources/swift_installer.cc | 425 +++++++ .../SwiftInstaller/SwiftInstaller.vcxproj | 100 ++ .../SwiftInstaller.vcxproj.filters | 43 + .../inc/Setup.Configuration.h | 1059 +++++++++++++++++ 9 files changed, 1865 insertions(+) create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/Headers/logging.hh create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/Headers/scoped_raii.hh create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/Headers/swift_installer.hh create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/Sources/dllmain.cc create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/Sources/logging.cc create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/Sources/swift_installer.cc create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj.filters create mode 100644 platforms/Windows/CustomActions/SwiftInstaller/ThirdParty/Microsoft.VisualStudio.Setup.Configuration.Native/inc/Setup.Configuration.h diff --git a/platforms/Windows/CustomActions/SwiftInstaller/Headers/logging.hh b/platforms/Windows/CustomActions/SwiftInstaller/Headers/logging.hh new file mode 100644 index 00000000..fafc8813 --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/Headers/logging.hh @@ -0,0 +1,62 @@ +// Copyright © 2021 Saleem Abdulrasool +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef SWIFT_INSTALLER_HEADERS_LOGGING_HH +#define SWIFT_INSTALLER_HEADERS_LOGGING_HH + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#define NOMINMAX +#include +#include +#include + +#include +#include + +namespace msi::logging { +enum class severity { + info, /// INSTALLMESSAGE_INFO + warning, /// INSTALLMESSAGE_WARNING + error, /// INSTALLMESSAGE_ERROR + fatal, /// INSTALLMESSAGE_FATALEXIT +}; + +class log_message { + MSIHANDLE install_; + const severity severity_; + const char *file_; + const unsigned line_; + std::ostringstream stream_; + + template + friend log_message &operator<<(log_message &, const Value_ &) noexcept; + + public: + log_message(MSIHANDLE install, severity severity, + const char *file, unsigned line); + ~log_message(); + + log_message(const log_message &) = delete; + log_message &operator=(const log_message &) = delete; + + std::string str() { return stream_.str(); } + severity severity() const { return severity_; } +}; + +template +log_message &operator<<(log_message &message, const Value_ &value) noexcept { + message.stream_ << value; + return message; +} + +extern template +log_message &operator<<(log_message &, + const std::wstring &) noexcept; +} + +#define LOG(Install,Severity) \ + msi::logging::log_message(Install, msi::logging::severity::##Severity, \ + __FILE__, __LINE__) + +#endif diff --git a/platforms/Windows/CustomActions/SwiftInstaller/Headers/scoped_raii.hh b/platforms/Windows/CustomActions/SwiftInstaller/Headers/scoped_raii.hh new file mode 100644 index 00000000..44498898 --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/Headers/scoped_raii.hh @@ -0,0 +1,51 @@ +// Copyright © 2021 Saleem Abdulrasool +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef SWIFT_INSTALLER_HEADERS_SCOPED_RAII_HH +#define SWIFT_INSTALLER_HEADERS_SCOPED_RAII_HH + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#define NOMINMAX +#include +#include + +namespace windows { +namespace raii { +class hkey { + HKEY hKey_; + + public: + explicit hkey(HKEY hKey) noexcept : hKey_(hKey) {} + + // TODO(compnerd) log failure + ~hkey() noexcept { (void)RegCloseKey(hKey_); } +}; + +class com_initializer { + HRESULT hr_; + + public: + enum threading_model { multithreaded }; + + explicit com_initializer() { + hr_ = ::CoInitializeEx(nullptr, + COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + } + + explicit com_initializer(threading_model) { + hr_ = ::CoInitializeEx(nullptr, + COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); + } + + ~com_initializer() { + if (SUCCEEDED(hr_)) + ::CoUninitialize(); + } + + bool succeeded() const { return SUCCEEDED(hr_); } +}; +} +} + +#endif diff --git a/platforms/Windows/CustomActions/SwiftInstaller/Headers/swift_installer.hh b/platforms/Windows/CustomActions/SwiftInstaller/Headers/swift_installer.hh new file mode 100644 index 00000000..923eb34d --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/Headers/swift_installer.hh @@ -0,0 +1,34 @@ +// Copyright © 2021 Saleem Abdulrasool +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef SWIFT_INSTALLER_HEADERS_SWIFT_INSTALLER_HH +#define SWIFT_INSTALLER_HEADERS_SWIFT_INSTALLER_HH + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#define NOMINMAX +#include +#include + +#if defined(_WINDLL) +# if defined(SwiftInstaller_EXPORTS) +# define SWIFT_INSTALLER_API __declspec(dllexport) +# else +# define SWIFT_INSTALLER_API __declspec(dllimport) +# endif +#else +# define SWIFT_INSTALLER_API +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +UINT SWIFT_INSTALLER_API +SwiftInstaller_InstallAuxiliaryFiles(MSIHANDLE hInstall); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/platforms/Windows/CustomActions/SwiftInstaller/Sources/dllmain.cc b/platforms/Windows/CustomActions/SwiftInstaller/Sources/dllmain.cc new file mode 100644 index 00000000..11b061a4 --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/Sources/dllmain.cc @@ -0,0 +1,19 @@ +// Copyright © 2021 Saleem Abdulrasool +// SPDX-License-Identifier: BSD-3-Clause + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRA_LEAN +#define NOMINMAX +#include + +extern "C" BOOL APIENTRY +DllMain(HANDLE hModule, DWORD ulReason, LPVOID lpReserved) { + switch (ulReason) { + case DLL_PROCESS_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} diff --git a/platforms/Windows/CustomActions/SwiftInstaller/Sources/logging.cc b/platforms/Windows/CustomActions/SwiftInstaller/Sources/logging.cc new file mode 100644 index 00000000..05cbba2f --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/Sources/logging.cc @@ -0,0 +1,72 @@ +// Copyright © 2021 Saleem Abdulrasool +// SPDX-License-Identifier: BSD-3-Clause + +#include "logging.hh" + +#include +#include +#include +#include +#include + +namespace { +std::string to_string(const msi::logging::severity &severity) { + switch (severity) { + case msi::logging::severity::info: return "INFO"; + case msi::logging::severity::warning: return "WARN"; + case msi::logging::severity::error: return "ERROR"; + case msi::logging::severity::fatal: return "FATAL"; + } + __assume(false); +} +} + +namespace msi::logging { +log_message::log_message(MSIHANDLE install, msi::logging::severity severity, + const char *file, unsigned line) + : install_(install), severity_(severity), file_(file), line_(line) { + std::string_view filename(file); + + auto separator = filename.find_last_of("\\/"); + if (separator != std::string_view::npos) + filename.remove_prefix(separator + 1); + + SYSTEMTIME time; + GetLocalTime(&time); + + stream_ << "[\\[]" + // TODO(compnerd) should we size the pid and tid? + << GetCurrentProcessId() << ':' << GetCurrentThreadId() << ':' + << std::setfill('0') + << std::setw(2) << time.wMonth + << std::setw(2) << time.wDay + << '/' + << std::setw(2) << time.wHour + << std::setw(2) << time.wMinute + << std::setw(2) << time.wSecond + << '.' + << std::setw(3) << time.wMilliseconds + << ':' + << to_string(severity_) + << ':' << filename << '(' << line << ')' + << "[\\]]" << ' '; +} + +log_message::~log_message() { + std::string message = stream_.str(); + + PMSIHANDLE record; + record = MsiCreateRecord(0); + (void)MsiRecordSetStringA(record, 0, message.c_str()); + (void)MsiProcessMessage(install_, INSTALLMESSAGE_INFO, record); +} + +template <> +log_message &operator<<(log_message &message, + const std::wstring &str) noexcept { + std::wstring_convert, + std::wstring::traits_type::char_type> utf8; + message.stream_ << utf8.to_bytes(str.data(), str.data() + str.size()); + return message; +} +} diff --git a/platforms/Windows/CustomActions/SwiftInstaller/Sources/swift_installer.cc b/platforms/Windows/CustomActions/SwiftInstaller/Sources/swift_installer.cc new file mode 100644 index 00000000..994a3067 --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/Sources/swift_installer.cc @@ -0,0 +1,425 @@ +// Copyright © 2021 Saleem Abdulrasool +// SPDX-License-Identifier: BSD-3-Clause + +#include "swift_installer.hh" +#include "logging.hh" +#include "scoped_raii.hh" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// NOTE(compnerd) `Unknwn.h` must be included before `Setup.Configuration.h` as +// the header is not fully self-contained. +#include +#include + +_COM_SMARTPTR_TYPEDEF(IEnumSetupInstances, __uuidof(IEnumSetupInstances)); +_COM_SMARTPTR_TYPEDEF(ISetupConfiguration, __uuidof(ISetupConfiguration)); +_COM_SMARTPTR_TYPEDEF(ISetupConfiguration2, __uuidof(ISetupConfiguration2)); +_COM_SMARTPTR_TYPEDEF(ISetupHelper, __uuidof(ISetupHelper)); +_COM_SMARTPTR_TYPEDEF(ISetupInstance, __uuidof(ISetupInstance)); +_COM_SMARTPTR_TYPEDEF(ISetupInstance2, __uuidof(ISetupInstance2)); +_COM_SMARTPTR_TYPEDEF(ISetupPackageReference, __uuidof(ISetupPackageReference)); + +namespace { +std::string contents(const std::filesystem::path &path) noexcept { + std::ostringstream buffer; + std::ifstream stream(path); + if (!stream) + return {}; + buffer << stream.rdbuf(); + return buffer.str(); +} + +template +void trim(std::basic_string &string) noexcept { + string.erase(std::remove_if(std::begin(string), std::end(string), + [](CharType_ ch) { return !std::isprint(ch); }), + std::end(string)); +} +} + +// This is technically a misnomer. We are not looking for the Windows SDK but +// rather the Universal CRT SDK. +// +// The Windows SDK installation is found by querying: +// HKLM\SOFTWARE\[Wow6432Node]\Microsoft\Microsoft SDKs\Windows\v10.0\InstallationFolder +// We can identify the SDK version using: +// HKLM\SOFTWARE\[Wow6432Node]\Microsoft\Microsoft SDKs\Windows\v10.0\ProductVersion +// +// We currently only query: +// HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots\KitsRoot10 +// which gives us the Universal CRT installation root. +// +// FIXME(compnerd) we should support additional installation configurations by +// also querying the HKCU hive. +namespace winsdk { +static const wchar_t kits_root_key[] = L"KitsRoot10"; +static const wchar_t kits_installed_roots_keypath[] = + L"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots"; + +std::filesystem::path install_root() noexcept { + DWORD cbData = 0; + + if (FAILED(RegGetValueW(HKEY_LOCAL_MACHINE, kits_installed_roots_keypath, + kits_root_key, RRF_RT_REG_SZ, nullptr, nullptr, + &cbData))) + return {}; + + if (cbData == 0) + return {}; + + std::vector buffer; + buffer.resize(cbData); + + if (FAILED(RegGetValueW(HKEY_LOCAL_MACHINE, kits_installed_roots_keypath, + kits_root_key, RRF_RT_REG_SZ, nullptr, buffer.data(), + &cbData))) + return {}; + + return std::filesystem::path(buffer.data()); +} + +std::vector available_versions() noexcept { + HKEY hKey; + + if (FAILED(RegOpenKeyExW(HKEY_LOCAL_MACHINE, kits_installed_roots_keypath, + 0, KEY_READ, &hKey))) + return {}; + + windows::raii::hkey key{hKey}; + + DWORD cSubKeys; + DWORD cbMaxSubKeyLen; + if (FAILED(RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &cSubKeys, + &cbMaxSubKeyLen, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr))) + return {}; + + std::vector buffer; + buffer.resize(static_cast(cbMaxSubKeyLen) + 1); + + std::vector versions; + for (DWORD dwIndex = 0; dwIndex < cSubKeys; ++dwIndex) { + DWORD cchName = cbMaxSubKeyLen + 1; + + // TODO(compnerd) handle error + (void)RegEnumKeyExW(hKey, dwIndex, buffer.data(), &cchName, nullptr, + nullptr, nullptr, nullptr); + + versions.emplace_back(buffer.data()); + } + return versions; +} +} + +namespace msvc { +// VS2019 v142 Build Tools +static const wchar_t toolset_v142_x86_x64[] = + L"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"; +static const wchar_t toolset_v142_arm[] = + L"Microsoft.VisualStudio.Component.VC.Tools.ARM"; +static const wchar_t toolset_v142_arm64[] = + L"Microsoft.VisualStudio.Component.VC.Tools.ARM64"; +static const wchar_t toolset_v142_arm64ec[] = + L"Microsoft.VisualStudio.Component.VC.Tools.ARM64EC"; + +// VS2017 v141 Build Tools +static const wchar_t toolset_v141_x86_x64[] = + L"Microsoft.VisualStudio.Component.VC.v141.x86.x64"; +static const wchar_t toolset_v141_arm[] = + L"Microsoft.VisualStudio.Component.VC.v141.ARM"; +static const wchar_t toolset_v141_arm64[] = + L"Microsoft.VisualStudio.Component.VC.v141.ARM64"; + +static const wchar_t *known_toolsets[] = { + toolset_v142_x86_x64, + toolset_v142_arm64ec, + toolset_v142_arm64, + toolset_v142_arm, + + toolset_v141_x86_x64, + toolset_v141_arm64, + toolset_v141_arm, +}; + +// The name is misleading. This currently returns the default toolset in all +// VS2015+ installations. +std::vector available_toolsets() noexcept { + windows::raii::com_initializer com; + + std::vector toolsets; + + ISetupConfigurationPtr configuration; + if (FAILED(configuration.CreateInstance(__uuidof(SetupConfiguration)))) + return toolsets; + + ISetupConfiguration2Ptr configuration2; + if (FAILED(configuration->QueryInterface(&configuration2))) + return toolsets; + + IEnumSetupInstancesPtr instances; + if (FAILED(configuration2->EnumAllInstances(&instances))) + return toolsets; + + ULONG fetched; + ISetupInstancePtr instance; + while (SUCCEEDED(instances->Next(1, &instance, &fetched)) && fetched) { + ISetupInstance2Ptr instance2; + if (FAILED(instance->QueryInterface(&instance2))) + continue; + + InstanceState state; + if (FAILED(instance2->GetState(&state))) + continue; + + // Ensure that the instance state matches + // eLocal: The instance installation path exists. + // eRegistered: A product is registered to the instance. + if (~state & eLocal or ~state & eRegistered) + continue; + + LPSAFEARRAY packages; + if (FAILED(instance2->GetPackages(&packages))) + continue; + + LONG lower, upper; + if (FAILED(SafeArrayGetLBound(packages, 1, &lower)) || + FAILED(SafeArrayGetUBound(packages, 1, &upper))) + continue; + + for (LONG index = 0, count = upper - lower + 1; index < count; ++index) { + IUnknownPtr element; + if (FAILED(SafeArrayGetElement(packages, &index, &element))) + continue; + + ISetupPackageReferencePtr package; + if (FAILED(element->QueryInterface(&package))) + continue; + + _bstr_t package_id; + if (FAILED(package->GetId(package_id.GetAddress()))) + continue; + + // Ensure that we are dealing with a (known) MSVC ToolSet + if (std::none_of(std::begin(known_toolsets), std::end(known_toolsets), + [package_id = package_id.GetBSTR()](const wchar_t *id) { + return wcscmp(package_id, id) == 0; + })) + continue; + + _bstr_t VSInstallDir; + if (FAILED(instance2->GetInstallationPath(VSInstallDir.GetAddress()))) + continue; + + std::filesystem::path VCInstallDir{static_cast(VSInstallDir)}; + VCInstallDir.append("VC"); + + std::string VCToolsVersion; + // VSInstallDir\VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt + // contains the default version of the v141 MSVC toolset. Prefer to use + // VSInstallDir\VC\Auxiliary\Build\Microsoft.VCToolsVersion.v142.default.txt + // which contains the default v142 version of the toolset. + for (const auto &file : {"Microsoft.VCToolsVersion.v142.default.txt", + "Microsoft.VCToolsVersion.default.txt"}) { + std::filesystem::path path{VCInstallDir}; + path.append("Auxiliary"); + path.append("Build"); + path.append(file); + + VCToolsVersion = contents(path); + // Strip any line ending characters from the contents of the file. + trim(VCToolsVersion); + if (!VCToolsVersion.empty()) + break; + } + + if (VCToolsVersion.empty()) + continue; + + std::filesystem::path VCToolsInstallDir{VCInstallDir}; + VCToolsInstallDir.append("Tools"); + VCToolsInstallDir.append("MSVC"); + VCToolsInstallDir.append(VCToolsVersion); + + // FIXME(compnerd) should we actually just walk the directory structure + // instead and populate all the toolsets? That would match roughly what + // we do with the UCRT currently. + + toolsets.push_back(VCToolsInstallDir); + } + } + + return toolsets; +} +} + +namespace msi { +std::wstring get_property(MSIHANDLE hInstall, std::wstring_view key) noexcept { + DWORD size = 0; + UINT status; + + status = MsiGetPropertyW(hInstall, key.data(), L"", &size); + assert(status == ERROR_MORE_DATA); + + std::vector buffer; + buffer.resize(size + 1); + + size = buffer.capacity(); + status = MsiGetPropertyW(hInstall, key.data(), buffer.data(), &size); + // TODO(compnerd) handle error + + return {buffer.data(), buffer.capacity()}; +} +} + +UINT SwiftInstaller_InstallAuxiliaryFiles(MSIHANDLE hInstall) { + std::wstring data = msi::get_property(hInstall, L"CustomActionData"); + trim(data); + + std::filesystem::path SDKROOT{data}; + LOG(hInstall, info) << "SDKROOT: " << SDKROOT.string(); + + // Copy SDK Module Maps + std::filesystem::path UniversalCRTSdkDir = winsdk::install_root(); + LOG(hInstall, info) << "UniversalCRTSdkDir: " << UniversalCRTSdkDir; + if (!UniversalCRTSdkDir.empty()) { + // FIXME(compnerd) Technically we are using the UniversalCRTSdkDir here + // instead of the WindowsSdkDir which would contain `um`. + + // FIXME(compnerd) we may end up in a state where the ucrt and Windows SDKs + // do not match. Users have reported cases where they somehow managed to + // setup such a configuration. We should split this up to explicitly + // handle the UCRT and WinSDK paths separately. + for (const auto &version : winsdk::available_versions()) { + const struct { + std::filesystem::path src; + std::filesystem::path dst; + } items[] = { + { SDKROOT / "usr" / "share" / "ucrt.modulemap", + UniversalCRTSdkDir / "Include" / version / "ucrt" / "module.modulemap" }, + { SDKROOT / "usr" / "share" / "winsdk.modulemap", + UniversalCRTSdkDir / "Include" / version / "um" / "module.modulemap" }, + }; + + for (const auto &item : items) { + static const constexpr std::filesystem::copy_options options = + std::filesystem::copy_options::overwrite_existing; + + std::error_code ec; + if (!std::filesystem::copy_file(item.src, item.dst, options, ec)) { + LOG(hInstall, error) + << "unable to copy " << item.src << " to " << item.dst << ": " + << ec.message(); + continue; + } + LOG(hInstall, info) << "Deployed " << item.dst; + } + } + } + + // Copy MSVC Tools Module Maps + for (const auto &VCToolsInstallDir : msvc::available_toolsets()) { + const struct { + std::filesystem::path src; + std::filesystem::path dst; + } items[] = { + { SDKROOT / "usr" / "share" / "visualc.modulemap", + VCToolsInstallDir / "include" / "module.modulemap" }, + { SDKROOT / "usr" / "share" / "visualc.apinotes", + VCToolsInstallDir / "include" / "visualc.apinotes" }, + }; + + for (const auto &item : items) { + static const constexpr std::filesystem::copy_options options = + std::filesystem::copy_options::overwrite_existing; + + std::error_code ec; + if (!std::filesystem::copy_file(item.src, item.dst, options, ec)) { + LOG(hInstall, error) + << "unable to copy " << item.src << " to " << item.dst << ": " + << ec.message(); + continue; + } + LOG(hInstall, info) << "Deployed " << item.dst; + } + } + + // TODO(compnerd) it would be ideal to record the files deployed here to the + // `RemoveFile` table which would allow them to be cleaned up on removal. + // This is tricky as we cannot modify the on-disk database. The deferred + // action is already executed post-InstallExecute which means that we can now + // identify the cached MSI by: + // + // std::wstring product_code = msi::get_property(hInstall, L"ProductCode"); + // + // DWORD size = 0; + // (void)MsiGetProductInfoW(product_code.c_str(), + // INSTALLPROPERTY_LOCALPACKAGE, L"", &size); + // std::vector buffer; + // buffer.resize(++size); + // (void)MsiGetProductInfoW(product_code.c_str(), + // INSTALLPROPERTY_LOCALPACKAGE, buffer.data(), + // &size); + // + // We can then create a new property for the location of the entry and a new + // RemoveFile entry for cleaning up the file. Note that we may have to tweak + // things to get repairs to work properly with the tracking. + // + // PMSIHANDLE database; + // (void)MsiOpenDatabaseW(buffer.data(), MSIDBOPEN_TRANSACT, &database); + // + // static const wchar_t query[] = + // LR"SQL( + //INSERT INTO `Property` (`Property`, `Value`) + // VALUES(?, ?); + //INSERT INTO `RemoveFile` (`FileKey`, `Component_`, `FileName`, `DirProperty`, `InstallMode` + // VALUES (?, ?, ?, ?, ?); + // )SQL"; + // + // PMSIHANDLE view; + // (void)MsiDatabaseOpenViewW(database, query, &view); + // + // std::hash hasher; + // + // std::wostringstream component; + // component << "cmp" << hasher(path.wstring()); + // + // std::wostringstream property; + // property << "prop" << hasher(path.wstring()); + // + // PMSIHANDLE record = MsiRecordCreate(7); + // (void)MsiRecordSetStringW(record, 1, property.str().c_str()); + // (void)MsiRecordSetStringW(record, 2, path.parent_path().wstring().c_str()); + // (void)MsiRecordSetStringW(record, 3, component.str().c_str()); + // (void)MsiRecordSetStringW(record, 4, component.str().c_str()); + // (void)MsiRecordSetStringW(record, 5, path.filename().wstring().c_str()); + // (void)MsiRecordSetStringW(record, 6, property.str().c_str()); + // (void)MsiRecordSetInteger(record, 7, 2); + // + // (void)MsiViewExecute(view, record); + // + // (void)MsiDatabaseCommit(database); + // + // Currently, this seems to fail with the commiting of the database, which is + // still a mystery to me. This relies on the clever usage of the + // `EnsureTable` in the WiX definition to ensure that we do not need to create + // the table. + // + // The error handling has been elided here for brevity's sake. + + return ERROR_SUCCESS; +} diff --git a/platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj b/platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj new file mode 100644 index 00000000..50cb53a1 --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj @@ -0,0 +1,100 @@ + + + + Debug + Win32 + + + + Release + Win32 + + + + Debug + x64 + + + + Release + x64 + + + + Debug + ARM64 + + + + Release + ARM64 + + + + + {84027311-67A4-4351-AD3A-53529767BFA0} + SwiftInstaller + + + + + + Unicode + DynamicLibrary + SwiftInstaller + v142 + .build\$(Configuration)\$(Platform)\ + .build\$(Configuration)\$(Platform)\$(TargetName)\ + + + + + $(ProjectDir)Headers;$(ProjectDir)ThirdParty\Microsoft.VisualStudio.Setup.Configuration.Native\inc + stdcpp17 + SwiftInstaller_EXPORTS;%(PreprocessorDefinitions) + + + msi.lib + + + + + + MultiThreadedDebug + + + + + + MultiThreaded + + + + + true + + + + false + + + + + + + + + + + + + + + + + + + + + + diff --git a/platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj.filters b/platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj.filters new file mode 100644 index 00000000..73c0300e --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/SwiftInstaller.vcxproj.filters @@ -0,0 +1,43 @@ + + + + + Source Files + + + Source Files + + + Source Files + + + + + + Header Files + + + Header Files + + + Header Files + + + + + + Header Files + + + + + + {485df023-ca0b-4390-b9e5-bb574625ac42} + h;hh + + + {b2fa78cd-13ff-4b88-9e63-112e1ac92329} + cc + + + diff --git a/platforms/Windows/CustomActions/SwiftInstaller/ThirdParty/Microsoft.VisualStudio.Setup.Configuration.Native/inc/Setup.Configuration.h b/platforms/Windows/CustomActions/SwiftInstaller/ThirdParty/Microsoft.VisualStudio.Setup.Configuration.Native/inc/Setup.Configuration.h new file mode 100644 index 00000000..81690bff --- /dev/null +++ b/platforms/Windows/CustomActions/SwiftInstaller/ThirdParty/Microsoft.VisualStudio.Setup.Configuration.Native/inc/Setup.Configuration.h @@ -0,0 +1,1059 @@ +// The MIT License(MIT) +// Copyright(C) Microsoft Corporation.All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +#pragma once + +// Constants +// +#ifndef E_NOTFOUND +#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND) +#endif + +#ifndef E_FILENOTFOUND +#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) +#endif + +#ifndef E_NOTSUPPORTED +#define E_NOTSUPPORTED HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) +#endif + +// Enumerations +// +/// +/// The state of an instance. +/// +enum InstanceState +{ + /// + /// The instance state has not been determined. + /// + eNone = 0, + + /// + /// The instance installation path exists. + /// + eLocal = 1, + + /// + /// A product is registered to the instance. + /// + eRegistered = 2, + + /// + /// No reboot is required for the instance. + /// + eNoRebootRequired = 4, + + /// + /// No errors were reported for the instance. + /// + eNoErrors = 8, + + /// + /// The instance represents a complete install. + /// + eComplete = MAXUINT, +}; + +// Forward interface declarations +// +#ifndef __ISetupInstance_FWD_DEFINED__ +#define __ISetupInstance_FWD_DEFINED__ +typedef struct ISetupInstance ISetupInstance; +#endif + +#ifndef __ISetupInstance2_FWD_DEFINED__ +#define __ISetupInstance2_FWD_DEFINED__ +typedef struct ISetupInstance2 ISetupInstance2; +#endif + +#ifndef __ISetupInstanceCatalog_FWD_DEFINED__ +#define __ISetupInstanceCatalog_FWD_DEFINED__ +typedef struct ISetupInstanceCatalog ISetupInstanceCatalog; +#endif + +#ifndef __ISetupLocalizedProperties_FWD_DEFINED__ +#define __ISetupLocalizedProperties_FWD_DEFINED__ +typedef struct ISetupLocalizedProperties ISetupLocalizedProperties; +#endif + +#ifndef __IEnumSetupInstances_FWD_DEFINED__ +#define __IEnumSetupInstances_FWD_DEFINED__ +typedef struct IEnumSetupInstances IEnumSetupInstances; +#endif + +#ifndef __ISetupConfiguration_FWD_DEFINED__ +#define __ISetupConfiguration_FWD_DEFINED__ +typedef struct ISetupConfiguration ISetupConfiguration; +#endif + +#ifndef __ISetupConfiguration2_FWD_DEFINED__ +#define __ISetupConfiguration2_FWD_DEFINED__ +typedef struct ISetupConfiguration2 ISetupConfiguration2; +#endif + +#ifndef __ISetupPackageReference_FWD_DEFINED__ +#define __ISetupPackageReference_FWD_DEFINED__ +typedef struct ISetupPackageReference ISetupPackageReference; +#endif + +#ifndef __ISetupProductReference_FWD_DEFINED__ +#define __ISetupProductReference_FWD_DEFINED__ +typedef struct ISetupProductReference ISetupProductReference; +#endif + +#ifndef __ISetupProductReference2_FWD_DEFINED__ +#define __ISetupProductReference2_FWD_DEFINED__ +typedef struct ISetupProductReference2 ISetupProductReference2; +#endif + +#ifndef __ISetupHelper_FWD_DEFINED__ +#define __ISetupHelper_FWD_DEFINED__ +typedef struct ISetupHelper ISetupHelper; +#endif + +#ifndef __ISetupErrorInfo_FWD_DEFINED__ +#define __ISetupErrorInfo_FWD_DEFINED__ +typedef struct ISetupErrorInfo ISetupErrorInfo; +#endif + +#ifndef __ISetupErrorState_FWD_DEFINED__ +#define __ISetupErrorState_FWD_DEFINED__ +typedef struct ISetupErrorState ISetupErrorState; +#endif + +#ifndef __ISetupErrorState2_FWD_DEFINED__ +#define __ISetupErrorState2_FWD_DEFINED__ +typedef struct ISetupErrorState2 ISetupErrorState2; +#endif + +#ifndef __ISetupErrorState3_FWD_DEFINED__ +#define __ISetupErrorState3_FWD_DEFINED__ +typedef struct ISetupErrorState3 ISetupErrorState3; +#endif + +#ifndef __ISetupFailedPackageReference_FWD_DEFINED__ +#define __ISetupFailedPackageReference_FWD_DEFINED__ +typedef struct ISetupFailedPackageReference ISetupFailedPackageReference; +#endif + +#ifndef __ISetupFailedPackageReference2_FWD_DEFINED__ +#define __ISetupFailedPackageReference2_FWD_DEFINED__ +typedef struct ISetupFailedPackageReference2 ISetupFailedPackageReference2; +#endif + +#ifndef __ISetupFailedPackageReference3_FWD_DEFINED__ +#define __ISetupFailedPackageReference3_FWD_DEFINED__ +typedef struct ISetupFailedPackageReference3 ISetupFailedPackageReference3; +#endif + +#ifndef __ISetupPropertyStore_FWD_DEFINED__ +#define __ISetupPropertyStore_FWD_DEFINED__ +typedef struct ISetupPropertyStore ISetupPropertyStore; +#endif + +#ifndef __ISetupLocalizedPropertyStore_FWD_DEFINED__ +#define __ISetupLocalizedPropertyStore_FWD_DEFINED__ +typedef struct ISetupLocalizedPropertyStore ISetupLocalizedPropertyStore; +#endif + +#ifndef __ISetupPolicy_FWD_DEFINED__ +#define __ISetupPolicy_FWD_DEFINED__ +typedef struct ISetupPolicy ISetupPolicy; +#endif + +// Forward class declarations +// +#ifndef __SetupConfiguration_FWD_DEFINED__ +#define __SetupConfiguration_FWD_DEFINED__ + +#ifdef __cplusplus +typedef class SetupConfiguration SetupConfiguration; +#endif + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Interface definitions +// +EXTERN_C const IID IID_ISetupInstance; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about an instance of a product. +/// +struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") DECLSPEC_NOVTABLE ISetupInstance : public IUnknown +{ + /// + /// Gets the instance identifier (should match the name of the parent instance directory). + /// + /// The instance identifier. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetInstanceId)( + _Out_ BSTR* pbstrInstanceId + ) = 0; + + /// + /// Gets the local date and time when the installation was originally installed. + /// + /// The local date and time when the installation was originally installed. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(GetInstallDate)( + _Out_ LPFILETIME pInstallDate + ) = 0; + + /// + /// Gets the unique name of the installation, often indicating the branch and other information used for telemetry. + /// + /// The unique name of the installation, often indicating the branch and other information used for telemetry. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(GetInstallationName)( + _Out_ BSTR* pbstrInstallationName + ) = 0; + + /// + /// Gets the path to the installation root of the product. + /// + /// The path to the installation root of the product. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(GetInstallationPath)( + _Out_ BSTR* pbstrInstallationPath + ) = 0; + + /// + /// Gets the version of the product installed in this instance. + /// + /// The version of the product installed in this instance. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(GetInstallationVersion)( + _Out_ BSTR* pbstrInstallationVersion + ) = 0; + + /// + /// Gets the display name (title) of the product installed in this instance. + /// + /// The LCID for the display name. + /// The display name (title) of the product installed in this instance. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(GetDisplayName)( + _In_ LCID lcid, + _Out_ BSTR* pbstrDisplayName + ) = 0; + + /// + /// Gets the description of the product installed in this instance. + /// + /// The LCID for the description. + /// The description of the product installed in this instance. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(GetDescription)( + _In_ LCID lcid, + _Out_ BSTR* pbstrDescription + ) = 0; + + /// + /// Resolves the optional relative path to the root path of the instance. + /// + /// A relative path within the instance to resolve, or NULL to get the root path. + /// The full path to the optional relative path within the instance. If the relative path is NULL, the root path will always terminate in a backslash. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined. + STDMETHOD(ResolvePath)( + _In_opt_z_ LPCOLESTR pwszRelativePath, + _Out_ BSTR* pbstrAbsolutePath + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupInstance2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about an instance of a product. +/// +struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance +{ + /// + /// Gets the state of the instance. + /// + /// The state of the instance. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetState)( + _Out_ InstanceState* pState + ) = 0; + + /// + /// Gets an array of package references registered to the instance. + /// + /// Pointer to an array of . + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined. + STDMETHOD(GetPackages)( + _Out_ LPSAFEARRAY* ppsaPackages + ) = 0; + + /// + /// Gets a pointer to the that represents the registered product. + /// + /// Pointer to an instance of . This may be NULL if does not return . + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined. + STDMETHOD(GetProduct)( + _Outptr_result_maybenull_ ISetupPackageReference** ppPackage + ) = 0; + + /// + /// Gets the relative path to the product application, if available. + /// + /// The relative path to the product application, if available. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetProductPath)( + _Outptr_result_maybenull_ BSTR* pbstrProductPath + ) = 0; + + /// + /// Gets the error state of the instance, if available. + /// + /// The error state of the instance, if available. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetErrors)( + _Outptr_result_maybenull_ ISetupErrorState** ppErrorState + ) = 0; + + /// + /// Gets a value indicating whether the instance can be launched. + /// + /// Whether the instance can be launched. + /// Standard HRESULT indicating success or failure. + /// + /// An instance could have had errors during install but still be launched. Some features may not work correctly, but others will. + /// + STDMETHOD(IsLaunchable)( + _Out_ VARIANT_BOOL* pfIsLaunchable + ) = 0; + + /// + /// Gets a value indicating whether the instance is complete. + /// + /// Whether the instance is complete. + /// Standard HRESULT indicating success or failure. + /// + /// An instance is complete if it had no errors during install, resume, or repair. + /// + STDMETHOD(IsComplete)( + _Out_ VARIANT_BOOL* pfIsComplete + ) = 0; + + /// + /// Gets product-specific properties. + /// + /// A pointer to an instance of . This may be NULL if no properties are defined. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetProperties)( + _Outptr_result_maybenull_ ISetupPropertyStore** ppProperties + ) = 0; + + /// + /// Gets the directory path to the setup engine that installed the instance. + /// + /// The directory path to the setup engine that installed the instance. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist. + STDMETHOD(GetEnginePath)( + _Outptr_result_maybenull_ BSTR* pbstrEnginePath + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupInstanceCatalog; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about a catalog used to install an instance. +/// +struct DECLSPEC_UUID("9AD8E40F-39A2-40F1-BF64-0A6C50DD9EEB") DECLSPEC_NOVTABLE ISetupInstanceCatalog : public IUnknown +{ + /// + /// Gets catalog information properties. + /// + /// A pointer to an instance of . + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property does not exist. + STDMETHOD(GetCatalogInfo)( + _Out_ ISetupPropertyStore** ppCatalogInfo + ) = 0; + + /// + /// Gets a value indicating whether the catalog is a prerelease. + /// + /// Whether the catalog for the instance is a prerelease version. + /// Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property does not exist. + STDMETHOD(IsPrerelease)( + _Out_ VARIANT_BOOL* pfIsPrerelease + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupLocalizedProperties; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Provides localized properties of an instance of a product. +/// +struct DECLSPEC_UUID("F4BD7382-FE27-4AB4-B974-9905B2A148B0") DECLSPEC_NOVTABLE ISetupLocalizedProperties : public IUnknown +{ + /// + /// Gets localized product-specific properties. + /// + /// A pointer to an instance of . This may be NULL if no properties are defined. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetLocalizedProperties)( + _Outptr_result_maybenull_ ISetupLocalizedPropertyStore** ppLocalizedProperties + ) = 0; + + /// + /// Gets localized channel-specific properties. + /// + /// A pointer to an instance of . This may be NULL if no channel properties are defined. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetLocalizedChannelProperties)( + _Outptr_result_maybenull_ ISetupLocalizedPropertyStore** ppLocalizedChannelProperties + ) = 0; +}; +#endif + +EXTERN_C const IID IID_IEnumSetupInstances; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// An enumerator of installed objects. +/// +struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown +{ + /// + /// Retrieves the next set of product instances in the enumeration sequence. + /// + /// The number of product instances to retrieve. + /// A pointer to an array of . + /// A pointer to the number of product instances retrieved. If is 1 this parameter may be NULL. + /// S_OK if the number of elements were fetched, S_FALSE if nothing was fetched (at end of enumeration), E_INVALIDARG if is greater than 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an could not be allocated. + STDMETHOD(Next)( + _In_ ULONG celt, + _Out_writes_to_(celt, *pceltFetched) ISetupInstance** rgelt, + _Out_opt_ _Deref_out_range_(0, celt) ULONG* pceltFetched + ) = 0; + + /// + /// Skips the next set of product instances in the enumeration sequence. + /// + /// The number of product instances to skip. + /// S_OK if the number of elements could be skipped; otherwise, S_FALSE; + STDMETHOD(Skip)( + _In_ ULONG celt + ) = 0; + + /// + /// Resets the enumeration sequence to the beginning. + /// + /// Always returns S_OK; + STDMETHOD(Reset)(void) = 0; + + /// + /// Creates a new enumeration object in the same state as the current enumeration object: the new object points to the same place in the enumeration sequence. + /// + /// A pointer to a pointer to a new interface. If the method fails, this parameter is undefined. + /// S_OK if a clone was returned; otherwise, E_OUTOFMEMORY. + STDMETHOD(Clone)( + _Deref_out_opt_ IEnumSetupInstances** ppenum + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupConfiguration; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Gets information about product instances installed on the machine. +/// +struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown +{ + /// + /// Enumerates all launchable product instances installed. + /// + /// An enumeration of completed, installed product instances. + /// Standard HRESULT indicating success or failure. + STDMETHOD(EnumInstances)( + _Out_ IEnumSetupInstances** ppEnumInstances + ) = 0; + + /// + /// Gets the instance for the current process path. + /// + /// The instance for the current process path. + /// + /// The instance for the current process path, or E_NOTFOUND if not found. + /// The may indicate the instance is invalid. + /// + /// + /// The returned instance may not be launchable. + /// +STDMETHOD(GetInstanceForCurrentProcess)( + _Out_ ISetupInstance** ppInstance + ) = 0; + + /// + /// Gets the instance for the given path. + /// + /// The instance for the given path. + /// + /// The instance for the given path, or E_NOTFOUND if not found. + /// The may indicate the instance is invalid. + /// + /// + /// The returned instance may not be launchable. + /// +STDMETHOD(GetInstanceForPath)( + _In_z_ LPCWSTR wzPath, + _Out_ ISetupInstance** ppInstance + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupConfiguration2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Gets information about product instances. +/// +struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration +{ + /// + /// Enumerates all product instances. + /// + /// An enumeration of all product instances. + /// Standard HRESULT indicating success or failure. + STDMETHOD(EnumAllInstances)( + _Out_ IEnumSetupInstances** ppEnumInstances + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupPackageReference; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a package. +/// +struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown +{ + /// + /// Gets the general package identifier. + /// + /// The general package identifier. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetId)( + _Out_ BSTR* pbstrId + ) = 0; + + /// + /// Gets the version of the package. + /// + /// The version of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetVersion)( + _Out_ BSTR* pbstrVersion + ) = 0; + + /// + /// Gets the target process architecture of the package. + /// + /// The target process architecture of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetChip)( + _Out_ BSTR* pbstrChip + ) = 0; + + /// + /// Gets the language and optional region identifier. + /// + /// The language and optional region identifier. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetLanguage)( + _Out_ BSTR* pbstrLanguage + ) = 0; + + /// + /// Gets the build branch of the package. + /// + /// The build branch of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetBranch)( + _Out_ BSTR* pbstrBranch + ) = 0; + + /// + /// Gets the type of the package. + /// + /// The type of the package. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetType)( + _Out_ BSTR* pbstrType + ) = 0; + + /// + /// Gets the unique identifier consisting of all defined tokens. + /// + /// The unique identifier consisting of all defined tokens. + /// Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required). + STDMETHOD(GetUniqueId)( + _Out_ BSTR* pbstrUniqueId + ) = 0; + + /// + /// Gets a value indicating whether the package refers to an external extension. + /// + /// A value indicating whether the package refers to an external extension. + /// Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required). + STDMETHOD(GetIsExtension)( + _Out_ VARIANT_BOOL* pfIsExtension + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupProductReference; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a product package. +/// +struct DECLSPEC_UUID("a170b5ef-223d-492b-b2d4-945032980685") DECLSPEC_NOVTABLE ISetupProductReference : public ISetupPackageReference +{ + /// + /// Gets a value indicating whether the product package is installed. + /// + /// A value indicating whether the product package is installed. + /// Standard HRESULT indicating success or failure, including E_NOTSUPPORTED if the reference is not to a product, or E_UNEXPECTED if the Installed property is the wrong type. + STDMETHOD(GetIsInstalled)( + _Out_ VARIANT_BOOL* pfIsInstalled + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupProductReference2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a product package. +/// +struct DECLSPEC_UUID("279a5db3-7503-444b-b34d-308f961b9a06") DECLSPEC_NOVTABLE ISetupProductReference2 : public ISetupProductReference +{ + /// + /// Gets a value indicating whether the product supports extensions. + /// + /// A value indicating whether the product supports extensions. + /// Standard HRESULT indicating success or failure, including E_NOTSUPPORTED if the reference is not to a product, or E_UNEXPECTED if the SupportsExtensions property is the wrong type. + STDMETHOD(GetSupportsExtensions)( + _Out_ VARIANT_BOOL* pfSupportsExtensions + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupHelper; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Helper functions. +/// +/// +/// You can query for this interface from the class. +/// +struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") DECLSPEC_NOVTABLE ISetupHelper : public IUnknown +{ + /// + /// Parses a dotted quad version string into a 64-bit unsigned integer. + /// + /// The dotted quad version string to parse, e.g. 1.2.3.4. + /// A 64-bit unsigned integer representing the version. You can compare this to other versions. + /// Standard HRESULT indicating success or failure, including E_INVALIDARG if the version is not valid. + STDMETHOD(ParseVersion)( + _In_ LPCOLESTR pwszVersion, + _Out_ PULONGLONG pullVersion + ) = 0; + + /// + /// Parses a dotted quad version string into a 64-bit unsigned integer. + /// + /// The string containing 1 or 2 dotted quad version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer. + /// A 64-bit unsigned integer representing the minimum version, which may be 0. You can compare this to other versions. + /// A 64-bit unsigned integer representing the maximum version, which may be MAXULONGLONG. You can compare this to other versions. + /// Standard HRESULT indicating success or failure, including E_INVALIDARG if the version range is not valid. + STDMETHOD(ParseVersionRange)( + _In_ LPCOLESTR pwszVersionRange, + _Out_ PULONGLONG pullMinVersion, + _Out_ PULONGLONG pullMaxVersion + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupErrorInfo; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about errors that occured during install of an instance. +/// +/// +/// Objects may also implement and . +/// +struct DECLSPEC_UUID("2A2F3292-958E-4905-B36E-013BE84E27AB") DECLSPEC_NOVTABLE ISetupErrorInfo : public IUnknown +{ + /// + /// Gets the HRESULT of the error. + /// + /// The HRESULT of the error. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetErrorHResult)( + _Out_ HRESULT* plHResult + ) = 0; + + /// + /// Gets the class name of the error (exception). + /// + /// The class name of the error (exception). + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetErrorClassName)( + _Outptr_result_maybenull_ BSTR* pbstrClassName + ) = 0; + + /// + /// Gets the error message. + /// + /// The error message. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetErrorMessage)( + _Outptr_result_maybenull_ BSTR* pbstrMessage + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupErrorState; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about the error state of an instance. +/// +struct DECLSPEC_UUID("46DCCD94-A287-476A-851E-DFBC2FFDBC20") DECLSPEC_NOVTABLE ISetupErrorState : public IUnknown +{ + /// + /// Gets an array of failed package references. + /// + /// Pointer to an array of , if packages have failed. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetFailedPackages)( + _Outptr_result_maybenull_ LPSAFEARRAY* ppsaFailedPackages + ) = 0; + + /// + /// Gets an array of skipped package references. + /// + /// Pointer to an array of , if packages have been skipped. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetSkippedPackages)( + _Outptr_result_maybenull_ LPSAFEARRAY* ppsaSkippedPackages + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupErrorState2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about the error state of an instance. +/// +struct DECLSPEC_UUID("9871385B-CA69-48F2-BC1F-7A37CBF0B1EF") DECLSPEC_NOVTABLE ISetupErrorState2 : public ISetupErrorState +{ + /// + /// Gets the path to the error log. + /// + /// The path to the error log. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetErrorLogFilePath)( + _Outptr_result_maybenull_ BSTR* pbstrErrorLogFilePath + ) = 0; + + /// + /// Gets the path to the main setup log. + /// + /// The path to the main setup log. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetLogFilePath)( + _Outptr_result_maybenull_ BSTR* pbstrLogFilePath + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupErrorState3; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Information about the error state of an instance. +/// +struct DECLSPEC_UUID("290019AD-28E2-46D5-9DE5-DA4B6BCF8057") DECLSPEC_NOVTABLE ISetupErrorState3 : public ISetupErrorState2 +{ + /// + /// Gets the runtime error that occured during install of an instance. + /// + /// The runtime error that occured during install of an instance. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetRuntimeError)( + _Outptr_result_maybenull_ ISetupErrorInfo** ppErrorInfo + ) = 0; +}; +#endif + +EXTERN_C const IID IID_ISetupFailedPackageReference; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a failed package. +/// +struct DECLSPEC_UUID("E73559CD-7003-4022-B134-27DC650B280F") DECLSPEC_NOVTABLE ISetupFailedPackageReference : public ISetupPackageReference +{ +}; + +#endif + +EXTERN_C const IID IID_ISetupFailedPackageReference2; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a failed package. +/// +struct DECLSPEC_UUID("0FAD873E-E874-42E3-B268-4FE2F096B9CA") DECLSPEC_NOVTABLE ISetupFailedPackageReference2 : public ISetupFailedPackageReference +{ + /// + /// Gets the path to the optional package log. + /// + /// The path to the optional package log. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetLogFilePath)( + _Outptr_result_maybenull_ BSTR* pbstrLogFilePath + ) = 0; + + /// + /// Gets the description of the package failure. + /// + /// The description of the package failure. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetDescription)( + _Outptr_result_maybenull_ BSTR* pbstrDescription + ) = 0; + + /// + /// Gets the signature to use for feedback reporting. + /// + /// The signature to use for feedback reporting. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetSignature)( + _Outptr_result_maybenull_ BSTR* pbstrSignature + ) = 0; + + /// + /// Gets the array of details for this package failure. + /// + /// Pointer to an array of details as BSTRs. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetDetails)( + _Out_ LPSAFEARRAY* ppsaDetails + ) = 0; + + /// + /// Gets an array of packages affected by this package failure. + /// + /// Pointer to an array of for packages affected by this package failure. This may be NULL. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetAffectedPackages)( + _Out_ LPSAFEARRAY* ppsaAffectedPackages + ) = 0; +}; + +#endif + +EXTERN_C const IID IID_ISetupFailedPackageReference3; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// A reference to a failed package. +/// +struct DECLSPEC_UUID("EBC3AE68-AD15-44E8-8377-39DBF0316F6C") DECLSPEC_NOVTABLE ISetupFailedPackageReference3 : public ISetupFailedPackageReference2 +{ + /// + /// Gets the action attempted when the package failed. + /// + /// The action, eg: Install, Download, etc. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetAction)( + _Outptr_result_maybenull_ BSTR* pbstrAction + ) = 0; + + /// + /// Gets the return code of the failure. + /// + /// The return code. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetReturnCode)( + _Outptr_result_maybenull_ BSTR* pbstrReturnCode + ) = 0; +}; + +#endif + +EXTERN_C const IID IID_ISetupPropertyStore; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Provides named properties. +/// +/// +/// You can get this from an , , or derivative. +/// +struct DECLSPEC_UUID("C601C175-A3BE-44BC-91F6-4568D230FC83") DECLSPEC_NOVTABLE ISetupPropertyStore : public IUnknown +{ + /// + /// Gets an array of property names in this property store. + /// + /// Pointer to an array of property names as BSTRs. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetNames)( + _Out_ LPSAFEARRAY* ppsaNames + ) = 0; + + /// + /// Gets the value of a named property in this property store. + /// + /// The name of the property to get. + /// The value of the property. + /// Standard HRESULT indicating success or failure, including E_NOTFOUND if the property is not defined or E_NOTSUPPORTED if the property type is not supported. + STDMETHOD(GetValue)( + _In_ LPCOLESTR pwszName, + _Out_ LPVARIANT pvtValue + ) = 0; +}; + +#endif + +EXTERN_C const IID IID_ISetupLocalizedPropertyStore; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Provides localized named properties. +/// +/// +/// You can get this from an . +/// +struct DECLSPEC_UUID("5BB53126-E0D5-43DF-80F1-6B161E5C6F6C") DECLSPEC_NOVTABLE ISetupLocalizedPropertyStore : public IUnknown +{ + /// + /// Gets an array of property names in this property store. + /// + /// The LCID for the property names. + /// Pointer to an array of property names as BSTRs. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetNames)( + _In_ LCID lcid, + _Out_ LPSAFEARRAY* ppsaNames + ) = 0; + + /// + /// Gets the value of a named property in this property store. + /// + /// The name of the property to get. + /// The LCID for the property. + /// The value of the property. + /// Standard HRESULT indicating success or failure, including E_NOTFOUND if the property is not defined or E_NOTSUPPORTED if the property type is not supported. + STDMETHOD(GetValue)( + _In_ LPCOLESTR pwszName, + _In_ LCID lcid, + _Out_ LPVARIANT pvtValue + ) = 0; +}; + +#endif + +EXTERN_C const IID IID_ISetupPolicy; + +#if defined(__cplusplus) && !defined(CINTERFACE) +/// +/// Gets setup policy values. +/// +/// +/// You can get this from an . +/// +struct DECLSPEC_UUID("E1DA4CBD-64C4-4C44-821D-98FAB64C4DA7") DECLSPEC_NOVTABLE ISetupPolicy : public IUnknown +{ + /// + /// Gets the value of the SharedInstallationPath policy. + /// + /// The value of the SharedInstallationPath policy. + /// Standard HRESULT indicating success or failure. + STDMETHOD(GetSharedInstallationPath)( + _Out_ BSTR* pbstrSharedInstallationPath + ) = 0; + + /// + /// Gets the value of a named policy. + /// + /// The name of the policy to get. + /// The value of the named policy. + /// Standard HRESULT indicating success or failure, including E_NOTSUPPORTED if the policy is not supported by this implementation. + STDMETHOD(GetValue)( + _In_ LPCOLESTR pwszName, + _Out_ LPVARIANT pvtValue + ) = 0; +}; + +#endif + +// Class declarations +// +EXTERN_C const CLSID CLSID_SetupConfiguration; + +#ifdef __cplusplus +/// +/// This class implements , , and . +/// +class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration; +#endif + +// Function declarations +// +/// +/// Gets an that provides information about product instances installed on the machine. +/// +/// The that provides information about product instances installed on the machine. +/// Reserved for future use. +/// Standard HRESULT indicating success or failure. +STDMETHODIMP GetSetupConfiguration( + _Out_ ISetupConfiguration** ppConfiguration, + _Reserved_ LPVOID pReserved +); + +#ifdef __cplusplus +} +#endif