Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

installed fonts not available until system is restarted

143 views
Skip to first unread message

Eduardo

unread,
Apr 30, 2013, 2:58:28 PM4/30/13
to
Tested on XP, I install fonts copying them to the system fonts folder, then
calling AddFontResource, then sending HWND_BROADCAST, WM_FONTCHANGE; but the
fonts appear in the fonts list but not usable by the installed program.
To make the fonts really available I need to restart Windows.

Do you have any idea how to install fonts and to make them available
immediately? Thanks.





ralph

unread,
Apr 30, 2013, 3:09:30 PM4/30/13
to
Check this out.
http://msdn.microsoft.com/en-us/library/dd144833%28v=vs.85%29.aspx

Especially the last paragraph.

"Whenever an application calls the functions that add and delete font
resources, it should also call the SendMessage function and send a
WM_FONTCHANGE message to all top-level windows in the system. This
message notifies other applications that the internal font table has
been altered by an application that added or removed a font."

-ralph

Karl E. Peterson

unread,
Apr 30, 2013, 3:15:42 PM4/30/13
to
Eduardo presented the following explanation :
I'm inclined to say, "What ralph said."

A question though, assuming you've done that, how about just restarting
the app that isn't responding to that message?

--
.NET: It's About Trust!
http://vfred.mvps.org


ralph

unread,
Apr 30, 2013, 5:57:05 PM4/30/13
to
On Tue, 30 Apr 2013 12:15:42 -0700, Karl E. Peterson <ka...@exmvps.org>
wrote:

>Eduardo presented the following explanation :
>> Tested on XP, I install fonts copying them to the system fonts folder, then
>> calling AddFontResource, then sending HWND_BROADCAST, WM_FONTCHANGE; but the
>> fonts appear in the fonts list but not usable by the installed program.
>> To make the fonts really available I need to restart Windows.
>>
>> Do you have any idea how to install fonts and to make them available
>> immediately? Thanks.
>
>I'm inclined to say, "What ralph said."
>

And then again I looked at this ... "not usable by the installed
program" ... more closely. I wonder if its not more a case of not
servicing the message queue?

Karl E. Peterson

unread,
Apr 30, 2013, 6:11:41 PM4/30/13
to
ralph presented the following explanation :
Yeah, I didn't really know what that meant. <shrug>

Eduardo

unread,
Apr 30, 2013, 7:00:40 PM4/30/13
to

"ralph" <nt_con...@yahoo.com> escribi� en el mensaje
news:4850o8dfd31cc62io...@4ax.com...
I had read that. And as I said, I broadcast the WM_FONTCHANGE message.
The font is not available even if I restart the program (any times). It's
available only after reboot.

May be because of a service disabled?


Karl E. Peterson

unread,
Apr 30, 2013, 7:42:55 PM4/30/13
to
Eduardo submitted this idea :
> I had read that. And as I said, I broadcast the WM_FONTCHANGE message.
> The font is not available even if I restart the program (any times). It's
> available only after reboot.

What program? Have you tried something dirt standard, like Microsoft
Word?

> May be because of a service disabled?

Nope.

Listen, as a programmer, guessing is never a good bet.

No one here wants to play that game. "Show us the code."

Eduardo

unread,
May 1, 2013, 12:20:21 AM5/1/13
to

"Karl E. Peterson" <ka...@exmvps.org> escribi� en el mensaje
news:klpknn$htv$1...@dont-email.me...
> Eduardo submitted this idea :
>> I had read that. And as I said, I broadcast the WM_FONTCHANGE message.
>> The font is not available even if I restart the program (any times). It's
>> available only after reboot.
>
> What program? Have you tried something dirt standard, like Microsoft
> Word?
>
>> May be because of a service disabled?
>
> Nope.
>
> Listen, as a programmer, guessing is never a good bet.
>
> No one here wants to play that game. "Show us the code."

The code is very simple, I'm using the P&DW, a modified version of Vb6
setup1.

In basSetup1, the declaration of AddFontResource is:

Private Declare Function AddFontResource Lib "gdi32" Alias
"AddFontResourceA" (ByVal lpFileName As String) As Long

In the procedure CopySection of basSetup1, there is a place with this code:

Select Case strExt
Case gsEXT_FONTTTF, gsEXT_FONTFON 'strExt, gsEXT_FONTTTF, and
gsEXT_FONTFON are all uppercase
AddFontResource strDestDir & strDestName
End Select

I changed it to

Select Case strExt
Case gsEXT_FONTTTF, gsEXT_FONTFON 'strExt, gsEXT_FONTTTF, and
gsEXT_FONTFON are all uppercase
AddFontResource strDestDir & strDestName
SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0, ByVal 0
End Select

The constants declarations are:

Private Const HWND_BROADCAST = &HFFFF&
Private Const WM_FONTCHANGE = &H1D

And SendMessage is declared in basCommon:

Public Declare Function SendMessageString Lib "user32" Alias "SendMessageA"
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam
As String) As Long

Before calling AddFontResource, the font files are copied in the line:

If CopyFile(strSrcDir, strDestDir, strDestName, strDestName, sFile.fShared,
sFile.fSystem) Then

Alternatively I tried copying with standard vb code (FileCopy), just in case
that could be something wrong with the function CopyFile (that is in
basSetup1 BTW), but I got the same result.

It must be something related to this VB setup1 installer, because I remember
that I installed fonts in the past with this same code (from another
program) without problem.


Eduardo

unread,
May 1, 2013, 12:23:48 AM5/1/13
to

"Eduardo" <m...@mm.com> escribi� en el mensaje
news:klq55k$gle$1...@speranza.aioe.org...

> And SendMessage is declared in basCommon:
>
> Public Declare Function SendMessageString Lib "user32" Alias
> "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As
> Long, ByVal lParam As String) As Long

Sorry, I copied another one.
The declaration is:

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal
hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As
Long


DaveO

unread,
May 1, 2013, 9:55:45 AM5/1/13
to

"Eduardo" <m...@mm.com> wrote in message
news:klq55k$gle$1...@speranza.aioe.org...
<snip>
> Select Case strExt
> Case gsEXT_FONTTTF, gsEXT_FONTFON 'strExt, gsEXT_FONTTTF, and
> gsEXT_FONTFON are all uppercase
> AddFontResource strDestDir & strDestName
> SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0, ByVal 0
> End Select

Hi

Back in antiquity (2007) I wrote a program to mount and demount fonts that I
only needed loaded briefly and the code I used was pretty much the same as
yours but with a couple of differences, I added a null to the end of the
font filename in the AddFontResource line:
So Try: AddFontResource strDestDir & strDestName & vbNullChar
To be honest I've no idea if it will help but it can't hurt to try.
Also my SendMessage line has an ampersand after the last zero
SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0, ByVal 0&
I really don't see why this should make any difference but I included it
back then so what the hell.

In XP it's normal but not recommended to alway run as administrator, if you
are being a good boy and not running with admin credentials then that might
be where the problem lies, I'll try my 2007 program in Windows7 later to see
if it works when not ran as administrator.

Regards
DaveO.


Karl E. Peterson

unread,
May 1, 2013, 12:03:55 PM5/1/13
to
Eduardo submitted this idea :
> Sorry, I copied another one.
> The declaration is:
>
> Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal
> hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As
> Long

Like Dave suggests, it's generally best to make sure you're using Longs
when you mean to send Longs. You're relying on ETC, here, which isn't
ever wise. Still, odds are, that's not likely the problem.

What's AddFontResource returning? More importantly, why aren't you
checking it?

I just tried this code on Windows 7 x64, from my FontPre sample, and it
worked flawlessly:

Private Declare Function AddFontResource Lib "gdi32" Alias
"AddFontResourceA" (ByVal lpszFileName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias
"SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As
Long, lParam As Any) As Long

Private Const HWND_BROADCAST As Long = &HFFFF&
Private Const WM_FONTCHANGE As Long = &H1D

Private Function AddFont(ByVal FileNameTTF As String) As Boolean
Dim nRet As Long
' Add resource to Windows font table.
nRet = AddFontResource(FileNameTTF)
If nRet Then
' Return success.
AddFont = True
' Alert all running apps?
If m_Broadcast Then
Call SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, ByVal
0&)
End If
End If
End Function

> Before calling AddFontResource, the font files are copied in the line:

Check that return value! Maybe the disk write buffer hasn't flushed?
How would you know? You're just blindly telling the rest of the system
you've done something that you have no business telling them you've
done since you never bothered to confirm it.

You should also try your code with a file that isn't being copied.
That'd tell you if you're dealing with poor code or an unrecognized
contributing factor.

It appears the problem hasn't been sufficiently isolated.

> It must be something related to this VB setup1 installer, because I remember
> that I installed fonts in the past with this same code (from another program)
> without problem.

Guessing isn't the answer. <-- Read, memorize, repeat!

Schmidt

unread,
May 3, 2013, 2:13:24 AM5/3/13
to
Am 01.05.2013 06:20, schrieb Eduardo:

> Before calling AddFontResource, the font files are copied in the line:
>
> If CopyFile(strSrcDir, strDestDir, strDestName, strDestName, sFile.fShared,
> sFile.fSystem) Then

IMO to behave in the same way as when you'd do it "manually"
(using the Explorer), you can't use normal (lower-level)
FileOps.

Better to use the Shell-Object - since it behaves in the same
way (triggers the same actions) as when using "your Mouse".

If you put into your Project the Reference:
'Microsoft Shell Controls and Automation'

Then the following should work, I think:

Const ssfFONTS = &H14
Dim FontFolder As Folder, FontPath As String

Set FontFolder = CreateObject("Shell.Application").NameSpace(ssfFONTS)
FontPath = FontFolder.Self.Path & "\"

'Loop over your Font-SourceFiles

If Not FileExists(FontPath & CurFontFileName) Then
FontFolder.CopyHere SrcPath & CurFontFileName
End if

'end loop

I think, this method even does the implicit Broadcasting.

Olaf

Eduardo

unread,
May 9, 2013, 11:36:23 AM5/9/13
to

"Schmidt" <n...@vbRichClient.com> escribi� en el mensaje
news:klvkbt$fuh$1...@dont-email.me...
I still couldn't test it because I'm working on some other issues of the
program.


Eduardo

unread,
May 10, 2013, 6:30:36 AM5/10/13
to

"Schmidt" <n...@vbRichClient.com> escribi� en el mensaje
news:klvkbt$fuh$1...@dont-email.me...
It worked, but it takes too long in my Pentium 4 -one core- machine (several
minutes for each font), mostly because setup.exe is taking most of the CPU
cycles.


Eduardo

unread,
May 10, 2013, 10:30:11 AM5/10/13
to

"Karl E. Peterson" <ka...@exmvps.org> escribi� en el mensaje
news:klre72$u14$1...@dont-email.me...
It is returning 1 or 2, depending on how many fonts the file has.
But I see that the AddFonResource (and also SendMessage) is called every
time even if the font is already on the system, so in a second installation
it should work. But it doesn't.

>
> It appears the problem hasn't been sufficiently isolated.
>
>> It must be something related to this VB setup1 installer, because I
>> remember that I installed fonts in the past with this same code (from
>> another program) without problem.

I also remember I did.
But searching on internet, I got many people asking about issues like this,
and there is no information.

One thing that I see, is that with AddFontResource, the font is not add to
the registry in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Fonts until the next system restart (on my XP) as it does
Olaf's method.

I tried writting that registry value by hand, but it didn't work (... but
now I'm not sure if it didn't work, because I see that after some font
addintions and deletions even Olaf method doesn't work, it need to do a
system restart and it works again)

But even if that method (or writting the font in the registry) worked, I
need a way to retrieve the font name(s) from the font file, and it seems
that there is not a direct function to do that.

Eduardo

unread,
May 10, 2013, 10:31:02 AM5/10/13
to

"DaveO" <d...@dial.pipex.com> escribi� en el mensaje
news:klr6mm$hfs$1...@dont-email.me...
I made those changes, but got the same result.
Thanks anyway.


DaveO

unread,
May 10, 2013, 11:20:08 AM5/10/13
to

"Eduardo" <m...@mm.com> wrote in message
news:kmj09c$7iu$1...@speranza.aioe.org...
>
> "Karl E. Peterson" <ka...@exmvps.org> escribi� en el mensaje
> news:klre72$u14$1...@dont-email.me...
>> Eduardo submitted this idea :

<< TRIM>>

> I tried writting that registry value by hand, but it didn't work (... but
> now I'm not sure if it didn't work, because I see that after some font
> addintions and deletions even Olaf method doesn't work, it need to do a
> system restart and it works again)
>
> But even if that method (or writting the font in the registry) worked, I
> need a way to retrieve the font name(s) from the font file, and it seems
> that there is not a direct function to do that.

You can read the font header directly to obtain the face name and family and
a few other metrics but it's not easy. I have a program I put together a
long time ago and now looking at the code I'm guessing I cribbed a fair bit
off that interweb thingy so I took a part of a line that was not in my style
and searched on it to try to find the original source or something like it
and this is what I found:
http://read.pudn.com/downloads120/sourcecode/windows/bitmap/510269/Class/CFontPreview.cls__.htm
It looks like it might be of some help to you

Due to the age of this code I suspect it might only work on TTF files but
you never know your luck.
Apparently it was written by somebody called Karl E. Peterson, never heard
of him but it might work. ;-)

Regards
DaveO.


Mike Williams

unread,
May 10, 2013, 1:33:23 PM5/10/13
to
"Eduardo" <m...@mm.com> wrote in message
news:kmj09c$7iu$1...@speranza.aioe.org...

> But even if that method (or writting the font in the registry) worked,
> I need a way to retrieve the font name(s) from the font file, and it
> seems that there is not a direct function to do that.

I've only just looked at your thread and I'm not really sure what problems
you are having installing fonts. I don't recall having any problems myself
when installing them with standard code using AddFontResourceEx, although I
usually install them for temporary use only by my own VB program using the
FR_PRIVATE flag. As for your problem with retrieving a face name from a font
file I think the CreateScalableFontResource function should help you with
that (see example code below).

Regarding the failure of the font to work as soon as it is installed, I
think I recall a little bug somewhere when using VB print methods in that in
order to get the font to be correctly selected first time as soon as it is
installed you need set any font attributes to something other than its
current setting /before/ you assign the newly installed font to you Form or
pictureBox or whatever and then set the attribute to what you really want
afterwards, for example:

Me.Font.Size = 1234
Me.Font.Name = "the newly installed font"
Me.Font.Size = 16

Anyway, here's some code which should get a font's face name from its ttf
file name:

Option Explicit
Private Declare Function CreateScalableFontResource _
Lib "gdi32" Alias "CreateScalableFontResourceA" _
(ByVal fHidden As Long, ByVal lpszResourceFile _
As String, ByVal lpszFontFile As String, _
ByVal lpszCurrentPath As String) As Long

Private Function GetFontName(FileNameTTF As String) As String
Dim s1 As String, sFontName As String, sTempFile As String
Dim fn As Long, p1 As Long, retVal As Long
' create a path/name for a .FOT file (must NOT already exist)
' (the following line will do for now, but there are better ways)
sTempFile = App.Path & "\MikeTemp" & CStr(Int(Timer)) & ".FOT"
retVal = CreateScalableFontResource _
(1, sTempFile, FileNameTTF, vbNullString)
If retVal = 0 Then Exit Function ' the Call failed
' Call succeded and .FOT file created, so examine its contents
fn = FreeFile ' get the ext available VB file number
Open sTempFile For Binary Access Read As fn
s1 = Space(LOF(fn))
Get fn, 1, s1
p1 = InStr(s1, "FONTRES:") + 8
sFontName = Mid$(s1, p1, InStr(p1, s1, vbNullChar) - p1)
Close fn
Kill sTempFile ' kill the temporary .FOT file
GetFontName = sFontName
End Function

Private Sub Command1_Click()
Print GetFontName("c:\temp\somefont.ttf")
End Sub

Mike


Eduardo

unread,
May 10, 2013, 2:05:46 PM5/10/13
to

"Karl E. Peterson" <ka...@exmvps.org> escribi� en el mensaje
news:klre72$u14$1...@dont-email.me...

> You should also try your code with a file that isn't being copied. That'd
> tell you if you're dealing with poor code or an unrecognized contributing
> factor.
>
> It appears the problem hasn't been sufficiently isolated.

It seems to be the case...
I just made a simple test program and it installed the fonts without any
problem with almost the same code.
I say almost because I used the intrinsic VB FileCopy (instead of CopyFile
from setup1)

But I still didn't isolate the cause.


Eduardo

unread,
May 10, 2013, 2:14:33 PM5/10/13
to

"Mike Williams" <Mi...@WhiskyAndCoke.com> escribi� en el mensaje
news:kmjaq9$806$1...@dont-email.me...
> "Eduardo" <m...@mm.com> wrote in message
> news:kmj09c$7iu$1...@speranza.aioe.org...
>
>> But even if that method (or writting the font in the registry) worked,
>> I need a way to retrieve the font name(s) from the font file, and it
>> seems that there is not a direct function to do that.
>
> I've only just looked at your thread and I'm not really sure what problems
> you are having installing fonts. I don't recall having any problems myself
> when installing them with standard code using AddFontResourceEx, although
> I usually install them for temporary use only by my own VB program using
> the FR_PRIVATE flag.

I considered this, but since they are fonts to support Hebrew and Greek
characters that can't be replaced with other ones unless there are already
one to support those characters on the system, and since I allow from the
program to copy texts to the clipboard (I use some Unicode clipboard
functions to do that), I would like to make the fonts available to the
entire system in case the user wants to go and paste to Word or to some
other program.

> As for your problem with retrieving a face name from a font file I think
> the CreateScalableFontResource function should help you with that (see
> example code below).

It was because I thought that perhaps writing the values to the registry at
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts it
could fix the problem, but I tested (I tested it again in a "clean" reboot)
and it does not fix it.

But thank you anyway for the code you posted.

Eduardo

unread,
May 10, 2013, 2:15:23 PM5/10/13
to

"DaveO" <d...@dial.pipex.com> escribi� en el mensaje
news:kmj30e$nas$1...@dont-email.me...

> http://read.pudn.com/downloads120/sourcecode/windows/bitmap/510269/Class/CFontPreview.cls__.htm

Thanks


Eduardo

unread,
May 11, 2013, 9:38:20 PM5/11/13
to

"Eduardo" <m...@mm.com> escribi� en el mensaje
news:klp480$2e5$1...@speranza.aioe.org...
Finally, I was able to make it work.
I could not isolate the specific cause of the problem, but I made a change
that worked:

Instead of registering the fonts in the CopySection procedure of basSetup1,
I stored their paths in a vector variable.
At the end, before the final message that the program was installed OK, I
register the fonts there:

Private Sub RegisterFonts()
Dim c As Long

For c = 1 To UBound(gNewFonts)
AddFontResource gNewFonts(c)
SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0&, ByVal 0&
Next c
End Sub


DaveO

unread,
May 13, 2013, 4:07:26 AM5/13/13
to

"Eduardo" <m...@mm.com> wrote in message
news:kmmrq3$i8p$1...@speranza.aioe.org...
Hi

As the SendMessage line does not contain a reference to the last font loaded
but instead (I assume) tells the system that the loaded fonts have changed
then wouldn't it make more sense like this:

For c = 1 To UBound(gNewFonts)
AddFontResource gNewFonts(c)
Next c
SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0&, ByVal 0&

Regards
DaveO


Eduardo

unread,
May 13, 2013, 4:18:33 AM5/13/13
to

"DaveO" <d...@dial.pipex.com> escribi� en el mensaje
news:kmq6ov$sho$1...@dont-email.me...
I thought about that, but I didn't test it.

I fact I have tested it before when I was trying to figure out what was
causing the problem that I was having, but changing that (sending just one
message) didn't fix it.

The installer is working well now, perhaps it can also work with sending
just one message (most probably it would), but it need to be tested for
being sure (each test take me several minutes: compile installer, make cab,
delete fonts from system, restart computer, install program, see what
happened).


ralph

unread,
May 13, 2013, 9:40:45 AM5/13/13
to
In my mind it re-enforces the belief that you were not servicing the
message queue as I mentioned earlier, but are now.

This is probably what was happening with the "setup" issue as well.

[As an aside ...
My advice is to take some time and review the basics of Windows Task
scheduling. I appreciate that you already know how it works, but in
the heat of the moment - dwelling on the "thread of the moment" - we
all tend to forget.
]

-ralph

Eduardo

unread,
May 13, 2013, 3:21:10 PM5/13/13
to

"ralph" <nt_con...@yahoo.com> escribi� en el mensaje
news:nap1p8tjhb1fe4p8s...@4ax.com...
If you mean to add DoEvents and Sleep's calls, I added a bunch of them in
that part of the code, it made no difference.
SendMessage allegedly is synchronous (PostMessage is not), but I don't know
how AddFontResource works.
The Sleep's calls that I added were of minimal values (1), may be I should
had tried with a couple of seconds.

Farnsworth

unread,
May 13, 2013, 11:40:16 PM5/13/13
to
"Eduardo" <m...@mm.com> wrote in message
news:kmmrq3$i8p$1...@speranza.aioe.org...
> Finally, I was able to make it work.
> I could not isolate the specific cause of the problem, but I made a change
> that worked:
>
> Instead of registering the fonts in the CopySection procedure of
> basSetup1, I stored their paths in a vector variable.
> At the end, before the final message that the program was installed OK, I
> register the fonts there:
>
> Private Sub RegisterFonts()
> Dim c As Long
>
> For c = 1 To UBound(gNewFonts)
> AddFontResource gNewFonts(c)
> SendMessage HWND_BROADCAST, WM_FONTCHANGE, 0&, ByVal 0&
> Next c
> End Sub

Take SendMessage out of the loop to reduce the time. You don't need to send
WM_FONTCHANGE after each call to AddFontResource(). Whenever any app use
SendMessage(HWND_BROADCAST), it risks hanging if any other app(That is
displaying a window) is busy doing heavy processing. Windows by default have
a built-in timeout for such cases, and it depends on the OS, I think it's
around 20 Seconds. Even if no other app is hanged, your is by design because
the call to SendMessage. DoEvents or Sleep will not fix the problem. One
solution is to use SendMessageTimeout() instead.




Eduardo

unread,
May 14, 2013, 2:41:48 AM5/14/13
to

"Farnsworth" <nos...@nospam.com> escribi� en el mensaje
news:kmsbna$ifo$1...@speranza.aioe.org...
Thanks for the consideration.

I removed the SendMessage line, and as I was suspecting, the installed
program (that still wasn't running at that time) could use the fonts without
any problem.
But, then I added a single PostMessage call outside the loop, just to make
it right and notify other applications that they could also use the new
fonts.


Eduardo

unread,
May 14, 2013, 2:56:14 AM5/14/13
to

"Eduardo" <m...@mm.com> escribi� en el mensaje
news:kmsmar$b0t$1...@speranza.aioe.org...

> But, then I added a single PostMessage call outside the loop, just to make
> it right and notify other applications that they could also use the new
> fonts.

And worked. I tested installing the program having Word opened, and after
the installation I could use the new fonts in Word.


0 new messages