[Solved] Can I use a font in my app without installing it first? lazarus / 34-Windows ---------------------------------------------------------------------- EganSolo · 2023-04-18 17:50 I'm writing an app that is required to run on Windows only. I would like to ship this app with a curated set of fonts that are not standard on Windows. Question: Is it possible to use the fonts in my app without installing them first in Windows? Perhaps the question could be asked differently: is it possible to load a font into a TFont instance from a file? Trouble is, neither TFont nor TFPCustomFont has a LoadFromFile method which is where I'm stumped... I looked at the examples project and did not find anything that could point me in the right direction. ---------------------------------------------------------------------- rvk · 2023-04-18 18:18 Yes, it is even possible to load a font directly from a resource so you wouldn't even need a font-file. A small snippet (for complete example see below/other post): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i const  C39CodeName = 'Code 3 de 9';var  hC39FontRes: cardinal; function CheckC39: boolean;var  ResS1: TResourceStream;  FontCount1: cardinal;  FontId: integer;begin  Result := True;  FontId := Screen.Fonts.IndexOf(C39CodeName);  if FontId > 0 then exit;  if hC39FontRes > 0 then exit;   Result := False;  FontCount1 := 0;  try  ResS1 := TResourceStream.Create(hInstance, 'C39_FONT', 'RT_FONT');  try      if ResS1.Size > 14 then        hC39FontRes := AddFontMemResourceEx(ResS1.Memory, ResS1.Size,          nil, @FontCount1);    finally      ResS1.Free;      Result := (FontCount1 = 1);    end;  except    on E: Exception do      ; //ShowException(E, 'Fout bij laden C39font');  end;end; // use   if CheckC39 then  begin    lbCode39.Font.Name := C39CodeName;    lbCode39.Font.Size := 50;    lbCode39.Caption := CodingCode39(edCode39.Text);  end;  I once posted a complete example project including barcode fonts etc. See https://forum.lazarus.freepascal.org/index.php/topic,53773.msg3986 04.html#msg398604 You can change the fonts from barcode to your own custom fonts of course. If you really want to load it from a file you could use AddFontResourceEx() instead of AddFontMemResourceEx(). ---------------------------------------------------------------------- KodeZwerg · 2023-04-18 18:18 Take a look in my demo. ---------------------------------------------------------------------- EganSolo · 2023-05-03 22:09 @rvk and @KodeZwerg: Thank you so much for your replies! I got busy with a bunch of other things but I didn't think that your answers were ignored! Much appreciated. ---------------------------------------------------------------------- flowCRANE · 2023-05-17 00:13 What you are looking for is accomplished with the AddFontResourceExW function. I've successfully used it to load fonts as private to the app and finally unregister them using the RemoveFontResourceExW function. Below is the code of a small class that searches for fonts from a given location (local subdirectory of the application). It is copied from one of my project, has few years but worked on Win7 and Win10. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Tool.Fonts; {$MODE OBJFPC}{$LONGSTRINGS ON} interface uses  FGL; type  TFontsMap = class(specialize TFPGMap)  private  function IsFontFile(const AFileName: String): Boolean;    procedure ListFonts(const APath: String);  public    procedure LoadFonts();    procedure UnloadFonts();  end; implementation uses  LazUTF8,  SysUtils,  Tool.WinAPI;  function TFontsMap.IsFontFile(const AFileName: String): Boolean;var  Extension: String;begin  Extension := ExtractFileExt(AFileName);  Result := Extension.ToLower().IndexOfAny(['.ttf', '.otf']) <> -1;end;  procedure TFontsMap.ListFonts(const APath: String);var  FoundItem: TSearchRec;  FontName: WideString;begin  if FindFirst(APath + '*', faAnyFile, FoundItem) = 0 then  try    repeat      if (FoundItem.Name = '.') or (FoundItem.Name = '..') then Continue;       if FoundItem.Attr and faDirectory = faDirectory then        ListFonts(APath + FoundItem.Name + '\')      else        if IsFontFile(FoundItem.Name) then        begin          FontName := UTF8ToUTF16(APath + FoundItem.Name);        Add(FontName, 0);        end;    until FindNext(FoundItem) <> 0;  finally    FindClose(FoundItem);  end;end;  procedure TFontsMap.LoadFonts();var  FontIndex: Integer;  FontName: WideString;  FontsCount: LongInt;begin  for FontIndex := 0 to Count - 1 do  begin  FontName := Keys[FontIndex];    FontsCount := AddFontResourceExW(PWideChar(FontName), FR_PRIVATE, nil);     Data[FontIndex] := FontsCount;  end;end;  procedure TFontsMap.UnloadFonts();var  FontIndex: Integer;  FontName: WideString;begin  for FontIndex := 0 to Count - 1 do    if Data[FontIndex] <> 0 then    begin      FontName := Keys[FontIndex];    RemoveFontResourceExW(PWideChar(FontName), FR_PRIVATE, nil);    end;end;  end. ---------------------------------------------------------------------- dsiders · 2023-05-17 00:51 Quote from: furious programming on May 17, 2023, 02:13:52 amWhat you are looking for is accomplished with the AddFontResourceExW function. I've successfully used it to load fonts as private to the app and finally unregister them using the RemoveFontResourceExW function. Below is the code of a small class that searches for fonts from a given location (local subdirectory of the application). It is copied from one of my project, has few years but worked on Win7 and Win10. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Tool.Fonts; {$MODE OBJFPC}{$LONGSTRINGS ON} interface uses  FGL; type  TFontsMap = class(specialize TFPGMap)  private  function IsFontFile(const AFileName: String): Boolean;    procedure ListFonts(const APath: String);  public    procedure LoadFonts();    procedure UnloadFonts();  end; implementation uses  LazUTF8,  SysUtils,  Tool.WinAPI;  function TFontsMap.IsFontFile(const AFileName: String): Boolean;var  Extension: String;begin  Extension := ExtractFileExt(AFileName);  Result := Extension.ToLower().IndexOfAny(['.ttf', '.otf']) <> -1;end;  procedure TFontsMap.ListFonts(const APath: String);var  FoundItem: TSearchRec;  FontName: WideString;begin  if FindFirst(APath + '*', faAnyFile, FoundItem) = 0 then  try    repeat      if (FoundItem.Name = '.') or (FoundItem.Name = '..') then Continue;       if FoundItem.Attr and faDirectory = faDirectory then        ListFonts(APath + FoundItem.Name + '\')      else        if IsFontFile(FoundItem.Name) then        begin          FontName := UTF8ToUTF16(APath + FoundItem.Name);        Add(FontName, 0);        end;    until FindNext(FoundItem) <> 0;  finally    FindClose(FoundItem);  end;end;  procedure TFontsMap.LoadFonts();var  FontIndex: Integer;  FontName: WideString;  FontsCount: LongInt;begin  for FontIndex := 0 to Count - 1 do  begin  FontName := Keys[FontIndex];    FontsCount := AddFontResourceExW(PWideChar(FontName), FR_PRIVATE, nil);     Data[FontIndex] := FontsCount;  end;end;  procedure TFontsMap.UnloadFonts();var  FontIndex: Integer;  FontName: WideString;begin  for FontIndex := 0 to Count - 1 do    if Data[FontIndex] <> 0 then    begin      FontName := Keys[FontIndex];    RemoveFontResourceExW(PWideChar(FontName), FR_PRIVATE, nil);    end;end;  end. No one can test or use this without the tool.winapi unit. ---------------------------------------------------------------------- ASerge · 2023-05-17 17:23 Quote from: dsiders on May 17, 2023, 02:51:45 amNo one can test or use this without the tool.winapi unit. Replace this unit with JwaWinGDI. ---------------------------------------------------------------------- flowCRANE · 2023-06-07 15:29 Sorry, I didn't notice that this module is attached. It simply contain WinAPI function imports: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  Windows; const  FR_PRIVATE  = $00000010;  FR_NOT_ENUM = $00000020;   function AddFontResourceExW(name: LPCWSTR; fl: DWORD; res: PVOID): LongInt; stdcall external 'gdi32.dll';  function RemoveFontResourceExW(name: LPCWSTR; fl: DWORD; pdv: PVOID): BOOL; stdcall external 'gdi32.dll'; You can use these constants and imports or find a unit with them (like JwaWinGDI).