By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,507 Members | 1,185 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,507 IT Pros & Developers. It's quick & easy.

Registering font at runtime under Windows XP

P: n/a
Hello!
We have a Windows application that is using Crystal Reports reports
containing Barcode fonts. Those reports are called through reflection into
a Crystal Report Viewer and we need to have the Barcode fonts to be
self-installed at runtime whenever a report is viewed.

I tried the following steps:
Public Shared Sub InstallFonts()
Dim fi As System.IO.FileInfo
Try
Dim res As Integer
fi = New System.IO.FileInfo(\\multi316\oasys\Reports\REQUIR ED
FONTS\3of9.ttf)
Dim fiTarget As New System.IO.FileInfo("C:\Windows\Fonts\3OF9.TTF")
If fiTarget.Exists Then Return
' copy the font
fi.CopyTo("C:\Windows\Fonts\3OF9.TTF")

' add the font
res = CreateScalableFontResource(0, "c:\windows\Temp\3OF9.FOT",
"c:\windows\fonts\3OF9.TTF", String.Empty)

res = AddFontResource("C:\Windows\Temp\3OF9.FOT")

If res > 0 Then
' alert all windows that a font was added
SendMessage(New System.IntPtr(HWND_BROADCAST), WM_FONTCHANGE, 0,
Nothing)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

Everything looks to be ok as my .FOT file is created and both
AddFontResource and CreateScalableFontResource have a return value of 1
meaning the font was correctly added to the font collection.

The problem I am having is with the final part, the line below keep
executing forever:
SendMessage(New System.IntPtr(HWND_BROADCAST), WM_FONTCHANGE, 0,
Nothing)

I also tried different version like :
SendMessage(Me.Handle, WM_FONTCHANGE, 0, Nothing)
and
SendMessage(CrystalReportViewer1.Handle, WM_FONTCHANGE, 0, Nothing)
But with both lines, GetLastError return error "126 - The specified module
could not be found"

Any help would be very appreciated.

Thanks,
--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
Nov 20 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a
Hi Sylvain,
The problem I am having is with the final part, the line below keep
executing forever:
SendMessage(New System.IntPtr(HWND_BROADCAST), WM_FONTCHANGE, 0,Nothing)


What do you mean by executing forever?
Do you mean when you press F5 to run your project, and the code stop at the
code line and did not run through, also your application stops responding?

If you I think you may try the code below.
Please try to declare the SendMessage API as below as try my code.
(The sample runs smoothly on my side, I create a new winform application
and add a button onto the form)
Private Declare Function CreateScalableFontResource Lib "gdi32" Alias
"CreateScalableFontResourceA" (ByVal fHidden As Integer, ByVal
lpszResourceFile As String, ByVal lpszFontFile As String, ByVal
lpszCurrentPath As String) As Integer

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

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer,
ByVal lParam As Integer) As Integer

Private Const WM_FONTCHANGE = &H1D

Private Const HWND_BROADCAST = &HFFFF&

Public Shared Sub InstallFonts()
Dim fi As System.IO.FileInfo
Try
Dim res As Integer
fi = New System.IO.FileInfo("c:\tunga.ttf")
Dim fiTarget As New
System.IO.FileInfo("C:\Windows\Fonts\tunga.ttf")
If fiTarget.Exists Then Return
' copy the font
fi.CopyTo("C:\Windows\Fonts\tunga.ttf")
' add the font
res = CreateScalableFontResource(0, "c:\tunga.fot",
"c:\windows\fonts\tunga.ttf", String.Empty)
Dim rt As Integer =
System.Runtime.InteropServices.Marshal.GetLastWin3 2Error()
res = AddFontResource("C:\tunga.FOT")
If res > 0 Then
' alert all windows that a font was added
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
InstallFonts()
End Sub

You may try my suggestion and let me know the result.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #2

P: n/a
Hi Peter,
Thanks for your reply. By "...keep executing forever", I meant the
application stop responding, like you said. I will try your code and get
back to you with results.

