[Function] MsgBox Font Information

Post your working scripts, libraries and tools
iPhilip
Posts: 407
Joined: 02 Oct 2013, 12:21

[Function] MsgBox Font Information

06 Aug 2015, 18:27

Hi Folks,

I would like to share a couple of functions that I developed recently: GetMsgBoxFontInfo and SetMsgBoxFontInfo. As the names suggest, the functions get and set user level information about the font of Message Boxes, aka MsgBox's in AHK. This information is normally accessed under the "Change window colors and metrics" Control Panel.

Code: Select all

GetMsgBoxFontInfo(ByRef Name:="", ByRef Size:=0, ByRef Weight:=0, ByRef IsItalic:=0) {
   ; SystemParametersInfo constant for retrieving the metrics associated with the nonclient area of nonminimized windows
   static SPI_GETNONCLIENTMETRICS := 0x0029
   
   static NCM_Size        := 40 + 5*(A_IsUnicode ? 92 : 60)   ; Size of NONCLIENTMETRICS structure (not including iPaddedBorderWidth)
   static MsgFont_Offset  := 40 + 4*(A_IsUnicode ? 92 : 60)   ; Offset for lfMessageFont in NONCLIENTMETRICS structure
   static Size_Offset     := 0    ; Offset for cbSize in NONCLIENTMETRICS structure
   
   static Height_Offset   := 0    ; Offset for lfHeight in LOGFONT structure
   static Weight_Offset   := 16   ; Offset for lfWeight in LOGFONT structure
   static Italic_Offset   := 20   ; Offset for lfItalic in LOGFONT structure
   static FaceName_Offset := 28   ; Offset for lfFaceName in LOGFONT structure
   static FACESIZE        := 32   ; Size of lfFaceName array in LOGFONT structure
                                  ; Maximum number of characters in font name string
   
   VarSetCapacity(NCM, NCM_Size, 0)              ; Set the size of the NCM structure and initialize it
   NumPut(NCM_Size, &NCM, Size_Offset, "UInt")   ; Set the cbSize element of the NCM structure
   ; Get the system parameters and store them in the NONCLIENTMETRICS structure (NCM)
   if !DllCall("SystemParametersInfo"            ; If the SystemParametersInfo function returns a NULL value ...
             , "UInt", SPI_GETNONCLIENTMETRICS
             , "UInt", NCM_Size
             , "Ptr", &NCM
             , "UInt", 0)                        ; Don't update the user profile
      Return false                               ; Return false
   Name   := StrGet(&NCM + MsgFont_Offset + FaceName_Offset, FACESIZE)          ; Get the font name
   Height := NumGet(&NCM + MsgFont_Offset + Height_Offset, "Int")               ; Get the font height
   Size   := DllCall("MulDiv", "Int", -Height, "Int", 72, "Int", A_ScreenDPI)   ; Convert the font height to the font size in points
   ; Reference: http://stackoverflow.com/questions/2944149/converting-logfont-height-to-font-size-in-points
   Weight   := NumGet(&NCM + MsgFont_Offset + Weight_Offset, "Int")             ; Get the font weight (400 is normal and 700 is bold)
   IsItalic := NumGet(&NCM + MsgFont_Offset + Italic_Offset, "UChar")           ; Get the italic state of the font
   Return true
}

SetMsgBoxFontInfo(Name:="", Size:=0, Weight:=0, IsItalic:=-1) {
   ; SystemParametersInfo constants for retrieving and setting the metrics associated with the nonclient area of nonminimized windows
   static SPI_GETNONCLIENTMETRICS := 0x0029
   static SPI_SETNONCLIENTMETRICS := 0x002A
   static SPIF_UPDATEINIFILE      := 0x01
   static SPIF_SENDCHANGE         := 0x02
   
   static NCM_Size        := 40 + 5*(A_IsUnicode ? 92 : 60)   ; Size of NONCLIENTMETRICS structure (not including iPaddedBorderWidth)
   static MsgFont_Offset  := 40 + 4*(A_IsUnicode ? 92 : 60)   ; Offset for lfMessageFont in NONCLIENTMETRICS structure
   static Size_Offset     := 0    ; Offset for cbSize in NONCLIENTMETRICS structure
   
   static Height_Offset   := 0    ; Offset for lfHeight in LOGFONT structure
   static Weight_Offset   := 16   ; Offset for lfWeight in LOGFONT structure
   static Italic_Offset   := 20   ; Offset for lfItalic in LOGFONT structure
   static FaceName_Offset := 28   ; Offset for lfFaceName in LOGFONT structure
   static FACESIZE        := 32   ; Size of lfFaceName array in LOGFONT structure
                                  ; Maximum number of characters in font name string
   
   VarSetCapacity(NCM, NCM_Size, 0)              ; Set the size of the NCM structure and initialize it
   NumPut(NCM_Size, &NCM, Size_Offset, "UInt")   ; Set the cbSize element of the NCM structure
   ; Get the system parameters and store them in the NONCLIENTMETRICS structure (NCM)
   if !DllCall("SystemParametersInfo"            ; If the SystemParametersInfo function returns a NULL value ...
             , "UInt", SPI_GETNONCLIENTMETRICS
             , "UInt", NCM_Size
             , "Ptr", &NCM
             , "UInt", 0)                        ; Don't update the user profile
      Return false                               ; Return false
   if Name                                                                       ; If the font name is not blank ...
      StrPut(Name, &NCM + MsgFont_Offset + FaceName_Offset, FACESIZE)            ; Set the font name
   if Size                                                                       ; If the font size is non-zero ...
   {  Height := -DllCall("MulDiv", "Int", Size, "Int", A_ScreenDPI, "Int", 72)   ; Convert the font size to the font height
      ; Reference: http://stackoverflow.com/questions/2944149/converting-logfont-height-to-font-size-in-points
      NumPut(Height, &NCM + MsgFont_Offset + Height_Offset, "Int")               ; Set the font height
   }
   if Weight                                                                     ; If the font weight is non-zero ...
      NumPut(Weight, &NCM + MsgFont_Offset + Weight_Offset, "Int")               ; Set the font weight (400 is normal and 700 is bold)
   if (IsItalic = 1 || IsItalic = 0)                                             ; If the italic state of the font is boolean ...
      NumPut(IsItalic, &NCM + MsgFont_Offset + Italic_Offset, "UChar")           ; Set the italic state of the font
   ; Set the system parameters in the NONCLIENTMETRICS structure (NCM)
   if !DllCall("SystemParametersInfo"                                            ; If the SystemParametersInfo function returns a NULL value ...
            , "UInt", SPI_SETNONCLIENTMETRICS
            , "UInt", NCM_Size
            , "Ptr", &NCM
            , "UInt", SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)                      ; Update the user profile
      Return false                                                               ; Return false
   Return true
}

; Note: The iPaddedBorderWidth element is not included in the NONCLIENTMETRICS structures above
; because it's not required and under Windows x64 setting it causes incorrect MsgBox behavior
; Reference: http://winaero.com/blog/winaero-tweaker-is-updated-to-version-0-1-0-1/

/*
Reference Information:

SystemParametersInfo function
Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947%28v=vs.85%29.aspx

BOOL WINAPI SystemParametersInfo(   Type
  _In_    UINT  uiAction,           UInt
  _In_    UINT  uiParam,            UInt
  _Inout_ PVOID pvParam,            Ptr
  _In_    UINT  fWinIni             UInt
);

NONCLIENTMETRICS structure
Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/ff729175%28v=vs.85%29.aspx

typedef struct tagNONCLIENTMETRICS {   Offset      Size     Type
  UINT    cbSize;                      0           4        UInt
  int     iBorderWidth;                4           4        Int
  int     iScrollWidth;                8           4        Int
  int     iScrollHeight;               12          4        Int
  int     iCaptionWidth;               16          4        Int
  int     iCaptionHeight;              20          4        Int
  LOGFONT lfCaptionFont;               24          60|92
  int     iSmCaptionWidth;             84|116      4        Int
  int     iSmCaptionHeight;            88|120      4        Int
  LOGFONT lfSmCaptionFont;             92|124      60|92
  int     iMenuWidth;                  152|216     4        Int
  int     iMenuHeight;                 156|220     4        Int
  LOGFONT lfMenuFont;                  160|224     60|92
  LOGFONT lfStatusFont;                220|316     60|92
  LOGFONT lfMessageFont;               280|408     60|92
#if (WINVER >= 0x0600)                 Windows Vista or later
  int     iPaddedBorderWidth;          340|500     4        Int
#endif                                 Total       344|504    
} NONCLIENTMETRICS, *PNONCLIENTMETRICS, *LPNONCLIENTMETRICS;

LOGFONT structure
Reference: https://msdn.microsoft.com/en-us/library/windows/desktop/dd145037%28v=vs.85%29.aspx

typedef struct tagLOGFONT {            Offset      Size     Type
  LONG  lfHeight;                      0           4        Int
  LONG  lfWidth;                       4           4        Int
  LONG  lfEscapement;                  8           4        Int
  LONG  lfOrientation;                 12          4        Int
  LONG  lfWeight;                      16          4        Int
  BYTE  lfItalic;                      20          1        UChar
  BYTE  lfUnderline;                   21          1        UChar
  BYTE  lfStrikeOut;                   22          1        UChar
  BYTE  lfCharSet;                     23          1        UChar
  BYTE  lfOutPrecision;                24          1        UChar
  BYTE  lfClipPrecision;               25          1        UChar
  BYTE  lfQuality;                     26          1        UChar
  BYTE  lfPitchAndFamily;              27          1        UChar
  TCHAR lfFaceName[LF_FACESIZE];       28          32|64    Char(A)|UShort(U)
} LOGFONT, *PLOGFONT;                  Total       60|92
*/
For a quick test, you can use following script:

Code: Select all

#NoEnv

Gosub ^F11              ; Get all the MsgBox font information and display it
if Size =               ; If there was an error, tell the user and exit  
{  MsgBox Error getting MsgBox font information.
   ExitApp
}
Starting_Size := Size   ; Set the starting font size
Return

; This hotkey gets all the Message Box font information and displays it in a MsgBox

^F11::
if GetMsgBoxFontInfo(Name, Size, Weight, IsItalic)
   MsgBox MsgBox Font Information`n`nName:`t%Name%`nSize:`t%Size%`nWeight:`t%Weight%`nItalic:`t%IsItalic%
Return

; This hotkey increases the font size by one and displays the information in a new MsgBox

^++::
if SetMsgBoxFontInfo(,Size+1)
   Gosub ^F11
Return

; This hotkey decreases the font size by one and displays the information in a new MsgBox

^+-::
if SetMsgBoxFontInfo(,Size-1)
   Gosub ^F11
Return

; This hotkey restores the font size to the original size and displays the information in a new MsgBox

^F12::
if SetMsgBoxFontInfo(,Starting_Size)
   Gosub ^F11
Return

#Include MsgBoxFontInfo.ahk
I only tested the code on Windows 7 x64 so I would appreciate it if you would let me know of any testing you do on any other plaform.

Cheers,

iPhilip
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)
User avatar
jballi
Posts: 568
Joined: 29 Sep 2013, 17:34

Re: [Function] MsgBox Font Information

08 Aug 2015, 16:25

Thanks for sharing. :)

I see a lot of use for the 'Get' function. There are several functions in the Fnt library that does similar stuff. I've seen developers use this font (name and size) as the font for their GUI because it is usually easier to read than the default GUI. I say "usually" because the user can set the font used in the MsgBox dialog to anything they want.

I haven't figured out a practical use for the 'Set' function yet. It's cool sure, but when does this font need to be changed programmatically? Lack of imagination on my part I'm sure.
iPhilip
Posts: 407
Joined: 02 Oct 2013, 12:21

Re: [Function] MsgBox Font Information

10 Aug 2015, 15:20

jballi wrote:Thanks for sharing. :)
You are welcome!
jballi wrote:I see a lot of use for the 'Get' function. There are several functions in the Fnt library that does similar stuff.
I just found your library here. It looks quite comprehensive. I hope my functions can be of help to people using your library.
jballi wrote:I've seen developers use this font (name and size) as the font for their GUI because it is usually easier to read than the default GUI. I say "usually" because the user can set the font used in the MsgBox dialog to anything they want.
Quite true except that, even after resizing the control and reposition buttons, MsgBox's don't look right. In that regard, you might be interested in taking a look at this thread which motivated me to generate the functions to begin with.
jballi wrote:I haven't figured out a practical use for the 'Set' function yet. It's cool sure, but when does this font need to be changed programmatically? Lack of imagination on my part I'm sure.
My imagination is lacking as well. :lol: I just thought it would be interesting to come up with a 'Set" function since wherever there is a 'Get' function there should be a 'Set' function ... or is it the other way around? ;)
Windows 7 Pro (64 bit) - AutoHotkey v1.1+ (Unicode 32-bit)

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 44 guests