Skip to content
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

Unpackaged Win32 app using WinUI3 Xaml Island - problems with external fonts referenced in xaml #10054

Open
PetrMinar opened this issue Oct 11, 2024 · 4 comments
Labels
bug Something isn't working needs-triage Issue needs to be triaged by the area owners

Comments

@PetrMinar
Copy link

PetrMinar commented Oct 11, 2024

Describe the bug

<TextBlock Text="Test" FontFamily="file:///c:/font.ttf#font" /> does not work.

It is probably a very old problem that no one tried to fix or find a workaround. It was reported almost five years ago...

WinUI3 Xaml does not support file: as part of Uri. It can be seen in ResourceManager::TryGetLocalResource where only ms-appdata:, ms-appx: and ms-resource: are handled.

That is understandable for UWP applicarions and Packaged Desktop applications (although when they have broadFileSystemAccess it should work too, right?). But it should work for Unpackaged Deskop application.

While searching for workaround I found that

  • ms-appdata: cannot be used because it requires packaged application.
  • ms-appx: and ms-resource: can be used in unpackaged application to reach files in exe directory (and its subdirectories)

ms-appx:///xxx is essentialy transformed to ms-resource:///files/xxx.
ms-resource:///files/xxx uses m_pFallbackResourceProvider and combines xxx with m_pBaseUri. m_pBaseUri is initialized to GetModuleFileName(NULL, applicationDirectory, MAX_PATH) in CommonResourceProvider::Create.

This workaround looks like implementation detail and might stop working in future. And of course is limited to exe directory only. What else should we use?

Steps to reproduce the bug

<TextBlock Text="Test" FontFamily="file:///c:/font.ttf#font" /> does not work.

Expected behavior

<TextBlock Text="Test" FontFamily="file:///c:/font.ttf#font" /> Should work.

Screenshots

No response

NuGet package version

WinUI 3 - Windows App SDK 1.6.1: 1.6.240923002

Windows version

Windows 11 (22H2): Build 22621

Additional context

No response

@PetrMinar PetrMinar added the bug Something isn't working label Oct 11, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the needs-triage Issue needs to be triaged by the area owners label Oct 11, 2024
@DarranRowe
Copy link

Well, there are two things to note about this.
First, it is the component itself that determines if it supports a URI scheme. I would also imagine, in this case, it would be the component that determines how it is referenced.
Second, WinUI 3 itself depends on ms-appx being interpreted as the current application's executable directory or .pri file when unpackaged.

Two examples of this:

//Extract from App.xaml.g.h, generated by the Xaml compiler.

void InitializeComponent()
{
    if (_contentLoaded)
        return;
           
   _contentLoaded = true;

    ::winrt::Windows::Foundation::Uri resourceLocator{ L"ms-appx:///App.xaml" };
    ::winrt::Microsoft::UI::Xaml::Application::LoadComponent(*this, resourceLocator);
}
//Extract from MainWindow.xaml.g.hpp, generated by the Xaml compiler.

template <typename D, typename ... I>
void MainWindowT<D, I...>::InitializeComponent()
{
    if (!_contentLoaded)
    {
        _contentLoaded = true;
        ::winrt::Windows::Foundation::Uri resourceLocator{ L"ms-appx:///MainWindow.xaml" };
        ::winrt::Microsoft::UI::Xaml::Application::LoadComponent(*this, resourceLocator, ComponentResourceLocation::Application);
    }
}

It is therefore tough to believe that Microsoft.UI.Xaml.Application.LoadComponent has been updated to work with unpackaged applications, but no other WinUI 3 component wouldn't have been updated for unpackaged application support. But yes, this behaviour really should be documented.

@PetrMinar
Copy link
Author

@DarranRowe Thank you for your response

First, it is the component itself that determines if it supports a URI scheme.
In this case the component is Microsoft::UI::Xaml::Media::FontFamily that uses builtin ResourceManager (probably shared by whole Microsoft-UI-Xaml framework). ResourceManager only supports the three mentioned Uri formats (can be seen in ResourceManager::TryGetLocalResource).

Second, WinUI 3 itself depends on ms-appx being interpreted as the current application's executable directory
Hmm that is more interesting... the code itself is in App.xaml.g.h / MainWindow.xaml.g.hpp and is generated during project build. So it "hard-wired" in all applications using WinUI3 and therefore it cannot be changed in future unless all existing apps are broken. Now I feel relieved to use it in production code, because that wouldn't happen... or would it?

But yes, this behaviour really should be documented.
Yes, I agree.

All this is only part of the problem. What if I want to target a file outside the exe directory? Should I copy it there? That sounds completly wrong...

@DarranRowe
Copy link

Now I feel relieved to use it in production code, because that wouldn't happen... or would it?

I would be very surprised if support for unpackaged applications is dropped. This is especially true because of the scenarios that the Xaml Islands are meant to be used in and the Xaml Islands sample is set up to use the Xaml compiler.
The documentation for MRT Core really feel like it was copied from the original MRT documentation prior to unpackaged support was introduced.

What if I want to target a file outside the exe directory?

This all depends. If your application is attempting to access a font outside of the .exe directory with the path hard coded in the Xaml, then you have bigger issues there. Remember, it is possible to run Windows setup and get it to set the system drive to something other than C. This would also force some other things which is problematic in an unpackaged application.
If you are activating an instance of the FontFamily runtime class via code, then yes, I understand why the lack of the file uri scheme is a problem. This is still one of the sticking points from the origins of WinUI 3, since UWP Xaml just wouldn't load a font from outside of the package.

@PetrMinar
Copy link
Author

I would be very surprised if support for unpackaged applications is dropped.
That is not what I had in mind.... Only that it is not possible for Microsoft to change ms-appx being interpreted as the current application's executable directory. At least not for already existing apps... So it is somewhat safe to use although not documented.

If your application is attempting to access a font outside of the .exe directory with the path hard coded in the Xaml, then...
Our application does not have an hardcoded path in xaml. Instead the path would be initialized in app resource dictionary by c++ code. Our app ditrectory structure looks like this:

.../AppDir/Bin32
.../AppDir/Bin64
.../AppDir/SharedResources

and the ttf font is in SharedResources that is used by both 32 bit executable and 64 bit executable. So it is outside the exe directory... Luckily just now it is single ttf font (cca 100KB) so our installer will just copy it to both locations (or create hardlink).

This is still one of the sticking points from the origins of WinUI 3, since UWP Xaml just wouldn't load a font from outside of the package.
I understand the reasons. UWP cannot run without packgage and is nicely isolated - it was a non issue back then. But it is limiting in "unpackaged desktop xaml island world"...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs-triage Issue needs to be triaged by the area owners
Projects
None yet
Development

No branches or pull requests

2 participants