From 9136f5e5038b5a446891520fe79aa5f32ab4d522 Mon Sep 17 00:00:00 2001 From: Vitalii Koshura Date: Wed, 15 Jan 2025 17:18:54 +0100 Subject: [PATCH] [windows] Fix and optimize Windows installer - Fix windows installer to comply with the MSI validation rules - Add automation test for MSI validation - Remove duplicate files from the installer - Add patched darice.cub file to the installer (https://github.com/AenBleidd/msi.darice.ice61) Signed-off-by: Vitalii Koshura --- .github/workflows/windows.yml | 20 ++ ci_tools/source_code_check.py | 1 + ci_tools/trailing_whitespaces_check.py | 1 + clientsetup/win/boinccas.cpp | 7 +- installer/ActionText.cpp | 4 +- installer/ActionTextTable.cpp | 49 +++- installer/ActionTextTable.h | 6 +- installer/AdminExecuteSequenceTable.cpp | 47 +++- installer/AdminExecuteSequenceTable.h | 6 +- installer/AdminUISequenceTable.cpp | 47 +++- installer/AdminUISequencetable.h | 4 +- installer/AdvtExecuteSequenceTable.cpp | 50 +++- installer/AdvtExecuteSequenceTable.h | 6 +- installer/BinaryTable.cpp | 37 ++- installer/BinaryTable.h | 6 +- installer/CheckboxTable.cpp | 40 ++- installer/CheckboxTable.h | 6 +- installer/Component.cpp | 12 +- installer/Component.h | 2 + installer/ComponentTable.cpp | 88 +++++- installer/ComponentTable.h | 6 +- installer/ControlConditionTable.cpp | 62 ++++- installer/ControlConditionTable.h | 6 +- installer/ControlEventTable.cpp | 88 +++++- installer/ControlEventTable.h | 6 +- installer/ControlTable.cpp | 176 +++++++++++- installer/ControlTable.h | 8 +- installer/CreateFolderTable.cpp | 34 ++- installer/CreateFolderTable.h | 6 +- installer/CustomActionTable.cpp | 73 ++++- installer/CustomActionTable.h | 6 +- installer/DialogTable.cpp | 143 +++++++++- installer/DialogTable.h | 7 +- installer/Directory.cpp | 2 +- installer/DirectoryTable.cpp | 74 ++++- installer/DirectoryTable.h | 7 +- installer/ErrorTable.cpp | 35 ++- installer/ErrorTable.h | 6 +- installer/EventMappingTable.cpp | 65 ++++- installer/EventMappingTable.h | 6 +- installer/FeatureComponentsTable.cpp | 34 ++- installer/FeatureComponentsTable.h | 6 +- installer/FeatureTable.cpp | 117 +++++++- installer/FeatureTable.h | 6 +- installer/File.cpp | 49 +++- installer/File.h | 16 +- installer/FileTable.cpp | 167 ++++++++++- installer/FileTable.h | 9 +- installer/FontTable.cpp | 35 ++- installer/FontTable.h | 6 +- installer/IconTable.cpp | 35 ++- installer/IconTable.h | 6 +- installer/InstallExecuteSequenceTable.cpp | 48 +++- installer/InstallExecuteSequenceTable.h | 6 +- installer/InstallUISequenceTable.cpp | 48 +++- installer/InstallUISequenceTable.h | 6 +- installer/Installer.cpp | 189 ++++++++----- installer/LaunchConditionTable.cpp | 37 ++- installer/LaunchConditionTable.h | 6 +- installer/Listbox.cpp | 32 +++ installer/Listbox.h | 36 +++ installer/ListboxTable.cpp | 99 +++++++ installer/ListboxTable.h | 34 +++ installer/MediaTable.cpp | 86 +++++- installer/MediaTable.h | 6 +- installer/MsiFileHashTable.cpp | 86 +++++- installer/MsiFileHashTable.h | 6 +- installer/PropertyTable.cpp | 35 ++- installer/PropertyTable.h | 6 +- installer/RadioButtonTable.cpp | 126 ++++++++- installer/RadioButtonTable.h | 6 +- installer/RegistryTable.cpp | 89 +++++- installer/RegistryTable.h | 6 +- installer/RemoveFileTable.cpp | 75 ++++- installer/RemoveFileTable.h | 6 +- installer/ServiceControlTable.cpp | 88 +++++- installer/ServiceControlTable.h | 6 +- installer/ServiceInstallTable.cpp | 182 +++++++++++- installer/ServiceInstallTable.h | 6 +- installer/ShortcutTable.cpp | 217 ++++++++++++++- installer/ShortcutTable.h | 6 +- installer/SummaryInformationTable.cpp | 4 +- installer/TextStyleTable.cpp | 74 ++++- installer/TextStyleTable.h | 6 +- installer/UITextTable.cpp | 35 ++- installer/UITextTable.h | 6 +- installer/UpgradeTable.cpp | 103 ++++++- installer/UpgradeTable.h | 6 +- installer/Validation.cpp | 35 +++ installer/Validation.h | 41 +++ installer/ValidationTable.cpp | 168 ++++++++++++ installer/ValidationTable.h | 56 ++++ installer/boinc.json | 320 +++++----------------- installer/darice.cub | Bin 0 -> 696320 bytes installer/res/placeholder.txt | 1 - tests/msi_validation.py | 66 +++++ win_build/installer.vcxproj | 11 +- win_build/installer_msi.vcxproj | 1 + 98 files changed, 3743 insertions(+), 510 deletions(-) create mode 100644 installer/Listbox.cpp create mode 100644 installer/Listbox.h create mode 100644 installer/ListboxTable.cpp create mode 100644 installer/ListboxTable.h create mode 100644 installer/Validation.cpp create mode 100644 installer/Validation.h create mode 100644 installer/ValidationTable.cpp create mode 100644 installer/ValidationTable.h create mode 100644 installer/darice.cub delete mode 100644 installer/res/placeholder.txt create mode 100644 tests/msi_validation.py diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 3877548419e..3d4690384c3 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -106,6 +106,22 @@ jobs: run: | python ./ci_tools/create_signing_metadata.py "${{ env.DMDF }}" "${{ env.AZURE_ENDPOINT }}" "${{ env.AZURE_CODE_SIGNING_NAME }}" "${{ env.AZURE_CERT_PROFILE_NAME }}" + - name: Install MsiVal2 and Orca tools + if: success() && matrix.type == 'msbuild' && !startsWith(github.ref, 'refs/tags/') + shell: powershell + run: | + md -Force ./temp + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\MsiVal2-x86_en-us.msi' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\8e4755178e6b5bcba8d3538c3630b7a5.cab' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\b80b7321357f7c9f281536f9440dfe68.cab' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\c2aabf6ea5c1d348ec22f3aeb92f8656.cab' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\Orca-x86_en-us.msi' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\838060235bcd28bf40ef7532c50ee032.cab' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\a35cd6c9233b6ba3da66eecaa9190436.cab' ./temp/ + cp 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\fe38b2fd0d440e3c6740b626f51a22fc.cab' ./temp/ + Start-Process "msiexec.exe" -ArgumentList "/i temp\MsiVal2-x86_en-us.msi" -Wait + Start-Process "msiexec.exe" -ArgumentList "/i temp\Orca-x86_en-us.msi" -Wait + - name: Build if: success() && matrix.type == 'msbuild' run: msbuild win_build\boinc.sln -p:Configuration=${{matrix.configuration}} -p:Platform=${{matrix.platform}} -p:VcpkgTripletConfig=ci -p:DLIB=${{ env.DLIB }} -p:DMDF=${{ env.DMDF }} -m @@ -119,6 +135,10 @@ jobs: working-directory: win_build\Build\${{matrix.platform}}\${{matrix.configuration}} run: ${{github.workspace}}\temp\OpenCppCoverage\OpenCppCoverage-x64\OpenCppCoverage.exe --cover_children --optimized_build --sources ${{github.workspace}} --export_type=cobertura:cobertura.xml -- unittests.exe --gtest_output=xml:gtest.xml + - name: Verify MSI file + if: success() && matrix.type == 'msbuild' && !startsWith(github.ref, 'refs/tags/') + run: python ./tests/msi_validation.py "C:\Program Files (x86)\MsiVal2\MsiVal2.exe" "${{github.workspace}}\win_build\Build\${{matrix.platform}}\${{matrix.configuration}}\boinc.msi" "${{github.workspace}}\installer\darice.cub" + - name: Run installation if: success() && matrix.platform == 'x64' && matrix.type == 'msbuild' shell: powershell diff --git a/ci_tools/source_code_check.py b/ci_tools/source_code_check.py index 0bd2ca88f5d..a75ec4f51de 100644 --- a/ci_tools/source_code_check.py +++ b/ci_tools/source_code_check.py @@ -97,6 +97,7 @@ def check(directory, bytes_to_check, exclude_dirs, exclude_extensions, exclude_f exclude_extensions = [ ".a", ".bmp", + ".cub", ".dll", ".exe", ".gif", diff --git a/ci_tools/trailing_whitespaces_check.py b/ci_tools/trailing_whitespaces_check.py index 88c668618dc..60dd58b6ccc 100644 --- a/ci_tools/trailing_whitespaces_check.py +++ b/ci_tools/trailing_whitespaces_check.py @@ -158,6 +158,7 @@ def check(directory, exclude_dirs, exclude_extensions, exclude_files, fix_errors exclude_extensions = [ ".a", ".bmp", + ".cub", ".dll", ".exe", ".gif", diff --git a/clientsetup/win/boinccas.cpp b/clientsetup/win/boinccas.cpp index efda5e0a943..d6044582ea6 100644 --- a/clientsetup/win/boinccas.cpp +++ b/clientsetup/win/boinccas.cpp @@ -1,6 +1,6 @@ // Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu -// Copyright (C) 2005 University of California +// Copyright (C) 2025 University of California // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -841,6 +841,11 @@ UINT BOINCCABase::GetComponentKeyFilename( // Save the string strComponentKeyFilename = szBuffer; + // strComponentKeyFilename format is [strComponentName]_[filename] + // Remove the component name from the string + strComponentKeyFilename = + strComponentKeyFilename.substr(strComponentName.size() + 1); + strMessage = _T("The key filename for component '"); strMessage += strComponentName; strMessage += _T("' is '"); diff --git a/installer/ActionText.cpp b/installer/ActionText.cpp index 1f87905dc64..03727a4744b 100644 --- a/installer/ActionText.cpp +++ b/installer/ActionText.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -15,8 +15,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . -#include - #include "ActionText.h" #include "MsiHelper.h" #include "JsonHelper.h" diff --git a/installer/ActionTextTable.cpp b/installer/ActionTextTable.cpp index 49585a30b14..1a6ed4a04ad 100644 --- a/installer/ActionTextTable.cpp +++ b/installer/ActionTextTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,11 +20,56 @@ #include "ActionTextTable.h" ActionTextTable::ActionTextTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { std::cout << "Loading ActionTextTable..." << std::endl; for (const auto& item : json) { values.emplace_back(item, installerStrings); } + const auto tableName = std::string("ActionText"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/actiontext-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the action.", url) + )); + validationTable->add(Validation( + tableName, + "Description", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("Localized description that is displayed in " + "the progress dialog box, or written to the log when the " + "action is executing.", url) + )); + validationTable->add(Validation( + tableName, + "Template", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryTemplate, + "", + DescriptionWithUrl("A localized format template that is used to " + "format action data records to display during action " + "execution.", url) + )); + } } bool ActionTextTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ActionTextTable.h b/installer/ActionTextTable.h index 10e0ee89e1d..60a21c2cd5d 100644 --- a/installer/ActionTextTable.h +++ b/installer/ActionTextTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -22,11 +22,13 @@ #include "ActionText.h" #include "InstallerStrings.h" #include "Generator.h" +#include "ValidationTable.h" class ActionTextTable : public Generator{ public: explicit ActionTextTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~ActionTextTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/AdminExecuteSequenceTable.cpp b/installer/AdminExecuteSequenceTable.cpp index 0d0c9d910f4..d9a0a281242 100644 --- a/installer/AdminExecuteSequenceTable.cpp +++ b/installer/AdminExecuteSequenceTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,12 +18,55 @@ #include "AdminExecuteSequenceTable.h" AdminExecuteSequenceTable::AdminExecuteSequenceTable( - const nlohmann::json& json) { + const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading AdminExecuteSequenceTable..." << std::endl; for (const auto& value : json) { actions.emplace_back(value); } + + const auto tableName = std::string("AdminExecuteSequence"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/adminexecutesequence-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the action to execute.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("Logical expression.", url) + )); + validationTable->add(Validation( + tableName, + "Sequence", + true, + -4, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A positive value indicates the " + "sequence position of the action.", url) + )); + } } bool AdminExecuteSequenceTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/AdminExecuteSequenceTable.h b/installer/AdminExecuteSequenceTable.h index f9c064c3e8a..38f76594bea 100644 --- a/installer/AdminExecuteSequenceTable.h +++ b/installer/AdminExecuteSequenceTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -22,10 +22,12 @@ #include "Action.h" #include "Generator.h" +#include "ValidationTable.h" class AdminExecuteSequenceTable : public Generator{ public: - explicit AdminExecuteSequenceTable(const nlohmann::json& json); + explicit AdminExecuteSequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~AdminExecuteSequenceTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/AdminUISequenceTable.cpp b/installer/AdminUISequenceTable.cpp index 0037708c878..1e4df8e8689 100644 --- a/installer/AdminUISequenceTable.cpp +++ b/installer/AdminUISequenceTable.cpp @@ -17,11 +17,56 @@ #include "AdminUISequenceTable.h" -AdminUISequenceTable::AdminUISequenceTable(const nlohmann::json& json) { +AdminUISequenceTable::AdminUISequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading AdminUISequenceTable..." << std::endl; for (const auto& value : json) { actions.emplace_back(value); } + + const auto tableName = std::string("AdminUISequence"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/adminuisequence-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the action to execute.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("Logical expression.", url) + )); + validationTable->add(Validation( + tableName, + "Sequence", + true, + -4, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A positive value indicates the sequence " + "position of the action. The negative values indicate that " + "the action is called if the installer returns the " + "termination flag.", url) + )); + } } bool AdminUISequenceTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/AdminUISequencetable.h b/installer/AdminUISequencetable.h index 3c99c28c307..a8ed418c1b7 100644 --- a/installer/AdminUISequencetable.h +++ b/installer/AdminUISequencetable.h @@ -19,10 +19,12 @@ #include "Action.h" #include "Generator.h" +#include "ValidationTable.h" class AdminUISequenceTable : public Generator { public: - explicit AdminUISequenceTable(const nlohmann::json& json); + explicit AdminUISequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~AdminUISequenceTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/AdvtExecuteSequenceTable.cpp b/installer/AdvtExecuteSequenceTable.cpp index 113915a922d..fae22373fac 100644 --- a/installer/AdvtExecuteSequenceTable.cpp +++ b/installer/AdvtExecuteSequenceTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,12 +18,58 @@ #include "AdvtExecuteSequenceTable.h" AdvtExecuteSequenceTable::AdvtExecuteSequenceTable( - const nlohmann::json& json) { + const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading AdvtExecuteSequenceTable..." << std::endl; for (const auto& value : json) { actions.emplace_back(value); } + + const auto tableName = std::string("AdvtExecuteSequence"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/advtexecutesequence-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the standard action the installer is " + "to execute.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("Logical expression.", url) + )); + validationTable->add(Validation( + tableName, + "Sequence", + true, + -4, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A positive value indicates the sequence " + "position of the action. The negative values indicate that " + "the action is called if the installer returns the " + "termination flag.", url) + )); + } } bool AdvtExecuteSequenceTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/AdvtExecuteSequenceTable.h b/installer/AdvtExecuteSequenceTable.h index 8b711bb1d13..4f7a6593861 100644 --- a/installer/AdvtExecuteSequenceTable.h +++ b/installer/AdvtExecuteSequenceTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Action.h" #include "Generator.h" +#include "ValidationTable.h" class AdvtExecuteSequenceTable : public Generator { public: - explicit AdvtExecuteSequenceTable(const nlohmann::json& json); + explicit AdvtExecuteSequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~AdvtExecuteSequenceTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/BinaryTable.cpp b/installer/BinaryTable.cpp index cac5ee517cf..6bda524ac7d 100644 --- a/installer/BinaryTable.cpp +++ b/installer/BinaryTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,19 +19,50 @@ BinaryTable::BinaryTable(const nlohmann::json& json, const std::filesystem::path& path, const std::string& platform, - const std::string& configuration) { + const std::string& configuration, + std::shared_ptr validationTable) { std::cout << "Loading BinaryTable..." << std::endl; for (const auto& element : json) { binaries.emplace_back(element, path, platform, configuration); } + + const auto tableName = std::string("Binary"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/binary-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Name", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("A unique key that identifies the particular " + "binary data.", url) + )); + validationTable->add(Validation( + tableName, + "Data", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryBinary, + "", + DescriptionWithUrl("The unformatted binary data.", url) + )); + } } bool BinaryTable::generate(MSIHANDLE hDatabase) { std::cout << "Generating BinaryTable..." << std::endl; const auto sql_create = "CREATE TABLE `Binary` (`Name` CHAR(72) NOT NULL, " - "`Data` OBJECT PRIMARY KEY `Name`)"; + "`Data` OBJECT NOT NULL PRIMARY KEY `Name`)"; const auto sql_insert = "INSERT INTO `Binary` (`Name`, `Data`) " "VALUES (?, ?)"; diff --git a/installer/BinaryTable.h b/installer/BinaryTable.h index 3b4611bc0d9..145c3e0180d 100644 --- a/installer/BinaryTable.h +++ b/installer/BinaryTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -21,12 +21,14 @@ #include "Generator.h" #include "Binary.h" +#include "ValidationTable.h" class BinaryTable : public Generator { public: explicit BinaryTable(const nlohmann::json& json, const std::filesystem::path& path, const std::string& platform, - const std::string& configuration); + const std::string& configuration, + std::shared_ptr validationTable); ~BinaryTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/CheckboxTable.cpp b/installer/CheckboxTable.cpp index 24ccd3142d6..7e9a0b02654 100644 --- a/installer/CheckboxTable.cpp +++ b/installer/CheckboxTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,20 +17,52 @@ #include "CheckboxTable.h" -CheckboxTable::CheckboxTable(const nlohmann::json& json) { +CheckboxTable::CheckboxTable(const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading CheckboxTable..." << std::endl; for (const auto& item : json) { properties.emplace_back(item); } + + const auto tableName = std::string("CheckBox"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/checkbox-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Property", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("A named property to be tied to this item.", + url) + )); + validationTable->add(Validation( + tableName, + "Value", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The value string associated with this item.", + url) + )); + } } bool CheckboxTable::generate(MSIHANDLE hDatabase) { std::cout << "Generating CheckboxTable..." << std::endl; - const auto sql_create = "CREATE TABLE `Checkbox` " + const auto sql_create = "CREATE TABLE `CheckBox` " "(`Property` CHAR(72) NOT NULL, `Value` CHAR(64) " "PRIMARY KEY `Property`)"; - const auto sql_insert = "INSERT INTO `Checkbox` " + const auto sql_insert = "INSERT INTO `CheckBox` " "(`Property`, `Value`) VALUES (?, ?)"; return Generator::generate(hDatabase, sql_create, sql_insert, properties); diff --git a/installer/CheckboxTable.h b/installer/CheckboxTable.h index b08ef2bdaf0..ef09e81d4e3 100644 --- a/installer/CheckboxTable.h +++ b/installer/CheckboxTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Generator.h" #include "Checkbox.h" +#include "ValidationTable.h" class CheckboxTable : public Generator { public: - explicit CheckboxTable(const nlohmann::json& json); + explicit CheckboxTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~CheckboxTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/Component.cpp b/installer/Component.cpp index 2649db12017..aa77c49a09c 100644 --- a/installer/Component.cpp +++ b/installer/Component.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -33,7 +33,7 @@ Component::Component(const nlohmann::json& json, const std::string& directory, component = parent + "_" + directory; } JsonHelper::handle(json, "Files", [&](const auto& file) { - files.emplace_back(file, component); + files.emplace_back(file, component, directory); }); JsonHelper::handle(json, "Registry", [&](const auto& registry) { registries.emplace_back(registry, component); @@ -99,3 +99,11 @@ std::vector Component::getServiceInstalls() const { std::vector Component::getShortcuts() const { return shortcuts; } + +std::string Component::getComponentName() const { + return component; +} + +std::string Component::getDirectory() const { + return directory; +} diff --git a/installer/Component.h b/installer/Component.h index a6da3cb8780..0c4c4a8dc05 100644 --- a/installer/Component.h +++ b/installer/Component.h @@ -45,6 +45,8 @@ class Component : public Record { std::vector getServiceControls() const; std::vector getServiceInstalls() const; std::vector getShortcuts() const; + std::string getComponentName() const; + std::string getDirectory() const; private: std::string component{}; std::string componentId{}; diff --git a/installer/ComponentTable.cpp b/installer/ComponentTable.cpp index f486ab4ade8..cab93e0d933 100644 --- a/installer/ComponentTable.cpp +++ b/installer/ComponentTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,12 +17,96 @@ #include "ComponentTable.h" -ComponentTable::ComponentTable(const std::vector& directories) { +ComponentTable::ComponentTable(const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { components.push_back(component); } } + + const auto tableName = std::string("Component"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/component-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Component", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Identifies the component record.", url) + )); + validationTable->add(Validation( + tableName, + "ComponentId", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryGuid, + "", + DescriptionWithUrl("A string GUID unique to this component, " + "version, and language.", url) + )); + validationTable->add(Validation( + tableName, + "Directory_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Directory", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key of an entry in the Directory " + "table.", url) + )); + validationTable->add(Validation( + tableName, + "Attributes", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column contains a bit flag that " + "specifies options for remote execution.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("This column contains a conditional statement " + "that can control whether a component is installed.", url) + )); + validationTable->add(Validation( + tableName, + "KeyPath", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "File;Registry", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("This value points to a file or folder " + "belonging to the component that the installer uses to detect " + "the component.", url) + )); + } } bool ComponentTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ComponentTable.h b/installer/ComponentTable.h index 23d0047bc5f..76c96614d2a 100644 --- a/installer/ComponentTable.h +++ b/installer/ComponentTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "Component.h" #include "Directory.h" +#include "ValidationTable.h" class ComponentTable : public Generator { public: - explicit ComponentTable(const std::vector& directories); + explicit ComponentTable(const std::vector& directories, + std::shared_ptr validationTable); ~ComponentTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/ControlConditionTable.cpp b/installer/ControlConditionTable.cpp index a669a610984..159095c6d96 100644 --- a/installer/ControlConditionTable.cpp +++ b/installer/ControlConditionTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,7 +19,65 @@ #include "ControlConditionTable.h" ControlConditionTable::ControlConditionTable( - const std::vector& controls) noexcept : controls(controls) {} + const std::vector& controls, + std::shared_ptr validationTable) : controls(controls) { + const auto tableName = std::string("ControlCondition"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/controlcondition-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Dialog_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Dialog", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the first column of the " + "Dialog table.", url) + )); + validationTable->add(Validation( + tableName, + "Control_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the second column of the " + "Control table.", url) + )); + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "Default;Disable;Enable;Hide;Show", + DescriptionWithUrl("The action that is to be taken on the " + "control.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("A conditional statement that specifies under " + "which conditions the action should be triggered.", url) + )); + } +} bool ControlConditionTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ControlConditionTable.h b/installer/ControlConditionTable.h index 8351dd281c1..698a8d8e488 100644 --- a/installer/ControlConditionTable.h +++ b/installer/ControlConditionTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -22,11 +22,13 @@ #include "Generator.h" #include "ControlCondition.h" #include "Control.h" +#include "ValidationTable.h" class ControlConditionTable : public Generator { public: explicit ControlConditionTable( - const std::vector& controls) noexcept; + const std::vector& controls, + std::shared_ptr validationTable); ~ControlConditionTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/ControlEventTable.cpp b/installer/ControlEventTable.cpp index b2cfa55d5bd..139bd221aeb 100644 --- a/installer/ControlEventTable.cpp +++ b/installer/ControlEventTable.cpp @@ -18,7 +18,93 @@ #include "ControlEventTable.h" ControlEventTable::ControlEventTable( - const std::vector& controls) noexcept : controls(controls) {} + const std::vector& controls, + std::shared_ptr validationTable) : controls(controls) { + const auto tableName = std::string("ControlEvent"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/controlevent-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Dialog_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Dialog", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the first column of the " + "Dialog table.", url) + )); + validationTable->add(Validation( + tableName, + "Control_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the second column of the " + "Control table.", url) + )); + validationTable->add(Validation( + tableName, + "Event", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("An identifier that specifies the type of " + "event that should take place when the user interacts with " + "the control specified by Dialog_ and Control_.", url) + )); + validationTable->add(Validation( + tableName, + "Argument", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("A value used as a modifier when triggering a " + "particular event.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("A conditional statement that determines " + "whether the installer activates the event in the Event " + "column.", url) + )); + validationTable->add(Validation( + tableName, + "Ordering", + true, + 0, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("An integer used to order several events tied " + "to the same control.", url) + )); + } +} bool ControlEventTable::generate(MSIHANDLE hDatabase) { std::cout << "Generating ControlEventTable..." << std::endl; diff --git a/installer/ControlEventTable.h b/installer/ControlEventTable.h index 6e947f3185f..92f53b61aa4 100644 --- a/installer/ControlEventTable.h +++ b/installer/ControlEventTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "ControlEvent.h" #include "Generator.h" #include "Control.h" +#include "ValidationTable.h" class ControlEventTable : public Generator { public: - explicit ControlEventTable(const std::vector& controls) noexcept; + explicit ControlEventTable(const std::vector& controls, + std::shared_ptr validationTable); ~ControlEventTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/ControlTable.cpp b/installer/ControlTable.cpp index 57b7fd43004..e2ff33bddb3 100644 --- a/installer/ControlTable.cpp +++ b/installer/ControlTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -23,8 +23,170 @@ #include "RadioButtonTable.h" #include "ControlTable.h" -ControlTable::ControlTable(const std::vector& dialogs) noexcept : - dialogs(dialogs) {} +ControlTable::ControlTable(const std::vector& dialogs, + std::shared_ptr validationTable) : dialogs(dialogs), + validationTable(validationTable) { + const auto tableName = std::string("Control"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/control-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Dialog_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Dialog", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key to the first column of the " + "Dialog table, the name of the dialog box.", url) + )); + validationTable->add(Validation( + tableName, + "Control", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the control.", url) + )); + validationTable->add(Validation( + tableName, + "Type", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The type of the control.", url) + )); + validationTable->add(Validation( + tableName, + "X", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Horizontal coordinate of the upper-left " + "corner of the rectangular boundary of the control.", url) + )); + validationTable->add(Validation( + tableName, + "Y", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Vertical coordinate of the upper-left corner " + "of the rectangular boundary of the control.", url) + )); + validationTable->add(Validation( + tableName, + "Width", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Width of the rectangular boundary of the " + "control.", url) + )); + validationTable->add(Validation( + tableName, + "Height", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Height of the rectangular boundary of the " + "control.", url) + )); + validationTable->add(Validation( + tableName, + "Attributes", + true, + 0, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A 32-bit word that specifies the bit flags to " + "be applied to this control.", url) + )); + validationTable->add(Validation( + tableName, + "Property", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The name of a defined property to be linked " + "to this control.", + url) + )); + validationTable->add(Validation( + tableName, + "Text", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("A localizable string used to set the initial " + "text contained in a control.", url) + )); + validationTable->add(Validation( + tableName, + "Control_Next", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The name of another control on the same " + "dialog box and an external key to the second column of the " + "Control table.", url) + )); + validationTable->add(Validation( + tableName, + "Help", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("Optional, localizable text strings that are " + "used with the Help button.", url) + )); + } +} bool ControlTable::generate(MSIHANDLE hDatabase) { @@ -35,19 +197,19 @@ bool ControlTable::generate(MSIHANDLE hDatabase) } } - if (!ControlConditionTable(controls).generate(hDatabase)) { + if (!ControlConditionTable(controls, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ControlConditionTable" << std::endl; return false; } - if (!ControlEventTable(controls).generate(hDatabase)) { + if (!ControlEventTable(controls, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ControlEventTable" << std::endl; return false; } - if (!EventMappingTable(controls).generate(hDatabase)) { + if (!EventMappingTable(controls, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate EventMappingTable" << std::endl; return false; } - if (!RadioButtonTable(controls).generate(hDatabase)) { + if (!RadioButtonTable(controls, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate RadioButtonTable" << std::endl; return false; } diff --git a/installer/ControlTable.h b/installer/ControlTable.h index f5c5bb1ccb1..07610182ca0 100644 --- a/installer/ControlTable.h +++ b/installer/ControlTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,13 +20,15 @@ #include #include "Dialog.h" #include "Control.h" - +#include "ValidationTable.h" class ControlTable : Generator { public: - explicit ControlTable(const std::vector& dialogs) noexcept; + explicit ControlTable(const std::vector& dialogs, + std::shared_ptr validationTable); ~ControlTable() = default; bool generate(MSIHANDLE hDatabase) override; private: const std::vector& dialogs; + std::shared_ptr validationTable; }; diff --git a/installer/CreateFolderTable.cpp b/installer/CreateFolderTable.cpp index 453a652d95b..8bea2db6518 100644 --- a/installer/CreateFolderTable.cpp +++ b/installer/CreateFolderTable.cpp @@ -18,7 +18,8 @@ #include "CreateFolderTable.h" CreateFolderTable::CreateFolderTable( - const std::vector& directories) { + const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { auto [result, record] = component.getCreateFolder(); @@ -27,6 +28,37 @@ CreateFolderTable::CreateFolderTable( } } } + + const auto tableName = std::string("CreateFolder"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/createfolder-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Directory_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Directory", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key into the first column of the " + "Directory table.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key into the first column of the " + "Component table.", url) + )); + } } bool CreateFolderTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/CreateFolderTable.h b/installer/CreateFolderTable.h index 3bc79a29922..a46c9de5b54 100644 --- a/installer/CreateFolderTable.h +++ b/installer/CreateFolderTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "Directory.h" #include "CreateFolder.h" +#include "ValidationTable.h" class CreateFolderTable : public Generator { public: - CreateFolderTable(const std::vector& directories); + CreateFolderTable(const std::vector& directories, + std::shared_ptr validationTable); ~CreateFolderTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/CustomActionTable.cpp b/installer/CustomActionTable.cpp index e411a145db1..1afb44c2b5b 100644 --- a/installer/CustomActionTable.cpp +++ b/installer/CustomActionTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,11 +17,80 @@ #include "CustomActionTable.h" -CustomActionTable::CustomActionTable(const nlohmann::json& json) { +CustomActionTable::CustomActionTable(const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading CustomActionTable..." << std::endl; for (const auto& customAction : json) { customActions.emplace_back(customAction); } + + const auto tableName = std::string("CustomAction"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/customaction-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the action.", url) + )); + validationTable->add(Validation( + tableName, + "Type", + false, + 1, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A field of flag bits specifying the basic " + "type of custom action and options.", url) + )); + validationTable->add(Validation( + tableName, + "Source", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCustomSource, + "", + DescriptionWithUrl("A property name or external key into another " + "table.", url) + )); + validationTable->add(Validation( + tableName, + "Target", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("An execution parameter that depends on the " + "basic type of custom action.", url) + )); + validationTable->add(Validation( + tableName, + "ExtendedType", + true, + 0, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The extended type of the action.", url) + )); + } } bool CustomActionTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/CustomActionTable.h b/installer/CustomActionTable.h index 22a484f96ab..ed721aad732 100644 --- a/installer/CustomActionTable.h +++ b/installer/CustomActionTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Generator.h" #include "CustomAction.h" +#include "ValidationTable.h" class CustomActionTable : public Generator { public: - explicit CustomActionTable(const nlohmann::json& json); + explicit CustomActionTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~CustomActionTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/DialogTable.cpp b/installer/DialogTable.cpp index 1129e61a078..b66ea03d5f7 100644 --- a/installer/DialogTable.cpp +++ b/installer/DialogTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,16 +20,153 @@ #include "Generator.h" DialogTable::DialogTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) : + validationTable(validationTable) { std::cout << "Loading DialogTable..." << std::endl; for (const auto& dialog : json) { dialogs.emplace_back(dialog, installerStrings); } + + const auto tableName = std::string("Dialog"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/dialog-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Dialog", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The primary key and name of the dialog box.", + url) + )); + validationTable->add(Validation( + tableName, + "HCentering", + false, + 0, + 100, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The horizontal position of the dialog box.", + url) + )); + validationTable->add(Validation( + tableName, + "VCentering", + false, + 0, + 100, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The vertical position of the dialog box.", url) + )); + validationTable->add(Validation( + tableName, + "Width", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The width of the rectangular boundary of the " + "dialog box.", url) + )); + validationTable->add(Validation( + tableName, + "Height", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The height of the rectangular boundary of the " + "dialog box.", url) + )); + validationTable->add(Validation( + tableName, + "Attributes", + true, + 0, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A 32-bit word that specifies the attribute " + "flags to be applied to this dialog box.", url) + )); + validationTable->add(Validation( + tableName, + "Title", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("A localizable text string specifying the " + "title to be displayed in the title bar of the dialog box.", + url) + )); + validationTable->add(Validation( + tableName, + "Control_First", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the second column of the " + "Control Table.", url) + )); + validationTable->add(Validation( + tableName, + "Control_Default", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the second column of the " + "Control Table.", url) + )); + validationTable->add(Validation( + tableName, + "Control_Cancel", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the second column of the " + "Control Table.", url) + )); + } } bool DialogTable::generate(MSIHANDLE hDatabase) { - if (!ControlTable(dialogs).generate(hDatabase)) { + if (!ControlTable(dialogs, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ControlTable" << std::endl; return false; } diff --git a/installer/DialogTable.h b/installer/DialogTable.h index 5ac8a0de029..a1135303466 100644 --- a/installer/DialogTable.h +++ b/installer/DialogTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,13 +20,16 @@ #include "Dialog.h" #include "InstallerStrings.h" #include "Generator.h" +#include "ValidationTable.h" class DialogTable : public Generator { public: explicit DialogTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~DialogTable() = default; bool generate(MSIHANDLE hDatabase) override; private: std::vector dialogs{}; + std::shared_ptr validationTable; }; diff --git a/installer/Directory.cpp b/installer/Directory.cpp index f87034ef4b8..b3e815c5dd0 100644 --- a/installer/Directory.cpp +++ b/installer/Directory.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License diff --git a/installer/DirectoryTable.cpp b/installer/DirectoryTable.cpp index 812facae9ca..0ea5335cb2d 100644 --- a/installer/DirectoryTable.cpp +++ b/installer/DirectoryTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -31,54 +31,102 @@ DirectoryTable::DirectoryTable(const nlohmann::json& json, const std::filesystem::path& root_path, const std::filesystem::path& output_path, InstallerStrings& installerStrings, const std::string& platform, - const std::string& configuration) : + const std::string& configuration, + std::shared_ptr validationTable) : root_path(root_path), output_path(output_path), platform(platform), - configuration(configuration) { + configuration(configuration), validationTable(validationTable) { std::cout << "Loading DirectoryTable..." << std::endl; for (const auto& directory : json) { directories.emplace_back(directory, "", installerStrings); } + + const auto tableName = std::string("Directory"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/directory-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Directory", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The Directory column contains a unique " + "identifier for a directory or directory path.", url) + )); + validationTable->add(Validation( + tableName, + "Directory_Parent", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Directory", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("This column is a reference to the directory's " + "parent directory.", url) + )); + validationTable->add(Validation( + tableName, + "DefaultDir", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryDefaultDir, + "", + DescriptionWithUrl("The DefaultDir column contains the " + "directory's name (localizable)under the parent directory.", + url) + )); + } } bool DirectoryTable::generate(MSIHANDLE hDatabase) { - if (!ComponentTable(directories).generate(hDatabase)) { + if (!ComponentTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ComponentTable" << std::endl; return false; } - if (!FeatureComponentsTable(directories).generate(hDatabase)) { + if (!FeatureComponentsTable(directories,validationTable).generate( + hDatabase)) { std::cerr << "Failed to generate FeatureComponentsTable" << std::endl; return false; } - if (!CreateFolderTable(directories).generate(hDatabase)) { + if (!CreateFolderTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate CreateFolderTable" << std::endl; return false; } if (!FileTable(directories, root_path, - output_path, platform, configuration).generate(hDatabase)) { + output_path, platform, configuration, validationTable).generate( + hDatabase)) { std::cerr << "Failed to generate FileTable" << std::endl; return false; } - if (!FontTable(directories).generate(hDatabase)) { + if (!FontTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate FontTable" << std::endl; return false; } - if (!RegistryTable(directories).generate(hDatabase)) { + if (!RegistryTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate RegistryTable" << std::endl; return false; } - if (!RemoveFileTable(directories).generate(hDatabase)) { + if (!RemoveFileTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate RemoveFileTable" << std::endl; return false; } - if (!ServiceControlTable(directories).generate(hDatabase)) { + if (!ServiceControlTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ServiceControlTable" << std::endl; return false; } - if (!ServiceInstallTable(directories).generate(hDatabase)) { + if (!ServiceInstallTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ServiceInstallTable" << std::endl; return false; } - if (!ShortcutTable(directories).generate(hDatabase)) { + if (!ShortcutTable(directories, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate ShortcutTable" << std::endl; return false; } diff --git a/installer/DirectoryTable.h b/installer/DirectoryTable.h index 3ed1825e2d3..78e42fb6af2 100644 --- a/installer/DirectoryTable.h +++ b/installer/DirectoryTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,6 +19,7 @@ #include "Generator.h" #include "Directory.h" +#include "ValidationTable.h" class DirectoryTable : public Generator { public: @@ -26,7 +27,8 @@ class DirectoryTable : public Generator { const std::filesystem::path& root_path, const std::filesystem::path& output_path, InstallerStrings& installerStrings, const std::string& platform, - const std::string& configuration); + const std::string& configuration, + std::shared_ptr validationTable); ~DirectoryTable() = default; bool generate(MSIHANDLE hDatabase) override; private: @@ -35,4 +37,5 @@ class DirectoryTable : public Generator { std::filesystem::path output_path{}; std::string platform{}; std::string configuration{}; + std::shared_ptr validationTable; }; diff --git a/installer/ErrorTable.cpp b/installer/ErrorTable.cpp index dc1d8b345d6..475e8eacfba 100644 --- a/installer/ErrorTable.cpp +++ b/installer/ErrorTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,12 +18,43 @@ #include "ErrorTable.h" ErrorTable::ErrorTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { std::cout << "Loading ErrorTable..." << std::endl; for (const auto& error : json) { errors.emplace_back(error, installerStrings); } + + const auto tableName = std::string("Error"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/error-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Error", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The error number.", url) + )); + validationTable->add(Validation( + tableName, + "Message", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryTemplate, + "", + DescriptionWithUrl("This column contains the localizable error " + "formatting template. ", url) + )); + } } bool ErrorTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ErrorTable.h b/installer/ErrorTable.h index f75bce22462..030e57e0993 100644 --- a/installer/ErrorTable.h +++ b/installer/ErrorTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,11 +20,13 @@ #include "Generator.h" #include "InstallerStrings.h" #include "Error.h" +#include "ValidationTable.h" class ErrorTable : public Generator { public: explicit ErrorTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~ErrorTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/EventMappingTable.cpp b/installer/EventMappingTable.cpp index 6434b113283..9b9e4623ed0 100644 --- a/installer/EventMappingTable.cpp +++ b/installer/EventMappingTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,8 +17,65 @@ #include "EventMappingTable.h" -EventMappingTable::EventMappingTable(const std::vector& controls) : - controls(controls) { +EventMappingTable::EventMappingTable(const std::vector& controls, + std::shared_ptr validationTable) : controls(controls) { + const auto tableName = std::string("EventMapping"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/eventmapping-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Dialog_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Dialog", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the first column of the " + "Dialog Table.", url) + )); + validationTable->add(Validation( + tableName, + "Control_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Control", + 2, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key to the second column of the " + "Control Table.", url) + )); + validationTable->add(Validation( + tableName, + "Event", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("This field is an identifier that specifies " + "the type of event that is subscribed to by the control.", url) + )); + validationTable->add(Validation( + tableName, + "Attribute", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The Argument of the event is passed as the " + "argument of the attribute call to change this attribute of " + "the control.", url) + )); + } } bool EventMappingTable::generate(MSIHANDLE hDatabase) { @@ -33,7 +90,7 @@ bool EventMappingTable::generate(MSIHANDLE hDatabase) { const auto sql_create = "CREATE TABLE `EventMapping` " "(`Dialog_` CHAR(72) NOT NULL, `Control_` CHAR(50) NOT NULL, " - "`Event` CHAR(50) NOT NULL, `Attribute` CHAR(50) " + "`Event` CHAR(50) NOT NULL, `Attribute` CHAR(50) NOT NULL " "PRIMARY KEY Dialog_, Control_, Event)"; const auto sql_insert = "INSERT INTO `EventMapping` " "(`Dialog_`, `Control_`, `Event`, `Attribute`) VALUES (?, ?, ?, ?)"; diff --git a/installer/EventMappingTable.h b/installer/EventMappingTable.h index 1ae693e3fb6..a90f1b4bc2a 100644 --- a/installer/EventMappingTable.h +++ b/installer/EventMappingTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "EventMapping.h" #include "Control.h" +#include "ValidationTable.h" class EventMappingTable : public Generator { public: - explicit EventMappingTable(const std::vector& controls); + explicit EventMappingTable(const std::vector& controls, + std::shared_ptr validationTable); ~EventMappingTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/FeatureComponentsTable.cpp b/installer/FeatureComponentsTable.cpp index 3baae93be2d..9ceddd672ed 100644 --- a/installer/FeatureComponentsTable.cpp +++ b/installer/FeatureComponentsTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,12 +18,42 @@ #include "FeatureComponentsTable.h" FeatureComponentsTable::FeatureComponentsTable( - const std::vector& directories) { + const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { featureComponents.emplace_back(component.getFeatureComponent()); } } + + const auto tableName = std::string("FeatureComponents"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/featurecomponents-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Feature_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Feature", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key into the first column of the Feature table.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An external key into the first column of the Component table.", url) + )); + } } bool FeatureComponentsTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/FeatureComponentsTable.h b/installer/FeatureComponentsTable.h index c16d4aee100..2c51a73288b 100644 --- a/installer/FeatureComponentsTable.h +++ b/installer/FeatureComponentsTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "FeatureComponents.h" #include "Directory.h" +#include "ValidationTable.h" class FeatureComponentsTable : public Generator { public: - explicit FeatureComponentsTable(const std::vector& directories); + explicit FeatureComponentsTable(const std::vector& directories, + std::shared_ptr validationTable); ~FeatureComponentsTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/FeatureTable.cpp b/installer/FeatureTable.cpp index b4ff505fcfa..a44d9e45078 100644 --- a/installer/FeatureTable.cpp +++ b/installer/FeatureTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,11 +18,124 @@ #include "FeatureTable.h" FeatureTable::FeatureTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { std::cout << "Loading FeatureTable..." << std::endl; for (const auto& feature : json) { features.emplace_back(feature, "", installerStrings); } + + const auto tableName = std::string("Feature"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/feature-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Feature", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The primary key that is used to identify a " + "specific feature record.", url) + )); + validationTable->add(Validation( + tableName, + "Feature_Parent", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Feature", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("An optional key of a parent record in the " + "same table.", url) + )); + validationTable->add(Validation( + tableName, + "Title", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("A short string of text that identifies a " + "feature.", url) + )); + validationTable->add(Validation( + tableName, + "Description", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("A longer string of text that describes a " + "feature.", url) + )); + validationTable->add(Validation( + tableName, + "Display", + true, + 0, + 3276, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The number in this field specifies the order " + "in which the feature is to be displayed in the user " + "interface.", url) + )); + validationTable->add(Validation( + tableName, + "Level", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The initial installation level of this " + "feature.", url) + )); + validationTable->add(Validation( + tableName, + "Directory_", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Directory", + 1, + ValidationCategoryUpperCase, + "", + DescriptionWithUrl("The Directory_ column specifies the name of a " + "directory that can be configured by a Selection Dialog.", url) + )); + validationTable->add(Validation( + tableName, + "Attributes", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "0;1;2;4;5;6;8;9;10;16;17;18;20;21;22;24;25;26;32;33;34;36;37;38;" + "48;49;50;52;53;54", + DescriptionWithUrl("The remote execution option for features that " + "are not installed and for which no feature state request is " + "made by using any of the following properties.", url) + )); + } } bool FeatureTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/FeatureTable.h b/installer/FeatureTable.h index 95056f136ee..8dfece6fe60 100644 --- a/installer/FeatureTable.h +++ b/installer/FeatureTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,11 +19,13 @@ #include "Generator.h" #include "Feature.h" +#include "ValidationTable.h" class FeatureTable : public Generator { public: explicit FeatureTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~FeatureTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/File.cpp b/installer/File.cpp index 2df40f50537..d632f5b32c4 100644 --- a/installer/File.cpp +++ b/installer/File.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -15,21 +15,23 @@ // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . +#include + #include "File.h" #include "MsiHelper.h" #include "JsonHelper.h" -File::File(const nlohmann::json& json, const std::string& component) : - component(component) { - JsonHelper::get(json, "File", file); - JsonHelper::get(json, "FileName", filename); +File::File(const nlohmann::json& json, const std::string& component, + const std::string& directory) : + component(component), directory(directory) { JsonHelper::get(json, "FilePath", filepath); JsonHelper::get(json, "IsFont", isFont); } MSIHANDLE File::getRecord() const { - return MsiHelper::MsiRecordSet({ file, component, filename, filesize, - version, language, attributes, sequence }); + return MsiHelper::MsiRecordSet({ getFileId(), component, + filename_short + "|" + filename_long, filesize, version, language, + attributes, sequence }); } std::filesystem::path File::getFilepath() const { @@ -37,7 +39,14 @@ std::filesystem::path File::getFilepath() const { } std::string File::getFileId() const { - return file; + auto result = component + "_" + filepath.filename().string(); + std::transform(result.begin(), result.end(), result.begin(), [](auto c) { + if (c == '-') { + return '_'; + } + return c; + }); + return result; } bool File::isFontFile() const noexcept { @@ -67,3 +76,27 @@ void File::setSequence(int s) noexcept { void File::setFilepath(const std::filesystem::path& p) { filepath = p; } + +void File::setShortFileName(const std::string& n) { + filename_short = n; +} + +void File::setLongFileName(const std::string& n) { + filename_long = n; +} + +std::string File::getShortFileName() const { + return filename_short; +} + +std::string File::getLongFileName() const { + return filename_long; +} + +bool File::isVersioned() const noexcept { + return !version.empty(); +} + +std::string File::getDirectory() const { + return directory; +} diff --git a/installer/File.h b/installer/File.h index f070ab3a9a5..604af0c6966 100644 --- a/installer/File.h +++ b/installer/File.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -23,7 +23,8 @@ class File : public Record { public: - explicit File(const nlohmann::json& json, const std::string& component); + explicit File(const nlohmann::json& json, const std::string& component, + const std::string& directory); ~File() = default; MSIHANDLE getRecord() const override; std::filesystem::path getFilepath() const; @@ -35,10 +36,16 @@ class File : public Record { void setAttributes(int a) noexcept; void setSequence(int s) noexcept; void setFilepath(const std::filesystem::path& p); + void setShortFileName(const std::string& n); + void setLongFileName(const std::string& n); + std::string getShortFileName() const; + std::string getLongFileName() const; + bool isVersioned() const noexcept; + std::string getDirectory() const; private: - std::string file{}; std::string component{}; - std::string filename{}; + std::string filename_short{}; + std::string filename_long{}; int filesize = MSI_NULL_INTEGER; std::string version{}; std::string language{}; @@ -46,4 +53,5 @@ class File : public Record { int sequence = MSI_NULL_INTEGER; std::filesystem::path filepath{}; bool isFont = false; + std::string directory{}; }; diff --git a/installer/FileTable.cpp b/installer/FileTable.cpp index 2e66722f379..ab45a2c6e8c 100644 --- a/installer/FileTable.cpp +++ b/installer/FileTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -16,6 +16,7 @@ // along with BOINC. If not, see . #include +#include #include "FileTable.h" #include "CabHelper.h" @@ -119,12 +120,56 @@ std::filesystem::path FileTable::GetAbsolutePath( return root_path / p; } +std::tuple FileTable::GetFileName( + const std::filesystem::path& filePath, const std::string& directory) { + auto extension = filePath.extension().string(); + if (extension.size() > 4) { + extension = extension.substr(0, 4); + } + std::transform(extension.begin(), extension.end(), extension.begin(), + ::toupper); + auto name = filePath.filename().stem().string(); + std::transform(name.begin(), name.end(), name.begin(), ::toupper); + auto i = 0; + const auto filename_long = name; + while (true) { + auto suffix_len = 1; + auto t = i; + while (t /= 10) { + suffix_len++; + } + ++suffix_len; + if (suffix_len > 6) { + suffix_len = 6; + } + if (filename_long.size() > 8) { + name = filename_long.substr(0, 8 - suffix_len) + "~" + + std::to_string(++i); + std::transform(name.begin(), name.end(), name.begin(), ::toupper); + } + auto found = false; + for (const auto& file : files) { + if (file.getDirectory() == directory && + file.getShortFileName() == name + extension) { + found = true; + break; + } + } + if (!found) { + break; + } + } + + return { name + extension, filePath.filename().string() }; +} + FileTable::FileTable(const std::vector& directories, const std::filesystem::path& root_path, const std::filesystem::path& output_path, const std::string& platform, - const std::string& configuration) : root_path(root_path), + const std::string& configuration, + std::shared_ptr validationTable) : root_path(root_path), output_path(output_path), platform(platform), - configuration(configuration) { + configuration(configuration), validationTable(validationTable) { int sequence = 0; for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { @@ -144,10 +189,122 @@ FileTable::FileTable(const std::vector& directories, } file.setFilesize(static_cast( GetFileSize(file.getFilepath().string()))); + auto [filename_short, filename_long] = + GetFileName(file.getFilepath(), + component.getDirectory()); + file.setShortFileName(filename_short); + file.setLongFileName(filename_long); files.push_back(file); } } } + + const auto tableName = std::string("File"); + const auto url = std::string("https://learn.microsoft.com/en-us/windows/win32/msi/file-table"); + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "File", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("A non-localized token that uniquely " + "identifies the file.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The external key into the first column of the " + "Component Table.", url) + )); + validationTable->add(Validation( + tableName, + "FileName", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFilename, + "", + DescriptionWithUrl("The file name used for installation.", url) + )); + validationTable->add(Validation( + tableName, + "FileSize", + false, + 0, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The size of the file in bytes.", url) + )); + validationTable->add(Validation( + tableName, + "Version", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "File", + 1, + ValidationCategoryVersion, + "", + DescriptionWithUrl("This field is the version string for a " + "versioned file.", url) + )); + validationTable->add(Validation( + tableName, + "Language", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryLanguage, + "", + DescriptionWithUrl("A list of decimal language IDs separated by " + "commas.", url) + )); + validationTable->add(Validation( + tableName, + "Attributes", + true, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The integer that contains bit flags that " + "represent file attributes.", url) + )); + validationTable->add(Validation( + tableName, + "Sequence", + false, + 1, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Sequence position of this file on the media " + "images.", url) + )); + } } bool FileTable::generate(MSIHANDLE hDatabase) { @@ -165,11 +322,11 @@ bool FileTable::generate(MSIHANDLE hDatabase) { std::filesystem::remove(output_path / cabname); if (!MediaTable({ Media(1, static_cast(files.size()), "1", - "#" + cabname, "DISK1", "")}).generate(hDatabase)) { + "#" + cabname, "DISK1", "") }, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate MediaTable" << std::endl; return false; } - if (!MsiFileHashTable(files).generate(hDatabase)) { + if (!MsiFileHashTable(files, validationTable).generate(hDatabase)) { std::cerr << "Failed to generate MsiFileHashTable" << std::endl; return false; } diff --git a/installer/FileTable.h b/installer/FileTable.h index 4c4caeed22b..41dccbe5fe7 100644 --- a/installer/FileTable.h +++ b/installer/FileTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,13 +20,15 @@ #include "Generator.h" #include "Directory.h" #include "File.h" +#include "ValidationTable.h" class FileTable : public Generator { public: explicit FileTable(const std::vector& directories, const std::filesystem::path& root_path, const std::filesystem::path& output_path, const std::string& platform, - const std::string& configuration); + const std::string& configuration, + std::shared_ptr validationTable); ~FileTable() = default; bool generate(MSIHANDLE hDatabase) override; private: @@ -35,9 +37,12 @@ class FileTable : public Generator { size_t GetFileSize(const std::string& filePath); std::filesystem::path GetAbsolutePath( const std::filesystem::path& filePath); + std::tuple GetFileName( + const std::filesystem::path& filePath, const std::string& directory); std::vector files{}; std::filesystem::path root_path{}; std::filesystem::path output_path{}; std::string platform{}; std::string configuration{}; + std::shared_ptr validationTable; }; diff --git a/installer/FontTable.cpp b/installer/FontTable.cpp index 8e128ccbc2d..6fe129302c4 100644 --- a/installer/FontTable.cpp +++ b/installer/FontTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,7 +17,8 @@ #include "FontTable.h" -FontTable::FontTable(const std::vector& directories) { +FontTable::FontTable(const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { for (const auto& file : component.getFiles()) { @@ -27,6 +28,36 @@ FontTable::FontTable(const std::vector& directories) { } } } + + const auto tableName = std::string("Font"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/font-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "File_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "File", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key into the File table entry for " + "the font file.", url) + )); + validationTable->add(Validation( + tableName, + "FontTitle", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("Font name.", url) + )); + } } bool FontTable::generate(MSIHANDLE database) { diff --git a/installer/FontTable.h b/installer/FontTable.h index ffd589ad4c0..6b38f58e8b4 100644 --- a/installer/FontTable.h +++ b/installer/FontTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "Font.h" #include "Directory.h" +#include "ValidationTable.h" class FontTable : public Generator { public: - explicit FontTable(const std::vector& directories); + explicit FontTable(const std::vector& directories, + std::shared_ptr validationTable); ~FontTable() = default; bool generate(MSIHANDLE database) override; private: diff --git a/installer/IconTable.cpp b/installer/IconTable.cpp index 1950e3108fd..3de033693dc 100644 --- a/installer/IconTable.cpp +++ b/installer/IconTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,12 +19,43 @@ IconTable::IconTable(const nlohmann::json& json, const std::filesystem::path& path, const std::string& platform, - const std::string& configuration) { + const std::string& configuration, + std::shared_ptr validationTable) { std::cout << "Loading IconTable..." << std::endl; for (const auto& item : json) { values.emplace_back(item, path, platform, configuration); } + + const auto tableName = std::string("Icon"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/icon-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Name", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the icon file.", url) + )); + validationTable->add(Validation( + tableName, + "Data", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryBinary, + "", + DescriptionWithUrl("The binary icon data in PE (.dll or .exe) or " + "icon (.ico) format.", url) + )); + } } bool IconTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/IconTable.h b/installer/IconTable.h index 3a2ce21bca9..09827c6df4e 100644 --- a/installer/IconTable.h +++ b/installer/IconTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,12 +19,14 @@ #include "Icon.h" #include "Generator.h" +#include "ValidationTable.h" class IconTable : public Generator { public: explicit IconTable(const nlohmann::json& json, const std::filesystem::path& path, const std::string& platform, - const std::string& configuration); + const std::string& configuration, + std::shared_ptr validationTable); ~IconTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/InstallExecuteSequenceTable.cpp b/installer/InstallExecuteSequenceTable.cpp index b91f937ec87..424438562bb 100644 --- a/installer/InstallExecuteSequenceTable.cpp +++ b/installer/InstallExecuteSequenceTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,12 +18,56 @@ #include "InstallExecuteSequenceTable.h" InstallExecuteSequenceTable::InstallExecuteSequenceTable( - const nlohmann::json& json) { + const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading InstallExecuteSequenceTable..." << std::endl; for (const auto& value : json) { actions.emplace_back(value); } + + const auto tableName = std::string("InstallExecuteSequence"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/installexecutesequence-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the action to execute.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("This field contains a conditional expression.", + url) + )); + validationTable->add(Validation( + tableName, + "Sequence", + true, + -4, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Number that determines the sequence position " + "in which this action is to be executed.", url) + )); + } } bool InstallExecuteSequenceTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/InstallExecuteSequenceTable.h b/installer/InstallExecuteSequenceTable.h index 421892461ea..e8fb5a88dcb 100644 --- a/installer/InstallExecuteSequenceTable.h +++ b/installer/InstallExecuteSequenceTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Action.h" #include "Generator.h" +#include "ValidationTable.h" class InstallExecuteSequenceTable : public Generator { public: - explicit InstallExecuteSequenceTable(const nlohmann::json& json); + explicit InstallExecuteSequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~InstallExecuteSequenceTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/InstallUISequenceTable.cpp b/installer/InstallUISequenceTable.cpp index bc8ce8609e0..5fe2b19470b 100644 --- a/installer/InstallUISequenceTable.cpp +++ b/installer/InstallUISequenceTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,12 +17,56 @@ #include "InstallUISequenceTable.h" -InstallUISequenceTable::InstallUISequenceTable(const nlohmann::json& json) { +InstallUISequenceTable::InstallUISequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading InstallUISequenceTable..." << std::endl; for (const auto& value : json) { actions.emplace_back(value); } + + const auto tableName = std::string("InstallUISequence"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/installuisequence-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Action", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of the action to execute.", url) + )); + validationTable->add(Validation( + tableName, + "Condition", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("This field contains a conditional expression.", + url) + )); + validationTable->add(Validation( + tableName, + "Sequence", + true, + -4, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The number in this column determines the " + "sequence position in which this action is run.", url) + )); + } } bool InstallUISequenceTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/InstallUISequenceTable.h b/installer/InstallUISequenceTable.h index d7734a0ab95..3b7042c3a5d 100644 --- a/installer/InstallUISequenceTable.h +++ b/installer/InstallUISequenceTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Action.h" #include "Generator.h" +#include "ValidationTable.h" class InstallUISequenceTable : public Generator { public: - explicit InstallUISequenceTable(const nlohmann::json& json); + explicit InstallUISequenceTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~InstallUISequenceTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/Installer.cpp b/installer/Installer.cpp index 10c177e985e..98c83eb2407 100644 --- a/installer/Installer.cpp +++ b/installer/Installer.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -36,14 +36,44 @@ #include "InstallExecuteSequenceTable.h" #include "InstallUISequenceTable.h" #include "LaunchConditionTable.h" +#include "ListboxTable.h" #include "PropertyTable.h" #include "RadioButtonTable.h" #include "TextStyleTable.h" #include "UITextTable.h" #include "UpgradeTable.h" +#include "ValidationTable.h" #include "Installer.h" +#if defined(_DEBUG) && !defined(MSI_VALIDATE) +#define MSI_VALIDATE +#endif + +const auto ActionTextTableName = std::string("ActionText"); +const auto AdminExecuteSequenceTableName = std::string("AdminExecuteSequence"); +const auto AdminUISequenceTableName = std::string("AdminUISequence"); +const auto AdvtExecuteSequenceTableName = std::string("AdvtExecuteSequence"); +const auto BinaryTableName = std::string("Binary"); +const auto CheckboxTableName = std::string("Checkbox"); +const auto CustomActionTableName = std::string("CustomAction"); +const auto DialogTableName = std::string("Dialog"); +const auto DirectoryTableName = std::string("Directory"); +const auto ErrorTableName = std::string("Error"); +const auto FeatureTableName = std::string("Feature"); +const auto IconTableName = std::string("Icon"); +const auto InstallExecuteSequenceTableName = + std::string("InstallExecuteSequence"); +const auto InstallUISequenceTableName = std::string("InstallUISequence"); +const auto LaunchConditionTableName = std::string("LaunchCondition"); +const auto ListboxTableName = std::string("Listbox"); +const auto PropertyTableName = std::string("Property"); +const auto SummaryTableName = std::string("Summary"); +const auto TextStyleTableName = std::string("TextStyle"); +const auto UITextTableName = std::string("UIText"); +const auto UpgradeTableName = std::string("Upgrade"); +const auto ValidationTableName = std::string("Validation"); + Installer::Installer(const std::filesystem::path& output_path, const std::string& platform, const std::string& configuration) : output_path(output_path), platform(platform), @@ -78,90 +108,113 @@ bool Installer::load_from_json(const nlohmann::json& json, return false; } } - if (JsonHelper::exists(json, "Summary")) { - tables["Summary"] = std::make_shared( - json["Summary"], installer_strings, platform); + // should always be first + std::shared_ptr validationTable = +#ifndef MSI_VALIDATE + nullptr; +#else + std::make_shared(); + tables[ValidationTableName] = validationTable; +#endif + if (JsonHelper::exists(json, SummaryTableName)) { + tables[SummaryTableName] = + std::make_shared( + json[SummaryTableName], installer_strings, platform); } - if (JsonHelper::exists(json, "ActionText")) { - tables["ActionText"] = std::make_shared( - json["ActionText"], installer_strings); + if (JsonHelper::exists(json, ActionTextTableName)) { + tables[ActionTextTableName] = std::make_shared( + json[ActionTextTableName], installer_strings, validationTable); } - if (JsonHelper::exists(json, "AdminExecuteSequence")) { - tables["AdminExecuteSequence"] = + if (JsonHelper::exists(json, AdminExecuteSequenceTableName)) { + tables[AdminExecuteSequenceTableName] = std::make_shared( - json["AdminExecuteSequence"]); + json[AdminExecuteSequenceTableName], validationTable); } - if (JsonHelper::exists(json, "AdminUISequence")) { - tables["AdminUISequence"] = std::make_shared( - json["AdminUISequence"]); + if (JsonHelper::exists(json, AdminUISequenceTableName)) { + tables[AdminUISequenceTableName] = + std::make_shared( + json[AdminUISequenceTableName], validationTable); } - if (JsonHelper::exists(json, "AdvtExecuteSequence")) { - tables["AdvtExecuteSequence"] = + if (JsonHelper::exists(json, AdvtExecuteSequenceTableName)) { + tables[AdvtExecuteSequenceTableName] = std::make_shared( - json["AdvtExecuteSequence"]); + json[AdvtExecuteSequenceTableName], validationTable); } - if (JsonHelper::exists(json, "Binary")) { - tables["Binary"] = std::make_shared( - json["Binary"], path, platform, configuration); + if (JsonHelper::exists(json, BinaryTableName)) { + tables[BinaryTableName] = std::make_shared( + json[BinaryTableName], path, platform, configuration, + validationTable); } - if (JsonHelper::exists(json, "Checkbox")) { - tables["Checkbox"] = std::make_shared( - json["Checkbox"]); + if (JsonHelper::exists(json, CheckboxTableName)) { + tables[CheckboxTableName] = std::make_shared( + json[CheckboxTableName], validationTable); } - if (JsonHelper::exists(json, "CustomAction")) { - tables["CustomAction"] = std::make_shared( - json["CustomAction"]); + if (JsonHelper::exists(json, CustomActionTableName)) { + tables[CustomActionTableName] = + std::make_shared( + json[CustomActionTableName], validationTable); } - if (JsonHelper::exists(json, "Dialog")) { - tables["Dialog"] = std::make_shared(json["Dialog"], - installer_strings); + if (JsonHelper::exists(json, DialogTableName)) { + tables[DialogTableName] = + std::make_shared(json[DialogTableName], + installer_strings, validationTable); } - if (JsonHelper::exists(json, "Directory")) { - tables["Directory"] = std::make_shared( - json["Directory"], path, output_path, installer_strings, - platform, configuration); + if (JsonHelper::exists(json, DirectoryTableName)) { + tables[DirectoryTableName] = std::make_shared( + json[DirectoryTableName], path, output_path, installer_strings, + platform, configuration, validationTable); } - if (JsonHelper::exists(json, "Error")) { - tables["Error"] = std::make_shared(json["Error"], - installer_strings); + if (JsonHelper::exists(json, ErrorTableName)) { + tables[ErrorTableName] = + std::make_shared(json[ErrorTableName], + installer_strings, validationTable); } - if (JsonHelper::exists(json, "Feature")) { - tables["Feature"] = std::make_shared(json["Feature"], - installer_strings); + if (JsonHelper::exists(json, FeatureTableName)) { + tables[FeatureTableName] = + std::make_shared(json[FeatureTableName], + installer_strings, validationTable); } - if (JsonHelper::exists(json, "Icon")) { - tables["Icon"] = std::make_shared(json["Icon"], path, - platform, configuration); + if (JsonHelper::exists(json, IconTableName)) { + tables[IconTableName] = + std::make_shared(json[IconTableName], path, + platform, configuration, validationTable); } - if (JsonHelper::exists(json, "InstallExecuteSequence")) { - tables["InstallExecuteSequence"] = + if (JsonHelper::exists(json, InstallExecuteSequenceTableName)) { + tables[InstallExecuteSequenceTableName] = std::make_shared( - json["InstallExecuteSequence"]); + json[InstallExecuteSequenceTableName], validationTable); } - if (JsonHelper::exists(json, "InstallUISequence")) { - tables["InstallUISequence"] = + if (JsonHelper::exists(json, InstallUISequenceTableName)) { + tables[InstallUISequenceTableName] = std::make_shared( - json["InstallUISequence"]); + json[InstallUISequenceTableName], validationTable); } - if (JsonHelper::exists(json, "LaunchCondition")) { - tables["LaunchCondition"] = std::make_shared( - json["LaunchCondition"], installer_strings); + if (JsonHelper::exists(json, LaunchConditionTableName)) { + tables[LaunchConditionTableName] = + std::make_shared( + json[LaunchConditionTableName], installer_strings, + validationTable); } - if (JsonHelper::exists(json, "Property")) { - tables["Property"] = std::make_shared( - json["Property"], installer_strings); + if (JsonHelper::exists(json, ListboxTableName)) { + tables[ListboxTableName] = std::make_shared( + json[ListboxTableName], installer_strings, validationTable); } - if (JsonHelper::exists(json, "TextStyle")) { - tables["TextStyle"] = std::make_shared( - json["TextStyle"]); + if (JsonHelper::exists(json, PropertyTableName)) { + tables[PropertyTableName] = std::make_shared( + json[PropertyTableName], installer_strings, validationTable); } - if (JsonHelper::exists(json, "UIText")) { - tables["UIText"] = std::make_shared(json["UIText"], - installer_strings); + if (JsonHelper::exists(json, TextStyleTableName)) { + tables[TextStyleTableName] = std::make_shared( + json[TextStyleTableName], validationTable); } - if (JsonHelper::exists(json, "Upgrade")) { - tables["Upgrade"] = std::make_shared( - json["Upgrade"]); + if (JsonHelper::exists(json, UITextTableName)) { + tables[UITextTableName] = + std::make_shared(json[UITextTableName], + installer_strings, validationTable); + } + if (JsonHelper::exists(json, UpgradeTableName)) { + tables[UpgradeTableName] = std::make_shared( + json[UpgradeTableName], validationTable); } } catch (const std::exception& e) { @@ -210,6 +263,9 @@ bool Installer::create_msi(const std::filesystem::path& msi) { } for (const auto& table : tables) { + if (table.first == ValidationTableName) { + continue; + } if (!table.second->generate(hDatabase)) { std::cerr << "Failed to write table " << table.first << std::endl; @@ -217,6 +273,15 @@ bool Installer::create_msi(const std::filesystem::path& msi) { } } + // should always be last + if (tables.find(ValidationTableName) != tables.end() && + tables[ValidationTableName] != nullptr) { + if (!tables[ValidationTableName]->generate(hDatabase)) { + std::cerr << "Failed to write table Validation" << std::endl; + return false; + } + } + result = MsiDatabaseCommit(hDatabase); if (result != ERROR_SUCCESS) { std::cerr << "MsiDatabaseCommit failed: " << result << std::endl; diff --git a/installer/LaunchConditionTable.cpp b/installer/LaunchConditionTable.cpp index 5fd55e2db2f..e70dd4b01e4 100644 --- a/installer/LaunchConditionTable.cpp +++ b/installer/LaunchConditionTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,12 +18,45 @@ #include "LaunchConditionTable.h" LaunchConditionTable::LaunchConditionTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { std::cout << "Loading LaunchConditionTable..." << std::endl; for (const auto& launchCondition : json) { launchConditions.emplace_back(launchCondition, installerStrings); } + + const auto tableName = std::string("LaunchCondition"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/launchcondition-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Condition", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCondition, + "", + DescriptionWithUrl("Expression that must evaluate to True for " + "installation to begin.", url) + )); + validationTable->add(Validation( + tableName, + "Description", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("Localizable text to display when the " + "condition fails and the installation must be terminated.", + url) + )); + } } bool LaunchConditionTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/LaunchConditionTable.h b/installer/LaunchConditionTable.h index 0733c8a91b9..eb05b2f9f67 100644 --- a/installer/LaunchConditionTable.h +++ b/installer/LaunchConditionTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,11 +19,13 @@ #include "Generator.h" #include "LaunchCondition.h" +#include "ValidationTable.h" class LaunchConditionTable : public Generator { public: explicit LaunchConditionTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~LaunchConditionTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/Listbox.cpp b/installer/Listbox.cpp new file mode 100644 index 00000000000..97d6f202a75 --- /dev/null +++ b/installer/Listbox.cpp @@ -0,0 +1,32 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#include "Listbox.h" +#include "MsiHelper.h" +#include "JsonHelper.h" + +Listbox::Listbox(const nlohmann::json& json, + InstallerStrings& installerStrings) { + JsonHelper::get(json, "Property", property); + JsonHelper::get(json, "Order", order); + JsonHelper::get(json, "Value", value); + JsonHelper::get(json, "Text", text, installerStrings); +} + +MSIHANDLE Listbox::getRecord() const { + return MsiHelper::MsiRecordSet({ property, order, value, text }); +} diff --git a/installer/Listbox.h b/installer/Listbox.h new file mode 100644 index 00000000000..3d0e616b389 --- /dev/null +++ b/installer/Listbox.h @@ -0,0 +1,36 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#pragma once + +#include + +#include "Record.h" +#include "InstallerStrings.h" + +class Listbox : public Record { +public: + explicit Listbox(const nlohmann::json& json, + InstallerStrings& installerStrings); + ~Listbox() = default; + MSIHANDLE getRecord() const override; +private: + std::string property{}; + int order = MSI_NULL_INTEGER; + std::string value{}; + std::string text{}; +}; diff --git a/installer/ListboxTable.cpp b/installer/ListboxTable.cpp new file mode 100644 index 00000000000..db1db09b067 --- /dev/null +++ b/installer/ListboxTable.cpp @@ -0,0 +1,99 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#include + +#include "ListboxTable.h" + +ListboxTable::ListboxTable(const nlohmann::json& json, + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { + std::cout << "Loading ListboxTable..." << std::endl; + for (const auto& item : json) { + values.emplace_back(item, installerStrings); + } + + const auto tableName = std::string("ListBox"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/listbox-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Property", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("A named property to be tied to this item.", + url) + )); + validationTable->add(Validation( + tableName, + "Order", + false, + 1, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A positive integer used to determine the " + "ordering of the items that appear in a single list box.", url) + )); + validationTable->add(Validation( + tableName, + "Value", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The value string associated with this item.", + url) + )); + validationTable->add(Validation( + tableName, + "Text", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The localizable, visible text to be assigned " + "to the item.", url) + )); + } +} + +bool ListboxTable::generate(MSIHANDLE hDatabase) { + std::cout << "Generating ListboxTable..." << std::endl; + + const auto sql_create = "CREATE TABLE `ListBox` " + "(`Property` CHAR(72) NOT NULL, `Order` SHORT NOT NULL, " + "`Value` CHAR(64) NOT NULL, `Text` CHAR(64) " + "PRIMARY KEY `Property`, `Order`)"; + const auto sql_insert = "INSERT INTO `ListBox` " + "(`Property`, `Order`, `Value`, `Text`) VALUES (?, ?, ?, ?)"; + + return Generator::generate(hDatabase, sql_create, sql_insert, values); +} diff --git a/installer/ListboxTable.h b/installer/ListboxTable.h new file mode 100644 index 00000000000..496821ca51b --- /dev/null +++ b/installer/ListboxTable.h @@ -0,0 +1,34 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#pragma once + +#include "Generator.h" +#include "InstallerStrings.h" +#include "Listbox.h" +#include "ValidationTable.h" + +class ListboxTable : public Generator { +public: + explicit ListboxTable(const nlohmann::json& json, + InstallerStrings& installerStrings, + std::shared_ptr validationTable); + ~ListboxTable() = default; + bool generate(MSIHANDLE hDatabase) override; +private: + std::vector values{}; +}; diff --git a/installer/MediaTable.cpp b/installer/MediaTable.cpp index e7b57ea470c..70aa0e8a0a3 100644 --- a/installer/MediaTable.cpp +++ b/installer/MediaTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,7 +17,89 @@ #include "MediaTable.h" -MediaTable::MediaTable(const std::vector& media) : media(media) { +MediaTable::MediaTable(const std::vector& media, + std::shared_ptr validationTable) : media(media) { + const auto tableName = std::string("Media"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/media-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "DiskId", + false, + 1, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Determines the sort order for the table.", url) + )); + validationTable->add(Validation( + tableName, + "LastSequence", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("File sequence number for the last file for " + "this media.", url) + )); + validationTable->add(Validation( + tableName, + "DiskPrompt", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The disk name, which is usually the visible " + "text printed on the disk.", url) + )); + validationTable->add(Validation( + tableName, + "Cabinet", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryCabinet, + "", + DescriptionWithUrl("The name of the cabinet if some or all of the " + "files stored on the media are compressed into a cabinet " + "file.", url) + )); + validationTable->add(Validation( + tableName, + "VolumeLabel", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The label attributed to the volume.", url) + )); + validationTable->add(Validation( + tableName, + "Source", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryProperty, + "", + DescriptionWithUrl("This field is only used by patching and is " + "otherwise left blank.", url) + )); + } } bool MediaTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/MediaTable.h b/installer/MediaTable.h index aedbf48c645..e2d4b57f977 100644 --- a/installer/MediaTable.h +++ b/installer/MediaTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Generator.h" #include "Media.h" +#include "ValidationTable.h" class MediaTable : public Generator { public: - explicit MediaTable(const std::vector& media); + explicit MediaTable(const std::vector& media, + std::shared_ptr validationTable); ~MediaTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/MsiFileHashTable.cpp b/installer/MsiFileHashTable.cpp index 3b8a3298231..7155d1f9f41 100644 --- a/installer/MsiFileHashTable.cpp +++ b/installer/MsiFileHashTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,8 +17,12 @@ #include "MsiFileHashTable.h" -MsiFileHashTable::MsiFileHashTable(const std::vector& files) { +MsiFileHashTable::MsiFileHashTable(const std::vector& files, + std::shared_ptr validationTable) { for (const auto& file : files) { + if (file.isVersioned()) { + continue; + } MSIFILEHASHINFO hashInfo; hashInfo.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); if (MsiGetFileHash(file.getFilepath().string().c_str(), 0, &hashInfo) @@ -30,6 +34,84 @@ MsiFileHashTable::MsiFileHashTable(const std::vector& files) { msiFileHashes.emplace_back(file.getFileId(), hashInfo.dwData[0], hashInfo.dwData[1], hashInfo.dwData[2], hashInfo.dwData[3]); } + + const auto tableName = std::string("MsiFileHash"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/msifilehash-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "File_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "File", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Foreign key to File table.", url) + )); + validationTable->add(Validation( + tableName, + "Options", + false, + 0, + 0, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column must be 0 and is reserved for " + "future use.", url) + )); + validationTable->add(Validation( + tableName, + "HashPart1", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("First 32 bits of hash.", url) + )); + validationTable->add(Validation( + tableName, + "HashPart2", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Second 32 bits of hash.", url) + )); + validationTable->add(Validation( + tableName, + "HashPart3", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Third 32 bits of hash.", url) + )); + validationTable->add(Validation( + tableName, + "HashPart4", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Fourth 32 bits of hash.", url) + )); + } } bool MsiFileHashTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/MsiFileHashTable.h b/installer/MsiFileHashTable.h index 7739e3f4cb4..d1a70b5cccd 100644 --- a/installer/MsiFileHashTable.h +++ b/installer/MsiFileHashTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "MsiFileHash.h" #include "File.h" +#include "ValidationTable.h" class MsiFileHashTable : public Generator { public: - explicit MsiFileHashTable(const std::vector& files); + explicit MsiFileHashTable(const std::vector& files, + std::shared_ptr validationTable); ~MsiFileHashTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/PropertyTable.cpp b/installer/PropertyTable.cpp index 38176300afd..9311b96dc8e 100644 --- a/installer/PropertyTable.cpp +++ b/installer/PropertyTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,13 +19,44 @@ #include "GuidHelper.h" PropertyTable::PropertyTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { std::cout << "Loading PropertyTable..." << std::endl; for (const auto& item : json) { properties.emplace_back(item, installerStrings); } std::cout << "Generating new ProductCode..." << std::endl; properties.emplace_back("ProductCode", GuidHelper::generate_guid()); + + const auto tableName = std::string("Property"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/property-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Property", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The name of the property.", url) + )); + validationTable->add(Validation( + tableName, + "Value", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("A localizable string value for the property.", + url) + )); + } } bool PropertyTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/PropertyTable.h b/installer/PropertyTable.h index faaf05cca84..e536bae2bd2 100644 --- a/installer/PropertyTable.h +++ b/installer/PropertyTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,11 +19,13 @@ #include "Generator.h" #include "Property.h" +#include "ValidationTable.h" class PropertyTable : public Generator { public: explicit PropertyTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~PropertyTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/RadioButtonTable.cpp b/installer/RadioButtonTable.cpp index 8ee1afd4103..527d4d2c3e6 100644 --- a/installer/RadioButtonTable.cpp +++ b/installer/RadioButtonTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,12 +17,134 @@ #include "RadioButtonTable.h" -RadioButtonTable::RadioButtonTable(const std::vector& controls) { +RadioButtonTable::RadioButtonTable(const std::vector& controls, + std::shared_ptr validationTable) { for (const auto& control : controls) { for (const auto& radioButton : control.get_radio_buttons()) { properties.emplace_back(radioButton); } } + + const auto tableName = std::string("RadioButton"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/radiobutton-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Property", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("A named property to be tied to this radio " + "button.", url) + )); + validationTable->add(Validation( + tableName, + "Order", + false, + 1, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A positive integer used to determine the " + "ordering of the items within one list.", url) + )); + validationTable->add(Validation( + tableName, + "Value", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The value string associated with this button.", + url) + )); + validationTable->add(Validation( + tableName, + "X", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The horizontal coordinate within the group of " + "the upper-left corner of the bounding rectangle of the radio " + "button.", url) + )); + validationTable->add(Validation( + tableName, + "Y", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The vertical coordinate within the group of " + "the upper-left corner of the bounding rectangle of the radio " + "button.", url) + )); + validationTable->add(Validation( + tableName, + "Width", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The width of the button.", url) + )); + validationTable->add(Validation( + tableName, + "Height", + false, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The height of the button.", url) + )); + validationTable->add(Validation( + tableName, + "Text", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The localizable, visible title to be assigned " + "to the radio button.", url) + )); + validationTable->add(Validation( + tableName, + "Help", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The Help strings used with the button.", url) + )); + } } bool RadioButtonTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/RadioButtonTable.h b/installer/RadioButtonTable.h index 7a5a118eed0..c50e2ef6d04 100644 --- a/installer/RadioButtonTable.h +++ b/installer/RadioButtonTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -21,10 +21,12 @@ #include "RadioButton.h" #include "Control.h" #include "InstallerStrings.h" +#include "ValidationTable.h" class RadioButtonTable : public Generator { public: - explicit RadioButtonTable(const std::vector& controls); + explicit RadioButtonTable(const std::vector& controls, + std::shared_ptr validationTable); ~RadioButtonTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/RegistryTable.cpp b/installer/RegistryTable.cpp index cd31e8c35f6..246e9cb4e3b 100644 --- a/installer/RegistryTable.cpp +++ b/installer/RegistryTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,7 +17,8 @@ #include "RegistryTable.h" -RegistryTable::RegistryTable(const std::vector& directories) { +RegistryTable::RegistryTable(const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { for (const auto& registry : component.getRegistries()) { @@ -25,6 +26,90 @@ RegistryTable::RegistryTable(const std::vector& directories) { } } } + + const auto tableName = std::string("Registry"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/registry-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Registry", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Primary key used to identify a registry " + "record.", url) + )); + validationTable->add(Validation( + tableName, + "Root", + false, + -1, + 3, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("he predefined root key for the registry " + "value.", url) + )); + validationTable->add(Validation( + tableName, + "Key", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryRegPath, + "", + DescriptionWithUrl("The localizable key for the registry value.", + url) + )); + validationTable->add(Validation( + tableName, + "Name", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column contains the registry value name " + "(localizable).", url) + )); + validationTable->add(Validation( + tableName, + "Value", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column is the localizable registry " + "value.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key into the first column of the " + "Component table referencing the component that controls the " + "installation of the registry value.", url) + )); + } } bool RegistryTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/RegistryTable.h b/installer/RegistryTable.h index 7d7409c72cb..fd8b25361ee 100644 --- a/installer/RegistryTable.h +++ b/installer/RegistryTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "Registry.h" #include "Directory.h" +#include "ValidationTable.h" class RegistryTable : public Generator { public: - explicit RegistryTable(const std::vector& directories); + explicit RegistryTable(const std::vector& directories, + std::shared_ptr validationTable); ~RegistryTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/RemoveFileTable.cpp b/installer/RemoveFileTable.cpp index bd8baf3b015..4fda3919d19 100644 --- a/installer/RemoveFileTable.cpp +++ b/installer/RemoveFileTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,13 +17,84 @@ #include "RemoveFileTable.h" -RemoveFileTable::RemoveFileTable(const std::vector& directories) { +RemoveFileTable::RemoveFileTable(const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { for (const auto& file : component.getRemoveFiles()) values.emplace_back(file); } } + + const auto tableName = std::string("RemoveFile"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/removefile-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "FileKey", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Primary key used to identify this particular " + "table entry.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key the first column of the " + "Component table.", url) + )); + validationTable->add(Validation( + tableName, + "FileName", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryWildCardFilename, + "", + DescriptionWithUrl("This column contains the localizable name of " + "the file to be removed.", url) + )); + validationTable->add(Validation( + tableName, + "DirProperty", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Name of a property whose value is assumed to " + "resolve to the full path to the folder of the file to be " + "removed.", url) + )); + validationTable->add(Validation( + tableName, + "InstallMode", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "1;2;3", + DescriptionWithUrl("Specifies the mode in which the file is installed.", url) + )); + } } bool RemoveFileTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/RemoveFileTable.h b/installer/RemoveFileTable.h index 944df78b836..909c2bc5540 100644 --- a/installer/RemoveFileTable.h +++ b/installer/RemoveFileTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Generator.h" #include "RemoveFile.h" #include "Directory.h" +#include "ValidationTable.h" class RemoveFileTable : public Generator { public: - explicit RemoveFileTable(const std::vector& directories); + explicit RemoveFileTable(const std::vector& directories, + std::shared_ptr validationTable); ~RemoveFileTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/ServiceControlTable.cpp b/installer/ServiceControlTable.cpp index a1c56e89148..40459d221f6 100644 --- a/installer/ServiceControlTable.cpp +++ b/installer/ServiceControlTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,7 +18,8 @@ #include "ServiceControlTable.h" ServiceControlTable::ServiceControlTable( - const std::vector& directories) { + const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { for (const auto& serviceControl : component.getServiceControls()) { @@ -26,6 +27,89 @@ ServiceControlTable::ServiceControlTable( } } } + + const auto tableName = std::string("ServiceControl"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/servicecontrol-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "ServiceControl", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("This is the primary key of this table.", url) + )); + validationTable->add(Validation( + tableName, + "Name", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column is the string naming the service.", + url) + )); + validationTable->add(Validation( + tableName, + "Event", + false, + 0, + 187, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column contains the operations to be " + "performed on the named service.", url) + )); + validationTable->add(Validation( + tableName, + "Arguments", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("A list of arguments for starting services.", + url) + )); + validationTable->add(Validation( + tableName, + "Wait", + true, + 0, + 1, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("Leaving this field null or entering a value " + "of 1 causes the installer to wait a maximum of 30 seconds " + "for the service to complete before proceeding.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key to column one of the Component " + "Table.", url) + )); + } } bool ServiceControlTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ServiceControlTable.h b/installer/ServiceControlTable.h index 5570e5ab5ce..00b52e24b34 100644 --- a/installer/ServiceControlTable.h +++ b/installer/ServiceControlTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "ServiceControl.h" #include "Generator.h" #include "Directory.h" +#include "ValidationTable.h" class ServiceControlTable : public Generator { public: - explicit ServiceControlTable(const std::vector& directories); + explicit ServiceControlTable(const std::vector& directories, + std::shared_ptr validationTable); ~ServiceControlTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/ServiceInstallTable.cpp b/installer/ServiceInstallTable.cpp index 17ac28d315f..48a86f26a5a 100644 --- a/installer/ServiceInstallTable.cpp +++ b/installer/ServiceInstallTable.cpp @@ -1,7 +1,6 @@ -#include "ServiceInstallTable.h" // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,7 +18,8 @@ #include "ServiceInstallTable.h" ServiceInstallTable::ServiceInstallTable( - const std::vector& directories) { + const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { for (const auto& serviceInstall : component.getServiceInstalls()) { @@ -27,6 +27,182 @@ ServiceInstallTable::ServiceInstallTable( } } } + + const auto tableName = std::string("ServiceInstall"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/serviceinstall-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "ServiceInstall", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("This is the primary key for the table.", url) + )); + validationTable->add(Validation( + tableName, + "Name", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column is the string that gives the " + "service name to install.", url) + )); + validationTable->add(Validation( + tableName, + "DisplayName", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column is the localizable string that " + "user interface programs use to identify the service.", url) + )); + validationTable->add(Validation( + tableName, + "ServiceType", + false, + -2147483647, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column is a set of bit flags that " + "specify the type of service.", url) + )); + validationTable->add(Validation( + tableName, + "StartType", + false, + 0, + 4, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column is a set of bit flags that " + "specify when to start the service.", url) + )); + validationTable->add(Validation( + tableName, + "ErrorControl", + false, + -2147483647, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column specifies the action taken by the " + "startup program if the service fails to start during " + "startup.", url) + )); + validationTable->add(Validation( + tableName, + "LoadOrderGroup", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column contains the string that names " + "the load ordering group of which this service is a member.", + url) + )); + validationTable->add(Validation( + tableName, + "Dependencies", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column is a list of names of services or " + "load ordering groups that the system must start before this " + "service.", url) + )); + validationTable->add(Validation( + tableName, + "StartName", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The service is logged on as the name given by " + "the string in this column.", url) + )); + validationTable->add(Validation( + tableName, + "Password", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This string is the password to the account " + "name specified in the StartName column.", url) + )); + validationTable->add(Validation( + tableName, + "Arguments", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column contains any command line " + "arguments or properties required to run the service.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("External key to column one of the Component " + "Table.", url) + )); + validationTable->add(Validation( + tableName, + "Description", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This column contains a localizable " + "description for the service being configured.", url) + )); + } } bool ServiceInstallTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ServiceInstallTable.h b/installer/ServiceInstallTable.h index ea5fd0719d4..fd3e87aaa76 100644 --- a/installer/ServiceInstallTable.h +++ b/installer/ServiceInstallTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "ServiceInstall.h" #include "Generator.h" #include "Directory.h" +#include "ValidationTable.h" class ServiceInstallTable : public Generator { public: - explicit ServiceInstallTable(const std::vector& directories); + explicit ServiceInstallTable(const std::vector& directories, + std::shared_ptr validationTable); ~ServiceInstallTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/ShortcutTable.cpp b/installer/ShortcutTable.cpp index 651c2c34345..f8d97420cc8 100644 --- a/installer/ShortcutTable.cpp +++ b/installer/ShortcutTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,7 +17,8 @@ #include "ShortcutTable.h" -ShortcutTable::ShortcutTable(const std::vector& directories) { +ShortcutTable::ShortcutTable(const std::vector& directories, + std::shared_ptr validationTable) { for (const auto& directory : directories) { for (const auto& component : directory.getComponents()) { for (const auto& shortcut : component.getShortcuts()) { @@ -25,6 +26,218 @@ ShortcutTable::ShortcutTable(const std::vector& directories) { } } } + + const auto tableName = std::string("Shortcut"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/shortcut-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Shortcut", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The key value for this table.", url) + )); + validationTable->add(Validation( + tableName, + "Directory_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Directory", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The external key into the first column of the " + "Directory table.", url) + )); + validationTable->add(Validation( + tableName, + "Name", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFilename, + "", + DescriptionWithUrl("The localizable name of the shortcut to be " + "created.", url) + )); + validationTable->add(Validation( + tableName, + "Component_", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Component", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The external key into the first column of the " + "Component table.", url) + )); + validationTable->add(Validation( + tableName, + "Target", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryShortcut, + "", + DescriptionWithUrl("The shortcut target.", url) + )); + validationTable->add(Validation( + tableName, + "Arguments", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The command-line arguments for the shortcut.", + url) + )); + validationTable->add(Validation( + tableName, + "Description", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The localizable description of the shortcut.", + url) + )); + validationTable->add(Validation( + tableName, + "Hotkey", + true, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The hotkey for the shortcut.", url) + )); + validationTable->add(Validation( + tableName, + "Icon_", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "Icon", + 1, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The external key to column one of the Icon " + "table.", url) + )); + validationTable->add(Validation( + tableName, + "IconIndex", + true, + -32767, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The icon index for the shortcut.", url) + )); + validationTable->add(Validation( + tableName, + "ShowCmd", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "1;3;7", + DescriptionWithUrl("The Show command for the application window.", + url) + )); + validationTable->add(Validation( + tableName, + "WkDir", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The name of the property that has the path of " + "the working directory for the shortcut.", url) + )); + validationTable->add(Validation( + tableName, + "DisplayResourceDll", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This field contains a Formatted string value " + "for the full path to the language-neutral portable " + "executable (LN file) that contains the resource " + "configuration (RC Config) data.", url) + )); + validationTable->add(Validation( + tableName, + "DisplayResourceId", + true, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The display name index for the shortcut.", url) + )); + validationTable->add(Validation( + tableName, + "DescriptionResourceDll", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("This field contains a Formatted string value " + "for the full path to the language-neutral portable " + "executable (LN file) that contains the resource " + "configuration (RC Config) data.", url) + )); + validationTable->add(Validation( + tableName, + "DescriptionResourceId", + true, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The description name index for the shortcut.", + url) + )); + } } bool ShortcutTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/ShortcutTable.h b/installer/ShortcutTable.h index 4bcc43796da..2ed10ffd528 100644 --- a/installer/ShortcutTable.h +++ b/installer/ShortcutTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -20,10 +20,12 @@ #include "Shortcut.h" #include "Directory.h" #include "Generator.h" +#include "ValidationTable.h" class ShortcutTable : public Generator { public: - explicit ShortcutTable(const std::vector& directories); + explicit ShortcutTable(const std::vector& directories, + std::shared_ptr validationTable); ~ShortcutTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/SummaryInformationTable.cpp b/installer/SummaryInformationTable.cpp index 48179bb9149..1979c10a7c2 100644 --- a/installer/SummaryInformationTable.cpp +++ b/installer/SummaryInformationTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -82,7 +82,7 @@ bool SummaryInformationTable::generate(MSIHANDLE hDatabase) { MSIHANDLE hSummaryInfo; const auto updateCount = summary.size(); - auto result =MsiGetSummaryInformation(hDatabase, nullptr, updateCount, + auto result = MsiGetSummaryInformation(hDatabase, nullptr, updateCount, &hSummaryInfo); if (result != ERROR_SUCCESS) { std::cerr << "MsiGetSummaryInformation failed: " << result diff --git a/installer/TextStyleTable.cpp b/installer/TextStyleTable.cpp index 7a2d669633d..8201bf4194f 100644 --- a/installer/TextStyleTable.cpp +++ b/installer/TextStyleTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,12 +17,82 @@ #include "TextStyleTable.h" -TextStyleTable::TextStyleTable(const nlohmann::json& json) { +TextStyleTable::TextStyleTable(const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading TextStyleTable..." << std::endl; for (const auto& textStyle : json) { textStyles.emplace_back(textStyle); } + + const auto tableName = std::string("TextStyle"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/textstyle-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "TextStyle", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("This column is the name of the font style.", + url) + )); + validationTable->add(Validation( + tableName, + "FaceName", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("A string indicating the name of the font.", + url) + )); + validationTable->add(Validation( + tableName, + "Size", + true, + 0, + 32767, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The font size measured in points.", url) + )); + validationTable->add(Validation( + tableName, + "Color", + true, + 0, + 16777215, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column specifies the text color " + "displayed by a Text Control.", url) + )); + validationTable->add(Validation( + tableName, + "StyleBits", + true, + 0, + 15, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("A combination of bits indicating the " + "formatting for the text.", url) + )); + } } bool TextStyleTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/TextStyleTable.h b/installer/TextStyleTable.h index be0de218f55..48f982b698b 100644 --- a/installer/TextStyleTable.h +++ b/installer/TextStyleTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Generator.h" #include "TextStyle.h" +#include "ValidationTable.h" class TextStyleTable : public Generator { public: - explicit TextStyleTable(const nlohmann::json& json); + explicit TextStyleTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~TextStyleTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/UITextTable.cpp b/installer/UITextTable.cpp index a9f006065ab..38796e765c7 100644 --- a/installer/UITextTable.cpp +++ b/installer/UITextTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -18,11 +18,42 @@ #include "UITextTable.h" UITextTable::UITextTable(const nlohmann::json& json, - InstallerStrings& installerStrings) { + InstallerStrings& installerStrings, + std::shared_ptr validationTable) { std::cout << "Loading UITextTable.." << std::endl; for (const auto& item : json) { uiTexts.emplace_back(item, installerStrings); } + + const auto tableName = std::string("UIText"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/uitext-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "Key", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("A unique key that identifies the particular " + "string.", url) + )); + validationTable->add(Validation( + tableName, + "Text", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The localized version of the string.", url) + )); + } } bool UITextTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/UITextTable.h b/installer/UITextTable.h index d639d03a59b..bdd1112db94 100644 --- a/installer/UITextTable.h +++ b/installer/UITextTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,11 +19,13 @@ #include "Generator.h" #include "UIText.h" +#include "ValidationTable.h" class UITextTable : public Generator { public: explicit UITextTable(const nlohmann::json& json, - InstallerStrings& installerStrings); + InstallerStrings& installerStrings, + std::shared_ptr validationTable); ~UITextTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/UpgradeTable.cpp b/installer/UpgradeTable.cpp index 058d9600356..94d6d30b53b 100644 --- a/installer/UpgradeTable.cpp +++ b/installer/UpgradeTable.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -17,12 +17,111 @@ #include "UpgradeTable.h" -UpgradeTable::UpgradeTable(const nlohmann::json& json) { +UpgradeTable::UpgradeTable(const nlohmann::json& json, + std::shared_ptr validationTable) { std::cout << "Loading UpgradeTable..." << std::endl; for (const auto& item : json) { values.emplace_back(item); } + + const auto tableName = std::string("Upgrade"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/upgrade-table"; + if (validationTable != nullptr) { + validationTable->add(Validation( + tableName, + "UpgradeCode", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryGuid, + "", + DescriptionWithUrl("The UpgradeCode property in this column " + "specifies the upgrade code of all products that are to be " + "detected by the FindRelatedProducts action.", url) + )); + validationTable->add(Validation( + tableName, + "VersionMin", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("Lower boundary of the range of product " + "versions detected by FindRelatedProducts.", url) + )); + validationTable->add(Validation( + tableName, + "VersionMax", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("Upper boundary of the range of product " + "versions detected by the FindRelatedProducts action.", url) + )); + validationTable->add(Validation( + tableName, + "Language", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("The set of languages detected by " + "FindRelatedProducts.", url) + )); + validationTable->add(Validation( + tableName, + "Attributes", + false, + 0, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This column contains bit flags specifying " + "attributes of the Upgrade table.", url) + )); + validationTable->add(Validation( + tableName, + "Remove", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryFormatted, + "", + DescriptionWithUrl("The installer sets the REMOVE property to " + "features specified in this column.", url) + )); + validationTable->add(Validation( + tableName, + "ActionProperty", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("When the FindRelatedProducts action detects a " + "related product installed on the system, it appends the " + "product code to the property specified in this field.", url) + )); + } } bool UpgradeTable::generate(MSIHANDLE hDatabase) { diff --git a/installer/UpgradeTable.h b/installer/UpgradeTable.h index e276bca03b8..5d64df7d9c4 100644 --- a/installer/UpgradeTable.h +++ b/installer/UpgradeTable.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // https://boinc.berkeley.edu -// Copyright (C) 2024 University of California +// Copyright (C) 2025 University of California // // BOINC is free software; you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License @@ -19,10 +19,12 @@ #include "Upgrade.h" #include "Generator.h" +#include "ValidationTable.h" class UpgradeTable : public Generator { public: - explicit UpgradeTable(const nlohmann::json& json); + explicit UpgradeTable(const nlohmann::json& json, + std::shared_ptr validationTable); ~UpgradeTable() = default; bool generate(MSIHANDLE hDatabase) override; private: diff --git a/installer/Validation.cpp b/installer/Validation.cpp new file mode 100644 index 00000000000..040b203d788 --- /dev/null +++ b/installer/Validation.cpp @@ -0,0 +1,35 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#include "Validation.h" +#include "MsiHelper.h" + +Validation::Validation(const std::string& table, const std::string& column, + bool nullable, int minValue, int maxValue, const std::string& keyTable, + int keyColumn, const std::string& category, const std::string& set, + const std::string& description) : table(table), column(column), + nullable(nullable), minValue(minValue), maxValue(maxValue), + keyTable(keyTable), keyColumn(keyColumn), category(category), set(set), + description(description) { +} + +MSIHANDLE Validation::getRecord() const { + const std::string yval = "Y"; + const std::string nval = "N"; + return MsiHelper::MsiRecordSet({ table, column, nullable ? yval : nval, + minValue, maxValue, keyTable, keyColumn, category, set, description }); +} diff --git a/installer/Validation.h b/installer/Validation.h new file mode 100644 index 00000000000..8c7dffd9c85 --- /dev/null +++ b/installer/Validation.h @@ -0,0 +1,41 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#pragma once + +#include "Record.h" + +class Validation : public Record { +public: + explicit Validation(const std::string& table, const std::string& column, + bool nullable, int minValue, int maxValue, const std::string& keyTable, + int keyColumn, const std::string& category, const std::string& set, + const std::string& description); + ~Validation() = default; + MSIHANDLE getRecord() const override; +private: + std::string table{}; + std::string column{}; + bool nullable = false; + int minValue = MSI_NULL_INTEGER; + int maxValue = MSI_NULL_INTEGER; + std::string keyTable{}; + int keyColumn = MSI_NULL_INTEGER; + std::string category{}; + std::string set{}; + std::string description{}; +}; diff --git a/installer/ValidationTable.cpp b/installer/ValidationTable.cpp new file mode 100644 index 00000000000..b7cf45b1749 --- /dev/null +++ b/installer/ValidationTable.cpp @@ -0,0 +1,168 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#include "ValidationTable.h" + +ValidationTable::ValidationTable() { + const auto tableName = std::string("_Validation"); + const auto url = "https://learn.microsoft.com/en-us/windows/win32/msi/-validation-table"; + values.emplace_back( + tableName, + "Table", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Used to identify a particular table.", url) + ); + values.emplace_back( + tableName, + "Column", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("Used to identify a particular column of the table", + url) + ); + values.emplace_back( + tableName, + "Nullable", + false, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "Y;N", + DescriptionWithUrl("Identifies whether the column may contain a Null " + "value.", url) + ); + values.emplace_back(tableName, + "MinValue", + true, + -2147483647, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The field contains the minimum permissible value.", + url) + ); + values.emplace_back(tableName, + "MaxValue", + true, + -2147483647, + 2147483647, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("The field is the maximum permissible value.", url) + ); + values.emplace_back(tableName, + "KeyTable", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryIdentifier, + "", + DescriptionWithUrl("The table name with the foreign keys", url) + ); + values.emplace_back(tableName, + "KeyColumn", + true, + 1, + 32, + "", + MSI_NULL_INTEGER, + "", + "", + DescriptionWithUrl("This field applies to table columns that are " + "external keys", url) + ); + values.emplace_back(tableName, + "Category", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + "", + "Text;Formatted;Template;Condition;Guid;Path;Version;Language;" + "Identifier;Binary;UpperCase;LowerCase;Filename;Paths;AnyPath;" + "WildCardFilename;RegPath;KeyFormatted;CustomSource;Property;Cabinet;" + "Shortcut;URL", + DescriptionWithUrl("This is the type of data contained by the " + "database field specified by the Table and Column columns of the " + "_Validation table.", url) + ); + values.emplace_back(tableName, + "Set", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("This is a list of permissible values for this " + "field separated by semicolons.", url) + ); + values.emplace_back(tableName, + "Description", + true, + MSI_NULL_INTEGER, + MSI_NULL_INTEGER, + "", + MSI_NULL_INTEGER, + ValidationCategoryText, + "", + DescriptionWithUrl("A description of the data that is stored in the " + "column.", url) + ); +} + +bool ValidationTable::generate(MSIHANDLE hDatabase) { + std::cout << "Generating ValidationTable..." << std::endl; + + const auto sql_create = "CREATE TABLE `_Validation` " + "(`Table` CHAR(32) NOT NULL, `Column` CHAR(32) NOT NULL, " + "`Nullable` CHAR(4) NOT NULL, `MinValue` LONG, `MaxValue` LONG, " + "`KeyTable` CHAR(255), `KeyColumn` SHORT, `Category` CHAR(32), " + "`Set` CHAR(255), `Description` CHAR(255) " + "PRIMARY KEY `Table`, `Column`)"; + const auto sql_insert = "INSERT INTO `_Validation` " + "(`Table`, `Column`, `Nullable`, `MinValue`, `MaxValue`, `KeyTable`, " + "`KeyColumn`, `Category`, `Set`, `Description`) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + return Generator::generate(hDatabase, sql_create, sql_insert, values); +} + +void ValidationTable::add(const Validation& value) { + values.emplace_back(value); +} diff --git a/installer/ValidationTable.h b/installer/ValidationTable.h new file mode 100644 index 00000000000..fff801ee245 --- /dev/null +++ b/installer/ValidationTable.h @@ -0,0 +1,56 @@ +// This file is part of BOINC. +// https://boinc.berkeley.edu +// Copyright (C) 2025 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#pragma once + +#include "Generator.h" +#include "Validation.h" + +const auto ValidationCategoryIdentifier = std::string("Identifier"); +const auto ValidationCategoryText = std::string("Text"); +const auto ValidationCategoryTemplate = std::string("Template"); +const auto ValidationCategoryCondition = std::string("Condition"); +const auto ValidationCategoryBinary = std::string("Binary"); +const auto ValidationCategoryFormatted = std::string("Formatted"); +const auto ValidationCategoryGuid = std::string("Guid"); +const auto ValidationCategoryCustomSource = std::string("CustomSource"); +const auto ValidationCategoryDefaultDir = std::string("DefaultDir"); +const auto ValidationCategoryUpperCase = std::string("UpperCase"); +const auto ValidationCategoryFilename = std::string("Filename"); +const auto ValidationCategoryVersion = std::string("Version"); +const auto ValidationCategoryLanguage = std::string("Language"); +const auto ValidationCategoryCabinet = std::string("Cabinet"); +const auto ValidationCategoryProperty = std::string("Property"); +const auto ValidationCategoryRegPath = std::string("RegPath"); +const auto ValidationCategoryWildCardFilename = +std::string("WildCardFilename"); +const auto ValidationCategoryShortcut = std::string("Shortcut"); + +const auto DescriptionWithUrl = [](const std::string& description, + const std::string& url) { + return description + " For more information, see " + url; + }; + +class ValidationTable : public Generator { +public: + explicit ValidationTable(); + ~ValidationTable() = default; + bool generate(MSIHANDLE hDatabase) override; + void add(const Validation& value); +private: + std::vector values{}; +}; diff --git a/installer/boinc.json b/installer/boinc.json index 894e6976c57..e8c80e2b35e 100644 --- a/installer/boinc.json +++ b/installer/boinc.json @@ -8,7 +8,7 @@ "comments": "IDS_FEATURE_BOINC_DESCRIPTION", "template": "%%PLATFORM%%;1033", "lastauthor": "BOINC", - "pagecount": "200:500", + "pagecount": "400:500", "wordcount": 0, "charcount": 0, "appname": "BOINC", @@ -1969,8 +1969,8 @@ "Text": "IDS_BACK", "Events": [ { - "Event": "NewDialog", - "Argument": "NoDialog", + "Event": "EndDialog", + "Argument": "Return", "Condition": "1", "Ordering": 1 } @@ -2599,7 +2599,7 @@ "Y": 75, "Width": 24, "Height": 24, - "Attributes": 5767169, + "Attributes": 6291457, "Binary_": "reinstall.ico" }, { @@ -2609,7 +2609,7 @@ "Y": 135, "Width": 24, "Height": 24, - "Attributes": 5767169, + "Attributes": 6291457, "Binary_": "remove.ico" }, { @@ -3084,8 +3084,8 @@ "Ordering": 0 }, { - "Event": "NewDialog", - "Argument": "NoDialog", + "Event": "EndDialog", + "Argument": "Return", "Condition": "ACTION <> \"ADMIN\"", "Ordering": 0 } @@ -4213,7 +4213,7 @@ "Y": 52, "Width": 24, "Height": 24, - "Attributes": 5767169, + "Attributes": 6291457, "Binary_": "folder.ico" }, { @@ -4223,7 +4223,7 @@ "Y": 87, "Width": 24, "Height": 24, - "Attributes": 5767169, + "Attributes": 6291457, "Binary_": "folder.ico" }, { @@ -4514,7 +4514,7 @@ "Y": 52, "Width": 24, "Height": 24, - "Attributes": 5767169, + "Attributes": 6291457, "Binary_": "folder.ico" }, { @@ -4524,7 +4524,7 @@ "Y": 87, "Width": 24, "Height": 24, - "Attributes": 5767169, + "Attributes": 6291457, "Binary_": "folder.ico" }, { @@ -5578,13 +5578,7 @@ "Feature_": "BOINC", "Component": "_BOINCDataProjects", "Attributes": 272, - "Files": [ - { - "File": "placeholder.txt1", - "FileName": "PLACEH~1.TXT|placeholder.txt", - "FilePath": "res\\placeholder.txt" - } - ] + "CreateFolder": true } ] }, @@ -5596,13 +5590,7 @@ "Feature_": "BOINC", "Component": "_BOINCDataSlots", "Attributes": 272, - "Files": [ - { - "File": "placeholder.txt2", - "FileName": "PLACEH~1.TXT|placeholder.txt", - "FilePath": "res\\placeholder.txt" - } - ] + "CreateFolder": true } ] } @@ -5612,16 +5600,10 @@ "Feature_": "BOINC", "Component": "_BOINCData", "Attributes": 272, + "CreateFolder": true, "Files": [ { - "File": "all_projects_list.xml", - "FileName": "ALL_PR~1.XML|all_projects_list.xml", "FilePath": "..\\win_build\\installerv2\\redist\\all_projects_list.xml" - }, - { - "File": "placeholder.txt", - "FileName": "PLACEH~1.TXT|placeholder.txt", - "FilePath": "res\\placeholder.txt" } ] } @@ -5651,28 +5633,18 @@ "Attributes": 256, "Files": [ { - "File": "DEFAULT_skin.xml", - "FileName": "skin.xml", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\skins\\\\Default\\skin.xml" }, { - "File": "DEFAULT_background_image.png", - "FileName": "background_image.png", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\skins\\\\Default\\background_image.png" }, { - "File": "DEFAULT_workunit_running_image.png", - "FileName": "workunit_running_image.png", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\skins\\\\Default\\workunit_running_image.png" }, { - "File": "DEFAULT_workunit_suspended_image.png", - "FileName": "workunit_suspended_image.png", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\skins\\\\Default\\workunit_suspended_image.png" }, { - "File": "DEFAULT_workunit_waiting_image.png", - "FileName": "workunit_waiting_image.png", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\skins\\\\Default\\workunit_waiting_image.png" } ] @@ -5686,7 +5658,7 @@ "DefaultDir": "locale", "Directories": [ { - "Directory": "ar", + "Directory": "locale_ar", "DefaultDir": "ar", "Components": [ { @@ -5694,8 +5666,6 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ar_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ar\\BOINC-Client.mo" } ] @@ -5703,7 +5673,7 @@ ] }, { - "Directory": "az", + "Directory": "locale_az", "DefaultDir": "az", "Components": [ { @@ -5711,13 +5681,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_az_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\az\\BOINC-Client.mo" }, { - "File": "LOCALE_az_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\az\\BOINC-Manager.mo" } ] @@ -5725,7 +5691,7 @@ ] }, { - "Directory": "bg", + "Directory": "locale_bg", "DefaultDir": "bg", "Components": [ { @@ -5733,13 +5699,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_bg_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\bg\\BOINC-Client.mo" }, { - "File": "LOCALE_bg_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\bg\\BOINC-Manager.mo" } ] @@ -5747,7 +5709,7 @@ ] }, { - "Directory": "ca", + "Directory": "locale_ca", "DefaultDir": "ca", "Components": [ { @@ -5755,13 +5717,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ca_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ca\\BOINC-Client.mo" }, { - "File": "LOCALE_ca_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ca\\BOINC-Manager.mo" } ] @@ -5769,7 +5727,7 @@ ] }, { - "Directory": "cs", + "Directory": "locale_cs", "DefaultDir": "cs", "Components": [ { @@ -5777,13 +5735,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_cs_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\cs\\BOINC-Client.mo" }, { - "File": "LOCALE_cs_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\cs\\BOINC-Manager.mo" } ] @@ -5791,7 +5745,7 @@ ] }, { - "Directory": "da", + "Directory": "locale_da", "DefaultDir": "da", "Components": [ { @@ -5799,13 +5753,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_da_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\da\\BOINC-Client.mo" }, { - "File": "LOCALE_da_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\da\\BOINC-Manager.mo" } ] @@ -5813,7 +5763,7 @@ ] }, { - "Directory": "de", + "Directory": "locale_de", "DefaultDir": "de", "Components": [ { @@ -5821,13 +5771,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_de_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\de\\BOINC-Client.mo" }, { - "File": "LOCALE_de_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\de\\BOINC-Manager.mo" } ] @@ -5835,7 +5781,7 @@ ] }, { - "Directory": "el", + "Directory": "locale_el", "DefaultDir": "el", "Components": [ { @@ -5843,8 +5789,6 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_el_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\el\\BOINC-Client.mo" } ] @@ -5852,7 +5796,7 @@ ] }, { - "Directory": "eo", + "Directory": "locale_eo", "DefaultDir": "eo", "Components": [ { @@ -5860,8 +5804,6 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_eo_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\eo\\BOINC-Client.mo" } ] @@ -5869,7 +5811,7 @@ ] }, { - "Directory": "es", + "Directory": "locale_es", "DefaultDir": "es", "Components": [ { @@ -5877,13 +5819,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_es_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\es\\BOINC-Client.mo" }, { - "File": "LOCALE_es_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\es\\BOINC-Manager.mo" } ] @@ -5891,7 +5829,7 @@ ] }, { - "Directory": "eu", + "Directory": "locale_eu", "DefaultDir": "eu", "Components": [ { @@ -5899,13 +5837,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_eu_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\eu\\BOINC-Client.mo" }, { - "File": "LOCALE_eu_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\eu\\BOINC-Manager.mo" } ] @@ -5913,7 +5847,7 @@ ] }, { - "Directory": "fa_IR", + "Directory": "locale_fa_IR", "DefaultDir": "fa_IR", "Components": [ { @@ -5921,8 +5855,6 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_fa_IR_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\fa_IR\\BOINC-Client.mo" } ] @@ -5930,7 +5862,7 @@ ] }, { - "Directory": "fi", + "Directory": "locale_fi", "DefaultDir": "fi", "Components": [ { @@ -5938,13 +5870,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_fi_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\fi\\BOINC-Client.mo" }, { - "File": "LOCALE_fi_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\fi\\BOINC-Manager.mo" } ] @@ -5952,7 +5880,7 @@ ] }, { - "Directory": "fr", + "Directory": "locale_fr", "DefaultDir": "fr", "Components": [ { @@ -5960,13 +5888,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_fr_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\fr\\BOINC-Client.mo" }, { - "File": "LOCALE_fr_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\fr\\BOINC-Manager.mo" } ] @@ -5974,7 +5898,7 @@ ] }, { - "Directory": "he", + "Directory": "locale_he", "DefaultDir": "he", "Components": [ { @@ -5982,13 +5906,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_hr_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\he\\BOINC-Client.mo" }, { - "File": "LOCALE_he_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\he\\BOINC-Manager.mo" } ] @@ -5996,7 +5916,7 @@ ] }, { - "Directory": "hu", + "Directory": "locale_hu", "DefaultDir": "hu", "Components": [ { @@ -6004,13 +5924,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_hu_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\hu\\BOINC-Client.mo" }, { - "File": "LOCALE_hu_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\hu\\BOINC-Manager.mo" } ] @@ -6018,7 +5934,7 @@ ] }, { - "Directory": "it", + "Directory": "locale_it", "DefaultDir": "it", "Components": [ { @@ -6026,13 +5942,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_it_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\it\\BOINC-Client.mo" }, { - "File": "LOCALE_it_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\it\\BOINC-Manager.mo" } ] @@ -6040,7 +5952,7 @@ ] }, { - "Directory": "it_IT", + "Directory": "locale_it_IT", "DefaultDir": "it_IT", "Components": [ { @@ -6048,13 +5960,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_it_IT_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\it_IT\\BOINC-Client.mo" }, { - "File": "LOCALE_it_IT_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\it_IT\\BOINC-Manager.mo" } ] @@ -6062,7 +5970,7 @@ ] }, { - "Directory": "ja", + "Directory": "locale_ja", "DefaultDir": "ja", "Components": [ { @@ -6070,13 +5978,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ja_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ja\\BOINC-Client.mo" }, { - "File": "LOCALE_ja_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ja\\BOINC-Manager.mo" } ] @@ -6084,7 +5988,7 @@ ] }, { - "Directory": "ka", + "Directory": "locale_ka", "DefaultDir": "ka", "Components": [ { @@ -6092,13 +5996,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ka_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ka\\BOINC-Client.mo" }, { - "File": "LOCALE_ka_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ka\\BOINC-Manager.mo" } ] @@ -6106,7 +6006,7 @@ ] }, { - "Directory": "ko", + "Directory": "locale_ko", "DefaultDir": "ko", "Components": [ { @@ -6114,13 +6014,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ko_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ko\\BOINC-Client.mo" }, { - "File": "LOCALE_ko_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ko\\BOINC-Manager.mo" } ] @@ -6128,7 +6024,7 @@ ] }, { - "Directory": "lt", + "Directory": "locale_lt", "DefaultDir": "lt", "Components": [ { @@ -6136,8 +6032,6 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_lt_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\lt\\BOINC-Client.mo" } ] @@ -6145,7 +6039,7 @@ ] }, { - "Directory": "lv", + "Directory": "locale_lv", "DefaultDir": "lv", "Components": [ { @@ -6153,13 +6047,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_lv_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\lv\\BOINC-Client.mo" }, { - "File": "LOCALE_lv_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\lv\\BOINC-Manager.mo" } ] @@ -6167,7 +6057,7 @@ ] }, { - "Directory": "nb", + "Directory": "locale_nb", "DefaultDir": "nb", "Components": [ { @@ -6175,13 +6065,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_nb_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\nb\\BOINC-Client.mo" }, { - "File": "LOCALE_nb_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\nb\\BOINC-Manager.mo" } ] @@ -6189,7 +6075,7 @@ ] }, { - "Directory": "nl", + "Directory": "locale_nl", "DefaultDir": "nl", "Components": [ { @@ -6197,13 +6083,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_nl_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\nl\\BOINC-Client.mo" }, { - "File": "LOCALE_nl_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\nl\\BOINC-Manager.mo" } ] @@ -6211,7 +6093,7 @@ ] }, { - "Directory": "pl", + "Directory": "locale_pl", "DefaultDir": "pl", "Components": [ { @@ -6219,13 +6101,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_pl_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\pl\\BOINC-Client.mo" }, { - "File": "LOCALE_pl_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\pl\\BOINC-Manager.mo" } ] @@ -6233,7 +6111,7 @@ ] }, { - "Directory": "pt_BR", + "Directory": "locale_pt_BR", "DefaultDir": "pt_BR", "Components": [ { @@ -6241,13 +6119,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_pt_BR_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\pt_BR\\BOINC-Client.mo" }, { - "File": "LOCALE_pt_BR_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\pt_BR\\BOINC-Manager.mo" } ] @@ -6255,7 +6129,7 @@ ] }, { - "Directory": "pt_PT", + "Directory": "locale_pt_PT", "DefaultDir": "pt_PT", "Components": [ { @@ -6263,13 +6137,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_pt_PT_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\pt_PT\\BOINC-Client.mo" }, { - "File": "LOCALE_pt_PT_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\pt_PT\\BOINC-Manager.mo" } ] @@ -6277,7 +6147,7 @@ ] }, { - "Directory": "ro", + "Directory": "locale_ro", "DefaultDir": "ro", "Components": [ { @@ -6285,13 +6155,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ro_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ro\\BOINC-Client.mo" }, { - "File": "LOCALE_ro_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ro\\BOINC-Manager.mo" } ] @@ -6299,7 +6165,7 @@ ] }, { - "Directory": "ru", + "Directory": "locale_ru", "DefaultDir": "ru", "Components": [ { @@ -6307,13 +6173,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_ru_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ru\\BOINC-Client.mo" }, { - "File": "LOCALE_ru_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\ru\\BOINC-Manager.mo" } ] @@ -6321,7 +6183,7 @@ ] }, { - "Directory": "sk", + "Directory": "locale_sk", "DefaultDir": "sk", "Components": [ { @@ -6329,13 +6191,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_sk_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\sk\\BOINC-Client.mo" }, { - "File": "LOCALE_sk_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\sk\\BOINC-Manager.mo" } ] @@ -6343,7 +6201,7 @@ ] }, { - "Directory": "sr@latin", + "Directory": "locale_sr_latin", "DefaultDir": "sr@latin", "Components": [ { @@ -6351,8 +6209,6 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_sr_latin_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\sr@latin\\BOINC-Client.mo" } ] @@ -6360,7 +6216,7 @@ ] }, { - "Directory": "sv", + "Directory": "locale_sv", "DefaultDir": "sv", "Components": [ { @@ -6368,13 +6224,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_sv_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\sv\\BOINC-Client.mo" }, { - "File": "LOCALE_sv_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\sv\\BOINC-Manager.mo" } ] @@ -6382,7 +6234,7 @@ ] }, { - "Directory": "tr", + "Directory": "locale_tr", "DefaultDir": "tr", "Components": [ { @@ -6390,13 +6242,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_tr_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\tr\\BOINC-Client.mo" }, { - "File": "LOCALE_tr_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\tr\\BOINC-Manager.mo" } ] @@ -6404,7 +6252,7 @@ ] }, { - "Directory": "uk", + "Directory": "locale_uk", "DefaultDir": "uk", "Components": [ { @@ -6412,13 +6260,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_uk_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\uk\\BOINC-Client.mo" }, { - "File": "LOCALE_uk_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\uk\\BOINC-Manager.mo" } ] @@ -6426,7 +6270,7 @@ ] }, { - "Directory": "vi", + "Directory": "locale_vi", "DefaultDir": "vi", "Components": [ { @@ -6434,13 +6278,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_vi_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\vi\\BOINC-Client.mo" }, { - "File": "LOCALE_vi_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\vi\\BOINC-Manager.mo" } ] @@ -6448,7 +6288,7 @@ ] }, { - "Directory": "zh_CN", + "Directory": "locale_zh_CN", "DefaultDir": "zh_CN", "Components": [ { @@ -6456,13 +6296,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_zh_CN_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\zh_CN\\BOINC-Client.mo" }, { - "File": "LOCALE_zh_CN_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\zh_CN\\BOINC-Manager.mo" } ] @@ -6470,7 +6306,7 @@ ] }, { - "Directory": "zh_TW", + "Directory": "locale_zh_TW", "DefaultDir": "zh_TW", "Components": [ { @@ -6478,13 +6314,9 @@ "Attributes": 256, "Files": [ { - "File": "LOCALE_zh_TW_BOINC-Client.mo", - "FileName": "BOINC-Client.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\zh_TW\\BOINC-Client.mo" }, { - "File": "LOCALE_zh_TW_BOINC-Manager.mo", - "FileName": "BOINC-Manager.mo", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\locale\\zh_TW\\BOINC-Manager.mo" } ] @@ -6509,13 +6341,6 @@ "Attributes": 256, "Condition": "ENABLEPROTECTEDAPPLICATIONEXECUTION3 = 1", "CreateFolder": true, - "Files": [ - { - "File": "boinc.exe1", - "FileName": "boinc.exe", - "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boinc.exe" - } - ], "ServiceControl": [ { "ServiceControl": "BOINC", @@ -6546,8 +6371,6 @@ "CreateFolder": true, "Files": [ { - "File": "boinc.exe", - "FileName": "boinc.exe", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boinc.exe" } ] @@ -6558,8 +6381,6 @@ "Attributes": 256, "Files": [ { - "File": "boinccmd.exe", - "FileName": "boinccmd.exe", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boinccmd.exe" } ] @@ -6570,13 +6391,9 @@ "Attributes": 256, "Files": [ { - "File": "copying", - "FileName": "COPYING", "FilePath": "..\\COPYING" }, { - "File": "copyright", - "FileName": "COPYRI~1|COPYRIGHT", "FilePath": "..\\COPYRIGHT" } ] @@ -6587,8 +6404,6 @@ "Attributes": 256, "Files": [ { - "File": "boincmgr.exe", - "FileName": "boincmgr.exe", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boincmgr.exe" } ], @@ -6670,18 +6485,12 @@ "Attributes": 264, "Files": [ { - "File": "boinc_logo_black.jpg", - "FileName": "BOINC_~1.JPG|boinc_logo_black.jpg", "FilePath": "..\\doc\\logo\\boinc_logo_black.jpg" }, { - "File": "boincscr.exe", - "FileName": "boincscr.exe", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boincscr.exe" }, { - "File": "liberationsans_regular.ttf", - "FileName": "LIBERA~1.TTF|LiberationSans-Regular.ttf", "FilePath": "..\\api\\ttf\\liberation-fonts-ttf-2.00.0\\LiberationSans-Regular.ttf", "IsFont": true } @@ -6691,11 +6500,8 @@ "Feature_": "BOINC", "Component": "_BOINCSvcCtrl", "Attributes": 256, - "CreateFolder": true, "Files": [ { - "File": "boincsvcctrl.exe", - "FileName": "BOINCS~1.EXE|boincsvcctrl.exe", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boincsvcctrl.exe" } ] @@ -6706,8 +6512,6 @@ "Attributes": 256, "Files": [ { - "File": "boinctray.exe", - "FileName": "BOINCT~1.EXE|boinctray.exe", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boinctray.exe" } ], @@ -6797,8 +6601,6 @@ "Attributes": 256, "Files": [ { - "File": "boinc.scr", - "FileName": "boinc.scr", "FilePath": "..\\win_build\\Build\\%%PLATFORM%%\\%%CONFIGURATION%%\\boinc.scr" } ] @@ -9934,10 +9736,12 @@ "Description": "ID_STRING39" }, { - "Condition": "AdminUser", + "Condition": "Privileged", "Description": "IDPROP_EXPRESS_LAUNCH_CONDITION_ADMIN" } ], + "Listbox": [ + ], "Property": [ { "Property": "ARPCOMMENTS", @@ -10113,7 +9917,7 @@ }, { "Property": "_IsMaintenance", - "Value": "Install" + "Value": "Reinstall" } ], "TextStyle": [ @@ -10339,24 +10143,24 @@ "Upgrade": [ { "UpgradeCode": "{76DD37FC-EE51-408D-9FB5-3D59FC8ED22A}", - "VersionMin": "0000.0000.0000", - "VersionMax": "9999.9999.9999", + "VersionMin": "0.0.0", + "VersionMax": "255.255.65535", "Attributes": 769, "ActionProperty": "ISACTIONPROP2", "Comments": "World Community Grid Upgrade (7.14.2)" }, { "UpgradeCode": "{862B80F6-835D-4F72-8C4F-EE68ED34C6F8}", - "VersionMin": "0000.0000.0000", - "VersionMax": "9999.9999.9999", + "VersionMin": "0.0.0", + "VersionMax": "255.255.65535", "Attributes": 769, "ActionProperty": "ISACTIONPROP1", "Comments": "World Community Grid Upgrade" }, { "UpgradeCode": "{E913E54D-5080-42EC-A312-B21948BA1C02}", - "VersionMin": "0000.0000.0000", - "VersionMax": "9999.9999.9999", + "VersionMin": "0.0.0", + "VersionMax": "255.255.65535", "Attributes": 769, "ActionProperty": "ACTPROP_E913E54D_5080_42EC_A312_B21948BA1C02", "Comments": "General Upgrade" diff --git a/installer/darice.cub b/installer/darice.cub new file mode 100644 index 0000000000000000000000000000000000000000..ea0ff829091c22b7dd253b6cf00baa7c80794fd9 GIT binary patch literal 696320 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 z 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�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. + +import os +import sys + +def main(): + if len(sys.argv) != 4: + print("Usage: msi_validation.py ") + sys.exit(1) + + msival2_path = sys.argv[1] + if not os.path.exists(msival2_path): + print(f"'{msival2_path}' not found") + sys.exit(1) + + msi_path = sys.argv[2] + if not os.path.exists(msi_path): + print(f"'{msi_path}' not found") + sys.exit(1) + + cub_path = sys.argv[3] + if not os.path.exists(cub_path): + print("'{cub_path}' not found") + sys.exit(1) + + ignore_list = [ + "ICE Type Description", + "ICE07 WARNING '_BOINCScreensaver_LiberationSans_Regular.ttf' is a Font and must be installed to the FontsFolder. Current Install Directory: 'INSTALLDIR'", + "ICE43 ERROR Component _BOINCManagerStartMenu has non-advertised shortcuts. It should use a registry key under HKCU as its KeyPath, not a file.", + "ICE57 ERROR Component '_ScreensaverEnableNT' has both per-user and per-machine data with a per-machine KeyPath.", + "ICE57 ERROR Component '_BOINCManagerStartup' has both per-user and per-machine data with a per-machine KeyPath.", + "ICE57 ERROR Component '_BOINCManagerStartMenu' has both per-user and per-machine data with a per-machine KeyPath.", + "ICE61 WARNING This product should remove only older versions of itself. The Maximum version is not less than the current product.", + ] + output = os.popen(f'"{msival2_path}" "{msi_path}" "{cub_path}" -f').read() + error_found = False + for line in output.splitlines(): + if line == '' or any(ignore in line for ignore in ignore_list): + continue + error_found = True + print(line) + + if error_found: + print("Validation failed") + sys.exit(1) + + print("Validation succeeded") + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/win_build/installer.vcxproj b/win_build/installer.vcxproj index 831937b390b..46a8abd8719 100644 --- a/win_build/installer.vcxproj +++ b/win_build/installer.vcxproj @@ -13,6 +13,7 @@ .;..;../api;../lib;$(VcpkgRootDir)\installed\arm64-windows-static\include\;%(AdditionalIncludeDirectories) _CONSOLE;%(PreprocessorDefinitions) + MSI_VALIDATE;%(PreprocessorDefinitions) stdcpp17 @@ -67,6 +68,8 @@ + + @@ -99,6 +102,8 @@ + + @@ -148,6 +153,8 @@ + + @@ -181,8 +188,10 @@ + + - + diff --git a/win_build/installer_msi.vcxproj b/win_build/installer_msi.vcxproj index e59b9d438a7..ad8ed80ac23 100644 --- a/win_build/installer_msi.vcxproj +++ b/win_build/installer_msi.vcxproj @@ -25,6 +25,7 @@ + $(SolutionDir)..\installer\boinc.json;$(SolutionDir)..\installer\locale\en.json;$(SolutionDir)Build\x64\$(Configuration)\installer.exe;$(SolutionDir)Build\$(Platform)\$(Configuration)\boinccas.dll $(SolutionDir)Build\x64\$(Configuration)\installer.exe -p $(Platform) $(OutDir)$(TargetName)$(TargetExt)