在 VS 2010 安装项目中安装 Type 1 字体

发布于 2024-12-07 06:04:03 字数 654 浏览 0 评论 0原文

我正在尝试使用 Visual Studio 2010 安装项目将一组 Type 1 字体打包到 MSI 文件中,以便于安装。

我已将安装项目配置为将所有 PFM 和 PFB 文件放入 Fonts 文件夹中,将所有 PFM 文件设置为 vsdrfFont 并修复了此处提到的命名问题:

http://cjwdev.wordpress.com/2011/03/14/installing-non-truetype-fonts-with-visual-studio-installer/

但是,这不适用于类型 1 字体。

Type 1 字体文件已安装,但该字体仍然无法识别,并且不会出现在 Fonts 窗口中。

如果手动安装,Type 1 字体将在 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Type 1 Installer\Type 1 Fonts 下注册并正常工作。

如何通过设置项目获得相同的结果?

I'm trying use a Visual Studio 2010 setup project to package a set of Type 1 fonts into a MSI file for easy installation.

I've configured my setup project to place all the PFM and PFB files in the Fonts folder, set all the PFM files to vsdrfFont and fixed the naming issue mentioned here:

http://cjwdev.wordpress.com/2011/03/14/installing-non-truetype-fonts-with-visual-studio-installer/

However, this isn't working for Type 1 fonts.

The Type 1 font files are installed but the font is still not recognized and doesn't appear in the Fonts window.

If installed manually, Type 1 fonts are registered under HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Type 1 Installer\Type 1 Fonts and work fine.

How can the same result be achieved with a setup project?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浪漫之都 2024-12-14 06:04:03

要安装 Type 1 字体,您需要执行以下操作:

  1. 在“Type 1 Fonts”下注册字体标题
  2. 将 PFM 和 PFB 复制到 Windows 字体目录
  3. 调用 AddFontResource 方法

在“Type 1 Fonts”下注册字体标题'

SOFTWARE\Microsoft\Windows NT\CurrentVersion\Type 1 Installer\Type 1 Fonts

字体标题是必需的,而不是提供将此信息发送给安装程序,以下代码片段将允许您从 PFM 读取字体标题。它基于从以下来源收集的信息:

http:// Partners.adobe.com/public/developer/en/font/5178.PFM.pdf

    private static string GetType1FontName(string filename)
    {
        StringBuilder postscriptName = new StringBuilder();

        FileInfo fontFile = new FileInfo(filename);
        using (FileStream fs = fontFile.OpenRead())
        {
            using (StreamReader sr = new StreamReader(fs))
            {
                using (BinaryReader inStream = new BinaryReader(fs))
                {
                    // PFM Header is 117 bytes
                    inStream.ReadBytes(117); // skip 117
                    short size = inStream.ReadInt16();
                    int extMetricsOffset = inStream.ReadInt32();
                    int extentTableOffset = inStream.ReadInt32();

                    inStream.ReadBytes(4); // skip 4
                    int kernPairOffset = inStream.ReadInt32();
                    int kernTrackOffset = inStream.ReadInt32();
                    int driverInfoOffset = inStream.ReadInt32();

                    fs.Position = driverInfoOffset;
                    while (inStream.PeekChar() != 0)
                    {
                        postscriptName.Append(inStream.ReadChar());
                    }
                }
            }
        }

        return postscriptName.ToString();
    }

将 PFM 和 PFB 复制到 Windows 字体目录

根据此博客 http://www.atalasoft .com/cs/blogs/stevehawley/archive/2008/08/25/getting-the-fonts-folder.aspx正确的方法获取windows字体文件夹如下:

    [DllImport("shell32.dll")]
    private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken,
               uint dwFlags, [Out] StringBuilder pszPath);

    public static string GetFontFolderPath()
    {
        StringBuilder sb = new StringBuilder();
        SHGetFolderPath(IntPtr.Zero, 0x0014, IntPtr.Zero, 0x0000, sb);

        return sb.ToString();
    }

调用AddFontResource方法

最后调用AddFontResource方法,参数lpFilename由pfm和pfb文件组成,以竖线“|”分隔。 。就我而言,我将完整路径放入似乎有效的 Windows 字体文件夹中。调用 AddFontResource 后,您需要使用 WM.FONTCHANGE (0x001D) 参数调用 PostMessage 来通知其他窗口更改。

    [DllImport("gdi32.dll")]
    static extern int AddFontResource(string lpFilename);

    // build the name for the api "<pfm>|<pfb>"
    string apiValue = string.Format("{0}|{1}", PfmFileDestination, PfbFileDestination);

    // Call the api to register the font
    int retVal = AddFontResource(apiValue);

    // Inform other windows of change
    PostMessage(HWND_BROADCAST, WM.FONTCHANGE, IntPtr.Zero, IntPtr.Zero);

To install Type 1 fonts you need to do the following:

  1. Register the font title under 'Type 1 Fonts'
  2. Copy both the PFM and the PFB to the windows fonts directory
  3. Call the AddFontResource method

