Как удалить файл PrivateFontCollection.AddFontFile?

Мы создаем большое количество шрифтов для краткосрочного использования. Шрифты встроены в документы. Я хочу удалить файлы шрифтов, если они больше не используются. Как мы можем это сделать? Следующий упрощенный код не работает:

PrivateFontCollection pfc = new PrivateFontCollection();
pfc.AddFontFile(fontFile);
FontFamily family = pfc.Families[0];
Console.WriteLine(family.GetName(0));

family.Dispose();
pfc.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
File.Delete(fontFile);

Удаление файла не удается, поскольку файл заблокирован. Что я могу сделать еще, чтобы снять блокировку файла?

PS: Прежде чем использовать AddMemoryFont. Это работает с Windows 7. Но с Windows 8 .NET использует неправильные файлы шрифтов после удаления первого FontFamily. Поскольку каждый документ может содержать другие шрифты, нам нужно очень большое количество шрифтов, и мы не можем хранить ссылки на все.


person Horcrux7    schedule 31.10.2014    source источник
comment
Добавлена ​​ошибка подключения connect.microsoft.com/VisualStudio/feedback/details/1379843.   -  person Peter    schedule 29.05.2015


Ответы (1)


Заглянув в код метода AddFontFile:

public void AddFontFile(string filename)
{
    IntSecurity.DemandReadFileIO(filename);
    int num = SafeNativeMethods.Gdip.GdipPrivateAddFontFile(new HandleRef(this, this.nativeFontCollection), filename);
    if (num != 0)
    {
        throw SafeNativeMethods.Gdip.StatusException(num);
    }
    SafeNativeMethods.AddFontFile(filename);
}

мы видим, что шрифт прописан 2 раза. Сначала в GDI+ и в последней строке в GDI32. Это отличается от метода AddMemoryFont. В методе Dispose он не зарегистрирован только в GDI+. Это приводит к утечке в GDI32.

Чтобы компенсировать это, вы можете вызвать следующее:

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int RemoveFontResourceEx(string lpszFilename, int fl, IntPtr pdv);

pfc.AddFontFile(fontFile);
RemoveFontResourceEx(fontFile, 16, IntPtr.Zero);
person Horcrux7    schedule 31.10.2014
comment
Для тех, кто интересуется этим «16»: это флаг FR_PRIVATE. - person Pieter Witvoet; 25.11.2014
comment
Если мы применим ваше исправление, что произойдет, если MS исправит эту ошибку? - person Peter; 29.05.2015
comment
@Peter Ничего не изменится, если вы удалите шрифт, который не был добавлен. Вы можете проверить это, если вызовете его 2 раза. Или вы вызываете его без AddFontFIle. - person Horcrux7; 30.05.2015
comment
fontFile и tempFile должны указывать на один и тот же путь к файлу, верно? - person Uwe Keim; 11.01.2016
comment
Да, это похоже на ошибку копирования и вставки. - person Horcrux7; 13.01.2016
comment
Спасибо за ваши усилия по изучению проблемы - сэкономили мне время :-) - person freakinpenguin; 16.07.2019
comment
Я думаю, что эта проблема исправлена ​​в текущем исходном коде referencesource.microsoft.com/#System.Drawing/commonui/System/, referencesource.microsoft.com/#System.Drawing/commonui/System/ - person live2; 31.12.2019