Page 1 of 2 1 2 LastLast
Results 1 to 15 of 16

Thread: Bestandsnamen tijdelijk geinstalleerde fonts

  1. #1

    Bestandsnamen tijdelijk geinstalleerde fonts

    Hoi allemaal,

    Na jaren van zelfredzaamheid heb ik nu weer een vraagstuk waar ik niet zo snel uit kom. Het is misschien meer een Windows dan een Delphi vraag maar ik probeer het toch via dit forum.

    Via de registry is het mogelijk om de geïnstalleerde fonts en bijbehorende bestandsnamen op te halen (HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts), tijdelijk geïnstalleerde fonts staan hier logisch niet bij maar worden toch ergens binnen Windows bijgehouden want deze tijdelijk geïnstalleerde fonts worden wel met de fontnaam weergegeven middels bv Screen.Fonts.

    Code:
    ListBox1.Items.Assign(Screen.Fonts);
    Dat maakt mij nieuwsgierig of binnen Windows ergens een lijst/tabel wordt bijgehouden met de bestandsnaam van de tijdelijk geïnstalleerde fonts. En zo ja, hoe krijg ik dan via Delphi toegang tot deze lijst/tabel.

    groet,
    Michel

  2. #2
    Senior Member Wok's Avatar
    Join Date
    Dec 2002
    Location
    Alkmaar
    Posts
    2,085
    Fonts staan toch gewoon in de Windows map C:\Windows\Fonts\
    10.4.2, Delphi2010, of Lazarus 2.2.0

  3. #3
    Misschien een rare vraag maar wat zijn "tijdelijk geïnstalleerde fonts".
    Last edited by rvk; 07-Sep-18 at 00:07.

  4. #4
    @Wok @rvk

    Meestal installeer je fonts in Windows permanent en worden deze geplaatst in de folder CSIDL_FONTS (en dat is dan weer meestal C:\Windows\Fonts). Niet altijd want een programma als bijvoorbeeld Acrobat Pro installeerd een aantal fonts permanent vanuit CSIDL_PROGRAM_FILES.

    Permanent geïnstalleerde fonts zijn altijd binnen Windows beschikbaar, ongeacht welke applicaties opgestart zijn. Een overzicht van deze fonts (font naam + bestandsnaam) vind je in de registry onder HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts.

    Tijdelijke fonts worden door een specifieke applicatie geïnstalleerd middels AddFontResource. Het maakt daarbij niet uit in welke folder de fonts staan. Zolang de applicatie welke de fonts tijdelijk installeerd actief is zijn de fonts binnen Windows aanwezig. Ze worden dan ook met Screen.Fonts zichtbaar. Omdat ze tijdelijk geïnstalleerd zijn worden ze echter niet toegevoegd aan HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts.

    Zodra de applicatie welke de tijdelijke fonts installeerd heeft wordt afgesloten of zodra de Windows sessie stopt zijn de tijdelijke fonts niet meer beschikbaar.

    In de microsoft beschrijving van de AddFontResource function wordt beschreven:

    The AddFontResource function adds the font resource from the specified file to the system font table. The font can subsequently be used for text output by any application.
    https://docs.microsoft.com/en-us/win...dfontresourcea

    Ergens wordt dus door Windows een "system font table" bijgehouden. Helaas geeft Microsoft in deze beschrijving niet aan waar de "system font table" dan bijgehouden wordt en welke informatie deze bevat.

    Voor mijn applicatie zou het ter controle prettig zijn om te weten wat de bestandsnamen van de tijdelijk geïnstalleerde fonts zijn. Staat de bestandsnaam van het font namelijk in "het lijstje" dan is het font tijdelijk geïnstalleerd, staat de bestandsnaam niet in "het lijstje" (en ook niet in de registry) dan is het font niet (tijdelijk) geïnstalleerd.

    De fontnaam alleen is niet bruikbaar want sommige varianten (bv italic) kunnen binnen Screen.Fonts dezelfde fontnaam delen en komen zo maar één keer voor in Screen.Fonts.
    Last edited by msis; 07-Sep-18 at 09:11.

  5. #5
    Misschien dat je voordat je het programma start met de tijdelijke fonts een export kunt maken van je registry en deze vergelijkt met een export van je registry als het programma met tijdelijke fonts draait. Als de tijdelijke fonts in het register worden opgeslagen dan zou je dit moeten kunnen zien.

  6. #6
    Helaas komen tijdelijke fonts niet in de registry terecht. Het doorzoeken van de registry op fontnaam of bestandsnaam na tijdelijke installatie geeft geen resultaat terug. Mijn vermoeden is dat de "system font table" niet in de registry staat.

  7. #7
    https://forums.adobe.com/thread/1749289 Als ik het goed begrijp wordt het in ieder geval bij Adobe opgeslagen onder AppData/loal/Temp. Misschien een poging waard.

  8. #8
    Als je Screen.Fonts gebruikt dan worden de fonts via EnumFontFamiliesEx() direct uit de interne Windows Font-table opgehaald.

    Dus als antwoord op jouw vraag... Ja, er wordt binnen Windows een interne font tabel bijgehouden en die kun jij benaderen door EnumFontFamiliesEx() (of het uitlezen van Screen.Fonts).

    Wat wil je er precies mee doen?

  9. #9
    O... PS. Je vroeg naar de bestandsnamen van de tijdelijke fonts. Maar wat als die font geen bestandsnaam heeft. Het is namelijk ook mogelijk om een font uit een resource direct naar het geheugen te pompen. Er is dan ook geen bestandsnaam. Dus dan vraag ik me af of deze wel bijgehouden wordt in de interne Font Table.

  10. #10
    @luigi

    Slim gevonden, ik heb het getest maar helaas komen tijdelijk geinstalleerde fonts vanuit andere applicaties niet in AppData/loal/Temp terecht. Is dus echt een Acrobat dingetje.

    @rvk

    Er is idd een interne font tabel naar die maakt geen onderscheid tussen varianten binnen hetzelfde font als bijvoorbeeld "Aileron-Black.otf" en "Aileron-BlackItalic.otf":

    "Aileron-Black.otf" wordt middels Screen.Fonts weergegeven als "Aileron Black" en staat in de registry als "Aileron Black"
    "Aileron-BlackItalic.otf" wordt middels Screen.Fonts ook weergegeven als "Aileron Black" maar staat in de registry als "Aileron Black Italic"

    Middels het vergelijken van Screen.Fonts kan ik, als "Aileron-Black.otf" al geïnstalleerd is dus niet controleren of "Aileron-BlackItalic.otf" nog niet geïnstalleerd is. Immers beide font files geven in Screen.Fonts dezelfde naam terug.

    Zou ik willen controleren of de tijdelijke installatie van "Aileron" is gelukt dan kan ik na installatie van "Aileron-Black.otf" controleren of "Aileron Black" aan "Screen.Fonts" is toegevoegd. Maar zodra "Aileron-Black.otf" is toegevoegd kan
    ik deze manier niet meer gebruiken om te contoleren of de tijdelijke installatie van "Aileron-BlackItalic.otf" ook gelukt is.

    Wat ik dus zoek is een manier om te controleren of de tijdelijke installatie / de-installatie van een font is gelukt. Daarnaast wil ik, als een font al in Windows aanwezig is, dit font niet opnemen in een lijst met mogelijk tijdelijk te installeren fonts.


    @rvk

    Je hebt gelijk dat fonts ook uit een resource geïnstalleerd kunnen worden waardoor een vergelijking op font naam zoals deze in de registry staat de meest veilige methode is. Helaas staan de tijdelijk geïnstalleerde fonts daar dan weer niet bij. En dan heb je ook nog het probleem van de oorsprong van naamgeving in de registry. Hoe komt Windows aan die naam? De naam van het font in de font file "Aileron-BlackItalic.otf" staat in het font "Aileron Black" maar wordt door Windows als "Aileron Black Italic" in de registry gezet. Bij sommige fonts werkt Windows bij de naamgeving in de registry met een tussenstreepje, bij andere weer niet.

  11. #11
    EnumFontFamiliesEx() geeft volgens mij in LOGFONT wel terug (met lfItalic) of een (deel)font italic is. Dus je kunt op die manier wel zien of italic al geïnstalleerd is.
    https://docs.microsoft.com/en-us/win...ontfamiliesexa

    lfCharSet = DEFAULT_CHARSET
    lfFaceName = a specific font
    Enumerates all character sets and styles in a specific font.

  12. #12
    Klopt, had ik ook gelezen, maar ik krijg het met mijn huidige kennis nog niet voor elkaar. Wat ik als voorbeeld heb gevonden (dank google) is:

    Code:
    function EnumFontsProc(var LogFont: TLogFont; var TextMetric: TTextMetric;
      FontType: Integer; Data: Pointer): Integer; stdcall;
    var
      S: TStrings;
      Temp: string;
    begin
      S := TStrings(Data);
      Temp := LogFont.lfFaceName;
      if (S.Count = 0) or (AnsiCompareText(S[S.Count-1], Temp) <> 0) then
        S.Add(Temp);
      Result := 1;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      DC: HDC;
      LFont: TLogFont;
      MyFonts: TStrings;
    begin
        MyFonts := TStringList.Create;
        DC := GetDC(0);
        try
          FillChar(LFont, sizeof(LFont), 0);
          LFont.lfCharset := DEFAULT_CHARSET;
          EnumFontFamiliesEx(DC, LFont, @EnumFontsProc, Winapi.Windows.LPARAM(MyFonts), 0);
          TStringList(MyFonts).Sorted := TRUE;
        finally
          ReleaseDC(0, DC);
        end;
      ListBox1.Items.Assign(MyFonts);
     MyFonts.Free;
    end;
    Bovenstaande code maakt alleen gebruik van lfFaceName, nog niet van lfItalic of lfUnderline.

    Een font als "Book Antiqua" (standaard Windows ?) komt nu terug als "Book Antiqua" maar bestaat eigenlijk uit "Book Antiqua Bold", "Book Antiqua Bold Italic", "Book Antiqua Italic" en "Book Antiqua Regular".

    Wat zijn de benodigde aanpassingen om alle vier de benamingen als resultaat terug te krijgen? Vermoedelijk is Bold een onderdeel van lfWeight (FW_Bold)?

  13. #13
    Ja, in de interne Font Table hebben al die fonts uit die verschillende files dezelfde font naam. Ze hebben alleen verschillende karakteristieken.

    Je krijgt alle karakteristieken als je lfFaceName op de naam van de font zet (anders krijg je geen dubbele). Nu heb je LFont gevuld met 0 maar je moet alleen nog even de LFont.lfFaceName op de juiste fontnaam zetten.

    Delphi Code:
    1. FillChar(LFont, sizeof(LFont), 0);
    2. LFont.lfFaceName := 'Calibri'; // <---- dit dus

    Als je nu in EnumFontsProc() de controle op de vorige fontnaam ook even weg haalt en bijvoorbeeld lfItalic opneemt in de ListBox dan zul je zien dat er fonts zijn met italic en zonder. Je zult nog meer fonts tegenkomen omdat je ook Bold+Italic e.d. hebt.

    Delphi Code:
    1. // if (S.Count = 0) or (AnsiCompareText(S[S.Count-1], Temp) <> 0) then
    2. S.Add(Temp + ' ' + LogFont.lfItalic.ToString);

    Maar als je dus een font Aileron Black hebt met lfItalic = 255 dan is die dus (e.v. tijdelijk) geïnstalleerd.

  14. #14
    Thanks, ik ben het aan het proberen en het lijkt dat we weer een stukje verder zijn maar zodra ik 'Calibri' vervang door een variabele krijg ik een foutmelding. lfFaceName is een Char, met een String krijg ik dus logisch een E2010 Incompatible types: 'array[0..31] of Char' and 'string', maar als ik de string omzet naar een array[0..31] of Char dan krijg ik een E2008 Incompatible types. Wat zie ik over het hoofd?

  15. #15
    Quote Originally Posted by msis View Post
    ... maar zodra ik 'Calibri' vervang door een variabele krijg ik een foutmelding.
    Delphi Code:
    1. var
    2.   FontNaam: String;
    3. begin
    4.   //...
    5.       FontNaam := 'Calibri';
    6.       StringToWideChar(FontNaam, LFont.lfFaceName, LF_FACESIZE);

Page 1 of 2 1 2 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •