Hi! I'm trying to find a way to check if any font file is missing. In AutoCAD, there's a little yellow icon displayed if this font file is missing:
I wrote a command to test, I can access FileName and BigFontFileName property of TextStyleTableRecord:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application;
[CommandMethod("TT")]
public void TT()
{
try
{
Document doc = AcadApplication.DocumentManager.MdiActiveDocument;
Database database = doc.Database;
Editor editor = doc.Editor;
using (var tr = database.TransactionManager.StartTransaction())
{
var textStyleTbl = database.TextStyleTableId.GetObject(OpenMode.ForRead) as TextStyleTable;
foreach (ObjectId objId in textStyleTbl)
{
var textStyle = objId.GetObject(OpenMode.ForRead) as TextStyleTableRecord;
editor.WriteMessage($"\nfont file:{textStyle.FileName}, " +
$"big font file:{textStyle.BigFontFileName}");
//...isFontMissing(textStyle.FileName);
}
}
}
catch (System.Exception ex)
{
AcadApplication.ShowAlertDialog("Unhandled Exception:\n" + ex.Message);
return;
}
}
Is it possible to do this via .NET api ? Any suggestion is really appreciated!
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Solved by SENL1362. Go to Solution.
Try these locations:
A. For (Big) font files named "*.ttf" look in the folder: System.Environment.SpecialFolder.Fonts
if not found then: missing...
B. For (Big) font files named "*.dbx" look in:
1. Acad.exe folder(Commandline arg[0])
2. Acad Search Path's("ACADPREFIX")
if not found then: missing...
C. For any other fontfile extension (*.shx, or no extension,...)
1. Search A
2. Search B
D. Don't forget to look in the Font MAP file C:\Program files\... *.fmp, %appdata%\...
It maps fontnames to TTF files.
var acadCmdline = Environment.CommandLine;
//Or
var acadArgs = Environment.GetCommandLineArgs();
Thanks for your help! I have try your suggestion and it seemed to work good. But I met some issue :
(1) some of dwg files I have tested has text style SIMPLEX and ITALIC, their FileName is also SIMPLEX and ITALIC(with no extension). I can't find them in every directories but in AutoCAD, they are not shown missing. should I skip them? or are they store in Font Map file as you mentioned before? but I'm not sure where would *.fmp file located. (I didn't see any of it in C:/ProgramFiles/... and %appdata%/... )
(2) I have tested one file that has a text style named C2. in AutoCAD its font file is txt.shx, but its FileName return txt(with no extension). that made the result being missing (but actually exists in one of search paths). but only one dwg file has this strange issue. I have checked some other dwg files which also contains txt.shx font, but in other files FileName property always return txt.shx
below is my code snippet for checking if font file missing based on logic you seggested :
bool checkIsFontFileMissing(TextStyleTableRecord textStyle)
{
bool isFontMissing = true;
bool isBigFontMissing = true;
string fileName = textStyle.FileName;
string bigFontFileName = textStyle.BigFontFileName;
if (fileName == "") isFontMissing = false;
if (bigFontFileName == "") isBigFontMissing = false;
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;
}
string extension = System.IO.Path.GetExtension(file);
if (extension == ".ttf")
{
return findSystemFontFolder();
}
else if (extension == ".dbx")
{
return findAcadFolder() || findSearchPath();
}
else
{
return findSystemFontFolder() || findAcadFolder() || findSearchPath();
}
}
isFontMissing = !checkFontFileExist(fileName);
isBigFontMissing = !checkFontFileExist(bigFontFileName);
return isFontMissing || isBigFontMissing;
}
apologize for the long code. do you have idea about the issues? thanks for your time and help!
(1)
Acad.fmp:
C:\Program Files\Autodesk\AutoCAD 20xx\UserDataCache\Support
DwgViewr.fmp:
C:\Program Files\Autodesk\DWG TrueView 2022 - English\UserDataCache\Support
%appdata%\Autodesk\...\Support\Simplex.shx
C:\Program Files\Autodesk\AutoCAD xxx\Fonts\italic.shx
There are a few ways to check Drawing dependencies, for Fonts, the easiest way may be:
1. Create or Open your drawing;
2. Add some Text in your Font;
3. Create Transmittal (Click AutoCAD Logo/Send/eTransmit)
4. View Report
Hi,
What about using the HostApplicationServices.FindFile method?
Here's an extension method:
public static bool TryFindFile(this Database db, string fileName, FindFileHint hint, out string path)
{
try
{
path = HostApplicationServices.Current.FindFile(fileName, db, hint);
return true;
}
catch
{
path = null;
return false;
}
}
Using example:
var db = HostApplicationServices.WorkingDatabase;
if (db.TryFindFile("china.shx", FindFileHint.FontFile, out string path))
{
// ...
}
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.
Can't find what you're looking for? Ask the community or share your knowledge.