-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Font Install #5042
base: master
Are you sure you want to change the base?
Font Install #5042
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
AICLI_LOG(CLI, Info, << "Creating font subkey with name: " << AppInstaller::Utility::ConvertToUTF8(title)); | ||
if (m_scope == Manifest::ScopeEnum::Machine) | ||
{ | ||
m_key.SetValue(title, fileName, REG_SZ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it truly always a 1:1 registry value to file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I believe so. Whenever I do a manual install of a font file, it creates a new registry value. I haven't seen an example where that hasn't happened yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value names must be unique, so we know that isn't an issue. But that leaves actual question in a more verbose form "Is it possible for multiple values to point to the same file, for instance a .ttc?". Maybe it is acceptable for us to install it as a single entry and the DWrite APIs take care of exposing the contents. But have you installed a TTC via explorer and examined the resulting registry changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A TTC also only has exactly one registry value when installed. Having multiple registry values point to the same font file doesn't appear to have any effect on how the font appears in the system.
AICLI_LOG(CLI, Info, << "Creating font subkey with name: " << AppInstaller::Utility::ConvertToUTF8(title)); | ||
if (m_scope == Manifest::ScopeEnum::Machine) | ||
{ | ||
m_key.SetValue(title, fileName, REG_SZ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value names must be unique, so we know that isn't an issue. But that leaves actual question in a more verbose form "Is it possible for multiple values to point to the same file, for instance a .ttc?". Maybe it is acceptable for us to install it as a single entry and the DWrite APIs take care of exposing the contents. But have you installed a TTC via explorer and examined the resulting registry changes?
@@ -69,6 +85,9 @@ namespace AppInstaller::CLI::Font | |||
{ | |||
m_key.SetValue(title, destinationPath, REG_SZ); | |||
} | |||
|
|||
AICLI_LOG(CLI, Info, << "Moving font file to: " << destinationPath); | |||
AppInstaller::Filesystem::RenameFile(filePath, destinationPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this handle the case where the target file already exists? If it deletes that file, this is probably bad. We should choose a new name if it does already exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a check to see if the installation will overwrite an existing font file. If that is true, I show an error message. This is only a temporary solution for now, we need a proper way to bring back those font files that we remove.
if (std::filesystem::exists(existingFontFilePath)) | ||
{ | ||
AICLI_LOG(CLI, Info, << "Removing existing font file at:" << existingFontFilePath); | ||
std::filesystem::remove(existingFontFilePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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:
- Create a temporary portable tracking database for the file and registry changes (probably requires some amount of addition to the tracked things)
- Set up a resume that can leverage the database to revert to the previous state
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 IOperationSteps
that you populate as you go. On exiting the operation, you either invoke Complete
or Revert
on all of the items, depending on success or failure. In this case, Complete
deletes the renamed file, while Revert
renames it back to its old state.
const auto& destinationPath = m_installLocation / fileName; | ||
if (m_key[fontFile.Title].has_value()) | ||
{ | ||
if (!std::filesystem::exists(m_key[fontFile.Title]->GetValue<Registry::Value::Type::String>())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Retrieve m_key[fontFile.Title]
once rather than in both conditions.
AICLI_LOG(CLI, Info, << "Existing font subkey found:" << AppInstaller::Utility::ConvertToUTF8(title)); | ||
std::filesystem::path existingFontFilePath = { m_key[title]->GetValue<Registry::Value::Type::String>() }; | ||
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>() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The 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.
|
||
for (const auto& file : filePaths) | ||
for (std::filesystem::path filePath : filePaths) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (std::filesystem::path filePath : filePaths) | |
for (const std::filesystem::path& filePath : filePaths) |
Did we need a copy?
@@ -132,6 +132,20 @@ namespace AppInstaller::Registry | |||
|
|||
return true; | |||
} | |||
|
|||
bool TryDeleteRegistryValueData(const wil::shared_hkey& key, const std::wstring& valueName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be called DeleteRegistryValueIfPresent
. Try
shouldn't throw, even on failure.
Related to: #392, #4842
Changes:
Adds Support for installing a font.
FontInstaller
that does two things based on the scope. place the file in the fonts directory, and writes the subkey entry in the Fonts Registry based on the title of the file.IsFontSupported
function that calls upon the Dwrite Analyze function to determine if the system can support installing the font. In the flow, if this fails, we error out with no way to override.font install
command but currently only supports installing from a local manifest. This means that the same font manifest will work for regularinstall
.Tests:
Microsoft Reviewers: Open in CodeFlow