Register the font title under 'Type 1 Fonts'

SOFTWARE\Microsoft\Windows NT\CurrentVersion\Type 1 Installer\Type 1 Fonts

The Font Title is required, rather than providing this to the installer, the following code snippet will allow you to read the font title from the PFM. It is based on information gathered from the following source:

http://partners.adobe.com/public/developer/en/font/5178.PFM.pdf

    private static string GetType1FontName(string filename)
    {
        StringBuilder postscriptName = new StringBuilder();

        FileInfo fontFile = new FileInfo(filename);
        using (FileStream fs = fontFile.OpenRead())
        {
            using (StreamReader sr = new StreamReader(fs))
            {
                using (BinaryReader inStream = new BinaryReader(fs))
                {
                    // PFM Header is 117 bytes
                    inStream.ReadBytes(117); // skip 117
                    short size = inStream.ReadInt16();
                    int extMetricsOffset = inStream.ReadInt32();
                    int extentTableOffset = inStream.ReadInt32();

                    inStream.ReadBytes(4); // skip 4
                    int kernPairOffset = inStream.ReadInt32();
                    int kernTrackOffset = inStream.ReadInt32();
                    int driverInfoOffset = inStream.ReadInt32();

                    fs.Position = driverInfoOffset;
                    while (inStream.PeekChar() != 0)
                    {
                        postscriptName.Append(inStream.ReadChar());
                    }
                }
            }
        }

        return postscriptName.ToString();
    }

Copy both the PFM and the PFB to the windows fonts directory

According to this blog http://www.atalasoft.com/cs/blogs/stevehawley/archive/2008/08/25/getting-the-fonts-folder.aspx the right way to get the windows fonts folder is as follows:

    [DllImport("shell32.dll")]
    private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken,
               uint dwFlags, [Out] StringBuilder pszPath);

    public static string GetFontFolderPath()
    {
        StringBuilder sb = new StringBuilder();
        SHGetFolderPath(IntPtr.Zero, 0x0014, IntPtr.Zero, 0x0000, sb);

        return sb.ToString();
    }

Call the AddFontResource method

Finally, the method AddFontResource should be called, the parameter lpFilename should be made up of the pfm and pfb files separated by the pipe character '|'. In my case I put the full path to the windows fonts folder which seemed to work. After calling AddFontResource you need to call PostMessage with a parameter of WM.FONTCHANGE (0x001D) to inform other windows of the change.

    [DllImport("gdi32.dll")]
    static extern int AddFontResource(string lpFilename);

    // build the name for the api "<pfm>|<pfb>"
    string apiValue = string.Format("{0}|{1}", PfmFileDestination, PfbFileDestination);

    // Call the api to register the font
    int retVal = AddFontResource(apiValue);

    // Inform other windows of change
    PostMessage(HWND_BROADCAST, WM.FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
听闻余生 2024-12-14 06:04:03

这是涉及 MSI 自定义操作的解决方案。我使用 C# 编写,但用户可以使用任何能够调用 DLL 的其他语言。以下是 C# 教程链接:演练:创建自定义操作

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.Runtime.InteropServices;

namespace InstallType1Font
{
    [RunInstaller(true)]
    public partial class Installer1 : Installer
    {
        public Installer1()
        {
            InitializeComponent();
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);

            // here, you'll have to determine the proper path
            string path = @"c:\Windows\Fonts\MyFont.pfm";
            if (File.Exists(path))
            {
                InstallFontFile(IntPtr.Zero, path, 0);
            }
        }

        [DllImport("fontext.dll", CharSet = CharSet.Auto)]
        private static extern void InstallFontFile(IntPtr hwnd, string filePath, int flags);

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }
    }
}

作为据我所知,InstallFontFile 没有文档记录,但允许永久安装字体。使用此功能需要您自担风险。

注意:您仍然需要修改 .MSI 以确保字体文件具有您提供的链接中所述的 FontTitle。

Here is a solution that involves an MSI custom action. I have written in using C#, but any other language capable of calling a DLL can be user. Here is a tutorial link for C#: Walkthrough: Creating a Custom Action

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.Runtime.InteropServices;

namespace InstallType1Font
{
    [RunInstaller(true)]
    public partial class Installer1 : Installer
    {
        public Installer1()
        {
            InitializeComponent();
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);

            // here, you'll have to determine the proper path
            string path = @"c:\Windows\Fonts\MyFont.pfm";
            if (File.Exists(path))
            {
                InstallFontFile(IntPtr.Zero, path, 0);
            }
        }

        [DllImport("fontext.dll", CharSet = CharSet.Auto)]
        private static extern void InstallFontFile(IntPtr hwnd, string filePath, int flags);

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }
    }
}

As far as I know, InstallFontFile is undocumented, but allows to install the font permanently. Use this at your own risk.

Note: you still need to modify the .MSI to ensure the Fonts file have a FontTitle as described in the link you gave.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文