Regards,
--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Peter Huang" <v-******@online.microsoft.com> wrote in message
news:L$***************@cpmsftngxa06.phx.gbl...
Hi Sylvain,
The problem I am having is with the final part, the line below keep
executing forever:
SendMessage(New System.IntPtr(HWND_BROADCAST), WM_FONTCHANGE, 0,
Nothing)


What do you mean by executing forever?
Do you mean when you press F5 to run your project, and the code stop at

the code line and did not run through, also your application stops responding?

If you I think you may try the code below.
Please try to declare the SendMessage API as below as try my code.
(The sample runs smoothly on my side, I create a new winform application
and add a button onto the form)
Private Declare Function CreateScalableFontResource Lib "gdi32" Alias
"CreateScalableFontResourceA" (ByVal fHidden As Integer, ByVal
lpszResourceFile As String, ByVal lpszFontFile As String, ByVal
lpszCurrentPath As String) As Integer

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

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer,
ByVal lParam As Integer) As Integer

Private Const WM_FONTCHANGE = &H1D

Private Const HWND_BROADCAST = &HFFFF&

Public Shared Sub InstallFonts()
Dim fi As System.IO.FileInfo
Try
Dim res As Integer
fi = New System.IO.FileInfo("c:\tunga.ttf")
Dim fiTarget As New
System.IO.FileInfo("C:\Windows\Fonts\tunga.ttf")
If fiTarget.Exists Then Return
' copy the font
fi.CopyTo("C:\Windows\Fonts\tunga.ttf")
' add the font
res = CreateScalableFontResource(0, "c:\tunga.fot",
"c:\windows\fonts\tunga.ttf", String.Empty)
Dim rt As Integer =
System.Runtime.InteropServices.Marshal.GetLastWin3 2Error()
res = AddFontResource("C:\tunga.FOT")
If res > 0 Then
' alert all windows that a font was added
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
InstallFonts()
End Sub

You may try my suggestion and let me know the result.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #3

P: n/a
Peter,
I tested out your code and it's getting me a bit further. This time the
application does not freeze at the SendMessage(...) line but after this line
execution, GetLastError returns :
Error number 126: The specified module could not be found.

To simplify things a bit, I created a new form with only a label using
my font and still no luck. But the label does show if I start the
application once the font is already installed within \windows\fonts.

Any idea?
--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Sylvain Audet" <sa****@hartco.com> wrote in message
news:O0****************@tk2msftngp13.phx.gbl...
Hi Peter,
Thanks for your reply. By "...keep executing forever", I meant the
application stop responding, like you said. I will try your code and get
back to you with results.

Regards,
--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Peter Huang" <v-******@online.microsoft.com> wrote in message
news:L$***************@cpmsftngxa06.phx.gbl...
Hi Sylvain,
The problem I am having is with the final part, the line below keep
executing forever:
SendMessage(New System.IntPtr(HWND_BROADCAST),
WM_FONTCHANGE, 0,
Nothing)


What do you mean by executing forever?
Do you mean when you press F5 to run your project, and the code stop at

the
code line and did not run through, also your application stops responding?
If you I think you may try the code below.
Please try to declare the SendMessage API as below as try my code.
(The sample runs smoothly on my side, I create a new winform application
and add a button onto the form)
Private Declare Function CreateScalableFontResource Lib "gdi32" Alias "CreateScalableFontResourceA" (ByVal fHidden As Integer, ByVal
lpszResourceFile As String, ByVal lpszFontFile As String, ByVal
lpszCurrentPath As String) As Integer

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

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer,
ByVal lParam As Integer) As Integer

Private Const WM_FONTCHANGE = &H1D

Private Const HWND_BROADCAST = &HFFFF&

Public Shared Sub InstallFonts()
Dim fi As System.IO.FileInfo
Try
Dim res As Integer
fi = New System.IO.FileInfo("c:\tunga.ttf")
Dim fiTarget As New
System.IO.FileInfo("C:\Windows\Fonts\tunga.ttf")
If fiTarget.Exists Then Return
' copy the font
fi.CopyTo("C:\Windows\Fonts\tunga.ttf")
' add the font
res = CreateScalableFontResource(0, "c:\tunga.fot",
"c:\windows\fonts\tunga.ttf", String.Empty)
Dim rt As Integer =
System.Runtime.InteropServices.Marshal.GetLastWin3 2Error()
res = AddFontResource("C:\tunga.FOT")
If res > 0 Then
' alert all windows that a font was added
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
InstallFonts()
End Sub

