Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using SetDefaultDllDirectories breaks Font handling

I recently got a problem in a program that used to work fine. I tracked it down to the following code:

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;
        }
    }
}

Once I use SetDefaultDllDirectories with anything but zero as a parameter the program crashes. I traced it to SafeNativeMethods.Gdip.GdipGetGenericFontFamilySansSerif(out fontfamily); which simply calls "GdipGetGenericFontFamilySansSerif". But this call fails with an FontFamilyNotFound error.

It works without the SetDefaultDllDirectories. And it even works, if I place the font assignment before AND after that call.

Is there anything on my system that causes this or was it an update from MS that causes this bug?

System: Win7 x64, fully updated, AMD Radeon HD with latest beta drivers used

Background: I need that function to use AddDllDirectory to add a subdirectory of my executables path (something like C:/MyProgram/myLibrariesX)

like image 491
Flamefire Avatar asked Apr 13 '26 11:04

Flamefire


1 Answers

I ran into the same problem as I needed native libraries to be found within an architecture folder under the base folder, i.e. x86 and x64. The work around I used was to instead append the architecture specific folder to the PATH environment variable.

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

The PATH isn't used for assembly probing but is used for native DLL probing. For assemblies I used the AppDomain.CurrentDomain.AssemblyResolve event.

like image 164
kjbartel Avatar answered Apr 15 '26 00:04

kjbartel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!