GetCharABCWidths (gdi32)
Last changed: -91.208.24.18

.
Summary

C# Signature:

    [DllImport("gdi32.dll", EntryPoint = "GetCharABCWidths", SetLastError = true, CharSet = CharSet.Auto)]
    static extern unsafe bool GetCharABCWidths(IntPtr hdc, uint uFirstChar,
       uint uLastChar, ABC* lpabc);

    [DllImport("gdi32.dll", EntryPoint = "GetCharABCWidthsW", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern unsafe bool GetCharABCWidthsW(IntPtr hdc, uint uFirstChar,
       uint uLastChar, ABC* lpabc);

    //CharSet = CharSet.Ansi is the default for C#. SetLastError = true adds some overhead and is default set false.
    [DllImport("gdi32.dll", EntryPoint = "GetCharABCWidthsA", SetLastError = true)]
    static extern unsafe bool GetCharABCWidthsA(IntPtr hdc, uint uFirstChar,
       uint uLastChar, ABC* lpabc);

User-Defined Types:

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

        public override string ToString()
        {
        return string.Format("A={0}, B={1}, C={2}", abcA, abcB, abcC);
        }
    }

Notes:

None.

Tips & Tricks:

Please add some!

Sample Code:

The following method can be used to get the width of a single character. Change to W for unicode

    /// <summary>
    /// Gets the width of an ANSI true type font character
    /// </summary>
    /// <param name="g">A graphics object</param>
    /// <param name="f">A font, note that all Fonts encapsulated
    /// in a Font object are True Type.</param>
    /// <param name="c">A character</param>
    public static ABC GetCharABCWidthsA_(Graphics g, Font f, char c)
    {
      IntPtr hDC = g.GetHdc();
      W32.ABC[] abc_array = new ABC[1];
      IntPtr abcptr = Marshal.UnsafeAddrOfPinnedArrayElement(abc_array, 0);
      IntPtr hFont = f.ToHfont();

      try
      {
        IntPtr hFontPreviouse = SelectObject(hDC, hFont);
        bool result = GetCharABCWidthsA(hDC, (uint) c, (uint) c, abcptr);
        SelectObject(hDC, hFontPreviouse);

        if (!result) //Propper error handeling..? Naahh
          Console.WriteLine("Did not find ABC: " + f.ToString());
      }
      finally
      {
        DeleteObject(hFont);
        g.ReleaseHdc(hDC);
      }

      return abc_array[0];
    }

    /// <summary>
    /// The SelectObject function selects an object into the specified device
    /// context (DC). The new object replaces the previous object of the same
    /// type.
    /// </summary>
    /// <param name="hdc">Handle to the DC.</param>
    /// <param name="hgdiobj">Handle to the object to be selected.</param>
    /// <returns>If IntPtr.Zero it's an error</returns>
    [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
    public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

    /// <summary>
    /// deletes a logical pen, brush, font, bitmap, region, or palette,
    /// freeing all system resources associated with the object.
    /// </summary>
    [DllImport("GDI32.dll")]
    public static extern bool DeleteObject(IntPtr objectHandle);

Alternative Managed API:

Do you know one? Please contribute it!

Documentation