【问题标题】:How do I install a font on a user's machine in VB.NET so applications like Word can use it?如何在 VB.NET 中的用户计算机上安装字体,以便 Word 等应用程序可以使用它?
【发布时间】:2011-06-11 04:32:33
【问题描述】:

需要在所有将使用我正在编写的应用程序的用户机器上安装一种字体,该应用程序在 Word 中创建自定义文档。这是一种条形码字体。

我已成功将字体添加到我的解决方案并将其构建操作设置为 Embedded Resource,并且还成功编写了代码以检查该字体是否已安装在用户的系统上。

现在我只需要弄清楚如何从我的解决方案中提取字体并将其安装到用户的计算机上,就好像他们自己安装了字体以用于 Office 应用程序等一样。

我发现的大多数示例都是在 VB.NET 应用程序内而不是在应用程序外使用字体,而我发现的那些似乎适合我的目的的示例对我不起作用。

【问题讨论】:

  • 只是要评论一下,您需要确保您被允许分发字体 - 字体就像您的程序一样是软件,在按照您描述的方式分发之前需要获得许可。
  • 这种事情通常(并且最好)由安装程序完成,而不是您的程序本身。告诉安装程序安装字体通常比在应用程序中安装字体更容易。
  • 那很好,但我认为这不是 Visual Studio 2010 附带的 ClickOnce 安装程序可以完成的事情,对吧?

标签: .net windows vb.net fonts


【解决方案1】:

我使用安装程序项目来安装我的应用程序所需的字体,并遵循此guide

【讨论】:

    【解决方案2】:

    首先将字体复制到 windows 字体文件夹,然后使用 p/invoke 调用 AddFontResource

    这是一个例子,它是用 C# 编写的,但你应该能够解决它:

    更新

    新网址

    http://brutaldev.com/post/2009/03/26/Installing-and-removing-fonts-using-C.aspx

    【讨论】:

    • 你确定这会起作用吗,在 AddFontResource 的文档中(msdn.microsoft.com/en-us/library/dd183326%28v=vs.85%29.aspx)it这个函数只为当前会话安装字体。当系统重新启动时,字体不会存在。要在重新启动系统后安装字体,字体必须列在注册表中。
    • 要在重新启动机器后可用,您需要在这种情况下更改相应的注册表项,(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts)
    【解决方案3】:

    将字体复制到 Windows 字体文件夹中,然后您需要将字体添加到注册表中。我自己没有尝试过,但我认为可以通过使用ShellExecuteA api 以类似于here 的方式打开字体来做到这一点。

    这里有一个 vbscript 方法,可以作为一个起点,因为您可以在 VB.Net 中使用类似的语法和函数:Hey, Scripting Guy! How Can I Install Fonts Using a Script?

    【讨论】:

    • 为什么要使用ShellExecute 的非Unicode 版本?究竟是如何将字体添加到注册表中的?我没有看到您提供的链接中的示例。
    • 这实际上是最简单的解决方案。此方法的行为就像您在 Windows 中双击字体一样,如果您不介意从 Windows 弹出安装进度条,那一点也不差。检查字体是否存在,如果不存在,将资源复制到任何地方,运行shellexecute然后删除提取的字体文件。
    • 不过,您绝对应该使用ShellExecute 的Unicode 版本。而且我不相信这会通知正在运行的应用程序系统字体表已被修改;如果您的应用程序正在安装字体时 Word 可能正在运行,请记住这一点。
    • 这和 Unicode 版本的 ShellExecute 有什么区别?
    • @Tom:A W 而不是 A。如果您使用标准的 .NET P/Invoke 语法,则不会有问题。但是,如果您尝试将 VBScript 示例复制粘贴到 VB.NET 中,您最终会遇到一团糟(原因太多了!)。
    【解决方案4】:

    首先,您需要将字体复制到 Windows\Fonts 目录(您需要确保使用 .NET Framework 提供的 Environment.GetFolderPath 方法,而不是硬编码 Windows 目录的典型路径,以防万一您的用户环境中的某些内容有所不同)。

    然后,您需要调用AddFontResource function 将字体添加到系统字体表中。由于AddFontResource 由Windows API 提供,因此您需要P/Invoke 才能从VB.NET 代码中调用它。声明看起来像这样(lpszFilename 参数是您要添加的字体文​​件的路径):

    <DllImport("gdi32.dll"), CharSet := CharSet.Auto> _
    Public Shared Function AddFontResource(ByVal lpszFilename As String) As Integer
    

    最后,如果在您从代码中调用 AddFontResource 函数时,Word(或您打算在其中使用字体的任何应用程序)正在运行,您需要通知它可用的字体变了。为此,您可以使用SendMessage 函数向所有顶级窗口发送WM_FONTCHANGE 消息并将hWnd 参数设置为HWND_BROADCAST。同样,您需要 P/Invoke;声明如下所示:

    Public Const HWND_BROADCAST As Integer = &HFFFF
    Public Const WM_FONTCHANGE As Integer = &H1D
    
    <DllImport("user32.dll"), CharSet := CharSet.Auto> _
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    

    你可以这样调用它来发送广播消息:

    SendMessage(New IntPtr(HWND_BROADCAST), WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero)
    

    注意:上述步骤仅安装当前 Windows 会话的字体。如果您需要字体在后续重新启动时可用,则需要将其添加到注册表中。修改的关键是这个:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
    

    【讨论】:

    • 我只是想问如何获取用户的字体目录,谢谢,但是使用此方法的字体文件夹没有属性:Environment.GetFolderPath(Environment.SpecialFolder.[Fonts])。有什么想法吗?
    • @Tom:是的,Environment.SpecialFolder 没有公开字体文件夹是对的。以下是关于如何在 .NET 中以正确方式处理它的说明:atalasoft.com/cs/blogs/stevehawley/archive/2008/08/25/…(不,您不只是将“\FONTS”添加到SpecialFolder.System 返回的路径中。)
    • MSDN 文档相当混乱。 The font installation topic 表示将字体文件复制到 Windows\Fonts 然后调用 AddFontResource 永久安装字体,但 AddFontResource page 表示字体必须列在注册表中
    • @MarkJ:是的,这对 MSDN 来说并不罕见。但这让我注意到您的第一个链接:“要临时安装字体,请调用 AddFontResource 或 AddFontResourceEx。这些函数会加载存储在字体资源文件中的字体。但是,这是临时安装,因为在重新启动字体后不会出现。”我想唯一确定的方法就是测试它,而我没有。
    猜你喜欢
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多