-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Font Install #5042
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Font Install #5042
Changes from all commits
aae3caa
42e53bf
4efa09f
aeab647
e73e8af
8678d12
745a4ed
b5f3c16
bc8221f
8f7a47d
fa1c995
9550aed
d21f3ee
1491913
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
| #include "pch.h" | ||
| #include "ExecutionContext.h" | ||
| #include "FontInstaller.h" | ||
| #include <winget/Fonts.h> | ||
| #include <winget/Manifest.h> | ||
| #include <winget/ManifestCommon.h> | ||
| #include <winget/Filesystem.h> | ||
| #include <AppInstallerErrors.h> | ||
| #include <AppInstallerRuntime.h> | ||
|
|
||
| namespace AppInstaller::CLI::Font | ||
| { | ||
| namespace | ||
| { | ||
| constexpr std::wstring_view s_FontsPathSubkey = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; | ||
| constexpr std::wstring_view s_TrueType = L" (TrueType)"; | ||
|
|
||
| bool IsTrueTypeFont(DWRITE_FONT_FILE_TYPE fileType) | ||
| { | ||
| return ( | ||
| fileType == DWRITE_FONT_FILE_TYPE_TRUETYPE || | ||
| fileType == DWRITE_FONT_FILE_TYPE_TRUETYPE_COLLECTION | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| FontFile::FontFile(std::filesystem::path filePath, DWRITE_FONT_FILE_TYPE fileType) | ||
| : FilePath(std::move(filePath)), FileType(fileType) | ||
| { | ||
| Title = AppInstaller::Fonts::GetFontFileTitle(FilePath); | ||
|
|
||
| if (IsTrueTypeFont(FileType)) | ||
| { | ||
| Title += s_TrueType; | ||
| } | ||
| } | ||
|
|
||
| FontInstaller::FontInstaller(Manifest::ScopeEnum scope) : m_scope(scope) | ||
| { | ||
| if (scope == Manifest::ScopeEnum::Machine) | ||
| { | ||
| m_installLocation = Runtime::GetPathTo(Runtime::PathName::FontsMachineInstallLocation); | ||
| m_key = Registry::Key::Create(HKEY_LOCAL_MACHINE, std::wstring{ s_FontsPathSubkey }); | ||
| } | ||
| else | ||
| { | ||
| m_installLocation = Runtime::GetPathTo(Runtime::PathName::FontsUserInstallLocation); | ||
| m_key = Registry::Key::Create(HKEY_CURRENT_USER, std::wstring{ s_FontsPathSubkey }); | ||
| } | ||
| } | ||
|
|
||
| bool FontInstaller::EnsureInstall() | ||
| { | ||
| for (auto& fontFile : m_fontFiles) | ||
| { | ||
| if (m_key[fontFile.Title].has_value()) | ||
| { | ||
| if (!std::filesystem::exists(m_key[fontFile.Title]->GetValue<Registry::Value::Type::String>())) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Retrieve |
||
| { | ||
| AICLI_LOG(CLI, Info, << "Removing existing font value as font file does not exist."); | ||
| m_key.DeleteValue(fontFile.Title); | ||
| } | ||
| else | ||
| { | ||
| AICLI_LOG(CLI, Info, << "Existing font value found: " << AppInstaller::Utility::ConvertToUTF8(fontFile.Title)); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| std::filesystem::path destinationPath = m_installLocation / fontFile.FilePath.filename(); | ||
| auto initialStem = fontFile.FilePath.stem(); | ||
| auto extension = fontFile.FilePath.extension(); | ||
|
|
||
| // If a file exists at the destination path, make the filename unique. | ||
| int index = 0; | ||
| while (std::filesystem::exists(destinationPath)) | ||
| { | ||
| std::filesystem::path unique = { "_" + std::to_string(index) }; | ||
| auto duplicateStem = initialStem; | ||
| duplicateStem += unique; | ||
| duplicateStem += extension; | ||
| destinationPath = m_installLocation / duplicateStem; | ||
| index++; | ||
| } | ||
|
|
||
| fontFile.DestinationPath = std::move(destinationPath); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void FontInstaller::Install() | ||
| { | ||
| bool isMachineScope = m_scope == Manifest::ScopeEnum::Machine; | ||
|
|
||
| for (const auto& fontFile : m_fontFiles) | ||
| { | ||
| AICLI_LOG(CLI, Info, << "Creating font value with name : " << AppInstaller::Utility::ConvertToUTF8(fontFile.Title)); | ||
| if (isMachineScope) | ||
| { | ||
| m_key.SetValue(fontFile.Title, fontFile.DestinationPath.filename(), REG_SZ); | ||
| } | ||
| else | ||
| { | ||
| m_key.SetValue(fontFile.Title, fontFile.DestinationPath, REG_SZ); | ||
| } | ||
| } | ||
|
|
||
| for (const auto& fontFile : m_fontFiles) | ||
| { | ||
| AICLI_LOG(CLI, Info, << "Moving font file to: " << fontFile.DestinationPath); | ||
| AppInstaller::Filesystem::RenameFile(fontFile.FilePath, fontFile.DestinationPath); | ||
| } | ||
| } | ||
|
|
||
| void FontInstaller::Uninstall() | ||
| { | ||
| for (const auto& fontFile : m_fontFiles) | ||
| { | ||
| if (m_key[fontFile.Title].has_value()) | ||
| { | ||
| AICLI_LOG(CLI, Info, << "Existing font value found:" << AppInstaller::Utility::ConvertToUTF8(fontFile.Title)); | ||
| std::filesystem::path existingFontFilePath = { m_key[fontFile.Title]->GetValue<Registry::Value::Type::String>() }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You will want to assign the path from a wide string; I think there is a registry value to get that directly. |
||
|
|
||
| if (m_scope == Manifest::ScopeEnum::Machine) | ||
| { | ||
| // Font entries in the HKEY_LOCAL_MACHINE hive only have the filename specified as the value. Prepend install location. | ||
| existingFontFilePath = m_installLocation / existingFontFilePath; | ||
| } | ||
|
|
||
| if (std::filesystem::exists(existingFontFilePath)) | ||
| { | ||
| AICLI_LOG(CLI, Info, << "Removing existing font file at:" << existingFontFilePath); | ||
| std::filesystem::remove(existingFontFilePath); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the operation fails, we cannot revert this. Much like my comment on the rest of the operation being reverted on failure, we want some mechanism to put things back the way they were. I would think that to make it maximally recoverable, one would need to:
But I don't think we need to be that extreme (handling full on process termination). A more modest approach would have a vector of |
||
| } | ||
|
|
||
| AICLI_LOG(CLI, Info, << "Deleting registry value:" << existingFontFilePath); | ||
| m_key.DeleteValue(fontFile.Title); | ||
| } | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.