我正在尝试使用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/
但是,这不适用于Type 1字体。
安装了Type 1字体文件,但字体仍然无法识别,并且未显示在Fonts
窗口中。
如果手动安装,则在HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Type 1 Installer\Type 1 Fonts
下注册Type 1字体并正常工作。
如何使用安装项目获得相同的结果?
答案 0 :(得分:2)
要安装Type 1字体,您需要执行以下操作:
在“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);
答案 1 :(得分:1)
这是一个涉及MSI自定义操作的解决方案。我用C#写过,但任何其他能够调用DLL的语言都可以是用户。以下是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);
}
}
}
据我所知,InstallFontFile
没有记录,但允许永久安装字体。使用此风险需要您自担风险。
注意:您仍然需要修改.MSI以确保字体文件具有FontTitle,如您提供的链接中所述。