You may try my suggestion and let me know the result.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no

rights.



Nov 20 '05 #4

P: n/a
Hi Sylvain,

Where do you call the GetLastWin32Error()

System.Runtime.InteropServices.Marshal.GetLastWin3 2Error()
Have you tried to call the GetLastWin32Error after the code line below.
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)

Because the return value of GetLastWin32Error will change every time you
call an API.

Returns the error code returned by the last unmanaged function called using
platform invoke that has the DllImportAttribute.SetLastError flag set.

Marshal.GetLastWin32Error Method
http://msdn.microsoft.com/library/de...us/cpref/html/
frlrfSystemRuntimeInteropServicesMarshalClassGetLa stWin32ErrorTopic.asp

Since I can not reproduce the problem, can you send the simpe reproduce
project to me by removing the "online" from my email address.
Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #5

P: n/a
Hi Peter,
My GetLastError was in my watch window, so I had the value for every
line. I will sure send my project to you later on this morning.

Thanks for your help,
--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Peter Huang" <v-******@online.microsoft.com> wrote in message
news:9V****************@cpmsftngxa06.phx.gbl...
Hi Sylvain,

Where do you call the GetLastWin32Error()

System.Runtime.InteropServices.Marshal.GetLastWin3 2Error()
Have you tried to call the GetLastWin32Error after the code line below.
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)

Because the return value of GetLastWin32Error will change every time you
call an API.

Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set.

Marshal.GetLastWin32Error Method
http://msdn.microsoft.com/library/de...us/cpref/html/ frlrfSystemRuntimeInteropServicesMarshalClassGetLa stWin32ErrorTopic.asp

Since I can not reproduce the problem, can you send the simpe reproduce
project to me by removing the "online" from my email address.
Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #6

P: n/a
Peter,
I tried to run the C++ application that you've sent me but
unfortunately, I still experience the same problem. I ran the application
on 4 different computers (one that was a brand new installation using XP, 2
running XP and 1 thinkpad with Windows 2000 on it).

One thing I noticed though is that the opened windows never get the
updated font until I go to the C:\Windows\Fonts directory using windows
explorer to refresh the list and then restart my application. It is doing
the same thing with my own code in VB.NET.

Any idea?

--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Sylvain Audet" <sa****@hartco.com> wrote in message
news:uq**************@tk2msftngp13.phx.gbl...
Hi Peter,
My GetLastError was in my watch window, so I had the value for every
line. I will sure send my project to you later on this morning.

Thanks for your help,
--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Peter Huang" <v-******@online.microsoft.com> wrote in message
news:9V****************@cpmsftngxa06.phx.gbl...
Hi Sylvain,

Where do you call the GetLastWin32Error()

System.Runtime.InteropServices.Marshal.GetLastWin3 2Error()
Have you tried to call the GetLastWin32Error after the code line below.
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0)

Because the return value of GetLastWin32Error will change every time you
call an API.

Returns the error code returned by the last unmanaged function called

using
platform invoke that has the DllImportAttribute.SetLastError flag set.

Marshal.GetLastWin32Error Method

http://msdn.microsoft.com/library/de...us/cpref/html/
frlrfSystemRuntimeInteropServicesMarshalClassGetLa stWin32ErrorTopic.asp

Since I can not reproduce the problem, can you send the simpe reproduce
project to me by removing the "online" from my email address.
Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no

rights.


Nov 20 '05 #7

P: n/a
Hi Sylvain,

Thanks for your quickly reply!

The behavior is somewhat strange.

Do you mean you still get the 126 error when you call the sendmessage with
the VC++ application I sent to you?

To troubleshoot the problem, please try to follow the steps below.
1. Make sure the 3of9.ttf was not installed.
2. copy the font to c:\windows\temp\3of9.ttf for test.
3. open an notepad.exe application
[NOTE: spy++ will ship with VS6 and VS.NET]
4. open the spy++ utility and Press Ctrl+M to open the Log message dialog,
Drag the find tool drop onto the notepad window(the whole window of notepad
app) so that the spy++ will capture the notepad app, click OK, the spy++
will not log the message for notepad.
5. minimized the notepad, and clear the message log for notepad by pressing
"del" key
6. run the VC++ app I sent to you, click Install Font
7. What result did you get after the four steps.
CopyFile
CreateScalableFontResource
AddFontResource
SendMessage

