Hi @_gile ! Thanks for your information. I tried your suggestion and implement the function using HostApplicationServices api like below:
(the Active.Database is a helper class in my project which provides an easy way to access Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database)
bool checkIsFontMissingByHostApplication(string fileName)
{
bool tryFindFile(FindFileHint hint)
{
try
{
HostApplicationServices.Current.FindFile(fileName, Active.Database, hint);
return true;
}
catch
{
return false;
}
}
return !tryFindFile(FindFileHint.Default) &&
!tryFindFile(FindFileHint.FontFile) &&
!tryFindFile(FindFileHint.TrueTypeFontFile) &&
!tryFindFile(FindFileHint.FontMapFile);
}
this api makes my code much more cleaner and run as expected. but there're 2 files arial.ttf/stylu.ttf can't be found by this approach. these 2 files is located in C:\Windows\Fonts.
So for now, my workaround is to merge my original approach and HostApplicationServices api together. I have tested some dwg files and this approach works as expected(at least in all my testing file). This approach may be messy and not a good one, but at least it can be a temporary solution. It looks like :
bool checkIsFontFileMissing(TextStyleTableRecord textStyle)
{
bool checkFontFileExist(string file)
{
bool findSystemFontFolder()
{
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
string filePath = System.IO.Path.Combine(folderPath, file);
return System.IO.File.Exists(filePath);
}
bool findAcadFolder()
{
string acadPath = Environment.GetCommandLineArgs()[0];
string acadFolder = System.IO.Path.GetDirectoryName(acadPath);
string filePath = System.IO.Path.Combine(acadPath, file);
return System.IO.File.Exists(filePath);
}
bool findSearchPath()
{
object acadObject = AcadApplication.AcadApplication;
object preferences = acadObject.GetType().InvokeMember("Preferences", System.Reflection.BindingFlags.GetProperty, null, acadObject, null);
object files = preferences.GetType().InvokeMember("Files", System.Reflection.BindingFlags.GetProperty, null, preferences, null);
string searchPathStr = (string)files.GetType().InvokeMember("SupportPath", System.Reflection.BindingFlags.GetProperty, null, files, null);
string[] searchPaths = searchPathStr.Split(';');
foreach (string folderPath in searchPaths)
{
string filePath = System.IO.Path.Combine(folderPath, file);
if (System.IO.File.Exists(filePath)) return true;
}
return false;
}
bool findByHostApplicationApi()
{
bool tryFindFile(FindFileHint hint)
{
try
{
HostApplicationServices.Current.FindFile(file, Active.Database, hint);
return true;
}
catch
{
return false;
}
}
return tryFindFile(FindFileHint.FontFile) ||
tryFindFile(FindFileHint.TrueTypeFontFile) ||
tryFindFile(FindFileHint.FontMapFile) ||
tryFindFile(FindFileHint.Default);
}
string extension = System.IO.Path.GetExtension(file);
if (extension == ".ttf")
{
return findSystemFontFolder() || findByHostApplicationApi();
}
else if (extension == ".dbx")
{
return findAcadFolder() || findSearchPath() || findByHostApplicationApi();
}
else
{
return findSystemFontFolder() || findAcadFolder() || findSearchPath() || findByHostApplicationApi();
}
}
bool isFontMissing = true;
bool isBigFontMissing = true;
string fileName = textStyle.FileName;
string bigFontFileName = textStyle.BigFontFileName;
if (fileName == "") isFontMissing = false;
if (bigFontFileName == "") isBigFontMissing = false;
isFontMissing = !checkFontFileExist(fileName);
isBigFontMissing = !checkFontFileExist(bigFontFileName);
return isFontMissing || isBigFontMissing;
}
Thanks for all the information you provided! It really helps a lot. I'll update if I find a better approach to do this.