Sign in to follow this  
azherdev

[.net] [C#] How to use GetCharABCWidths? Please help.

Recommended Posts

I am trying to get the ABC structure of the font and have big problems with it. Here is what I have: struct ABC { int abcA; uint abcB; int abcC; } [System.Runtime.InteropServices.DllImport("gdi32.dll")] static extern bool GetCharABCWidths(IntPtr hdc, uint uFirstChar, uint uLastChar, out ABC [] lpabc); public bool SetFont(System.Drawing.Font font) { ABC [] _temp = new ABC[224]; GetCharABCWidths(font.ToHfont(), 32, 255, out _temp); } The above code does not work (there is more code around it, but this is the part that does not work. GetCharABCWindths returns FALSE and the _temp object is set to null. There is little info on this and I can't make it work in C#. Can anyone please help? Thanks.

Share this post


Link to post
Share on other sites
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/fontext_8icz.asp

If the function returns 0 (false) then call GetLastError to find out what failed.

That help page also says that the current font should also be a true type font. Is that the case?

Does it work if you use different character ranges? e.g. 65-66

The help page uses a device context as the first argument, you are passing in a font handle. I'm not sure if these are the same things or not.

Share this post


Link to post
Share on other sites
Yeah, I've looked through that page. I can't get it. I tried passing different ranges and nothing. I am trying to get the width of Arial font.

In my program, I am creating a class, so all I know is what font you want to use by having the System.Drawing.Font object. I do not know who called it (which form). So how do I create a device context, or use the one that the font was created on?

I've never done Windows C++ programming so I am very lost in DC area.

Share this post


Link to post
Share on other sites
I know that this is an old post but recently I needed this function to work in C#, and I wanted to share my solution.

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct ABC
{
public int abcA;
public uint abcB;
public int abcC;
}

[DllImport("gdi32.dll", ExactSpelling = true)]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObj);

[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
public static extern int DeleteObject(IntPtr hObj);

[DllImport("gdi32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool GetCharABCWidthsW(IntPtr hdc, uint uFirstChar, uint uLastChar, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStruct, SizeConst=1)] ABC[] lpabc);

private ABC GetCharWidthABC(char ch, Font font, Graphics gr)
{
ABC[] _temp = new ABC[1];
IntPtr hDC = gr.GetHdc();
Font ft = (Font)font.Clone();
IntPtr hFt = ft.ToHfont();
SelectObject(hDC, hFt);
GetCharABCWidthsW(hDC, ch, ch, _temp);
DeleteObject(hFt);
gr.ReleaseHdc();
return _temp[0];
}

Well I made it this way to make it generic but the you can change your declaration in SizeConst to return a fixed number of results different than 1, unfortunatelly I couldn't find a way to keep it dynamic.

The trick here is to assign the handle of the font to the handle of the Graphics object (this object can be obtained from the OnPaint event or using the CreateGraphics() method from Control class) using the SelectObject method.

After that is very simple but don't forget to release the handles or you will have memory leaks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this