Install font from ClickOnce application

G

Guest

How can I distribute a TrueType font with my Windows Forms application using
ClickOnce?

Is there a direct/supported way to install via ClickOnce?

I tried including the ttf files as resources and copying to the fonts folder
on startup. This worked fine, but I can't manage to get them 'registered'
properly (in spite of making registry entries and api calls for
AddFontResource, CreateScalableFontResource, and SendMessage). These calls
appear to work, but I still can't use the font. So, if there is no direct
way to install with ClickOnce, any advice on doing the work from C# would be
appreciated.
 
J

Jeffrey Tan[MSFT]

Hi Thomas,

Based on my understanding, your ClickOnce application copies TTF file to
the system fonts folder and p/invokes win32 AddFontResource API to register
the font. However, you find that your application still can not use the new
registered font yet.

Yes, I can reproduce this behavior in a normal .Net Winform application by
using the code snippet below:

<DllImport("gdi32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=True)>
_
Friend Shared Function AddFontResourceW(ByVal filename As String) As
Integer
End Function

<DllImport("gdi32.dll", CharSet:=CharSet.Unicode, ExactSpelling:=True)>
_
Friend Shared Function RemoveFontResourceW(ByVal filename As String) As
Boolean
End Function

Public sFontFile As String = "C:\cookiehollow.ttf"
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
System.IO.File.Copy(sFontFile, "C:\windows\fonts\cookiehollow.ttf")
Dim ret As Integer =
AddFontResourceW("C:\windows\fonts\cookiehollow.ttf")
If ret = 0 Then
MessageBox.Show(Marshal.GetLastWin32Error())
End If
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles cmdRefresh2.Click
Me.Button1.Font = New Font("CookieHollow", 10, FontStyle.Regular)
End Sub

However, after closing the application and running it again, I find that we
can use the cookiehollow.ttf now. So it seems that AddFontResource
registration does not take effect untile we restart the application. This
leads me to mention another known bug of .Net Winform:
InstalledFontCollection.GetFamilies does not detect fonts installed (or
removed) after GDI+ was started. This is actually not a .Net bug, but the
GDI+ bug, which is filed in our internal bug database. So I think the
AddFontResource GDI API may have the similar problem.

To workaround the problem, we may use .Net PrivateFontCollection class. For
example, the first time you are registering the TTF font, since the
application will not see the font yet. You may add the font into
PrivateFontCollection class, this will make the font usable to the current
running application:

Public oPFC As New PrivateFontCollection
Public sFontFile As String = "C:\cookiehollow.ttf"
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
oPFC.AddFontFile(sFontFile)
Me.Button1.Font = New Font(oPFC.Families(0), 10)
End Sub

Then in next running, you may use the already installed font without any
problem now. This works well on my side.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Thanks for the reply, Jeffrey. I don't think I can get by with making it a
private font since the application can write files for use by other
applications (e.g., Excel), and the font will be need by the other
applications. So, I really need to to a 'regular' install of the font in
Windows.

I got the following prototype code working. Well, at least it appears to
work on a clean Win XP machine; it still does not work on a Win 2003 machine
(even under an admin account), but maybe that's a problem on that specific
machine.

internal static void InstallFont()
{
string fontsPath = GetFontsPath();
string ttfFile = System.IO.Path.Combine(fontsPath, "MyFont.TTF");;
string fotFile = System.IO.Path.Combine(fontsPath, "MyFont.FOT");;
int ret;

if (!System.IO.File.Exists(ttfFile))
{
//Write file from embedded resource
System.IO.File.WriteAllBytes(ttfFile, Properties.Resources.MyFont);
//Write resource file
ret = CreateScalableFontResource(0, fotFile, ttfFile, String.Empty);
//Add font resource
ret = AddFontResource(fotFile);
//Add registry entry so the font is also available next session
Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Fonts", "My Font (TrueType)", "MyFont.TTF",
RegistryValueKind.String);
//Broadcast to let all top-level windows know about change
ret = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, new IntPtr(0), new
IntPtr(0));
}
}

// PInvoke to look up fonts path
[System.Runtime.InteropServices.DllImport("shfolder.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder,
IntPtr hToken, int dwFlags, StringBuilder lpszPath);
private const int CSIDL_FONTS = 0x0014;
private const int MAX_PATH = 260;
private static string GetFontsPath()
{
StringBuilder sb = new StringBuilder(MAX_PATH);
SHGetFolderPath(IntPtr.Zero, CSIDL_FONTS, IntPtr.Zero, 0, sb);
return sb.ToString();
}

// PInvoke to 'register' fonts and broadcast addition
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int AddFontResource(string lpszFilename);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int CreateScalableFontResource(uint fdwHidden, string
lpszFontRes, string lpszFontFile, string lpszCurrentPath);
private static IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const uint WM_FONTCHANGE = 0x001D;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
IntPtr lParam);

So, if anyone can point out something I'm doing wrong here, that would be
great.

I'm also still thinking that ClickOnce should support font installs; this
seems like a common task. Is there no way to get ClickOnce to do this for me?
 
J

Jeffrey Tan[MSFT]

Hi Thomas,

Thanks for the feedback.

Actually, ClickOnce is only a deployment technology, it does not offer any
support for font installation currently, since this operation requires
extra coding. We have to code the font installation logic in the
application. So this question is not a ClickOnce specific.

Based on my test using the code snippet below, after I called InstallFont,
the Word application can use the font without any problem, so I think it
should work for Excel application. But without restarting the application,
the .Net winform application still can not use it. , do you get different
result? My testing machine is Win2003 SP1.

private void button1_Click(object sender, EventArgs e)
{
InstallFont();
}

internal static void InstallFont()
{

string fontsPath = GetFontsPath();
string ttfFile = System.IO.Path.Combine(fontsPath, "cookiehollow.ttf");
System.IO.File.Copy(@"C:\cookiehollow.ttf", ttfFile);
int ret;

if (System.IO.File.Exists(ttfFile))
{
//Add font resource
ret = AddFontResource(ttfFile);
//Add registry entry so the font is also available next session
Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Fonts",
"Cookie Hollow Regular (TrueType)", "cookiehollow.ttf",
RegistryValueKind.String);
//Broadcast to let all top-level windows know about change
ret = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, new IntPtr(0), new
IntPtr(0));
}
}

// PInvoke to look up fonts path
[System.Runtime.InteropServices.DllImport("shfolder.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder,
IntPtr hToken, int dwFlags, StringBuilder lpszPath);
private const int CSIDL_FONTS = 0x0014;
private const int MAX_PATH = 260;
private static string GetFontsPath()
{
StringBuilder sb = new StringBuilder(MAX_PATH);
SHGetFolderPath(IntPtr.Zero, CSIDL_FONTS, IntPtr.Zero, 0, sb);
return sb.ToString();
}

// PInvoke to 'register' fonts and broadcast addition
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int AddFontResource(string lpszFilename);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int CreateScalableFontResource(uint fdwHidden, string
lpszFontRes, string lpszFontFile, string lpszCurrentPath);
private static IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const uint WM_FONTCHANGE = 0x001D;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet
=System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
IntPtr lParam);

private void button2_Click(object sender, EventArgs e)
{
this.button2.Font = new Font("CookieHollow", 10, FontStyle.Regular);
}

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Jeffrey,

Yes, I am able to use the font, at least on my development machine (Win
2003) and a test machine (Win XP). I think the difference is that you have
to create the fot file (with CreateScalableFontResource) for GDI to be able
to use the font. At least that's what I understand from the API docs. I
still feel like I don't fully understand what I'm doing.

Thanks again for the response.
Thomas

"Jeffrey Tan[MSFT]" said:
Hi Thomas,

Thanks for the feedback.

Actually, ClickOnce is only a deployment technology, it does not offer any
support for font installation currently, since this operation requires
extra coding. We have to code the font installation logic in the
application. So this question is not a ClickOnce specific.

Based on my test using the code snippet below, after I called InstallFont,
the Word application can use the font without any problem, so I think it
should work for Excel application. But without restarting the application,
the .Net winform application still can not use it. , do you get different
result? My testing machine is Win2003 SP1.

private void button1_Click(object sender, EventArgs e)
{
InstallFont();
}

