2012-06-18 5 views
5

Questa è la prima volta, in anni di esperienza nell'utilizzo dell'API di Windows, che mi trovo ad affrontare una situazione in cui devo fare qualcosa, che non posso, con l'attuale interfaccia di programmazione di Windows.Perché MS non ha nella sua win32api una funzione che restituisce il nome del file del font, dato l'handle del font?

Secondo la mia ricerca, il tipo di carattere "Arial Black" utilizza il file arialblk.ttf e non c'è nessun file per il font "Arial Black Italic", nè per il font "Arial Black Bold", almeno nel mio computer con a Windows 7.

Ho inserito sotto un programma per mostrare alcune righe di testo utilizzando il carattere "Arial Black", da solo, e quindi con corsivo e grassetto. Con mia sorpresa il testo in corsivo è stato reso normalmente e il testo in grassetto è stato reso come se fosse solo "Arial Black". Poi ho capito che la stessa cosa succede con MS Word. Ho anche inserito uno screenshot di un documento Word, sovrapposto all'output del codice qui sotto. Cosa sta succedendo qui ? Devo indovinare, quale file di font viene utilizzato in ogni caso? Apparentemente l'API di Windows non mi dà la possibilità di una risposta. Perché il mistero?

#include <Windows.h> 

LRESULT CALLBACK WndProc(HWND, UINT, UINT, LONG); 


int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow) 
{ 
    WNDCLASSEX wndclassx; 

    wndclassx.cbSize  = sizeof(WNDCLASSEX); 
    wndclassx.style   = CS_HREDRAW | CS_VREDRAW; 
    wndclassx.lpfnWndProc = WndProc; 
    wndclassx.cbClsExtra = 0; 
    wndclassx.cbWndExtra = 0; 
    wndclassx.hInstance  = hInstance; 
    wndclassx.hIcon   = nullptr; 
    wndclassx.hCursor  = LoadCursor(NULL, IDC_ARROW); 
    wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 
    wndclassx.lpszMenuName = nullptr; 
    wndclassx.lpszClassName = L"WndProc"; 
    wndclassx.hIconSm  = nullptr; 

    if(!RegisterClassEx(&wndclassx)) return 0; 

    HWND hWnd = CreateWindow(L"WndProc", nullptr, WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, CW_USEDEFAULT, 
          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr); 

    ShowWindow(hWnd, SW_MAXIMIZE); 
    UpdateWindow(hWnd); 

    MSG msg; 
    while(GetMessage(&msg, nullptr, 0, 0)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    return (int)msg.wParam; 
} 


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam) 
{ 
    static HFONT s_hArialBlack, s_hArialBlackItalic, s_hArialBlackBold; 

    switch (message) 
    { 
     case WM_CREATE: 
     { 
      LOGFONT lf; 
      memset(&lf, 0, sizeof(LOGFONT)); 
      lf.lfHeight = -MulDiv(20, 96, 72); 
      wcscpy_s(lf.lfFaceName, LF_FACESIZE, L"Arial Black"); 


      if(!(s_hArialBlack = CreateFontIndirect(&lf))) return -1; 

      lf.lfItalic = true; 

      if(!(s_hArialBlackItalic = CreateFontIndirect(&lf))) 
      { 
       DeleteObject(s_hArialBlack); 
       return -1; 
      } 

      lf.lfWeight = FW_BOLD; 
      lf.lfItalic = false; 

      if(!(s_hArialBlackBold = CreateFontIndirect(&lf))) 
      { 
       DeleteObject(s_hArialBlackItalic); 
       DeleteObject(s_hArialBlack); 
       return -1; 
      } 
     } 
     break; 

     case WM_PAINT: 
     { 
      PAINTSTRUCT ps; 
      BeginPaint(hwnd, &ps); 
      HFONT hFont = (HFONT)SelectObject(ps.hdc, s_hArialBlack); 
      TextOut(ps.hdc, 20, 10, L"Font Arial Black", 16); 
      SelectObject(ps.hdc, s_hArialBlackItalic); 
      TextOut(ps.hdc, 20, 50, L"Font Arial Black Italic", 23); 
      SelectObject(ps.hdc, s_hArialBlackBold); 
      TextOut(ps.hdc, 20, 90, L"Font Arial Black Bold", 21); 
      SelectObject(ps.hdc, hFont); 
      EndPaint(hwnd, &ps); 
     } 
     break; 

     case WM_DESTROY: 
     DeleteObject(s_hArialBlackBold); 
     DeleteObject(s_hArialBlackItalic); 
     DeleteObject(s_hArialBlack); 
     PostQuitMessage(0); 
     break; 

     default: 

     return DefWindowProc(hwnd, message, wParam, lParam); 
    } 
    return 0; 
} 

