From 3ba45277781b39b228788405c1905169f6eb8fe9 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Wed, 23 Feb 2022 00:00:16 -0500 Subject: [PATCH 01/14] Migrate DWrite Factory to managed. Contributes to dotnet/wpf#5305 --- .../Windows/Interop.HRESULT_FROM_WIN32.cs | 19 ++ .../Windows/Kernel32/Interop.FreeLibrary.cs | 14 + .../Kernel32/Interop.GetModuleHandle.cs | 14 + .../Kernel32/Interop.GetProcAddress.cs | 14 + .../Windows/Kernel32/Interop.LoadLibrary.cs | 14 + .../Windows/Kernel32/Interop.LoadLibraryEx.cs | 16 + .../CPP/DWriteWrapper/Factory.cpp | 286 +----------------- .../CPP/DWriteWrapper/Factory.h | 161 +--------- .../CPP/DWriteWrapper/Font.cpp | 2 +- .../CPP/DWriteWrapper/FontFileEnumerator.cpp | 2 +- .../CPP/DWriteWrapper/TextAnalyzer.cpp | 7 +- .../CPP/DWriteWrapper/TextAnalyzer.h | 8 +- .../src/DirectWriteForwarder/main.cpp | 96 +----- .../Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs | 15 + .../Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs | 9 + .../internal/Interop/DWrite/IDWriteFactory.cs | 102 +++++++ .../Interop/DWrite/IDWriteFontCollection.cs | 39 +++ .../DWrite/IDWriteFontCollectionLoader.cs | 39 +++ .../Interop/DWrite/IDWriteFontFace.cs | 39 +++ .../Interop/DWrite/IDWriteFontFile.cs | 39 +++ .../Interop/DWrite/IDWriteFontFileLoader.cs | 39 +++ .../Interop/DWrite/IDWriteTextAnalyzer.cs | 39 +++ .../MS/internal/Interop/IUnknown.cs | 13 + .../Interop/NativePointerCriticalHandle.cs | 37 +++ .../MS/internal/Shaping/TypefaceMap.cs | 2 +- .../Text/TextInterface/DWriteLoader.cs | 95 ++++++ .../internal/Text/TextInterface/DWriteUtil.cs | 60 ++++ .../MS/internal/Text/TextInterface/Factory.cs | 247 +++++++++++++++ .../src/PresentationCore/ModuleInitializer.cs | 8 + .../PresentationCore/PresentationCore.csproj | 28 ++ 30 files changed, 954 insertions(+), 549 deletions(-) create mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs create mode 100644 src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs new file mode 100644 index 00000000000..2d225456e80 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +internal static partial class Interop +{ + // Implementation of HRESULT_FROM_WIN32 macro + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static int HRESULT_FROM_WIN32(int errorCode) + { + if (errorCode <= 0 || (errorCode & 0x80000000) == 0x80000000) + { + return errorCode; + } + + return (errorCode & 0x0000FFFF) | unchecked((int)0x80070000); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs new file mode 100644 index 00000000000..b98655a9132 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32, SetLastError = true, ExactSpelling = true)] + internal static extern int FreeLibrary(IntPtr hModule); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs new file mode 100644 index 00000000000..a963c3962d9 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + internal static extern IntPtr GetModuleHandleW(string moduleName); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs new file mode 100644 index 00000000000..cc52de7f977 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] + internal static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs new file mode 100644 index 00000000000..9cf0ac772c0 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + internal static extern IntPtr LoadLibraryW(string libFilename); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs new file mode 100644 index 00000000000..3f47dbc8c3d --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Kernel32 + { + public const int LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; + + [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] + internal static extern IntPtr LoadLibraryExW(string lpwLibFileName, IntPtr hFile, uint dwFlags); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.cpp index f96c34564fa..03b56e99336 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.cpp @@ -18,281 +18,14 @@ extern void *GetDWriteCreateFactoryFunctionPointer(); namespace MS { namespace Internal { namespace Text { namespace TextInterface { - Factory^ Factory::Create( - FactoryType factoryType, - IFontSourceCollectionFactory^ fontSourceCollectionFactory, - IFontSourceFactory^ fontSourceFactory - ) - { - return gcnew Factory(factoryType, fontSourceCollectionFactory, fontSourceFactory); - } - - Factory::Factory( - FactoryType factoryType, - IFontSourceCollectionFactory^ fontSourceCollectionFactory, - IFontSourceFactory^ fontSourceFactory - ) : CriticalHandle(IntPtr::Zero) - { - Initialize(factoryType); - _wpfFontFileLoader = gcnew FontFileLoader(fontSourceFactory); - _wpfFontCollectionLoader = gcnew FontCollectionLoader( - fontSourceCollectionFactory, - _wpfFontFileLoader - ); - - _fontSourceFactory = fontSourceFactory; - - IntPtr pIDWriteFontFileLoaderMirror = Marshal::GetComInterfaceForObject( - _wpfFontFileLoader, - IDWriteFontFileLoaderMirror::typeid); - - // Future improvement note: - // This seems a bit hacky, but unclear at this time how to implement this any better. - // When we attempt to unregister these, do we need to keep around the same IntPtr - // representing the result of GetComInterfaceForObject to free it ? Or will it - // be the same if we call it again? - - - - HRESULT hr = _pFactory->RegisterFontFileLoader( - (IDWriteFontFileLoader *)pIDWriteFontFileLoaderMirror.ToPointer() - ); - - Marshal::Release(pIDWriteFontFileLoaderMirror); - - ConvertHresultToException(hr, "Factory::Factory"); - - IntPtr pIDWriteFontCollectionLoaderMirror = Marshal::GetComInterfaceForObject( - _wpfFontCollectionLoader, - IDWriteFontCollectionLoaderMirror::typeid); - hr = _pFactory->RegisterFontCollectionLoader( - (IDWriteFontCollectionLoader *)pIDWriteFontCollectionLoaderMirror.ToPointer() - ); - - Marshal::Release(pIDWriteFontCollectionLoaderMirror); - - ConvertHresultToException(hr, "Factory::Factory"); - } - - __declspec(noinline) void Factory::Initialize( - FactoryType factoryType - ) - { - IUnknown* factoryTemp; - DWRITECREATEFACTORY pfnDWriteCreateFactory = (DWRITECREATEFACTORY)GetDWriteCreateFactoryFunctionPointer(); - - HRESULT hr = (*pfnDWriteCreateFactory)( - DWriteTypeConverter::Convert(factoryType), - __uuidof(IDWriteFactory), - &factoryTemp - ); - - ConvertHresultToException(hr, "Factory::Initialize"); - - _pFactory = (IDWriteFactory*)factoryTemp; - } - - __declspec(noinline) bool Factory::ReleaseHandle() - { - if (_wpfFontCollectionLoader != nullptr) - { - IntPtr pIDWriteFontCollectionLoaderMirror = Marshal::GetComInterfaceForObject( - _wpfFontCollectionLoader, - IDWriteFontCollectionLoaderMirror::typeid); - - _pFactory->UnregisterFontCollectionLoader((IDWriteFontCollectionLoader *)pIDWriteFontCollectionLoaderMirror.ToPointer()); - Marshal::Release(pIDWriteFontCollectionLoaderMirror); - _wpfFontCollectionLoader = nullptr; - } - - if (_wpfFontFileLoader != nullptr) - { - IntPtr pIDWriteFontFileLoaderMirror = Marshal::GetComInterfaceForObject( - _wpfFontFileLoader, - IDWriteFontFileLoaderMirror::typeid); - - _pFactory->UnregisterFontFileLoader((IDWriteFontFileLoader *)pIDWriteFontFileLoaderMirror.ToPointer()); - Marshal::Release(pIDWriteFontFileLoaderMirror); - _wpfFontFileLoader = nullptr; - } - - if (_pFactory != NULL) - { - _pFactory ->Release(); - _pFactory = NULL; - } - - return true; - } - - __declspec(noinline) FontFile^ Factory::CreateFontFile( - System::Uri^ filePathUri - ) - { - IDWriteFontFile* dwriteFontFile = NULL; - HRESULT hr = Factory::CreateFontFile(_pFactory, _wpfFontFileLoader, filePathUri, &dwriteFontFile); - - // If DWrite's CreateFontFileReference fails then try opening the file using WPF's logic. - // The failures that WPF returns are more granular than the HRESULTs that DWrite returns - // thus we use WPF's logic to open the file to throw the same exceptions that - // WPF would have thrown before. - if (FAILED(hr)) - { - IFontSource^ fontSource = _fontSourceFactory->Create(filePathUri->AbsoluteUri); - fontSource->TestFileOpenable(); - - } - - //This call is made to prevent this object from being collected and hence get its finalize method called - //While there are others referencing it. - System::GC::KeepAlive(this); - - ConvertHresultToException(hr, "FontFile^ Factory::CreateFontFile"); - - return gcnew FontFile(dwriteFontFile); - - } - - FontFace^ Factory::CreateFontFace( - System::Uri^ filePathUri, - unsigned int faceIndex - ) - { - return CreateFontFace( - filePathUri, - faceIndex, - FontSimulations::None - ); - } - - FontFace^ Factory::CreateFontFace( - System::Uri^ filePathUri, - unsigned int faceIndex, - FontSimulations fontSimulationFlags - ) - { - FontFile^ fontFile = CreateFontFile(filePathUri); - DWRITE_FONT_FILE_TYPE dwriteFontFileType; - DWRITE_FONT_FACE_TYPE dwriteFontFaceType; - unsigned int numberOfFaces = 0; - - HRESULT hr; - if (fontFile->Analyze( - dwriteFontFileType, - dwriteFontFaceType, - numberOfFaces, - hr - )) - { - if (faceIndex >= numberOfFaces) - { - throw gcnew System::ArgumentOutOfRangeException("faceIndex"); - } - - unsigned char dwriteFontSimulationsFlags = DWriteTypeConverter::Convert(fontSimulationFlags); - IDWriteFontFace* dwriteFontFace = NULL; - IDWriteFontFile* dwriteFontFile = fontFile->DWriteFontFileNoAddRef; - - HRESULT hr = _pFactory->CreateFontFace( - dwriteFontFaceType, - 1, - &dwriteFontFile, - faceIndex, - (DWRITE_FONT_SIMULATIONS) dwriteFontSimulationsFlags, - &dwriteFontFace - ); - System::GC::KeepAlive(fontFile); - System::GC::KeepAlive(this); - - ConvertHresultToException(hr, "FontFace^ Factory::CreateFontFace"); - - return gcnew FontFace(dwriteFontFace); - } - - // This path is here because there is a behavior mismatch between DWrite and WPF. - // If a directory was given instead of a font uri WPF previously throws - // System.UnauthorizedAccessException. We handle most of the exception behavior mismatch - // in FontFile^ Factory::CreateFontFile by opening the file using WPF's previous (prior to DWrite integration) logic if - // CreateFontFileReference fails (please see comments in FontFile^ Factory::CreateFontFile). - // However in this special case DWrite's CreateFontFileReference will succeed if given - // a directory instead of a font file and it is the Analyze() call will fail returning DWRITE_E_FILEFORMAT. - // Thus, incase the hr returned from Analyze() was DWRITE_E_FILEFORMAT we do as we did in FontFile^ Factory::CreateFontFile - // to try and open the file using WPF old logic and throw System.UnauthorizedAccessException as WPF used to do. - // If a file format exception is expected then opening the file should succeed and ConvertHresultToException() - // Should throw the correct exception. - // A final note would be that this overhead is only incurred in error conditions and so the normal execution path should - // not be affected. - else - { - if (hr == DWRITE_E_FILEFORMAT) - { - IFontSource^ fontSource = _fontSourceFactory->Create(filePathUri->AbsoluteUri); - fontSource->TestFileOpenable(); - } - ConvertHresultToException(hr, "FontFace^ Factory::CreateFontFace"); - } - - return nullptr; - } - - FontCollection^ Factory::GetSystemFontCollection() - { - return GetSystemFontCollection(false); - } - - __declspec(noinline) FontCollection^ Factory::GetSystemFontCollection( - bool checkForUpdates - ) - { - IDWriteFontCollection* dwriteFontCollection = NULL; - HRESULT hr = _pFactory->GetSystemFontCollection( - &dwriteFontCollection, - checkForUpdates - ); - System::GC::KeepAlive(this); - - ConvertHresultToException(hr, "FontCollection^ Factory::GetSystemFontCollection"); - - return gcnew FontCollection(dwriteFontCollection); - } - - __declspec(noinline) FontCollection^ Factory::GetFontCollection(System::Uri^ uri) - { - System::String^ uriString = uri->AbsoluteUri; - IDWriteFontCollection* dwriteFontCollection = NULL; - pin_ptr uriPathWChar = PtrToStringChars(uriString); - - IntPtr pIDWriteFontCollectionLoaderMirror = Marshal::GetComInterfaceForObject( - _wpfFontCollectionLoader, - IDWriteFontCollectionLoaderMirror::typeid); - - IDWriteFontCollectionLoader * pIDWriteFontCollectionLoader = - (IDWriteFontCollectionLoader *)pIDWriteFontCollectionLoaderMirror.ToPointer(); - - HRESULT hr = _pFactory->CreateCustomFontCollection( - pIDWriteFontCollectionLoader, - uriPathWChar, - (uriString->Length+1) * sizeof(WCHAR), - &dwriteFontCollection - ); - - Marshal::Release(pIDWriteFontCollectionLoaderMirror); - - System::GC::KeepAlive(this); - - ConvertHresultToException(hr, "FontCollection^ Factory::GetFontCollection"); - - return gcnew FontCollection(dwriteFontCollection); - } - - HRESULT Factory::CreateFontFile( + HRESULT InternalFactory::CreateFontFile( IDWriteFactory* factory, FontFileLoader^ fontFileLoader, System::Uri^ filePathUri, __out IDWriteFontFile** dwriteFontFile ) { - bool isLocal = Factory::IsLocalUri(filePathUri); + bool isLocal = InternalFactory::IsLocalUri(filePathUri); HRESULT hr = E_FAIL; if (isLocal) @@ -402,23 +135,10 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface return hr; } - __declspec(noinline) void Factory::CleanupTimeStampCache() + __declspec(noinline) void InternalFactory::CleanupTimeStampCache() { _timeStampCacheCleanupOp = nullptr; _timeStampCache->Clear(); } - __declspec(noinline) TextAnalyzer^ Factory::CreateTextAnalyzer() - { - IDWriteTextAnalyzer* textAnalyzer = NULL; - HRESULT hr = _pFactory->CreateTextAnalyzer(&textAnalyzer); - System::GC::KeepAlive(this); - ConvertHresultToException(hr, "TextAnalyzer^ Factory::CreateTextAnalyzer"); - return gcnew TextAnalyzer(textAnalyzer); - } - - bool Factory::IsInvalid::get() - { - return (_pFactory == NULL); - } }}}}//MS::Internal::Text::TextInterface diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.h b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.h index 894c1e9278f..e49f9bb81a8 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.h +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Factory.h @@ -25,159 +25,18 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface /// /// The root factory interface for all DWrite objects. /// - private ref class Factory sealed : public CriticalHandle + private ref class InternalFactory abstract sealed { private: - - /// - /// A pointer to the wrapped DWrite factory object. - /// - IDWriteFactory* _pFactory; - - /// - /// Constructs a factory object. - /// - /// Identifies whether the factory object will be shared or isolated. - /// A factory object that will create managed FontSourceCollection - /// objects that will be utilized to load embedded fonts. - /// A factory object that will create managed FontSource - /// objects that will be utilized to load embedded fonts. - /// - /// The factory just created. - /// - Factory( - FactoryType factoryType, - IFontSourceCollectionFactory^ fontSourceCollectionFactory, - IFontSourceFactory^ fontSourceFactory - ); - - /// - /// Initializes a factory object. - /// - /// Identifies whether the factory object will be shared or isolated. - void Initialize(FactoryType factoryType); - - /// - /// The custom loader used by WPF to load font collections. - /// - FontCollectionLoader^ _wpfFontCollectionLoader; - - /// - /// The custom loader used by WPF to load font files. - /// - FontFileLoader^ _wpfFontFileLoader; - - IFontSourceFactory^ _fontSourceFactory; - [ThreadStatic] - static Dictionary^ _timeStampCache; - + static Dictionary^ _timeStampCache; + [ThreadStatic] static DispatcherOperation^ _timeStampCacheCleanupOp; - - static void CleanupTimeStampCache(); - - protected: - - virtual bool ReleaseHandle() override; + static void CleanupTimeStampCache(); internal: - property IDWriteFactory* DWriteFactoryAddRef - { - IDWriteFactory* get() - { - _pFactory->AddRef(); - return _pFactory; - } - } - - /// - /// Creates a DirectWrite factory object that is used for subsequent creation of individual DirectWrite objects. - /// - /// Identifies whether the factory object will be shared or isolated. - /// A factory object that will create managed FontSourceCollection - /// objects that will be utilized to load embedded fonts. - /// A factory object that will create managed FontSource - /// objects that will be utilized to load embedded fonts. - /// - /// The factory just created. - /// - static Factory^ Create( - FactoryType factoryType, - IFontSourceCollectionFactory^ fontSourceCollectionFactory, - IFontSourceFactory^ fontSourceFactory - ); - - - /// - /// Creates a font file object from a local font file. - /// - /// file path uri. - /// - /// Newly created font file object, or NULL in case of failure. - /// - FontFile^ CreateFontFile(System::Uri^ filePathUri); - - /// - /// Creates a font face object. - /// - /// The file path of the font face. - /// The zero based index of a font face in cases when the font files contain a collection of font faces. - /// If the font files contain a single face, this value should be zero. - /// Font face simulation flags for algorithmic emboldening and italicization. - /// - /// Newly created font face object, or NULL in case of failure. - /// - FontFace^ CreateFontFace( - System::Uri^ filePathUri, - unsigned int faceIndex, - FontSimulations fontSimulationFlags - ); - - /// - /// Creates a font face object. - /// - /// The file path of the font face. - /// The zero based index of a font face in cases when the font files contain a collection of font faces. - /// If the font files contain a single face, this value should be zero. - /// - /// Newly created font face object, or NULL in case of failure. - /// - FontFace^ CreateFontFace( - System::Uri^ filePathUri, - unsigned int faceIndex - ); - - /// - /// Gets a font collection representing the set of installed fonts. - /// - /// - /// The system font collection. - /// - FontCollection^ GetSystemFontCollection(); - - /// - /// Gets a font collection in a custom location. - /// - /// The uri of the font collection. - /// - /// The font collection. - /// - FontCollection^ GetFontCollection(System::Uri^ uri); - - /// - /// Gets a font collection representing the set of installed fonts. - /// - /// If this parameter is true, the function performs an immediate check for changes to the set of - /// installed fonts. If this parameter is FALSE, the function will still detect changes if the font cache service is running, but - /// there may be some latency. For example, an application might specify TRUE if it has itself just installed a font and wants to - /// be sure the font collection contains that font. - /// - /// The system font collection. - /// - FontCollection^ GetSystemFontCollection(bool checkForUpdates); - static bool IsLocalUri(System::Uri^ uri) { return (uri->IsFile && uri->IsLoopback && !uri->IsUnc); @@ -213,18 +72,6 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface return transform; } - - TextAnalyzer^ CreateTextAnalyzer(); - - public: - - virtual property bool IsInvalid - { - #pragma warning (disable : 4950) // The Constrained Execution Region (CER) feature is not supported. - [ReliabilityContract(Consistency::WillNotCorruptState, Cer::Success)] - #pragma warning (default : 4950) // The Constrained Execution Region (CER) feature is not supported. - bool get() override; - } }; }}}}//MS::Internal::Text::TextInterface diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Font.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Font.cpp index 3d8008f5715..d7cc67b2aa4 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Font.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/Font.cpp @@ -306,7 +306,7 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface IDWriteFontFace* fontFace = NULL; HRESULT hr = _font->Value->CreateFontFace(&fontFace); ConvertHresultToException(hr, "FontMetrics^ Font::DisplayMetrics"); - DWRITE_MATRIX transform = Factory::GetIdentityTransform(); + DWRITE_MATRIX transform = InternalFactory::GetIdentityTransform(); hr = fontFace->GetGdiCompatibleMetrics( emSize, pixelsPerDip, diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileEnumerator.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileEnumerator.cpp index 896c016a9e8..9837aca7b9c 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileEnumerator.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/FontFileEnumerator.cpp @@ -46,7 +46,7 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface return E_INVALIDARG; } - return Factory::CreateFontFile( + return InternalFactory::CreateFontFile( _factory, _fontFileLoader, _fontSourceCollectionEnumerator->Current->Uri, diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp index c06c4bc8ddf..604366e1ea8 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp @@ -20,7 +20,7 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface __in_ecount(length) const WCHAR* text, UINT32 length, CultureInfo^ culture, - Factory^ factory, + IDWriteFactory* pDWriteFactory, bool isRightToLeftParagraph, CultureInfo^ numberCulture, bool ignoreUserOverride, @@ -39,9 +39,6 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface IDWriteTextAnalysisSink* pTextAnalysisSink = NULL; IDWriteTextAnalysisSource* pTextAnalysisSource = NULL; - // We obtain an AddRef factory so as not to worry about having to call GC::KeepAlive(factory) - // which puts unnecessary maintenance cost on this code. - IDWriteFactory* pDWriteFactory = factory->DWriteFactoryAddRef; HRESULT hr = S_OK; try { @@ -607,7 +604,7 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface { String^ localeName = cultureInfo->IetfLanguageTag; pin_ptr pLocaleName = Native::Util::GetPtrToStringChars(localeName); - DWRITE_MATRIX transform = Factory::GetIdentityTransform(); + DWRITE_MATRIX transform = InternalFactory::GetIdentityTransform(); if (features != nullptr) { diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.h b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.h index 7e79bf93aca..437ad6ab4ba 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.h +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.h @@ -32,12 +32,6 @@ using namespace MS::Internal::Text::TextInterface::Generics; namespace MS { namespace Internal { namespace Text { namespace TextInterface { - /*******************************************************************************************************************************/ - //Forward declaration of Factory since there was a circular reference between "TextAnalyzer" & "Factory" - ref class Factory; - /*******************************************************************************************************************************/ - - // The 4 delegates below are used to introduce a level of indirection so we can define // the external methods that reference PresentationNative*.dll in PresenationCore.dll. // The reason we define the methods in PresentationCore.dll is that the string values for the @@ -157,7 +151,7 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface __in_ecount(length) const WCHAR* text, UINT32 length, CultureInfo^ culture, - Factory^ factory, + IDWriteFactory* pDWriteFactory, bool isRightToLeftParagraph, CultureInfo^ numberCulture, bool ignoreUserOverride, diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp index 06ba7f1c1b5..3f204965ed1 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp @@ -50,49 +50,7 @@ private ref class NativeWPFDLLLoader sealed // static void LoadDwrite( ) { - // We load dwrite here because it's cleanup logic is different from the other native dlls - // and don't want to abstract that - VOID *pTemp = NULL; - m_hDWrite = System::IntPtr(WPFUtils::LoadDWriteLibraryAndGetProcAddress(&pTemp)); - if (m_hDWrite == IntPtr::Zero) - throw gcnew DllNotFoundException(gcnew String(L"dwrite.dll"), gcnew Win32Exception()); - if (pTemp == NULL) - throw gcnew InvalidOperationException(); - m_pfnDWriteCreateFactory = pTemp; } - - __declspec(noinline) - static void UnloadDWrite() - { - ClearDWriteCreateFactoryFunctionPointer(); - - if (m_hDWrite != IntPtr::Zero) - { - if (!FreeLibrary((HMODULE)(m_hDWrite.ToPointer()))) - { - DWORD lastError = GetLastError(); - Marshal::ThrowExceptionForHR(__HRESULT_FROM_WIN32(lastError)); - } - - m_hDWrite = IntPtr::Zero; - } - } - - static void *GetDWriteCreateFactoryFunctionPointer() - { - return m_pfnDWriteCreateFactory; - } - - static void ClearDWriteCreateFactoryFunctionPointer() - { - m_pfnDWriteCreateFactory = NULL; - } - -private: - - static System::IntPtr m_hDWrite; - - static void *m_pfnDWriteCreateFactory; }; }} // namespace MS.Internal @@ -101,49 +59,14 @@ private class CModuleInitialize public: // Constructor of class CModuleInitialize - __declspec(noinline) CModuleInitialize(void (*cleaningUpFunc)()) + __declspec(noinline) CModuleInitialize() { - MS::Internal::NativeWPFDLLLoader::LoadDwrite(); - // Initialize some global arrays. MS::Internal::TtfDelta::GlobalInit::Init(); MS::Internal::TtfDelta::ControlTableInit::Init(); - atexit(cleaningUpFunc); - } - - // Previously we had this as a class dtor but we found out that - // we can't use a destructor due to an issue with how it's registered to be called on exit: - // A compiler-generated function calls _atexit_m_appdomain(). But that generated function is transparenct, - // which causes a violation because _atexit_m_appdomain() is Critical. - __declspec(noinline) void UnInitialize() - { - MS::Internal::NativeWPFDLLLoader::UnloadDWrite(); - - MS::Internal::NativeWPFDLLLoader::ClearDWriteCreateFactoryFunctionPointer(); - // - // Finalizers run after this dtor so if we unload dwrite now - // we may end up making calls into unloaded code. Yes, this - // is a "leak" but it's only really a leak if no more WPF - // AppDomains are present and it's a single leak since only - // one instance of a version of a CLR may be in proc at - // once. - // - // We could also use a critical finalizer for the handle - // but that requires changing this code quite a bit plus - // if other critical finalizers ever call dwrite code - // we have the same problem again. - // - // MS::Internal::NativeWPFDLLLoader::UnloadDWrite(); - } - - void *GetDWriteCreateFactoryFunctionPointer() - { - return MS::Internal::NativeWPFDLLLoader::GetDWriteCreateFactoryFunctionPointer(); } }; -void CleanUp(); - /// /// This method is a workaround to bug in the compiler. /// The compiler generates a static unsafe method to initialize cmiStartupRunner @@ -152,7 +75,7 @@ void CleanUp(); /// __declspec(noinline) static System::IntPtr CreateCModuleInitialize() { - return System::IntPtr(new CModuleInitialize(CleanUp)); + return System::IntPtr(new CModuleInitialize()); } // Important Note: This variable is declared as System::IntPtr to fool the compiler into creating @@ -160,18 +83,3 @@ __declspec(noinline) static System::IntPtr CreateCModuleInitialize() // Then the generated method is unsafe, fails NGENing and causes Jitting. __declspec(appdomain) static System::IntPtr cmiStartupRunner = CreateCModuleInitialize(); -void CleanUp() -{ - CModuleInitialize* pCmiStartupRunner = static_cast(cmiStartupRunner.ToPointer()); - - pCmiStartupRunner->UnInitialize(); - delete pCmiStartupRunner; - cmiStartupRunner = System::IntPtr(NULL); - -} - -void *GetDWriteCreateFactoryFunctionPointer() -{ - return (static_cast(cmiStartupRunner.ToPointer()))->GetDWriteCreateFactoryFunctionPointer(); -} - diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs new file mode 100644 index 00000000000..614aaa248c1 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs @@ -0,0 +1,15 @@ +namespace MS.Internal.Interop.DWrite +{ + internal enum DWRITE_FONT_FACE_TYPE + { + DWRITE_FONT_FACE_TYPE_CFF, + DWRITE_FONT_FACE_TYPE_TRUETYPE, + DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, + DWRITE_FONT_FACE_TYPE_TYPE1, + DWRITE_FONT_FACE_TYPE_VECTOR, + DWRITE_FONT_FACE_TYPE_BITMAP, + DWRITE_FONT_FACE_TYPE_UNKNOWN, + DWRITE_FONT_FACE_TYPE_RAW_CFF, + DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION = DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs new file mode 100644 index 00000000000..1e71901bff9 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs @@ -0,0 +1,9 @@ +namespace MS.Internal.Interop.DWrite +{ + internal enum DWRITE_FONT_SIMULATIONS + { + DWRITE_FONT_SIMULATIONS_NONE = 0x0000, + DWRITE_FONT_SIMULATIONS_BOLD = 0x0001, + DWRITE_FONT_SIMULATIONS_OBLIQUE = 0x0002, + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs new file mode 100644 index 00000000000..67c868b1a3f --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs @@ -0,0 +1,102 @@ +using System; +using System.Runtime.CompilerServices; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteFactory : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle); + } + } + + internal int GetSystemFontCollection(void* fontCollection, int checkForUpdate) + { + var function = (delegate* unmanaged)Vtbl[3]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle, fontCollection, checkForUpdate); + } + } + + internal int CreateCustomFontCollection(IDWriteFontCollectionLoader* collectionLoader, void* collectionKey, uint collectionKeySize, IDWriteFontCollection** fontCollection) + { + var function = (delegate* unmanaged)Vtbl[4]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle, collectionLoader, collectionKey, collectionKeySize, fontCollection); + } + } + + public int RegisterFontCollectionLoader(IDWriteFontCollectionLoader* fontCollectionLoader) + { + var function = (delegate* unmanaged)Vtbl[5]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle, fontCollectionLoader); + } + } + + internal int CreateFontFace(DWRITE_FONT_FACE_TYPE fontFaceType, uint numberOfFiles, IDWriteFontFile** fontFiles, uint faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) + { + var function = (delegate* unmanaged)Vtbl[9]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle, fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); + } + } + + internal int RegisterFontFileLoader(IDWriteFontFileLoader* fontFileLoader) + { + var function = (delegate* unmanaged)Vtbl[13]; + + fixed (IDWriteFactory* handle = &this) + { + return function(handle, fontFileLoader); + } + } + + internal int CreateTextAnalyzer(IDWriteTextAnalyzer** textAnalyzer) + { + var function = (delegate* unmanaged)Vtbl[21]; + + fixed (IDWriteFactory* handle = &this) + { + int hr = function(handle, textAnalyzer); + + return hr; + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs new file mode 100644 index 00000000000..d35ce0f15e9 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs @@ -0,0 +1,39 @@ +using System; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteFontCollection : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteFontCollection* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteFontCollection* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteFontCollection* handle = &this) + { + return function(handle); + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs new file mode 100644 index 00000000000..7b25ea6e161 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs @@ -0,0 +1,39 @@ +using System; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteFontCollectionLoader : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteFontCollectionLoader* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteFontCollectionLoader* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteFontCollectionLoader* handle = &this) + { + return function(handle); + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs new file mode 100644 index 00000000000..22d91e6da2b --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs @@ -0,0 +1,39 @@ +using System; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteFontFace : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteFontFace* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteFontFace* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteFontFace* handle = &this) + { + return function(handle); + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs new file mode 100644 index 00000000000..4f74e51a2b2 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs @@ -0,0 +1,39 @@ +using System; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteFontFile : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteFontFile* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteFontFile* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteFontFile* handle = &this) + { + return function(handle); + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs new file mode 100644 index 00000000000..fa7fa0ecbf6 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs @@ -0,0 +1,39 @@ +using System; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteFontFileLoader : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteFontFileLoader* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteFontFileLoader* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteFontFileLoader* handle = &this) + { + return function(handle); + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs new file mode 100644 index 00000000000..37fb5b50f92 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs @@ -0,0 +1,39 @@ +using System; + +namespace MS.Internal.Interop.DWrite +{ + internal unsafe struct IDWriteTextAnalyzer : IUnknown + { + private readonly void** Vtbl; + + public int QueryInterface(Guid* guid, void** comObject) + { + var function = (delegate* unmanaged)Vtbl[0]; + + fixed (IDWriteTextAnalyzer* handle = &this) + { + return function(handle, guid, comObject); + } + } + + public uint AddReference() + { + var function = (delegate* unmanaged)Vtbl[1]; + + fixed (IDWriteTextAnalyzer* handle = &this) + { + return function(handle); + } + } + + public uint Release() + { + var function = (delegate* unmanaged)Vtbl[2]; + + fixed (IDWriteTextAnalyzer* handle = &this) + { + return function(handle); + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs new file mode 100644 index 00000000000..d70582942f3 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs @@ -0,0 +1,13 @@ +using System; + +namespace MS.Internal.Interop +{ + internal unsafe interface IUnknown + { + int QueryInterface(Guid* guid, void** comObject); + + uint AddReference(); + + uint Release(); + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs new file mode 100644 index 00000000000..b98ee1fb8bf --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs @@ -0,0 +1,37 @@ +using System; +using System.Runtime.InteropServices; + +namespace MS.Internal.Interop +{ + internal abstract unsafe class NativePointerCriticalHandle : CriticalHandle + where TClass : unmanaged + { + public NativePointerCriticalHandle(IntPtr nativePointer) + : base(IntPtr.Zero) + { + SetHandle(nativePointer); + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + public TClass* Value => (TClass*)handle; + } + + internal unsafe class NativeIUnknownWrapper : NativePointerCriticalHandle + where TClass : unmanaged, IUnknown + { + public NativeIUnknownWrapper(void* nativePointer) + : base((IntPtr)nativePointer) + { + } + + protected override bool ReleaseHandle() + { + Value->Release(); + + handle = IntPtr.Zero; + + return true; + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs index 9961ecde59d..e6f661fde37 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs @@ -120,7 +120,7 @@ TextFormattingMode textFormattingMode (char*)ptext.ToPointer(), (uint)stringLength, culture, - MS.Internal.FontCache.DWriteFactory.Instance, + (MS.Internal.Text.TextInterface.Native.IDWriteFactory*)MS.Internal.FontCache.DWriteFactory.Instance.DWriteFactoryAddRef, isRightToLeftParagraph, digitCulture, ignoreUserOverride, diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs new file mode 100644 index 00000000000..3278f44b07a --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs @@ -0,0 +1,95 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; + +using static Interop; + +namespace MS.Internal.Text.TextInterface +{ + internal static unsafe class DWriteLoader + { + private static IntPtr _dwrite; + private static delegate* unmanaged _dwriteCreateFactory; + + internal static void LoadDWrite() + { + _dwrite = LoadDWriteLibraryAndGetProcAddress(out delegate* unmanaged dwriteCreateFactory); + + if (_dwrite == IntPtr.Zero) + throw new DllNotFoundException("dwrite.dll", new Win32Exception()); + + if (dwriteCreateFactory == null) + throw new InvalidOperationException(); + + _dwriteCreateFactory = dwriteCreateFactory; + } + + internal static void UnloadDWrite() + { + ClearDWriteCreateFactoryFunctionPointer(); + + if (_dwrite != IntPtr.Zero) + { + if (Kernel32.FreeLibrary(_dwrite) != 0) + { + int lastError = Marshal.GetLastPInvokeError(); + Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(lastError)); + } + + _dwrite = IntPtr.Zero; + } + } + + internal static delegate* unmanaged GetDWriteCreateFactoryFunctionPointer() + { + return _dwriteCreateFactory; + } + + private static void ClearDWriteCreateFactoryFunctionPointer() + { + _dwriteCreateFactory = null; + } + + private static IntPtr LoadDWriteLibraryAndGetProcAddress(out delegate* unmanaged DWriteCreateFactory) + { + IntPtr hDWriteLibrary = IntPtr.Zero; + + // KB2533623 introduced the LOAD_LIBRARY_SEARCH_SYSTEM32 flag. It also introduced + // the AddDllDirectory function. We test for presence of AddDllDirectory as an + // indirect evidence for the support of LOAD_LIBRARY_SEARCH_SYSTEM32 flag. + IntPtr hKernel32 = Kernel32.GetModuleHandleW(Libraries.Kernel32); + + if (hKernel32 != IntPtr.Zero) + { + if (Kernel32.GetProcAddress(hKernel32, "AddDllDirectory") != IntPtr.Zero) + { + // All supported platforms newer than Vista SP2 shipped with dwrite.dll. + // On Vista SP2, the .NET servicing process will ensure that a MSU containing + // dwrite.dll will be delivered as a prerequisite - effectively guaranteeing that + // this following call to LoadLibraryEx(dwrite.dll) will succeed, and that it will + // not be susceptible to typical DLL planting vulnerability vectors. + hDWriteLibrary = Kernel32.LoadLibraryExW("dwrite.dll", IntPtr.Zero, Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32); + } + else + { + // LOAD_LIBRARY_SEARCH_SYSTEM32 is not supported on this OS. + // Fall back to using plain ol' LoadLibrary + // There is risk that this call might fail, or that it might be + // susceptible to DLL hijacking. + hDWriteLibrary = Kernel32.LoadLibraryW("dwrite.dll"); + } + } + + if (hDWriteLibrary != IntPtr.Zero) + { + DWriteCreateFactory = (delegate* unmanaged)Kernel32.GetProcAddress(hDWriteLibrary, "DWriteCreateFactory"); + } + else + { + DWriteCreateFactory = null; + } + + return hDWriteLibrary; + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs new file mode 100644 index 00000000000..a5d4eaf39e5 --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs @@ -0,0 +1,60 @@ +namespace MS.Internal.Text.TextInterface +{ + internal static class DWriteUtil + { + private const int COR_E_INVALIDOPERATION = 0x1509; + private const int DWRITE_E_FILENOTFOUND = unchecked((int)0x88985003L); + private const int DWRITE_E_FILEACCESS = unchecked((int)0x88985004L); + private const int DWRITE_E_FILEFORMAT = unchecked((int)0x88985000L); + + internal static void ConvertHresultToException(int hr) + { + + if (hr != 0) + { + if (hr == DWRITE_E_FILENOTFOUND) + { + throw new System.IO.FileNotFoundException(); + } + else if (hr == DWRITE_E_FILEACCESS) + { + throw new System.UnauthorizedAccessException(); + } + else if (hr == DWRITE_E_FILEFORMAT) + { + throw new System.IO.FileFormatException(); + } + else + { + SanitizeAndThrowIfKnownException(hr); + + // ThrowExceptionForHR method returns an exception based on the IErrorInfo of + // the current thread if one is set. When this happens, the errorCode parameter + // is ignored. + // We pass an IntPtr that has a value of -1 so that ThrowExceptionForHR ignores + // IErrorInfo of the current thread. + System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(hr, new System.IntPtr(-1)); + } + } + } + + /// + /// Exceptions known to have security sensitive data are sanitized in this method, + /// by throwing a copy of the original exception without security sensitive data. + /// Or, to put another way - this function acts only on a list of security sensitive HRESULT/IErrorInfo combinations, throwing for matches. + /// The IErrorInfo is taken into account in a call to GetExceptionForHR(HRESULT), see MSDN for more details. + /// + + private static void SanitizeAndThrowIfKnownException(int hr) + { + if (hr == COR_E_INVALIDOPERATION) + { + System.Exception e = System.Runtime.InteropServices.Marshal.GetExceptionForHR(hr); + if (e is System.Net.WebException) + { + throw e; + } + } + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs new file mode 100644 index 00000000000..ea4725d9e6d --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -0,0 +1,247 @@ +using System; +using System.Runtime.InteropServices; +using MS.Internal.Interop; +using MS.Internal.Interop.DWrite; +using MS.Internal.Text.TextInterface.Interfaces; + +namespace MS.Internal.Text.TextInterface +{ + internal unsafe class Factory + { + private const int DWRITE_E_FILEFORMAT = unchecked((int)0x88985000L); + private NativeIUnknownWrapper _factory; + + private IFontSourceFactory _fontSourceFactory; + private FontFileLoader _wpfFontFileLoader; + private FontCollectionLoader _wpfFontCollectionLoader; + + // b859ee5a-d838-4b5b-a2e8-1adc7d93db48 + private static readonly Guid IID_IDWriteFactory = new Guid(0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48); + + private Factory(IDWriteFactory* nativePointer) + { + _factory = new NativeIUnknownWrapper(nativePointer); + } + + internal IDWriteFactory* DWriteFactoryAddRef + { + get + { + _factory.Value->AddReference(); + + return _factory.Value; + } + } + + private Factory(FactoryType factoryType, IFontSourceCollectionFactory fontSourceCollectionFactory, IFontSourceFactory fontSourceFactory) + { + Initialize(factoryType); + + _wpfFontFileLoader = new FontFileLoader(fontSourceFactory); + _wpfFontCollectionLoader = new FontCollectionLoader( + fontSourceCollectionFactory, + _wpfFontFileLoader + ); + + _fontSourceFactory = fontSourceFactory; + + IntPtr pIDWriteFontFileLoaderMirror = Marshal.GetComInterfaceForObject( + _wpfFontFileLoader, + typeof(IDWriteFontFileLoaderMirror)); + + // Future improvement note: + // This seems a bit hacky, but unclear at this time how to implement this any better. + // When we attempt to unregister these, do we need to keep around the same IntPtr + // representing the result of GetComInterfaceForObject to free it ? Or will it + // be the same if we call it again? + + + + int hr = _factory.Value->RegisterFontFileLoader( + (IDWriteFontFileLoader*)pIDWriteFontFileLoaderMirror.ToPointer() + ); + + Marshal.Release(pIDWriteFontFileLoaderMirror); + + DWriteUtil.ConvertHresultToException(hr); + + IntPtr pIDWriteFontCollectionLoaderMirror = Marshal.GetComInterfaceForObject( + _wpfFontCollectionLoader, + typeof(IDWriteFontCollectionLoaderMirror)); + hr = _factory.Value->RegisterFontCollectionLoader( + (IDWriteFontCollectionLoader*)pIDWriteFontCollectionLoaderMirror.ToPointer() + ); + + Marshal.Release(pIDWriteFontCollectionLoaderMirror); + + DWriteUtil.ConvertHresultToException(hr); + } + + private void Initialize(FactoryType factoryType) + { + Guid iid = IID_IDWriteFactory; + IDWriteFactory* factory = null; + + delegate* unmanaged pfnDWriteCreateFactory = DWriteLoader.GetDWriteCreateFactoryFunctionPointer(); + + int hr = pfnDWriteCreateFactory((int)DWriteTypeConverter.Convert(factoryType), &iid, &factory); + + DWriteUtil.ConvertHresultToException(hr); + + _factory = new NativeIUnknownWrapper(factory); + } + + internal static Factory Create( + FactoryType factoryType, + IFontSourceCollectionFactory fontSourceCollectionFactory, + IFontSourceFactory fontSourceFactory) + { + return new Factory(factoryType, fontSourceCollectionFactory, fontSourceFactory); + } + + internal TextAnalyzer CreateTextAnalyzer() + { + IDWriteTextAnalyzer* textAnalyzer = null; + + _factory.Value->CreateTextAnalyzer(&textAnalyzer); + + return new TextAnalyzer((Native.IDWriteTextAnalyzer*)textAnalyzer); + } + + internal FontFile CreateFontFile(Uri filePathUri) + { + Native.IDWriteFontFile* dwriteFontFile = null; + int hr = InternalFactory.CreateFontFile((Native.IDWriteFactory*)_factory.Value, null, filePathUri, &dwriteFontFile); + + // If DWrite's CreateFontFileReference fails then try opening the file using WPF's logic. + // The failures that WPF returns are more granular than the HRESULTs that DWrite returns + // thus we use WPF's logic to open the file to throw the same exceptions that + // WPF would have thrown before. + if (hr != 0) + { + IFontSource fontSource = _fontSourceFactory.Create(filePathUri.AbsoluteUri); + fontSource.TestFileOpenable(); + + } + + //This call is made to prevent this object from being collected and hence get its finalize method called + //While there are others referencing it. + GC.KeepAlive(this); + + DWriteUtil.ConvertHresultToException(hr); + + return new FontFile(dwriteFontFile); + } + + internal FontFace CreateFontFace(Uri filePathUri, uint faceIndex) + { + return CreateFontFace( + filePathUri, + faceIndex, + FontSimulations.None + ); + } + + internal FontFace CreateFontFace(Uri filePathUri, uint faceIndex, FontSimulations fontSimulationFlags) + { + FontFile fontFile = CreateFontFile(filePathUri); + Native.DWRITE_FONT_FILE_TYPE dwriteFontFileType; + Native.DWRITE_FONT_FACE_TYPE dwriteFontFaceType; + uint numberOfFaces = 0; + + int hr; + if (fontFile.Analyze( + out dwriteFontFileType, + out dwriteFontFaceType, + out numberOfFaces, + &hr + )) + { + if (faceIndex >= numberOfFaces) + { + throw new ArgumentOutOfRangeException("faceIndex"); + } + + byte dwriteFontSimulationsFlags = DWriteTypeConverter.Convert(fontSimulationFlags); + IDWriteFontFace* dwriteFontFace = null; + IDWriteFontFile* dwriteFontFile = (IDWriteFontFile*)fontFile.DWriteFontFileNoAddRef; + + hr = _factory.Value->CreateFontFace( + (DWRITE_FONT_FACE_TYPE)dwriteFontFaceType, + 1, + &dwriteFontFile, + faceIndex, + (DWRITE_FONT_SIMULATIONS)dwriteFontSimulationsFlags, + &dwriteFontFace + ); + GC.KeepAlive(fontFile); + GC.KeepAlive(this); + + DWriteUtil.ConvertHresultToException(hr); + + return new FontFace((Native.IDWriteFontFace*)dwriteFontFace); + } + + // This path is here because there is a behavior mismatch between DWrite and WPF. + // If a directory was given instead of a font uri WPF previously throws + // System.UnauthorizedAccessException. We handle most of the exception behavior mismatch + // in FontFile^ Factory::CreateFontFile by opening the file using WPF's previous (prior to DWrite integration) logic if + // CreateFontFileReference fails (please see comments in FontFile^ Factory::CreateFontFile). + // However in this special case DWrite's CreateFontFileReference will succeed if given + // a directory instead of a font file and it is the Analyze() call will fail returning DWRITE_E_FILEFORMAT. + // Thus, incase the hr returned from Analyze() was DWRITE_E_FILEFORMAT we do as we did in FontFile^ Factory::CreateFontFile + // to try and open the file using WPF old logic and throw System.UnauthorizedAccessException as WPF used to do. + // If a file format exception is expected then opening the file should succeed and ConvertHresultToException() + // Should throw the correct exception. + // A final note would be that this overhead is only incurred in error conditions and so the normal execution path should + // not be affected. + else + { + if (hr == DWRITE_E_FILEFORMAT) + { + IFontSource fontSource = _fontSourceFactory.Create(filePathUri.AbsoluteUri); + fontSource.TestFileOpenable(); + } + DWriteUtil.ConvertHresultToException(hr); + } + + return null; + } + + internal FontCollection GetSystemFontCollection() + { + return GetSystemFontCollection(false); + } + + private FontCollection GetSystemFontCollection(bool checkForUpdate) + { + IDWriteFontCollection* fontCollection = null; + int checkForUpdateInt = checkForUpdate ? 1 : 0; + int hr = _factory.Value->GetSystemFontCollection(&fontCollection, checkForUpdateInt); + + DWriteUtil.ConvertHresultToException(hr); + + return new FontCollection((Native.IDWriteFontCollection*)fontCollection); + } + + internal FontCollection GetFontCollection(Uri uri) + { + IDWriteFontCollection* fontCollection = null; + + string uriString = uri.AbsoluteUri; + + fixed (char* uriStringPtr = uriString) + { + uint collectionKeySize = (uint)((uriString.Length + 1) * sizeof(char)); + _factory.Value->CreateCustomFontCollection(null, uriStringPtr, collectionKeySize, &fontCollection); + } + + return new FontCollection((Native.IDWriteFontCollection*)fontCollection); + } + + internal static bool IsLocalUri(Uri uri) + { + return uri.IsFile && uri.IsLoopback && !uri.IsUnc; + } + } +} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/ModuleInitializer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/ModuleInitializer.cs index 2d68e3c6ce1..732e4302df5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/ModuleInitializer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/ModuleInitializer.cs @@ -2,6 +2,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using MS.Internal.Text.TextInterface; internal static class ModuleInitializer { @@ -19,6 +20,13 @@ public static void Initialize() { IsProcessDpiAware(); + DWriteLoader.LoadDWrite(); + + AppDomain.CurrentDomain.ProcessExit += static (object sender, EventArgs e) => + { + DWriteLoader.UnloadDWrite(); + }; + MS.Internal.NativeWPFDLLLoader.LoadDwrite(); } #pragma warning restore CA2255 diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj index dd775ca091c..6f0505e07b2 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj @@ -25,6 +25,20 @@ Common\System\SR.cs + + + + + + + @@ -231,6 +245,17 @@ + + + + + + + + + + + @@ -264,6 +289,9 @@ + + + From b59b4542aca1d4087f45a95d565c2f97164c8d0a Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Wed, 23 Feb 2022 00:19:23 -0500 Subject: [PATCH 02/14] Add license + cleanup --- .../MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs | 3 +++ .../MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs | 3 +++ .../MS/internal/Interop/DWrite/IDWriteFactory.cs | 4 +++- .../MS/internal/Interop/DWrite/IDWriteFontCollection.cs | 3 +++ .../internal/Interop/DWrite/IDWriteFontCollectionLoader.cs | 3 +++ .../MS/internal/Interop/DWrite/IDWriteFontFace.cs | 3 +++ .../MS/internal/Interop/DWrite/IDWriteFontFile.cs | 3 +++ .../MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs | 3 +++ .../MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs | 3 +++ .../src/PresentationCore/MS/internal/Interop/IUnknown.cs | 3 +++ .../MS/internal/Interop/NativePointerCriticalHandle.cs | 3 +++ .../MS/internal/Text/TextInterface/DWriteLoader.cs | 5 ++++- .../MS/internal/Text/TextInterface/DWriteUtil.cs | 5 ++++- .../MS/internal/Text/TextInterface/Factory.cs | 5 ++++- 14 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs index 614aaa248c1..8898971dc05 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_FACE_TYPE.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + namespace MS.Internal.Interop.DWrite { internal enum DWRITE_FONT_FACE_TYPE diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs index 1e71901bff9..01fbd4619f7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/DWRITE_FONT_SIMULATIONS.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + namespace MS.Internal.Interop.DWrite { internal enum DWRITE_FONT_SIMULATIONS diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs index 67c868b1a3f..f3c10b4e003 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs @@ -1,5 +1,7 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; -using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs index d35ce0f15e9..6d571bc13ae 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop.DWrite diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs index 7b25ea6e161..b60e7d68171 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop.DWrite diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs index 22d91e6da2b..4dbb50deb9a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop.DWrite diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs index 4f74e51a2b2..aee54e1ba1b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop.DWrite diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs index fa7fa0ecbf6..95677d2b673 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop.DWrite diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs index 37fb5b50f92..92c2c0d8d19 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop.DWrite diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs index d70582942f3..42be15bec64 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; namespace MS.Internal.Interop diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs index b98ee1fb8bf..631330ba478 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/NativePointerCriticalHandle.cs @@ -1,3 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + using System; using System.Runtime.InteropServices; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs index 3278f44b07a..c103c3a7354 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs @@ -1,4 +1,7 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; using System.ComponentModel; using System.Runtime.InteropServices; diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs index a5d4eaf39e5..03a8a2e9710 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteUtil.cs @@ -1,4 +1,7 @@ -namespace MS.Internal.Text.TextInterface +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace MS.Internal.Text.TextInterface { internal static class DWriteUtil { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index ea4725d9e6d..73914e9f000 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -1,4 +1,7 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; using System.Runtime.InteropServices; using MS.Internal.Interop; using MS.Internal.Interop.DWrite; From 3fb201807ebb0aa020324e15e38b74ecec60ad2e Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Wed, 23 Feb 2022 20:40:43 -0500 Subject: [PATCH 03/14] Fix Release build --- src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp index 3f204965ed1..61ff8727d81 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/main.cpp @@ -50,7 +50,12 @@ private ref class NativeWPFDLLLoader sealed // static void LoadDwrite( ) { + // Used to force the compiler to keep LoadDwrite in Release because it is called from PresentationCore. + m_temp = NULL; } + +private: + static void *m_temp; }; }} // namespace MS.Internal From 693d46ae547baa9d1002c90ba834694f43ba0b73 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Wed, 23 Feb 2022 22:42:19 -0500 Subject: [PATCH 04/14] Fix potential memory leak --- .../CPP/DWriteWrapper/TextAnalyzer.cpp | 3 +++ .../MS/internal/Shaping/TypefaceMap.cs | 2 +- .../MS/internal/Text/TextInterface/Factory.cs | 11 ++--------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp index 604366e1ea8..b7186f36dfd 100644 --- a/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp +++ b/src/Microsoft.DotNet.Wpf/src/DirectWriteForwarder/CPP/DWriteWrapper/TextAnalyzer.cpp @@ -39,6 +39,9 @@ namespace MS { namespace Internal { namespace Text { namespace TextInterface IDWriteTextAnalysisSink* pTextAnalysisSink = NULL; IDWriteTextAnalysisSource* pTextAnalysisSource = NULL; + // We obtain an AddRef factory so as not to worry about having to call GC::KeepAlive(factory) + // which puts unnecessary maintenance cost on this code. + pDWriteFactory->AddRef(); HRESULT hr = S_OK; try { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs index e6f661fde37..358b84d3f0f 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Shaping/TypefaceMap.cs @@ -120,7 +120,7 @@ TextFormattingMode textFormattingMode (char*)ptext.ToPointer(), (uint)stringLength, culture, - (MS.Internal.Text.TextInterface.Native.IDWriteFactory*)MS.Internal.FontCache.DWriteFactory.Instance.DWriteFactoryAddRef, + (MS.Internal.Text.TextInterface.Native.IDWriteFactory*)MS.Internal.FontCache.DWriteFactory.Instance.DWriteFactory, isRightToLeftParagraph, digitCulture, ignoreUserOverride, diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index 73914e9f000..78a36dd95e5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -26,15 +26,8 @@ private Factory(IDWriteFactory* nativePointer) _factory = new NativeIUnknownWrapper(nativePointer); } - internal IDWriteFactory* DWriteFactoryAddRef - { - get - { - _factory.Value->AddReference(); - - return _factory.Value; - } - } + internal IDWriteFactory* DWriteFactory + => _factory.Value; private Factory(FactoryType factoryType, IFontSourceCollectionFactory fontSourceCollectionFactory, IFontSourceFactory fontSourceFactory) { From 6944a795509c37c96808f9ecc4919c31239108da Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Wed, 23 Feb 2022 23:14:28 -0500 Subject: [PATCH 05/14] Add back comments + cleanup --- .../Text/TextInterface/DWriteLoader.cs | 2 + .../MS/internal/Text/TextInterface/Factory.cs | 133 ++++++++++++++---- 2 files changed, 111 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs index c103c3a7354..8c4d6ae3dee 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs @@ -16,6 +16,8 @@ internal static unsafe class DWriteLoader internal static void LoadDWrite() { + // We load dwrite here because it's cleanup logic is different from the other native dlls + // and don't want to abstract that _dwrite = LoadDWriteLibraryAndGetProcAddress(out delegate* unmanaged dwriteCreateFactory); if (_dwrite == IntPtr.Zero) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index 78a36dd95e5..99fc8ca4e3b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -9,26 +9,44 @@ namespace MS.Internal.Text.TextInterface { + /// + /// The root factory interface for all DWrite objects. + /// internal unsafe class Factory { private const int DWRITE_E_FILEFORMAT = unchecked((int)0x88985000L); - private NativeIUnknownWrapper _factory; - - private IFontSourceFactory _fontSourceFactory; - private FontFileLoader _wpfFontFileLoader; - private FontCollectionLoader _wpfFontCollectionLoader; // b859ee5a-d838-4b5b-a2e8-1adc7d93db48 private static readonly Guid IID_IDWriteFactory = new Guid(0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48); - private Factory(IDWriteFactory* nativePointer) - { - _factory = new NativeIUnknownWrapper(nativePointer); - } - - internal IDWriteFactory* DWriteFactory - => _factory.Value; + /// + /// A pointer to the wrapped DWrite factory object. + /// + private NativeIUnknownWrapper _factory; + /// + /// The custom loader used by WPF to load font files. + /// + private readonly FontFileLoader _wpfFontFileLoader; + + /// + /// The custom loader used by WPF to load font collections. + /// + private readonly FontCollectionLoader _wpfFontCollectionLoader; + + private readonly IFontSourceFactory _fontSourceFactory; + + /// + /// Constructs a factory object. + /// + /// Identifies whether the factory object will be shared or isolated. + /// A factory object that will create managed FontSourceCollection + /// objects that will be utilized to load embedded fonts. + /// A factory object that will create managed FontSource + /// objects that will be utilized to load embedded fonts. + /// + /// The factory just created. + /// private Factory(FactoryType factoryType, IFontSourceCollectionFactory fontSourceCollectionFactory, IFontSourceFactory fontSourceFactory) { Initialize(factoryType); @@ -73,6 +91,13 @@ private Factory(FactoryType factoryType, IFontSourceCollectionFactory fontSource DWriteUtil.ConvertHresultToException(hr); } + internal IDWriteFactory* DWriteFactory + => _factory.Value; + + /// + /// Initializes a factory object. + /// + /// Identifies whether the factory object will be shared or isolated. private void Initialize(FactoryType factoryType) { Guid iid = IID_IDWriteFactory; @@ -87,6 +112,17 @@ private void Initialize(FactoryType factoryType) _factory = new NativeIUnknownWrapper(factory); } + /// + /// Creates a DirectWrite factory object that is used for subsequent creation of individual DirectWrite objects. + /// + /// Identifies whether the factory object will be shared or isolated. + /// A factory object that will create managed FontSourceCollection + /// objects that will be utilized to load embedded fonts. + /// A factory object that will create managed FontSource + /// objects that will be utilized to load embedded fonts. + /// + /// The factory just created. + /// internal static Factory Create( FactoryType factoryType, IFontSourceCollectionFactory fontSourceCollectionFactory, @@ -95,15 +131,13 @@ internal static Factory Create( return new Factory(factoryType, fontSourceCollectionFactory, fontSourceFactory); } - internal TextAnalyzer CreateTextAnalyzer() - { - IDWriteTextAnalyzer* textAnalyzer = null; - - _factory.Value->CreateTextAnalyzer(&textAnalyzer); - - return new TextAnalyzer((Native.IDWriteTextAnalyzer*)textAnalyzer); - } - + /// + /// Creates a font file object from a local font file. + /// + /// file path uri. + /// + /// Newly created font file object, or NULL in case of failure. + /// internal FontFile CreateFontFile(Uri filePathUri) { Native.IDWriteFontFile* dwriteFontFile = null; @@ -129,6 +163,15 @@ internal FontFile CreateFontFile(Uri filePathUri) return new FontFile(dwriteFontFile); } + /// + /// Creates a font face object. + /// + /// The file path of the font face. + /// The zero based index of a font face in cases when the font files contain a collection of font faces. + /// If the font files contain a single face, this value should be zero. + /// + /// Newly created font face object, or NULL in case of failure. + /// internal FontFace CreateFontFace(Uri filePathUri, uint faceIndex) { return CreateFontFace( @@ -138,6 +181,16 @@ internal FontFace CreateFontFace(Uri filePathUri, uint faceIndex) ); } + /// + /// Creates a font face object. + /// + /// The file path of the font face. + /// The zero based index of a font face in cases when the font files contain a collection of font faces. + /// If the font files contain a single face, this value should be zero. + /// Font face simulation flags for algorithmic emboldening and italicization. + /// + /// Newly created font face object, or NULL in case of failure. + /// internal FontFace CreateFontFace(Uri filePathUri, uint faceIndex, FontSimulations fontSimulationFlags) { FontFile fontFile = CreateFontFile(filePathUri); @@ -204,22 +257,45 @@ internal FontFace CreateFontFace(Uri filePathUri, uint faceIndex, FontSimulation return null; } + /// + /// Gets a font collection representing the set of installed fonts. + /// + /// + /// The system font collection. + /// internal FontCollection GetSystemFontCollection() { return GetSystemFontCollection(false); } - private FontCollection GetSystemFontCollection(bool checkForUpdate) + /// + /// Gets a font collection representing the set of installed fonts. + /// + /// If this parameter is true, the function performs an immediate check for changes to the set of + /// installed fonts. If this parameter is FALSE, the function will still detect changes if the font cache service is running, but + /// there may be some latency. For example, an application might specify TRUE if it has itself just installed a font and wants to + /// be sure the font collection contains that font. + /// + /// The system font collection. + /// + private FontCollection GetSystemFontCollection(bool checkForUpdates) { IDWriteFontCollection* fontCollection = null; - int checkForUpdateInt = checkForUpdate ? 1 : 0; - int hr = _factory.Value->GetSystemFontCollection(&fontCollection, checkForUpdateInt); + int checkForUpdatesInt = checkForUpdates ? 1 : 0; + int hr = _factory.Value->GetSystemFontCollection(&fontCollection, checkForUpdatesInt); DWriteUtil.ConvertHresultToException(hr); return new FontCollection((Native.IDWriteFontCollection*)fontCollection); } + /// + /// Gets a font collection in a custom location. + /// + /// The uri of the font collection. + /// + /// The font collection. + /// internal FontCollection GetFontCollection(Uri uri) { IDWriteFontCollection* fontCollection = null; @@ -235,6 +311,15 @@ internal FontCollection GetFontCollection(Uri uri) return new FontCollection((Native.IDWriteFontCollection*)fontCollection); } + internal TextAnalyzer CreateTextAnalyzer() + { + IDWriteTextAnalyzer* textAnalyzer = null; + + _factory.Value->CreateTextAnalyzer(&textAnalyzer); + + return new TextAnalyzer((Native.IDWriteTextAnalyzer*)textAnalyzer); + } + internal static bool IsLocalUri(Uri uri) { return uri.IsFile && uri.IsLoopback && !uri.IsUnc; From 7dd48dc6f06f714274106c14ee5906bdce8c0707 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Sat, 12 Mar 2022 15:15:24 -0500 Subject: [PATCH 06/14] Use code closer to generated ClangSharp code --- .../internal/Interop/DWrite/IDWriteFactory.cs | 80 ++++--------------- .../Interop/DWrite/IDWriteFontCollection.cs | 26 ++---- .../DWrite/IDWriteFontCollectionLoader.cs | 26 ++---- .../Interop/DWrite/IDWriteFontFace.cs | 26 ++---- .../Interop/DWrite/IDWriteFontFile.cs | 26 ++---- .../Interop/DWrite/IDWriteFontFileLoader.cs | 26 ++---- .../Interop/DWrite/IDWriteTextAnalyzer.cs | 26 ++---- 7 files changed, 53 insertions(+), 183 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs index f3c10b4e003..44df1b29e5b 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs @@ -2,103 +2,57 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteFactory : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFactory*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); } - internal int GetSystemFontCollection(void* fontCollection, int checkForUpdate) + public int GetSystemFontCollection(IDWriteFontCollection** fontCollection, int checkForUpdates = 0) { - var function = (delegate* unmanaged)Vtbl[3]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle, fontCollection, checkForUpdate); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[3]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollection, checkForUpdates); } - internal int CreateCustomFontCollection(IDWriteFontCollectionLoader* collectionLoader, void* collectionKey, uint collectionKeySize, IDWriteFontCollection** fontCollection) + public int CreateCustomFontCollection(IDWriteFontCollectionLoader* collectionLoader, void* collectionKey, uint collectionKeySize, IDWriteFontCollection** fontCollection) { - var function = (delegate* unmanaged)Vtbl[4]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle, collectionLoader, collectionKey, collectionKeySize, fontCollection); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[4]))((IDWriteFactory*)Unsafe.AsPointer(ref this), collectionLoader, collectionKey, collectionKeySize, fontCollection); } public int RegisterFontCollectionLoader(IDWriteFontCollectionLoader* fontCollectionLoader) { - var function = (delegate* unmanaged)Vtbl[5]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle, fontCollectionLoader); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[5]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollectionLoader); } - internal int CreateFontFace(DWRITE_FONT_FACE_TYPE fontFaceType, uint numberOfFiles, IDWriteFontFile** fontFiles, uint faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) + public int CreateFontFace(DWRITE_FONT_FACE_TYPE fontFaceType, uint numberOfFiles, IDWriteFontFile** fontFiles, uint faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { - var function = (delegate* unmanaged)Vtbl[9]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle, fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[9]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); } - internal int RegisterFontFileLoader(IDWriteFontFileLoader* fontFileLoader) + public int RegisterFontFileLoader(IDWriteFontFileLoader* fontFileLoader) { - var function = (delegate* unmanaged)Vtbl[13]; - - fixed (IDWriteFactory* handle = &this) - { - return function(handle, fontFileLoader); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[13]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFileLoader); } - internal int CreateTextAnalyzer(IDWriteTextAnalyzer** textAnalyzer) + public int CreateTextAnalyzer(IDWriteTextAnalyzer** textAnalyzer) { - var function = (delegate* unmanaged)Vtbl[21]; - - fixed (IDWriteFactory* handle = &this) - { - int hr = function(handle, textAnalyzer); - - return hr; - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[21]))((IDWriteFactory*)Unsafe.AsPointer(ref this), textAnalyzer); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs index 6d571bc13ae..f2ae0ba5c80 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs @@ -2,41 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteFontCollection : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteFontCollection* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteFontCollection* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteFontCollection* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs index b60e7d68171..f6d2207d8c3 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs @@ -2,41 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteFontCollectionLoader : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteFontCollectionLoader* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteFontCollectionLoader* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteFontCollectionLoader* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs index 4dbb50deb9a..4c772c43549 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs @@ -2,41 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteFontFace : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteFontFace* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFace*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteFontFace* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteFontFace* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs index aee54e1ba1b..b00bcaddb16 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs @@ -2,41 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteFontFile : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteFontFile* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFile*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteFontFile* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteFontFile* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs index 95677d2b673..3f46228b23c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs @@ -2,41 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteFontFileLoader : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteFontFileLoader* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteFontFileLoader* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteFontFileLoader* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs index 92c2c0d8d19..31bf0b8f6f0 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs @@ -2,41 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; namespace MS.Internal.Interop.DWrite { internal unsafe struct IDWriteTextAnalyzer : IUnknown { - private readonly void** Vtbl; + public void** lpVtbl; - public int QueryInterface(Guid* guid, void** comObject) + public int QueryInterface(Guid* riid, void** ppvObject) { - var function = (delegate* unmanaged)Vtbl[0]; - - fixed (IDWriteTextAnalyzer* handle = &this) - { - return function(handle, guid, comObject); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddReference() { - var function = (delegate* unmanaged)Vtbl[1]; - - fixed (IDWriteTextAnalyzer* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); } public uint Release() { - var function = (delegate* unmanaged)Vtbl[2]; - - fixed (IDWriteTextAnalyzer* handle = &this) - { - return function(handle); - } + return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); } } } From 1a866dce36b02a7f6c1523ce79813b6fb64dd110 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Sat, 12 Mar 2022 16:53:33 -0500 Subject: [PATCH 07/14] Rename IUnknown.AddReference to AddRef --- .../MS/internal/Interop/DWrite/IDWriteFactory.cs | 2 +- .../MS/internal/Interop/DWrite/IDWriteFontCollection.cs | 2 +- .../MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs | 2 +- .../MS/internal/Interop/DWrite/IDWriteFontFace.cs | 2 +- .../MS/internal/Interop/DWrite/IDWriteFontFile.cs | 2 +- .../MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs | 2 +- .../MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs | 2 +- .../src/PresentationCore/MS/internal/Interop/IUnknown.cs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs index 44df1b29e5b..8dbc52d8c25 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFactory*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs index f2ae0ba5c80..a3c8204f6fb 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs index f6d2207d8c3..794f88dbb47 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs index 4c772c43549..90b09e057f7 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFace*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs index b00bcaddb16..12ef4b0f086 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFile*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs index 3f46228b23c..984f5929a6e 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs index 31bf0b8f6f0..c4f8f72b4b6 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs @@ -15,7 +15,7 @@ public int QueryInterface(Guid* riid, void** ppvObject) return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this), riid, ppvObject); } - public uint AddReference() + public uint AddRef() { return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs index 42be15bec64..fcab94b4427 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/IUnknown.cs @@ -9,7 +9,7 @@ internal unsafe interface IUnknown { int QueryInterface(Guid* guid, void** comObject); - uint AddReference(); + uint AddRef(); uint Release(); } From e1bc4938f89a2568238df6a619239b703179acf2 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Tue, 15 Mar 2022 22:02:40 -0400 Subject: [PATCH 08/14] Add missing Factory.GetFontCollection code --- .../MS/internal/Text/TextInterface/Factory.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index 99fc8ca4e3b..5f97afde4a5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -298,17 +298,31 @@ private FontCollection GetSystemFontCollection(bool checkForUpdates) /// internal FontCollection GetFontCollection(Uri uri) { - IDWriteFontCollection* fontCollection = null; - string uriString = uri.AbsoluteUri; + IDWriteFontCollection* dwriteFontCollection = null; + + IntPtr pIDWriteFontCollectionLoaderMirror = Marshal.GetComInterfaceForObject( + _wpfFontCollectionLoader, + typeof(IDWriteFontCollectionLoaderMirror)); + + IDWriteFontCollectionLoader * pIDWriteFontCollectionLoader = + (IDWriteFontCollectionLoader *)pIDWriteFontCollectionLoaderMirror.ToPointer(); + + int hr; fixed (char* uriStringPtr = uriString) { uint collectionKeySize = (uint)((uriString.Length + 1) * sizeof(char)); - _factory.Value->CreateCustomFontCollection(null, uriStringPtr, collectionKeySize, &fontCollection); + hr = _factory.Value->CreateCustomFontCollection(pIDWriteFontCollectionLoader, uriStringPtr, collectionKeySize, &dwriteFontCollection); } - return new FontCollection((Native.IDWriteFontCollection*)fontCollection); + Marshal.Release(pIDWriteFontCollectionLoaderMirror); + + GC.KeepAlive(this); + + DWriteUtil.ConvertHresultToException(hr); + + return new FontCollection((Native.IDWriteFontCollection*)dwriteFontCollection); } internal TextAnalyzer CreateTextAnalyzer() From 6523904c1adc1aa7edda859c22e47bd550bea8fb Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Tue, 15 Mar 2022 22:33:07 -0400 Subject: [PATCH 09/14] Fix format --- .../MS/internal/Text/TextInterface/Factory.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index 5f97afde4a5..ea9a22532a6 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -305,8 +305,8 @@ internal FontCollection GetFontCollection(Uri uri) _wpfFontCollectionLoader, typeof(IDWriteFontCollectionLoaderMirror)); - IDWriteFontCollectionLoader * pIDWriteFontCollectionLoader = - (IDWriteFontCollectionLoader *)pIDWriteFontCollectionLoaderMirror.ToPointer(); + IDWriteFontCollectionLoader* pIDWriteFontCollectionLoader = + (IDWriteFontCollectionLoader*)pIDWriteFontCollectionLoaderMirror.ToPointer(); int hr; From a1978aba864978e259d1f47b99490ae3df35c09f Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Wed, 6 Apr 2022 23:04:28 -0400 Subject: [PATCH 10/14] Remove explicit calling convention --- .../internal/Interop/DWrite/IDWriteFactory.cs | 18 +++++++++--------- .../Interop/DWrite/IDWriteFontCollection.cs | 6 +++--- .../DWrite/IDWriteFontCollectionLoader.cs | 6 +++--- .../internal/Interop/DWrite/IDWriteFontFace.cs | 6 +++--- .../internal/Interop/DWrite/IDWriteFontFile.cs | 6 +++--- .../Interop/DWrite/IDWriteFontFileLoader.cs | 6 +++--- .../Interop/DWrite/IDWriteTextAnalyzer.cs | 6 +++--- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs index 8dbc52d8c25..4d3a61b279d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs @@ -12,47 +12,47 @@ internal unsafe struct IDWriteFactory : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFactory*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteFactory*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteFactory*)Unsafe.AsPointer(ref this)); } public int GetSystemFontCollection(IDWriteFontCollection** fontCollection, int checkForUpdates = 0) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[3]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollection, checkForUpdates); + return ((delegate* unmanaged)(lpVtbl[3]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollection, checkForUpdates); } public int CreateCustomFontCollection(IDWriteFontCollectionLoader* collectionLoader, void* collectionKey, uint collectionKeySize, IDWriteFontCollection** fontCollection) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[4]))((IDWriteFactory*)Unsafe.AsPointer(ref this), collectionLoader, collectionKey, collectionKeySize, fontCollection); + return ((delegate* unmanaged)(lpVtbl[4]))((IDWriteFactory*)Unsafe.AsPointer(ref this), collectionLoader, collectionKey, collectionKeySize, fontCollection); } public int RegisterFontCollectionLoader(IDWriteFontCollectionLoader* fontCollectionLoader) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[5]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollectionLoader); + return ((delegate* unmanaged)(lpVtbl[5]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollectionLoader); } public int CreateFontFace(DWRITE_FONT_FACE_TYPE fontFaceType, uint numberOfFiles, IDWriteFontFile** fontFiles, uint faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[9]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); + return ((delegate* unmanaged)(lpVtbl[9]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); } public int RegisterFontFileLoader(IDWriteFontFileLoader* fontFileLoader) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[13]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFileLoader); + return ((delegate* unmanaged)(lpVtbl[13]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFileLoader); } public int CreateTextAnalyzer(IDWriteTextAnalyzer** textAnalyzer) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[21]))((IDWriteFactory*)Unsafe.AsPointer(ref this), textAnalyzer); + return ((delegate* unmanaged)(lpVtbl[21]))((IDWriteFactory*)Unsafe.AsPointer(ref this), textAnalyzer); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs index a3c8204f6fb..9107e4e8f53 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollection.cs @@ -12,17 +12,17 @@ internal unsafe struct IDWriteFontCollection : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteFontCollection*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs index 794f88dbb47..44fddcccd47 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontCollectionLoader.cs @@ -12,17 +12,17 @@ internal unsafe struct IDWriteFontCollectionLoader : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteFontCollectionLoader*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs index 90b09e057f7..4ca49c06a39 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFace.cs @@ -12,17 +12,17 @@ internal unsafe struct IDWriteFontFace : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFace*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteFontFace*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteFontFace*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs index 12ef4b0f086..ddb46baae68 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFile.cs @@ -12,17 +12,17 @@ internal unsafe struct IDWriteFontFile : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFile*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteFontFile*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteFontFile*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs index 984f5929a6e..8841d32884a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFontFileLoader.cs @@ -12,17 +12,17 @@ internal unsafe struct IDWriteFontFileLoader : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteFontFileLoader*)Unsafe.AsPointer(ref this)); } } } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs index c4f8f72b4b6..308d6b87c18 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteTextAnalyzer.cs @@ -12,17 +12,17 @@ internal unsafe struct IDWriteTextAnalyzer : IUnknown public int QueryInterface(Guid* riid, void** ppvObject) { - return ((delegate* unmanaged[Stdcall])(lpVtbl[0]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this), riid, ppvObject); + return ((delegate* unmanaged)(lpVtbl[0]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this), riid, ppvObject); } public uint AddRef() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[1]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[1]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); } public uint Release() { - return ((delegate* unmanaged[Stdcall])(lpVtbl[2]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); + return ((delegate* unmanaged)(lpVtbl[2]))((IDWriteTextAnalyzer*)Unsafe.AsPointer(ref this)); } } } From 19bd765911aac689f883d5495834ca0de97f3705 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Tue, 9 May 2023 22:44:45 -0400 Subject: [PATCH 11/14] Sync managed DWriteLoader with C++/CLI following dotnet/wpf#6538 --- .../Text/TextInterface/DWriteLoader.cs | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs index 8c4d6ae3dee..776ba22ce5d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs @@ -57,33 +57,7 @@ private static void ClearDWriteCreateFactoryFunctionPointer() private static IntPtr LoadDWriteLibraryAndGetProcAddress(out delegate* unmanaged DWriteCreateFactory) { - IntPtr hDWriteLibrary = IntPtr.Zero; - - // KB2533623 introduced the LOAD_LIBRARY_SEARCH_SYSTEM32 flag. It also introduced - // the AddDllDirectory function. We test for presence of AddDllDirectory as an - // indirect evidence for the support of LOAD_LIBRARY_SEARCH_SYSTEM32 flag. - IntPtr hKernel32 = Kernel32.GetModuleHandleW(Libraries.Kernel32); - - if (hKernel32 != IntPtr.Zero) - { - if (Kernel32.GetProcAddress(hKernel32, "AddDllDirectory") != IntPtr.Zero) - { - // All supported platforms newer than Vista SP2 shipped with dwrite.dll. - // On Vista SP2, the .NET servicing process will ensure that a MSU containing - // dwrite.dll will be delivered as a prerequisite - effectively guaranteeing that - // this following call to LoadLibraryEx(dwrite.dll) will succeed, and that it will - // not be susceptible to typical DLL planting vulnerability vectors. - hDWriteLibrary = Kernel32.LoadLibraryExW("dwrite.dll", IntPtr.Zero, Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32); - } - else - { - // LOAD_LIBRARY_SEARCH_SYSTEM32 is not supported on this OS. - // Fall back to using plain ol' LoadLibrary - // There is risk that this call might fail, or that it might be - // susceptible to DLL hijacking. - hDWriteLibrary = Kernel32.LoadLibraryW("dwrite.dll"); - } - } + IntPtr hDWriteLibrary = Kernel32.LoadLibraryExW("dwrite.dll", IntPtr.Zero, Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32); if (hDWriteLibrary != IntPtr.Zero) { From 49550d13a0069b9529630e5f37671825b02b1d73 Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Tue, 9 May 2023 23:18:09 -0400 Subject: [PATCH 12/14] Use NativeLibrary instead of direct P/Invoke --- .../Windows/Interop.HRESULT_FROM_WIN32.cs | 19 ------------------- .../Windows/Kernel32/Interop.FreeLibrary.cs | 14 -------------- .../Kernel32/Interop.GetModuleHandle.cs | 14 -------------- .../Kernel32/Interop.GetProcAddress.cs | 14 -------------- .../Windows/Kernel32/Interop.LoadLibrary.cs | 14 -------------- .../Windows/Kernel32/Interop.LoadLibraryEx.cs | 16 ---------------- .../Text/TextInterface/DWriteLoader.cs | 12 +++--------- .../PresentationCore/PresentationCore.csproj | 14 -------------- 8 files changed, 3 insertions(+), 114 deletions(-) delete mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs delete mode 100644 src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs deleted file mode 100644 index 2d225456e80..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Interop.HRESULT_FROM_WIN32.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; - -internal static partial class Interop -{ - // Implementation of HRESULT_FROM_WIN32 macro - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static int HRESULT_FROM_WIN32(int errorCode) - { - if (errorCode <= 0 || (errorCode & 0x80000000) == 0x80000000) - { - return errorCode; - } - - return (errorCode & 0x0000FFFF) | unchecked((int)0x80070000); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs deleted file mode 100644 index b98655a9132..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.FreeLibrary.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Kernel32 - { - [DllImport(Libraries.Kernel32, SetLastError = true, ExactSpelling = true)] - internal static extern int FreeLibrary(IntPtr hModule); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs deleted file mode 100644 index a963c3962d9..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetModuleHandle.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Kernel32 - { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] - internal static extern IntPtr GetModuleHandleW(string moduleName); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs deleted file mode 100644 index cc52de7f977..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.GetProcAddress.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Kernel32 - { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] - internal static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs deleted file mode 100644 index 9cf0ac772c0..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibrary.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Kernel32 - { - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] - internal static extern IntPtr LoadLibraryW(string libFilename); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs b/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs deleted file mode 100644 index 3f47dbc8c3d..00000000000 --- a/src/Microsoft.DotNet.Wpf/src/Common/src/Interop/Windows/Kernel32/Interop.LoadLibraryEx.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.InteropServices; - -internal static partial class Interop -{ - internal static partial class Kernel32 - { - public const int LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800; - - [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)] - internal static extern IntPtr LoadLibraryExW(string lpwLibFileName, IntPtr hFile, uint dwFlags); - } -} diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs index 776ba22ce5d..e60312cbb69 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/DWriteLoader.cs @@ -5,8 +5,6 @@ using System.ComponentModel; using System.Runtime.InteropServices; -using static Interop; - namespace MS.Internal.Text.TextInterface { internal static unsafe class DWriteLoader @@ -35,11 +33,7 @@ internal static void UnloadDWrite() if (_dwrite != IntPtr.Zero) { - if (Kernel32.FreeLibrary(_dwrite) != 0) - { - int lastError = Marshal.GetLastPInvokeError(); - Marshal.ThrowExceptionForHR(HRESULT_FROM_WIN32(lastError)); - } + NativeLibrary.Free(_dwrite); _dwrite = IntPtr.Zero; } @@ -57,11 +51,11 @@ private static void ClearDWriteCreateFactoryFunctionPointer() private static IntPtr LoadDWriteLibraryAndGetProcAddress(out delegate* unmanaged DWriteCreateFactory) { - IntPtr hDWriteLibrary = Kernel32.LoadLibraryExW("dwrite.dll", IntPtr.Zero, Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32); + IntPtr hDWriteLibrary = NativeLibrary.Load("dwrite.dll", typeof(DWriteLoader).Assembly, DllImportSearchPath.System32); if (hDWriteLibrary != IntPtr.Zero) { - DWriteCreateFactory = (delegate* unmanaged)Kernel32.GetProcAddress(hDWriteLibrary, "DWriteCreateFactory"); + DWriteCreateFactory = (delegate* unmanaged)NativeLibrary.GetExport(hDWriteLibrary, "DWriteCreateFactory"); } else { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj index 6c78fdaa81c..41d91b7317a 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/PresentationCore.csproj @@ -25,20 +25,6 @@ Common\System\SR.cs - - - - - - - From 8a874fab059a1ab888e6c06e90319ea6e331f0de Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Tue, 26 Sep 2023 23:27:55 -0400 Subject: [PATCH 13/14] Try to fix Annotations Test --- .../PresentationCore/MS/internal/Text/TextInterface/Factory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index ea9a22532a6..135f985b1b6 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -141,7 +141,7 @@ internal static Factory Create( internal FontFile CreateFontFile(Uri filePathUri) { Native.IDWriteFontFile* dwriteFontFile = null; - int hr = InternalFactory.CreateFontFile((Native.IDWriteFactory*)_factory.Value, null, filePathUri, &dwriteFontFile); + int hr = InternalFactory.CreateFontFile((Native.IDWriteFactory*)_factory.Value, _wpfFontFileLoader, filePathUri, &dwriteFontFile); // If DWrite's CreateFontFileReference fails then try opening the file using WPF's logic. // The failures that WPF returns are more granular than the HRESULTs that DWrite returns From 34fe0074049db68f4f817ccf2a9f57ee7591e0cc Mon Sep 17 00:00:00 2001 From: ThomasGoulet73 Date: Sun, 15 Oct 2023 20:31:57 -0400 Subject: [PATCH 14/14] Unregister and release FontFileLoader and FontCollectionLoader --- .../internal/Interop/DWrite/IDWriteFactory.cs | 10 ++++ .../MS/internal/Text/TextInterface/Factory.cs | 48 +++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs index 4d3a61b279d..1c41dd285c2 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Interop/DWrite/IDWriteFactory.cs @@ -40,6 +40,11 @@ public int RegisterFontCollectionLoader(IDWriteFontCollectionLoader* fontCollect return ((delegate* unmanaged)(lpVtbl[5]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollectionLoader); } + public int UnregisterFontCollectionLoader(IDWriteFontCollectionLoader* fontCollectionLoader) + { + return ((delegate* unmanaged)(lpVtbl[6]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontCollectionLoader); + } + public int CreateFontFace(DWRITE_FONT_FACE_TYPE fontFaceType, uint numberOfFiles, IDWriteFontFile** fontFiles, uint faceIndex, DWRITE_FONT_SIMULATIONS fontFaceSimulationFlags, IDWriteFontFace** fontFace) { return ((delegate* unmanaged)(lpVtbl[9]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFaceType, numberOfFiles, fontFiles, faceIndex, fontFaceSimulationFlags, fontFace); @@ -50,6 +55,11 @@ public int RegisterFontFileLoader(IDWriteFontFileLoader* fontFileLoader) return ((delegate* unmanaged)(lpVtbl[13]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFileLoader); } + public int UnregisterFontFileLoader(IDWriteFontFileLoader* fontFileLoader) + { + return ((delegate* unmanaged)(lpVtbl[14]))((IDWriteFactory*)Unsafe.AsPointer(ref this), fontFileLoader); + } + public int CreateTextAnalyzer(IDWriteTextAnalyzer** textAnalyzer) { return ((delegate* unmanaged)(lpVtbl[21]))((IDWriteFactory*)Unsafe.AsPointer(ref this), textAnalyzer); diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs index 135f985b1b6..d7b077ea9f5 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Text/TextInterface/Factory.cs @@ -22,17 +22,17 @@ internal unsafe class Factory /// /// A pointer to the wrapped DWrite factory object. /// - private NativeIUnknownWrapper _factory; + private NativeFactoryWrapper _factory; /// /// The custom loader used by WPF to load font files. /// - private readonly FontFileLoader _wpfFontFileLoader; + private FontFileLoader _wpfFontFileLoader; /// /// The custom loader used by WPF to load font collections. /// - private readonly FontCollectionLoader _wpfFontCollectionLoader; + private FontCollectionLoader _wpfFontCollectionLoader; private readonly IFontSourceFactory _fontSourceFactory; @@ -109,7 +109,7 @@ private void Initialize(FactoryType factoryType) DWriteUtil.ConvertHresultToException(hr); - _factory = new NativeIUnknownWrapper(factory); + _factory = new NativeFactoryWrapper(factory, this); } /// @@ -338,5 +338,45 @@ internal static bool IsLocalUri(Uri uri) { return uri.IsFile && uri.IsLoopback && !uri.IsUnc; } + + private sealed unsafe class NativeFactoryWrapper : NativeIUnknownWrapper + { + private readonly Factory _managedFactory; + + public NativeFactoryWrapper(void* nativePointer, Factory managedFactory) + : base(nativePointer) + { + _managedFactory = managedFactory; + } + + protected override bool ReleaseHandle() + { + FontCollectionLoader wpfFontCollectionLoader = _managedFactory._wpfFontCollectionLoader; + if (wpfFontCollectionLoader != null) + { + IntPtr pIDWriteFontCollectionLoaderMirror = Marshal.GetComInterfaceForObject( + wpfFontCollectionLoader, + typeof(IDWriteFontCollectionLoaderMirror)); + + Value->UnregisterFontCollectionLoader((IDWriteFontCollectionLoader*)pIDWriteFontCollectionLoaderMirror.ToPointer()); + Marshal.Release(pIDWriteFontCollectionLoaderMirror); + _managedFactory._wpfFontCollectionLoader = null; + } + + FontFileLoader wpfFontFileLoader = _managedFactory._wpfFontFileLoader; + if (wpfFontFileLoader != null) + { + IntPtr pIDWriteFontFileLoaderMirror = Marshal.GetComInterfaceForObject( + wpfFontFileLoader, + typeof(IDWriteFontFileLoaderMirror)); + + Value->UnregisterFontFileLoader((IDWriteFontFileLoader*)pIDWriteFontFileLoaderMirror.ToPointer()); + Marshal.Release(pIDWriteFontFileLoaderMirror); + _managedFactory._wpfFontFileLoader = null; + } + + return base.ReleaseHandle(); + } + } } }