Jump to content
  • Advertisement
Sign in to follow this  

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

This topic is 3100 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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

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;

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);
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
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!