If all is OK you may get the "***** Succeed", or you will the detailed
error number.

From you description I assume you have got the first three "***** Succeed".
Then did you still get the 126 error after SendMessage, or other error,
please post here.

If all things OK. You will get SendMessage Succeed.
And in the spy++ utility window, you will find WM_FONTCHANGE message, which
means that the notepad has got the message.
Stop the Spy++ by pressing F8, restore the notepad window we minimized just
now and we will find that the font 3 of 9 Barcode can be used now.
Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #8

P: n/a
Hi Sylvain,

Thanks for posting in the community.

Did my test steps help you?
If you still have any question on this problem , please feel free to post
here.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #9

P: n/a
Hi Peter,
I ran the tests you asked me to do and SPY++ reported that the notepad
application (along with my own application - the one having a label using my
font) are receiving the following messages:

- When copying the file to \windows\fonts -> generated 2 "DEVICE CHANGE"
messages
- SendMessage generated 2 messages "WM_FONTCHANGE"
- all other actions did not generate any messages in SPY++ but I did get the
SUCCEED message for every steps

Yes the font is available within notepad (by selecting Format->Font) but it
is still not available to my own application until I close it, refresh the
\windows\fonts directory and the reopen it. Weird heh!?

What do you suggest next?

Thanks,

--
Sylvain Audet - MCP+SB
Visitez les astuces .NET sur dotNET-fr.org
http://www.dotnet-fr.org/sections.ph...ticles&secid=6
"Peter Huang" <v-******@online.microsoft.com> wrote in message
news:iR*************@cpmsftngxa06.phx.gbl...
Hi Sylvain,

Thanks for posting in the community.

Did my test steps help you?
If you still have any question on this problem , please feel free to post
here.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #10

P: n/a
Hi Sylvain,

Thanks for your quickly reply!

From your description, I assume the sendmessage should work on your side(
the NOTEPAD will get the WM_FONTCHANGE message).

So I think, in your senario, you have a windows form application which host
a crystal report viewer control and you want the crystal report viewer
control to get the WM_FONTCHANGE message.

From the msdn,
[in] Handle to the window whose window procedure will receive the message.
If this parameter is HWND_BROADCAST, the message is sent to all top-level
windows in the system, including disabled or invisible unowned windows,
overlapped windows, and pop-up windows; but the message is not sent to
child windows.

SendMessage Function
http://msdn.microsoft.com/library/de...us/winui/winui
/windowsuserinterface/windowing/messagesandmessagequeues/messagesandmessageq
ueuesreference/messagesandmessagequeuesfunctions/sendmessage.asp

We know when you sendmessage to the HWND_BROADCAST, all the toplevel window
will get the message, but not the control as a child window(e.g. crystal
report viewer control ) will get the message.

That's why the notepad will get the WM_FONTCHANGE message in both your
and my test. And I assume the main form of the windows application should
get the message WM_FONTCHANGE. Because they are all toplevel windows.

Also we can sendmessage to the handle of crystal report viewer control, but
the message will not be send to the control's child windows by default. If
you need to do so, I think you need to transvisit all the child window of
the crystal report viewer control to notity them the
WM_FONTCHANGE message explicitly.

Here I write some code snippet on how to transvisit the child control's
handles of the crystal reporter viewer control.
Private Sub RecursiveGetWindow(ByVal ctl As Control, ByVal level As
String)
Debug.WriteLine(level + ctl.Handle.ToString())
If ctl.Controls.Count = 0 Then
Return
End If
level += " + *"
For Each cldcon As Control In ctl.Controls
RecursiveGetWindow(cldcon, level)
Next
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
RecursiveGetWindow(CrystalReportViewer1, "*")
End Sub

You may change the code to meet your request.

If you still have any concern on this issue, please feel free to post here.
Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 20 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.