Create an API hFont from a VB StdFont object
If you are working with API based controls you will find that to set fonts you need a GDI
hFont handle to the font. The StdFont object does not directly supply you with this handle.
Although it is possible to cast the StdFont object as an IFont object, which does have
a hFont handle property, you still don't get full control over the
setting of the font properties, and note that since you cannot call the AddRefhFont method from VB there may be instances in which the handle unexpectedly
becomes invalid.
The alternative to this is to create a GDI font from first principles using the API call
CreateFontIndirect. This takes a LOGFONT structure which specifies the font to be created.
The LOGFONT structure's members are quite closely related to the StdFont object's properties -
but you need to be careful when specifying the font name and size. This tip contains a reliable
function to transform a StdFont object into a LOGFONT and briefly demonstrates using
a GDI font created by this method.
The demonstration is a bit pointless - it only does what could be done more simply
using the StdFont object and the Print method. However, this code is
really useful if you are building a control using the API or you need to draw on a GDI device context.
Start a new project in VB, and add a standard module. Then add the following code to the module:
' Font:
Private Const LF_FACESIZE = 32
Private Type LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName(LF_FACESIZE) As Byte
End Type
Private Const FW_NORMAL = 400
Private Const FW_BOLD = 700
Private Const FF_DONTCARE = 0
Private Const DEFAULT_QUALITY = 0
Private Const DEFAULT_PITCH = 0
Private Const DEFAULT_CHARSET = 1
Private Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" ( _
lpLogFont As LOGFONT) As Long
Private Declare Function MulDiv Lib "kernel32" ( _
ByVal nNumber As Long, ByVal nNumerator As Long, ByVal nDenominator As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" ( _
ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Const LOGPIXELSY = 90
' Testing the font:
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function DrawText Lib "user32" Alias "DrawTextA" ( _
ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, _
lpRect As RECT, ByVal wFormat As Long) As Long
Private Const DT_CALCRECT = &H400
Private Declare Function SelectObject Lib "gdi32" ( _
ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function OffsetRect Lib "user32" ( _
lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
Public Sub Test(ByVal hdc As Long, fntThis As StdFont)
Dim tLF As LOGFONT
Dim hFnt As Long
Dim hFntOld As Long
Dim tR As RECT
' Create a LOGFONT structure equivalent to the
' StdFont font:
pOLEFontToLogFont fntThis, hdc, tLF
' Convert the LOGFONT into a font handle:
hFnt = CreateFontIndirect(tLF)
' Test the font out:
hFntOld = SelectObject(hdc, hFnt)
DrawText hdc, "This is a test", -1, tR, DT_CALCRECT
OffsetRect tR, 32, 32
DrawText hdc, "This is a test", -1, tR, 0&
SelectObject hdc, hFntOld
' Always remember to delete the font when finished
' with it:
DeleteObject hFnt
End Sub
Private Sub pOLEFontToLogFont(fntThis As StdFont, ByVal hdc As Long, tLF As LOGFONT)
Dim sFont As String
Dim iChar As Integer
Dim b() As Byte
' Convert an OLE StdFont to a LOGFONT structure:
With tLF
sFont = fntThis.Name
b = StrConv(sFont, vbFromUnicode)
For iChar = 1 To Len(sFont)
.lfFaceName(iChar - 1) = b(iChar - 1)
Next iChar
' Based on the Win32SDK documentation:
.lfHeight = -MulDiv((fntThis.Size), (GetDeviceCaps(hdc, LOGPIXELSY)), 72)
.lfItalic = fntThis.Italic
If (fntThis.Bold) Then
.lfWeight = FW_BOLD
Else
.lfWeight = FW_NORMAL
End If
.lfUnderline = fntThis.Underline
.lfStrikeOut = fntThis.Strikethrough
.lfCharSet = fntThis.Charset
End With
End Sub
To try out the code, add a Command Button to your test project's main form. Then add this code to the
Button's Click event:
Private Sub Command1_Click()
Dim sFnt As New StdFont
sFnt.Name = "Arial"
sFnt.Size = 48
Test Me.hdc, sFnt
End Sub
Run the project. It will draw the text "This is a Test" in
48-point Arial by selecting a GDI font into the form's device context.
|
|