Questa è la schermata di cui ho parlato sopra:

enter image description here

+2

C'è un motivo per cui è necessario conoscere il nome del file del font, quando si conosce il tipo di carattere desiderato? – crashmstr

+0

Non vorrei entrare in questo dettaglio. Ma Windows deve farlo. Ad esempio, quando un programma chiama GetFontData(), dove il primo argomento della funzione è un handle DC, Windows deve determinare il nome del file del font, in base al font selezionato nel DC. Perché tale funzione non esiste nell'API di Windows? – WaldB

+0

È possibile che il renderer del font stia semplicemente distorcendo e addensando il font, piuttosto che usando una definizione TTF. Sono particolarmente sospettoso della versione in corsivo, ma non sono un tipo di font, quindi non posso dirlo con certezza. –

risposta

3

Non tutti i font hanno progettato le versioni corsivo o grassetto. Arial Black è uno di quelli.

Non credo che la maggior parte delle applicazioni debba essere in grado di determinare quale file di font viene effettivamente utilizzato. Da qui la mancanza di un'API diretta.

Detto questo, ci sono alcuni vecchi campioni che affermano di fare questo. Non ho provato nessuno dei metodi.

Get the font filename (like tahoma.ttf) con un C# esempio a partire dal 2006.
Finding a Font file from a Font name su CodeProject dal 2001

+0

Supponiamo che un programma chiami GetFontData() due volte per ottenere una copia dei file di font contenenti i caratteri "Arial Black" e "Arial Black Italic" in memoria. Senza sapere che i file sono gli stessi, il programma dovrebbe conservare due copie dello stesso file in memoria !! – WaldB

+0

Nel link CodeProject sopra riportato, troverai questa frase "Sfortunatamente, questo non può essere considerato un metodo efficace al 100% per trovare il nome di un file di font" – WaldB

+0

Sì, l'ho letto. Il codice C# potrebbe essere più fattibile. Non funzionando con i font a questo livello, non so quanti dati vengono restituiti da 'GetFontData'. – crashmstr

4

La funzione non esiste, semplicemente perché non v'è alcuna mappatura uno-a-uno da caratteri logiche a caratteri fisici. L'hai già scoperto parzialmente scoprendo che non hai un set dedicato di profili per il corsivo. Windows sintetizza gli stili mancanti applicando una trasformazione sul contorno. Quella stessa sintesi non ha fatto nulla di speciale con lo stile audace, il carattere è già audace.

Diventa molto più complicato quando si visualizza il testo che utilizza glifi per i quali il carattere non ha una struttura. Come i caratteri cinesi Quindi Windows completamente sostituisce un altro font con l'icona richiesta. Chiaramente questo rende impossibile implementare il tipo di funzione che desideri.

Considerare l'API Uniscribe se si desidera un migliore controllo su questo processo.

+0

>> La funzione non esiste semplicemente perché non esiste un mapping uno-a-uno dai caratteri logici a quelli fisici << Ma esiste una mappatura molti-a-uno, quindi questa funzione è valida e utile, come Ho spiegato con il mio esempio sopra, dove dovresti tenere due copie dello stesso file di font in memoria, senza sapere che rappresentano lo stesso file. – WaldB

+0

>> Considerare l'API di Uniscribe se si desidera un controllo migliore su questo processo. << Supponiamo di voler elaborare i file dei font da solo, senza utilizzare le librerie di Uniscribe. Come posso essere sicuro che non avrò copie duplicate in memoria di quei file ?? – WaldB

+0

Perché pensi che ci sia una duplicazione? Sicuramente non c'è. Non puoi scoprirlo comunque, quindi è abbastanza irrilevante. –

Problemi correlati