【问题标题】:Using SetDefaultDllDirectories breaks Font handling使用 SetDefaultDllDirectories 会中断字体处理
【发布时间】:2014-11-07 05:03:00
【问题描述】:

我最近在一个过去可以正常工作的程序中遇到问题。我追踪到以下代码:

using System.Drawing;
using System.Runtime.InteropServices;

namespace Foo
{
    static class CProgram
    {
        [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetDefaultDllDirectories(int directoryFlags);

        public const int LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x000001000;

        private static void Main()
        {
            SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
            Font font = SystemFonts.DefaultFont;
        }
    }
}

一旦我将 SetDefaultDllDirectories 用作参数而不是零,程序就会崩溃。我追踪到 SafeNativeMethods.Gdip.GdipGetGenericFontFamilySansSerif(out fontfamily);它简单地称为“GdipGetGenericFontFamilySansSerif”。但此调用失败并出现 FontFamilyNotFound 错误。

它可以在没有 SetDefaultDllDirectories 的情况下工作。如果我在调用之前和之后放置字体分配,它甚至可以工作。

我的系统上是否有任何东西导致了这个问题,或者是 MS 的更新导致了这个错误?

系统:Win7 x64,完全更新,AMD Radeon HD 使用最新的 beta 驱动程序

背景:我需要该函数来使用 AddDllDirectory 添加我的可执行文件路径的子目录(类似于 C:/MyProgram/myLibrariesX)

【问题讨论】:

  • Hmya,这是最糟糕的全局变量。 Gdiplus.dll 有两个版本,您基本上永远不会想要 system32 中的兼容版本,那就是龙。这是一个 XY 问题,它肯定比 that 有更好的答案。不仅限于避免故意给 Windows 带来麻烦,只需将 DLL 复制到正确的位置即可。
  • 我同意汉斯的观点。换句话说,AFAIK,问题只是 .NET 不支持对 SetDefaultDllDirectories 的调用。
  • 同意。你需要解决问题的根源。
  • 用调试器查看加载的库显示,在这两种情况下,加载了来自 WinSxS 文件夹的相同 dll。目录的背景是,一个包含 x86 和一个 x64 dll。在启动时(使用“任何”架构编译)它会选择正确的文件夹来加载。还有很多 gstreamer 插件最好放在一个单独的文件夹中,而不是在一个文件夹中包含 100 个文件。跟进“.NET 不支持对 SetDefaultDllDirectories 的调用”:为什么?调用本身有效...当前解决方法:在使用该功能之前访问 SystemFonts.DefaultFont...
  • 由于MS14-045/CVE-2014-1819,MS 最近改变了字体加载的工作方式。我不知道这是否与您的问题特别相关,但如果您想更深入地了解代码失败的确切原因,请尝试运行Process Monitor

标签: .net winforms winapi fonts gdi


【解决方案1】:

我无法在 Windows 8.1 x64 中重现 Visual Studio 2013 的问题,而我可以在 Windows 7 上重现它。所以现在似乎已修复。

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,因为我需要在基本文件夹下的架构文件夹中找到本机库,即 x86 和 x64。我使用的解决方法是将特定于体系结构的文件夹附加到 PATH 环境变量中。

    var archPath = $"{AppDomain.CurrentDomain.BaseDirectory}{Environment.Is64BitProcess ? "x64" : "x86"}\\";
    var pathVariable = Environment.GetEnvironmentVariable("PATH");
    pathVariable = $"{archPath};{pathVariable}";
    Environment.SetEnvironmentVariable("PATH", pathVariable);
    

    PATH 不用于assembly probing,但用于native DLL probing。对于程序集,我使用了AppDomain.CurrentDomain.AssemblyResolve 事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-09
      • 1970-01-01
      • 2016-03-09
      • 2022-11-01
      • 1970-01-01
      • 2020-12-03
      相关资源
      最近更新 更多