AddFontFile XP C# - c#

I have a project where I need to load a Postscript font from disk.
I found I could use "AddFontFile". Doing some research I see that I have to pipe the two fonts http://msdn.microsoft.com/en-us/library/system.drawing.text.privatefontcollection.addfontfile.aspx together so I tried:
fontCollection = new PrivateFontCollection();
fontCollection.AddFontFile(#"C:\Temp\Font\myfont.PFM|C:\Temp\Font\myfont.PFB");
I'm getting a a error "Illegal characters in path".
I'm not sure if I'm piping the two fonts correctly.
Any help would be great, I should mention we are still on XP not sure if that makes a differnts or not.
Mike

You cannot have the pipe | character in your filename. PrivateFontCollection.AddFontFile requires a valid filepath. Hence your "Illegal characters in path" exception. The input at MSDN is A String that contains the file name of the font to add. Try passing a single file at a time - I don't know about this piping idea..
As for your Postscript desire, the Remarks section states that OpenTypes have limited support.

After some searching I got it to work and I'd like to share on how I solved the this:
AddFontFile was the wrong API i Needed to use AddFontResource instead
String fontPath = #"C:\Temp\Font2\GXSTRA03.PFM|C:\Temp\Font2\GXSTRA03.PFB";
int result = AddFontResource(fontPath);
long msg = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
to remove the font resource
RemoveFontResource(#"C:\Temp\Font2\GXSTRA03.PFM|C:\Temp\Font2\GXSTRA03.PFB");
long msg = SendMessage(HWND_BROADCAST, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
If anyone is new on making a external WinApi call here is the import and import DLL code that I used
using System.Runtime.InteropServices;
private static uint WM_FONTCHANGE = 0x1D;
Import("gdi32.dll")]
static extern int AddFontResource(string lpFilename);
[DllImport("gdi32.dll")]
static extern bool RemoveFontResource(string lpFileName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
This fonts now shows in word and notepad ect..

Related

Read all text from external Application

I have a hotkey window application in C# and I want all the text from the focused window of other application on pressing hotkey like notepad, browser, command window(cmd), Turbo c++, Pascal etc.
So Is it possible?
If any one have idea please help me with code example.
I have attach screen shot. I want to read text from this window. On pressing hotkey I want to read text "This is my test text".
There is a GetWindowText() in user32 API,
but if you need to get text from a control in another process, GetWindowText() won't work.
You have to use SendMessage() with WM_GETTEXT instead:
const UInt32 WM_GETTEXT = 0x000D;
const UInt32 WM_GETTEXTLENGTH = 0x000E;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam);
static string GetWindowTextRaw(IntPtr hwnd)
{
// Allocate string length
int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
StringBuilder sb = new StringBuilder(length + 1);
// Get window text
SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
Application that call themselves "Screen Reader" (for visually impaired people) do that kind of things, sort of.
They use the old MSSA (Microsoft Active Accessibility) APIs and/or the new UIAutomation APIs.
With the two APIs, if you have a "Main Window" HWND, you can then browse the tree of the componants making the app. You can then retrieve properties, such as "Text" or "Name" and so on.
If the application doesn't support Accessive technologies, you fall back on case by case solutions, which means eventually awful hacks (as APIs hooking) or more regular methods (as DLL injection and use of the JNI Invocation API in the JAVA case).
Its is not directly possible through C#,
Still microsoft provides with WMI services which can utilized to get at max information on the machine and processes. Kindly check MSDN
You can download WMI tool from here and possible check Win32 classes and methods, you may find useful information for your requirement

How to remove/replace fonts currently in use

I'd like to deploy font packages programmatically during our update process. Therefore, I need to replace the old font files in \Windows\Fonts with the new ones extracted from a ZIP archive. Deleting an existing font file will cause an IOException, because of another process accessing the file.
I tried to release the font by calling RemoveFontResource and propagating the change with a WM_FONTCHANGE message, but no luck. RemoveFontResource returns false with native error 2 (file not found?) and HRESULT -2147467259. The file actually does exist.
Sample code:
[DllImport("coredll.dll", SetLastError = true)]
private static extern int RemoveFontResource(string lpName);
[DllImport("coredll.dll", SetLastError = true)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
private const int WM_FONTCHANGE = 0x001D;
private const int HWND_BROADCAST = 0xffff;
public const string SAMPLE_FILE = #"\Windows\Fonts\MyFont.ttf";
public void RemoveFont()
{
if (!RemoveFontResource(SAMPLE_FILE))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
SendMessage(new IntPtr(HWND_BROADCAST), WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
File.Delete(SAMPLE_FILE);
}
Is there actually a clean way to deploy and replace fonts system-wide?
If the font files are part of the OS image, they have the eXecute-In-Place (XIP) attribute set (read-only, system, ROM) and cannot simply replaced. Although one can copy a file of the same name on top, which hides the original file. If the file copied on top is deleted, the original file is back. This is the case with all XIP files.
I recommend you use the SysCache dir to replace the files. This will work with all file replacements, regardless if they are XIP, drivers, DLLs, in-use or otherwise locked for replacement.
If you place files with the same name as the origibal file in the syscache dir, these will be used instead of the original files. But you have to warmboot the device after placing files in the syscache dir. Windows CE/Mobile will recognize and 'use' the syscache files only during the OS startup.
The location of the syscache dir may vary, depending on OS version and OEM decisions. On WM 6 devices it should be \Windows\System\syscache. Check the file system of the device for an existing syscache directory.
BTW: font files do not need to be placed into \Windows\Fonts, it is OK to place them in \Windows.

MoveFileWithProgress throws "The system cannot move the file to a different disk drive" – why?

I have:
[SuppressUnmanagedCodeSecurity]
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool MoveFileWithProgress(
string lpExistingFileName, string lpNewFileName,
CopyProgressRoutine lpProgressRoutine,
int dwFlags);
public enum MoveFileOptions
{
MOVEFILE_COPY_ALLOWED = 0x2
}
And calling it with:
if (!MoveFileWithProgress(source.FullName, destination.FullName, cpr, (int)options)) {
throw new IOException(new Win32Exception().Message);
}
Where: options is MoveFileOptions.MOVEFILE_COPY_ALLOWED
It works fine when moving in the hard drive. But when I try moving to a Flash-drive, I get: The system cannot move the file to a different disk drive.
Why?
Your DllImport is incorrect. Your function has only 4 parameters, but the real function has 5. Presumably what is happening is that MOVEFILE_COPY_ALLOWED is being passed to lpData and is ignored. The dwFlags parameter is just whatever happens to be sitting on the stack.
Fixing your p/invoke will probably solve the problem. Also, dwFlags should be unsigned.
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool MoveFileWithProgress(
string lpExistingFileName,
string lpNewFileName,
CopyProgressRoutine lpProgressRoutine,
IntPtr lpData,
uint dwFlags
);
With this correct you need to decide what to pass to lpData. Since you appear not to be using it at the moment, it doesn't really matter and IntPtr.Zero seems the obvious choice.
From this Microsoft | Technet page, it says:
The file cannot be moved to a different disk drive at the same time you rename it using the Rename command.
Try renaming the file before moving it.
Are you perhaps moving a directory?
According to the documentation for MoveFileWithProgress at MSDN (emphasis added):
When moving a file, lpNewFileName can be on a different file system or volume. If lpNewFileName is on another drive, you must set the MOVEFILE_COPY_ALLOWED flag in dwFlags.
When moving a directory, lpExistingFileName and lpNewFileName must be on the same drive.

how to use ORIYA font in smart device development?

I am developing an application for WINDOWS CE5.0 based device. It requires ORIYA language(INDIAN REGIONAL LANGUAGE) to be used completely. As visual studio use ENGLISH as standard language, please tell me how to proceed? I tried to copy the font in WINDOWS CE device's WINDOWS/FONTS folder but as i restart the device that font file disappears. I developed the application in c# and changed labels text into oriyaa in Development system. It looks fine on the development system but as i deployed it into device, All label text appears in ENGLISH. I dont know whats happening? I also need to set the LABEL.TEXT property in ORIYA language. Is it possible? How to take user input in ORIYA? Please help..... Thanks...
Not very sure as what you meant by browser but for the Forms you can go about using PrivateFontCollection
you can load the font from a folder in your app and then use
AddFontFile or AddMemoryFont as per your need. So now the Client can see the controls in the font you set and its available to it irrespective of its installed or not
I have used the following approach with English-based fonts, but I am not sure if it will work on your case. The original source of this approach is a nice post from Chris Tacke (SO user #ctacke) with some modifications.
[DllImport("coredll.dll")]
private static extern int AddFontResource(string lpszFilename);
[DllImport("coredll.dll", SetLastError = true)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
static IntPtr HWND_BROADCAST = (IntPtr)0xFFFF;
const int WM_Fontchange = 0x001D;
private static void RegisterFont(string aFontPath, string aTargetFontPath)
{
IntPtr thir = (IntPtr)0;
IntPtr fourth = (IntPtr)0;
try
{
if (!System.IO.File.Exists(aTargetFontPath))
System.IO.File.Copy(aFontPath, aFontTargetPath);
}
catch { throw; }
int _Loaded = AddFontResource(aFontTargetPath);
if (_Loaded != 0)
SendMessage(HWND_BROADCAST, WM_Fontchange, thir, fourth);
}

P/Invoke problems with basic CRT functions (i.e., putchar, puts)

I've noticed something very strange. I was trying to call the CRT function "putchar", and was unable to get it to work. So I double-checked that I wasn't missing something, and I copied the code directly from the P/Invoke tutorial on MSDN to see if it worked.
http://msdn.microsoft.com/en-us/library/aa288468%28VS.71%29.aspx
You'll notice that they import "puts".
So I tested the exact code copied from MSDN. It didn't work! So now I got frustrated. I've never had this problem before.
Then I just so happened to run WITHOUT debugging (hit ctrl+f5), and it worked! I tested other functions which output to the console too, and none of them work when debugging but all work when not debugging.
I then wrote a simple C dll which exports a function called "PrintChar(char c)". When I call that function from C#, it works even if I'm debugging or not, without any problems.
What is the deal with this?
The Visual Studio hosting process is capable of redirecting console output to the Output window. How exactly it manages to do this is not documented at all, but it gets in the way here. It intercepts the WriteFile() call that generates the output of puts().
Project + Properties, Debug tab, untick "Enable the Visual Studio hosting process". On that same page, enabling unmanaged debugging also fixes the problem.
It's a bad example, using the C-Runtime Library DLL to call puts. Keep reading the tutorial as there is good info there, but try making Win32 API calls instead.
Here is a better introduction to p/invoke: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
It's old, but the information is still good.
Edited
My explaination was wrong.
I went looking for a correct explaination and I discovered that the C-Runtime puts method and the .NET Framework Console.Write method differ in how they write to the console (Console.Write works where the p/invoke to puts does not). I thought maybe the answer was in there, so I whipped up this demonstration:
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
class Program
{
public static void Main()
{
int written;
string outputString = "Hello, World!\r\n";
byte[] outputBytes = Encoding.Default.GetBytes(outputString);
//
// This is the way the C-Runtime Library method puts does it
IntPtr conOutHandle = CreateFile("CONOUT$", 0x40000000, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
WriteConsole(conOutHandle, outputBytes, outputString.Length, out written, IntPtr.Zero);
//
// This is the way Console.Write does it
IntPtr stdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
WriteFile(stdOutputHandle, outputBytes, outputBytes.Length, out written, IntPtr.Zero);
// Pause if running under debugger
if (Debugger.IsAttached)
{
Console.Write("Press any key to continue . . . ");
Console.ReadKey();
}
}
const int STD_OUTPUT_HANDLE = -11;
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int WriteFile(IntPtr handle, [In] byte[] bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
static extern bool WriteConsole(IntPtr hConsoleOutput, [In] byte[] lpBuffer, int nNumberOfCharsToWrite, out int lpNumberOfCharsWritten, IntPtr mustBeZero);
}
Both of those successfully output under the debugger, even with the hosting process enabled. So that is a dead end.
I wanted to share it in case it leads someone else to figuring out why it happens -- Hans?

Categories