在Visual Basic 2010中嵌入自定义字体FOT文本框的使用

问题描述:

好,我正在处理一个问题,试图在文本框中嵌入LCD型真型字体.对于某些背景,如果将字体安装到系统上,然后将其作为文本框的字体类型加载,则可以显示液晶字体.但是,它不能用作应用程序中的嵌入式字体.我正在Windows 7盒子上的Microsoft Visual Studio 2010中使用Visual Basic中的Windows窗体应用程序.

OK I'm working on a problem tyring to embed a LCD type true type font in a text box. As for some background, I can get the lcd font to display if I install the font onto my system, then load it as the font type for the text box and it works great. However, it will not work as an embedded font in the application. I"m using a a Windows Forms Application in Visual Basic, from the Microsoft Visual Studio 2010 on a Windows 7 box.

在将字体存储为资源文件并将属性设置为嵌入资源之后,我尝试使用内存中的私有字体集合执行以下代码.

I have tried the following code using a private font collection from memory after storing the font as a resource file and setting the property to embed resource.

Imports System.Drawing.Text

Imports System.Runtime.InteropServices

Module CustomFont

'PRIVATE FONT COLLECTION TO HOLD THE DYNAMIC FONT

Private _pfc As PrivateFontCollection = Nothing

Public ReadOnly Property GetInstance(ByVal Size As Single, _

                                     ByVal style As FontStyle) As Font

    Get

        'IF THIS IS THE FIRST TIME GETTING AN INSTANCE

        'LOAD THE FONT FROM RESOURCES

        If _pfc Is Nothing Then LoadFont()

        'RETURN A NEW FONT OBJECT BASED ON THE SIZE AND STYLE PASSED IN

        Return New Font(_pfc.Families(0), Size, style)


    End Get

End Property



Private Sub LoadFont()

    Try

        'INIT THE FONT COLLECTION

        _pfc = New PrivateFontCollection



        'LOAD MEMORY POINTER FOR FONT RESOURCE

        Dim fontMemPointer As IntPtr = _

            Marshal.AllocCoTaskMem( _

            My.Resources.DIGITALDREAMNARROW.Length)



        'COPY THE DATA TO THE MEMORY LOCATION

        Marshal.Copy(My.Resources.DIGITALDREAMNARROW, _

                     0, fontMemPointer, _

                     My.Resources.DIGITALDREAMNARROW.Length)



        'LOAD THE MEMORY FONT INTO THE PRIVATE FONT COLLECTION

        _pfc.AddMemoryFont(fontMemPointer, _

                           My.Resources.DIGITALDREAMNARROW.Length)


        'FREE UNSAFE MEMORY

        Marshal.FreeCoTaskMem(fontMemPointer)

    Catch ex As Exception

        'ERROR LOADING FONT. HANDLE EXCEPTION HERE

    End Try


End Sub

End Module

此代码的问题是您应该将控件的UseCompatibleTextRendering属性设置为true.如果在标签或按钮文本上使用此模块,则效果很好.但是,对于文本框,没有UseCompatibleTextRendering属性.

The problem with this code is that you are supposed to enable the control's UseCompatibleTextRendering property to true. Granted if using this module on a lable or button text it works great. For a text box however, there is no UseCompatibleTextRendering property.

我已经了解到文本框使用GDI渲染,而其他文本控件使用GDI +(我可能将它们切换了,所以请不要在此引用我,我只记得它们是不同的).

I've come to understand that the text boxes use GDI rendering whereas the other text controls use GDI+ ( I may have those switched around, so don't quote me on that, All i remember is that they are different).

我发现一些较旧的代码片段尝试使用Windows中gdi32.dll文件中的AddFontMemResourceEX函数,还有一些声称可以在文本框中使用.因此,我创建了以下课程.

I found some older code snipits trying that use the AddFontMemResourceEX function from the gdi32.dll file in windows, and some have claimed that it works for use in text boxes. So I created the following class.

Imports System
Imports System.Drawing.Text
Imports System.IO
Imports System.Reflection

Public Class GetLCDFont
Private Declare Auto Function AddFontMemResourceEX Lib "gdi32.dll" _
    (ByVal pbFont As Integer, ByVal cbFont As Integer, _
     ByVal pdv As Integer, ByRef pcFonts As Integer) As IntPtr

Public Shared Function GetFont(ByVal fontName As String) As FontFamily

    Dim exeCurrent As [Assembly] = [Assembly].GetExecutingAssembly()
    Dim nameSpc As String = exeCurrent.GetName().Name.ToString()
    Dim fontCollection As New PrivateFontCollection
    Dim loadStream As Stream = exeCurrent.GetManifestResourceStream( _
        nameSpc + "." + fontName)
    Dim byteBuffer(CType(loadStream.Length, Integer)) As Byte

    loadStream.Read(byteBuffer, 0, Int(CType(loadStream.Length, Integer)))

    Dim fontPtr As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal( _
        Runtime.InteropServices.Marshal.SizeOf(GetType(Byte)) * _
        byteBuffer.Length)

    Runtime.InteropServices.Marshal.Copy(byteBuffer, 0, fontPtr, byteBuffer.Length)

    fontCollection.AddMemoryFont(fontPtr, byteBuffer.Length)

    Dim pcFonts As Int32 = 1

    AddFontMemResourceEX(fontPtr, byteBuffer.Length, 0, pcFonts)

    Runtime.InteropServices.Marshal.FreeHGlobal(fontPtr)
    Return fontCollection.Families(0)

End Function

Public Sub New()

End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
End Sub
End Class

但是,当调用此类时,我收到一个InvalidOperatioException未处理.该错误是无法在DLL'gdi32.dll'中找到名为'AddFontMemResourceEX'的条目.

However when calling this class, I get a InvalidOperatioException was unhandled. The error is Unable to find an entry pointed named 'AddFontMemResourceEX in DLL 'gdi32.dll'.

希望某人可以帮助我告诉我我出了什么问题,或者向我指出一个方向,该方向可以帮助我将字体嵌入在与Windows Forms Application一起使用的文本框中.

Hoping someone could help me either tell me what i'm going wrong, or point me in a direction that would help me embed a font for use in text boxes for use with a Windows Forms Application.

MSDN上引用的大多数示例都指向使用WPF应用程序时如何打包字体.

Most of the examples referenced at MSDN all point to how to package fonts when using a WPF application.

谢谢.

虽然不是很干净,但是您可以使用安装程序将字体放在应用程序目录中,然后使用以下命令将其加载到PrivateFontCollection中:

Although it's not as clean, you can use your installer to put the fonts in your application directory, and load them into your PrivateFontCollection using:

    For Each fontfile As String In System.IO.Directory.GetFiles(filepath & "\Fonts", "*.ttf")
        _pfc.AddFontFile(fontfile)
    Next fontfile

我不确定为什么Microsoft会对此加以区别,但是我的TextBoxes和ComboBoxes现在使用我的自定义字体,即使它们没有UseCompatibleTextRendering属性也是如此.

I'm not sure why Microsoft treats this differently, but my TextBoxes and ComboBoxes now use my custom fonts even though they don't have a UseCompatibleTextRendering property.