internal static void InstallFont()
{

string fontsPath = GetFontsPath();
string ttfFile = System.IO.Path.Combine(fontsPath, "cookiehollow.ttf");
System.IO.File.Copy(@"C:\cookiehollow.ttf", ttfFile);
int ret;

if (System.IO.File.Exists(ttfFile))
{
//Add font resource
ret = AddFontResource(ttfFile);
//Add registry entry so the font is also available next session
Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Fonts",
"Cookie Hollow Regular (TrueType)", "cookiehollow.ttf",
RegistryValueKind.String);
//Broadcast to let all top-level windows know about change
ret = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, new IntPtr(0), new
IntPtr(0));
}
}

// PInvoke to look up fonts path
[System.Runtime.InteropServices.DllImport("shfolder.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder,
IntPtr hToken, int dwFlags, StringBuilder lpszPath);
private const int CSIDL_FONTS = 0x0014;
private const int MAX_PATH = 260;
private static string GetFontsPath()
{
StringBuilder sb = new StringBuilder(MAX_PATH);
SHGetFolderPath(IntPtr.Zero, CSIDL_FONTS, IntPtr.Zero, 0, sb);
return sb.ToString();
}

// PInvoke to 'register' fonts and broadcast addition
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int AddFontResource(string lpszFilename);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int CreateScalableFontResource(uint fdwHidden, string
lpszFontRes, string lpszFontFile, string lpszCurrentPath);
private static IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const uint WM_FONTCHANGE = 0x001D;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet
=System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
IntPtr lParam);

private void button2_Click(object sender, EventArgs e)
{
this.button2.Font = new Font("CookieHollow", 10, FontStyle.Regular);
}

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Thomas,

Thanks for your feedback!

Oh, I missed this CreateScalableFontResource API, sorry for this.

Yes, to install a TrueType font, a scalable font resource file needs to be
created. This scalable font resource file stores the name of a TrueType
font file so that GDI knows where to find the file. To create a scalable
font resource file, call the GDI function CreateScalableFontResource with
an integer flag, the name of the font resource file to be generated, an
existing TrueType font file name, and the path to the files if they do not
contain a complete path.

Thank you for pointing this out.

Do you mean you can use the font after installation in other
Applications(such as Excel) or you can use it in your ClickOnce
installation application? Based on my testing(full code listed below),
after adding CreateScalableFontResource calling, I still can not use the
installed font in the .Net winform application without restarting the
application. Do you get the same behavior as me? Thank you for confirming
this.

private void button1_Click(object sender, EventArgs e)
{
InstallFont();
}

internal static void InstallFont()
{

string fontsPath = GetFontsPath();
string ttfFile = System.IO.Path.Combine(fontsPath, "cookiehollow.ttf");
string fotFile = System.IO.Path.Combine(fontsPath, "cookiehollow.fot");
System.IO.File.Copy(@"C:\cookiehollow.ttf", ttfFile);
int ret;

if (System.IO.File.Exists(ttfFile))
{
ret = CreateScalableFontResource(0, fotFile, ttfFile, null);
if (ret==0)
{
MessageBox.Show("CreateScalableFontResource failed with error"
+ Marshal.GetLastWin32Error().ToString());
return;
}
//Add font resource
ret = AddFontResource(ttfFile);
if (ret==0)
{
MessageBox.Show("AddFontResource failed with error" +
Marshal.GetLastWin32Error().ToString());
return;
}
//Add registry entry so the font is also available next session
Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Fonts",
"Cookie Hollow Regular (TrueType)", "cookiehollow.ttf",
RegistryValueKind.String);
//Broadcast to let all top-level windows know about change
ret = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, new IntPtr(0), new
IntPtr(0));
}
}

// PInvoke to look up fonts path
[System.Runtime.InteropServices.DllImport("shfolder.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder,
IntPtr hToken, int dwFlags, StringBuilder lpszPath);
private const int CSIDL_FONTS = 0x0014;
private const int MAX_PATH = 260;
private static string GetFontsPath()
{
StringBuilder sb = new StringBuilder(MAX_PATH);
SHGetFolderPath(IntPtr.Zero, CSIDL_FONTS, IntPtr.Zero, 0, sb);
return sb.ToString();
}

// PInvoke to 'register' fonts and broadcast addition
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int AddFontResource(string lpszFilename);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int CreateScalableFontResource(uint fdwHidden, string
lpszFontRes, string lpszFontFile, string lpszCurrentPath);
private static IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const uint WM_FONTCHANGE = 0x001D;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet
=System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
IntPtr lParam);

Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

