From ffecab95be25e86425d65bf3ad3fc6bfd63c8d3c Mon Sep 17 00:00:00 2001 From: ema Date: Mon, 30 Dec 2024 03:05:06 +0800 Subject: [PATCH] New built-in plugin FontViewer --- .../.gitattributes | 8 + .../FreeTypeApi.cs | 51 +++++ .../FreeTypeDllMap.cs | 71 +++++++ .../QuickLook.Plugin.FontViewer/Plugin.cs | 176 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 66 +++++++ .../QuickLook.Plugin.FontViewer.csproj | 104 +++++++++++ .../Resources/font2html.html | 167 +++++++++++++++++ .../Translations.config | 7 + .../WebpagePanel.cs | 9 +- .../QuickLook.Plugin.MarkdownViewer/Plugin.cs | 3 +- QuickLook.sln | 12 ++ 11 files changed, 671 insertions(+), 3 deletions(-) create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/.gitattributes create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeApi.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeDllMap.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/Plugin.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/Properties/AssemblyInfo.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/QuickLook.Plugin.FontViewer.csproj create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/Resources/font2html.html create mode 100644 QuickLook.Plugin/QuickLook.Plugin.FontViewer/Translations.config diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/.gitattributes b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/.gitattributes new file mode 100644 index 000000000..8bca8e4a5 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/.gitattributes @@ -0,0 +1,8 @@ +# Ignore HTML files in Resources and subdirectories +Resources/**/*.html linguist-vendored + +# Ignore CSS files in Resources and subdirectories +Resources/**/*.css linguist-vendored + +# Ignore JS files in Resources and subdirectories +Resources/**/*.js linguist-vendored diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeApi.cs b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeApi.cs new file mode 100644 index 000000000..5254eaa42 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeApi.cs @@ -0,0 +1,51 @@ +// Copyright © 2024 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using FreeTypeSharp; +using System; +using System.IO; +using System.Runtime.InteropServices; +using static FreeTypeSharp.FT; + +namespace QuickLook.Plugin.FontViewer; + +internal unsafe static class FreeTypeApi +{ + static FreeTypeApi() + { + FreeTypeDllMap.LoadNativeLibrary(); + } + + public static string GetFontFamilyName(string path) + { + if (!File.Exists(path)) return null; + + FT_LibraryRec_* lib; + FT_FaceRec_* face; + FT_Error error = FT_Init_FreeType(&lib); + + error = FT_New_Face(lib, (byte*)Marshal.StringToHGlobalAnsi(path), IntPtr.Zero, &face); + + if (error == FT_Error.FT_Err_Ok) + { + var familyName = Marshal.PtrToStringAnsi((nint)face->family_name); + return familyName; + } + + return null; + } +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeDllMap.cs b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeDllMap.cs new file mode 100644 index 000000000..6242ee367 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/FreeTypeDllMap.cs @@ -0,0 +1,71 @@ +// Copyright © 2024 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace QuickLook.Plugin.FontViewer; + +/// +/// To implement a similar architecture detection logic in .NET Framework +/// https://github.com/ryancheung/FreeTypeSharp/blob/main/FreeTypeSharp/FT.DllMap.cs +/// +internal static class FreeTypeDllMap +{ + public static void LoadNativeLibrary() + { + _ = ImportResolver(); + } + + private static nint ImportResolver() + { + string actualLibraryName = "freetype.dll"; + string rootDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string arch = (RuntimeInformation.OSArchitecture == Architecture.Arm64) + ? "arm64" + : (Environment.Is64BitProcess ? "x64" : "x86"); + + var searchPaths = new[] + { + // This is where native libraries in our nupkg should end up + Path.Combine(rootDirectory, "runtimes", "win-" + arch, "native"), + Path.Combine(rootDirectory, "runtimes", "win-" + arch), + Path.Combine(rootDirectory, "win-" + arch), + Path.Combine(rootDirectory, arch), + Path.Combine(rootDirectory) + }; + + foreach (var searchPath in searchPaths) + { + SetDllDirectory(searchPath); + nint handle = LoadLibrary(Path.Combine(searchPath, actualLibraryName)); + + if (handle != IntPtr.Zero) + return handle; + } + + return IntPtr.Zero; + } + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern nint LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern bool SetDllDirectory(string lpPathName); +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Plugin.cs new file mode 100644 index 000000000..b8a708e80 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Plugin.cs @@ -0,0 +1,176 @@ +// Copyright © 2024 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using QuickLook.Common.Helpers; +using QuickLook.Common.Plugin; +using QuickLook.Plugin.HtmlViewer; +using System; +using System.IO; +using System.IO.Packaging; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Windows; +using System.Windows.Resources; + +namespace QuickLook.Plugin.FontViewer; + +public class Plugin : IViewer +{ + private static readonly string _resourcePath = Path.Combine(SettingHelper.LocalDataPath, "QuickLook.Plugin.FontViewer"); + + private WebpagePanel _panel; + + public int Priority => int.MaxValue; + + public void Init() + { + } + + public bool CanHandle(string path) + { + // The `*.eot` and `*.svg` font types are not supported + return !Directory.Exists(path) && new string[] { ".ttf", ".otf", ".woff", ".woff2" }.Any(path.ToLower().EndsWith); + } + + public void Prepare(string path, ContextObject context) + { + context.PreferredSize = new Size { Width = 1300, Height = 650 }; + } + + public void View(string path, ContextObject context) + { + _panel = new WebpagePanel(); + + if (OSThemeHelper.AppsUseDarkTheme()) + { + // Invoke using reflection: WebView2.CreationProperties.AdditionalBrowserArguments + // This approach allows the library to avoid direct dependency on WebView2 + if (typeof(WebpagePanel).GetField("_webView", BindingFlags.NonPublic | BindingFlags.Instance) is FieldInfo fieldInfo) + { + object webView2 = fieldInfo.GetValue(_panel); + + if (webView2?.GetType().GetProperty("CreationProperties", BindingFlags.Public | BindingFlags.Instance) is PropertyInfo creationPropertiesProperty) + { + object creationProperties = creationPropertiesProperty.GetValue(webView2); + + if (creationProperties?.GetType().GetProperty("AdditionalBrowserArguments", BindingFlags.Public | BindingFlags.Instance) is PropertyInfo additionalBrowserArgumentsProperty) + { + string additionalBrowserArguments = (additionalBrowserArgumentsProperty.GetValue(creationProperties) as string) ?? string.Empty; + additionalBrowserArgumentsProperty.SetValue(creationProperties, additionalBrowserArguments + " --enable-features=WebContentsForceDark"); + } + } + } + } + + context.ViewerContent = _panel; + context.Title = Path.GetFileName(path); + + var html = GenerateFontHtml(path); + var htmlPath = Path.Combine(_resourcePath, "font2html.html"); + + if (!Directory.Exists(Path.GetDirectoryName(htmlPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(htmlPath)); + } + File.WriteAllText(htmlPath, html); + + _panel.FallbackPath = Path.GetDirectoryName(path); + _panel.NavigateToFile(htmlPath); + + context.IsBusy = false; + } + + private string GenerateFontHtml(string path) + { + string fontFamilyName = FreeTypeApi.GetFontFamilyName(path); + StreamResourceInfo info = Application.GetResourceStream(new Uri($"pack://application:,,,/QuickLook.Plugin.FontViewer;component/Resources/font2html.html")); + using Stream stream = info?.Stream; + using StreamReader streamReader = new(stream, Encoding.UTF8); + string html = streamReader.ReadToEnd(); + + // src: url('xxx.eot'); + // src: url('xxx?#iefix') format('embedded-opentype'), + // url('xxx.woff') format('woff'), + // url('xxx.ttf') format('truetype'), + // url('xxx.svg#xxx') format('svg'); + var fileName = Path.GetFileName(path); + var fileExt = Path.GetExtension(fileName); + static string GenerateRandomString(int length) + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + Random random = new(); + char[] result = new char[length]; + + for (int i = 0; i < length; i++) + { + result[i] = chars[random.Next(chars.Length)]; + } + + return new string(result); + } + + string cssUrl = $"src: url('{fileName}'), url('{fileName.Substring(0, fileExt.Length)}?#{GenerateRandomString(5)}{fileExt}')" + + Path.GetExtension(path) + switch + { + ".eot" => " format('embedded-opentype');", + ".woff" => " format('woff');", + ".woff2" => " format('woff2');", + ".ttf" => " format('truetype');", + ".otf" => " format('opentype');", + _ => ";", + }; + + html = html.Replace("--font-family;", $"font-family: '{fontFamilyName}';") + .Replace("--font-url;", cssUrl) + .Replace("{{h1}}", fontFamilyName ?? fileName); + + return html; + } + + public void Cleanup() + { + GC.SuppressFinalize(this); + } +} + +file static class ResourcesProvider +{ + static ResourcesProvider() + { + if (!UriParser.IsKnownScheme("pack")) + { + _ = PackUriHelper.UriSchemePack; + } + } + + public static bool TryGetStream(Uri uri, out Stream stream) + { + try + { + StreamResourceInfo info = Application.GetResourceStream(uri); + stream = info?.Stream; + return true; + } + catch + { + } + stream = null; + return false; + } +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Properties/AssemblyInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..2a95bb747 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Properties/AssemblyInfo.cs @@ -0,0 +1,66 @@ +// Copyright © 2024 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("QuickLook.Plugin.FontViewer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("pooi.moe")] +[assembly: AssemblyProduct("QuickLook.Plugin.FontViewer")] +[assembly: AssemblyCopyright("Copyright © QL-Win Contributors")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/QuickLook.Plugin.FontViewer.csproj b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/QuickLook.Plugin.FontViewer.csproj new file mode 100644 index 000000000..9fb48fdf9 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/QuickLook.Plugin.FontViewer.csproj @@ -0,0 +1,104 @@ + + + + Library + net462 + QuickLook.Plugin.FontViewer + QuickLook.Plugin.FontViewer + 512 + false + true + latest + false + false + false + MinimumRecommendedRules.ruleset + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB} + true + + + + true + full + false + ..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.FontViewer\ + DEBUG;TRACE + prompt + + + + pdbonly + true + ..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.FontViewer\ + TRACE + prompt + + + + true + full + ..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.FontViewer\ + DEBUG;TRACE + x86 + prompt + + + + ..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.FontViewer\ + TRACE + true + pdbonly + x86 + prompt + + + + + Designer + PreserveNewest + + + + + + + PreserveNewest + $(OutDir)win-x64\ + runtimes\win-x64\freetype.dll + + + PreserveNewest + $(OutDir)win-x86\ + runtimes\win-x86\freetype.dll + + + + + + + + + + + {85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95} + QuickLook.Common + False + + + {CE22A1F3-7F2C-4EC8-BFDE-B58D0EB625FC} + QuickLook.HtmlViewer + False + + + + + + Properties\GitVersion.cs + + + + diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Resources/font2html.html b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Resources/font2html.html new file mode 100644 index 000000000..d8149d8aa --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Resources/font2html.html @@ -0,0 +1,167 @@ + + + + + Transfonter demo + + + +
+
+