sdc

This is not working with .PFM or .PFB font file so please help me how can i install .pfm or .pfb font.
I am working with .Net Framwork 1.1 with C#.
 
G

Guest

Jeffrey,

Sorry for the extremely slow response. It may be moot at this point, but I
wanted to respond in case it's useful to someone else.

To answer your question, yes, I can use the font after running the code from
my previous post (I did not try your code, but it looks pretty much the same).

To be specific, I can create a new font:
Font myFont = new Font("MyFont", 32f);

And then I can use it to draw on a graphics object:

g.DrawString("Hello", mFont, Brushes.Black, new PointF(10, 10));

Thanks again for the responses.

I still think lack of support for font installs in ClickOnce is a big hole.
ClickOnce rocks, but installing a font seems like a REALLY common task.
 
J

Jeffrey Tan[MSFT]

Hi Thomas,

Thanks very much for your feedback.

Since the test result on my side reveals that it still can be used in the
current winform application without restarting, I assume you mean that you
can use the font in *other* applications after its installation with code,
yes?

Yes, I see your concern, installing a new font may be a common requirement
in ClickOnce application, so including such a feature should be useful.

The reason the ClickOnce did not include this feature is that the ClickOnce
deloyment normally does not touch the system directories. This is an
important difference with MSI deployment technology. In the table of "Key
Differences" section of the article below, you will see that, the ClickOnce
deployment does not conver:
"Install to GAC"(GAC is another system directory)
"Write to Registry"
"Install for All Users"
etc... While these can all be done with MSI:
"Choosing Between ClickOnce and Windows Installer"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/ht
ml/clickoncevsinstaller.asp

So we have to code ourselves for the font installation.

Hope this makes sense to you. Thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Jeffrey,

I was using the newly installed font to draw pages for printing via
PrintDocument. This does seem to work fine without restarting the
application. Specifically, I can print to "Microsoft Office Document Image
Writer", and the new font works fine.

However, if I try to set the font for a label on a form or draw directly on
the form, the font does not work. I think this confirms the behavior that
described seeing.

Below is the code for a simple form that I used to test (it's in two parts:
form and code-behind).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;

namespace FontTest
{
public partial class FontInstallTestForm : Form
{
public FontInstallTestForm()
{
InitializeComponent();
}

private void installButton_Click(object sender, EventArgs e)
{
string fontsPath = GetFontsPath();
string destFile;
string fotFile;
int ret;

destFile = System.IO.Path.Combine(fontsPath, "FREE3OF9.TTF");
if (!System.IO.File.Exists(destFile))
{
string sourceFile = @"c:\FREE3OF9.TTF";
System.IO.File.Copy(sourceFile, destFile);
fotFile = System.IO.Path.Combine(fontsPath, "FREE3OF9.FOT");
ret = CreateScalableFontResource(0, fotFile, destFile, String.Empty);
ret = AddFontResource(fotFile);
Registry.SetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Fonts", "Free 3 of 9 Regular (TrueType)", "FREE3OF9.TTF",
RegistryValueKind.String);
ret = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, new IntPtr(0), new
IntPtr(0));
}
}

private void setFontButton_Click(object sender, EventArgs e)
{
Font font = new Font("Free 3 of 9", 32f);

label.Font = font;
label.Text = textBox.Text;

Graphics g = this.CreateGraphics();
g.DrawString(textBox.Text, font, Brushes.Black, 12, 200);

}

#region PInvoke to look up fonts path
[System.Runtime.InteropServices.DllImport("shfolder.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder,
IntPtr hToken, int dwFlags, StringBuilder lpszPath);
private const int CSIDL_FONTS = 0x0014;
private const int MAX_PATH = 260;
public static string GetFontsPath()
{
StringBuilder sb = new StringBuilder(MAX_PATH);
SHGetFolderPath(IntPtr.Zero, CSIDL_FONTS, IntPtr.Zero, 0, sb);
return sb.ToString();
}
#endregion

#region PInvoke to 'register' fonts and broadcast addition
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int AddFontResource(string lpszFilename);
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
static extern int CreateScalableFontResource(uint fdwHidden, string
lpszFontRes, string lpszFontFile, string lpszCurrentPath);
private static IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const uint WM_FONTCHANGE = 0x001D;
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet =
System.Runtime.InteropServices.CharSet.Auto)]
static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr
lParam);
#endregion

}
}


namespace FontTest
{
partial class FontInstallTestForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed;
otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.installButton = new System.Windows.Forms.Button();
this.textBox = new System.Windows.Forms.TextBox();
this.label = new System.Windows.Forms.Label();
this.setFontButton = new System.Windows.Forms.Button();
this.textBoxLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// installButton
//
this.installButton.Location = new System.Drawing.Point(12, 12);
this.installButton.Name = "installButton";
this.installButton.Size = new System.Drawing.Size(119, 23);
this.installButton.TabIndex = 0;
this.installButton.Text = "Install Font";
this.installButton.UseVisualStyleBackColor = true;
this.installButton.Click += new System.EventHandler(this.installButton_Click);
//
// textBox
//
this.textBox.Location = new System.Drawing.Point(93, 64);
this.textBox.Name = "textBox";
this.textBox.Size = new System.Drawing.Size(200, 20);
this.textBox.TabIndex = 1;
this.textBox.Text = "*123ABC*";
//
// label
//
this.label.AutoSize = true;
this.label.Location = new System.Drawing.Point(12, 151);
this.label.Name = "label";
this.label.Size = new System.Drawing.Size(41, 13);
this.label.TabIndex = 2;
this.label.Text = "<label>";
//
// setFontButton
//
this.setFontButton.Location = new System.Drawing.Point(12, 110);
this.setFontButton.Name = "setFontButton";
this.setFontButton.Size = new System.Drawing.Size(119, 23);
this.setFontButton.TabIndex = 3;
this.setFontButton.Text = "Set Font and Text";
this.setFontButton.UseVisualStyleBackColor = true;
this.setFontButton.Click += new System.EventHandler(this.setFontButton_Click);
//
// textBoxLabel
//
this.textBoxLabel.AutoSize = true;
this.textBoxLabel.Location = new System.Drawing.Point(12, 67);
this.textBoxLabel.Name = "textBoxLabel";
this.textBoxLabel.Size = new System.Drawing.Size(75, 13);
this.textBoxLabel.TabIndex = 4;
this.textBoxLabel.Text = "Text for Label:";
//
// FontInstallTestForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(447, 285);
this.Controls.Add(this.textBoxLabel);
this.Controls.Add(this.setFontButton);
this.Controls.Add(this.label);
this.Controls.Add(this.textBox);
this.Controls.Add(this.installButton);
this.Name = "FontInstallTestForm";
this.Text = "Font Install Test";
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.Button installButton;
private System.Windows.Forms.TextBox textBox;
private System.Windows.Forms.Label label;
private System.Windows.Forms.Button setFontButton;
private System.Windows.Forms.Label textBoxLabel;
}
}
 
J

Jeffrey Tan[MSFT]

Hi Thomas,

Yes, I think we have confirmed the same behavior.

I think the reason printing to "Microsoft Office Document Image Writer"
works fine for new font is that the PrintDialog.RunDialog method will
communicate with spoolsv.exe(Spooler SubSystem App). And the spoolsv.exe
will finally launch MSPVIEW.EXE(Microsoft Office Document Imaging) process
to display the print result. So it is the new launched MSPVIEW.EXE process
that uses the new installed font, which should be expected.

To workaround the problem of can't using the new font in the current
ClickOnce application, you may use .Net PrivateFontCollection class as I
provided in the first reply.

Hope this makes sense to you. If you still have any concern, please feel
free to tell me, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Joined
Feb 11, 2012
Messages
1
Reaction score
0
Hi, i am also working for a similar solution. I am just trying to register custom font which I can do it using PrivateFontCollection class and I want to let other applications to be able to use those fonts and I cannot make use of win32 calls.

Also, there is one more problem which is that I would also like to uninstall all those fonts on closing my application which again is possible using PrivateFontCollection but when i try other applications are not able to make use of that font.

Note: Other applications will use the font before I close my application.

Thanks you in advance, please help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top