{{h1}}

+
+

+ abcdefghijklmnopqrstuvwxyz
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789.:,;()*!?'@#<>$%&^+-=~ +

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+

The quick brown fox jumps over the lazy dog. 0123456789

+
+
+
+ + \ No newline at end of file diff --git a/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Translations.config b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Translations.config new file mode 100644 index 000000000..c4cbbd90a --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.FontViewer/Translations.config @@ -0,0 +1,7 @@ + + + + + The quick brown fox jumped over the lazy dog. 1234567890 + + diff --git a/QuickLook.Plugin/QuickLook.Plugin.HtmlViewer/WebpagePanel.cs b/QuickLook.Plugin/QuickLook.Plugin.HtmlViewer/WebpagePanel.cs index 63aca3e3e..0a94e9786 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.HtmlViewer/WebpagePanel.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.HtmlViewer/WebpagePanel.cs @@ -36,6 +36,12 @@ public class WebpagePanel : UserControl private string _fallbackPath; private WebView2 _webView; + public string FallbackPath + { + get => _fallbackPath; + set => _fallbackPath = value; + } + public WebpagePanel() { if (!Helper.IsWebView2Available()) @@ -59,12 +65,11 @@ public WebpagePanel() } } - public void NavigateToFile(string path, string fallbackPath = null) + public void NavigateToFile(string path) { try { _primaryPath = Path.GetDirectoryName(path); - _fallbackPath = fallbackPath; } catch (Exception e) { diff --git a/QuickLook.Plugin/QuickLook.Plugin.MarkdownViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.MarkdownViewer/Plugin.cs index 8728a0ae2..07dcd2e64 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.MarkdownViewer/Plugin.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.MarkdownViewer/Plugin.cs @@ -66,7 +66,8 @@ public void View(string path, ContextObject context) context.Title = Path.GetFileName(path); var htmlPath = GenerateMarkdownHtml(path); - _panel.NavigateToFile(htmlPath, Path.GetDirectoryName(path)); + _panel.FallbackPath = Path.GetDirectoryName(path); + _panel.NavigateToFile(htmlPath); _panel.Dispatcher.Invoke(() => { context.IsBusy = false; }, DispatcherPriority.Loaded); } diff --git a/QuickLook.sln b/QuickLook.sln index e370fd5c7..4a9836eac 100644 --- a/QuickLook.sln +++ b/QuickLook.sln @@ -50,6 +50,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "QuickLook.Installer", "Quic {CE22A1F3-7F2C-4EC8-BFDE-B58D0EB625FC} = {CE22A1F3-7F2C-4EC8-BFDE-B58D0EB625FC} {BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA} = {BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA} {8D50A1DA-601C-4C26-9A7E-7D477EA8430A} = {8D50A1DA-601C-4C26-9A7E-7D477EA8430A} + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB} = {CE40160D-5E3C-4A41-9BDA-C4F414C174EB} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native64", "QuickLook.Native\QuickLook.Native64\QuickLook.Native64.vcxproj", "{794E4DCF-F715-4836-9D30-ABD296586D23}" @@ -74,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.PluginInst EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.PEViewer", "QuickLook.Plugin\QuickLook.Plugin.PEViewer\QuickLook.Plugin.PEViewer.csproj", "{8D50A1DA-601C-4C26-9A7E-7D477EA8430A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.FontViewer", "QuickLook.Plugin\QuickLook.Plugin.FontViewer\QuickLook.Plugin.FontViewer.csproj", "{CE40160D-5E3C-4A41-9BDA-C4F414C174EB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -212,6 +215,14 @@ Global {8D50A1DA-601C-4C26-9A7E-7D477EA8430A}.Release|Any CPU.Build.0 = Release|Any CPU {8D50A1DA-601C-4C26-9A7E-7D477EA8430A}.Release|x86.ActiveCfg = Release|Any CPU {8D50A1DA-601C-4C26-9A7E-7D477EA8430A}.Release|x86.Build.0 = Release|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Debug|x86.ActiveCfg = Debug|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Debug|x86.Build.0 = Debug|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Release|Any CPU.Build.0 = Release|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Release|x86.ActiveCfg = Release|Any CPU + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -231,6 +242,7 @@ Global {45E94893-3076-4A8E-8969-6955B6340739} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {8D50A1DA-601C-4C26-9A7E-7D477EA8430A} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} + {CE40160D-5E3C-4A41-9BDA-C4F414C174EB} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}