Link to home
Start Free TrialLog in
Avatar of graber
graberFlag for United States of America

asked on

Getting and using TextMetrics from dgi32.dll

I am attempting to "TextMetrics" from the gdi32.dll library.

the compiler if flaggin the function GetTextMetrics with
Error      1      Inconsistent accessibility: parameter type 'WindowsControlLibrary1.SW.TEXTMETRIC' is less accessible than method 'WindowsControlLibrary1.SW.GetTextMetrics(System.IntPtr, WindowsControlLibrary1.SW.TEXTMETRIC)'      C:\Users\garaber\Documents\Dev Software\BitSWTest\WindowsControlLibrary1\UserControl1.cs      41      33      WindowsControlLibrary1
I've seen this example out on the web and it seems to be working for others.  Thanks guys
[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
      public static extern bool GetTextMetrics(IntPtr hdc, TEXTMETRIC lptm);

Open in new window

Avatar of Carl Tawn
Carl Tawn
Flag of United Kingdom of Great Britain and Northern Ireland image

It sounds like you have a struct defined called TEXTMETRIC that has an accessibility level of private, internal or protected. Its complaining because that would give it a lower accessibility level than the method.
Avatar of graber

ASKER

TEXTMETRIC is defined just above.  The IDE has identified the function GetTextMetrics as the problem.  Not sure what I'm doing wrong.
public partial class SW : UserControl
   {
      struct TEXTMETRIC
      { 
         public int tmHeight; 
         public int tmAscent; 
         public int tmDescent; 
         public int tmInternalLeading; 
         public int tmExternalLeading; 
         public int tmAveCharWidth; 
         public int tmMaxCharWidth; 
         public int tmWeight; 
         public int tmOverhang; 
         public int tmDigitizedAspectX; 
         public int tmDigitizedAspectY; 
         public char tmFirstChar; 
         public char tmLastChar; 
         public char tmDefaultChar; 
         public char tmBreakChar; 
         public char tmItalic; 
         public char tmUnderlined; 
         public char tmStruckOut; 
         public char tmPitchAndFamily; 
         public char tmCharSet; 
      }

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool GetTextMetrics(IntPtr hdc, TEXTMETRIC lptm);

Open in new window

C-.jpg
You need to change the line:

    struct TEXTMETRIC

To:

    public struct TEXTMETRIC

If you don't say otherwise then a nested struct is private. In this case that is causing a problem because it gives the struct a more restrictive visibility that the method for which it is a parameter. If you change the declaration, as above, so that it is public then it should sort the problem.
Avatar of graber

ASKER

I've been writing software for some time now and I still get tag by this stuff.  This is embarrassing.  Thanks Carl.  As it turns out I'm a cheep date :)
Avatar of graber

ASKER

GetText Metrics is returning false.... Did I miss something?
   public partial class Form1 : Form
   {
      public struct TEXTMETRIC
      {
         public int tmHeight; 
         public int tmAscent; 
         public int tmDescent; 
         public int tmInternalLeading; 
         public int tmExternalLeading; 
         public int tmAveCharWidth; 
         public int tmMaxCharWidth; 
         public int tmWeight; 
         public int tmOverhang; 
         public int tmDigitizedAspectX; 
         public int tmDigitizedAspectY; 
         public char tmFirstChar; 
         public char tmLastChar; 
         public char tmDefaultChar; 
         public char tmBreakChar; 
         public char tmItalic; 
         public char tmUnderlined; 
         public char tmStruckOut; 
         public char tmPitchAndFamily; 
         public char tmCharSet; 
      }

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool GetTextMetrics(IntPtr hDC, TEXTMETRIC lptm);

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

      [DllImport("Gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool DeleteObject(IntPtr hdc);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern UInt32 GetLastError();


      public Form1()
      {
         InitializeComponent();
      }

      private void Form1_Paint(object sender, PaintEventArgs e)
      {
         Font font = new Font(Font.FontFamily, 10, FontStyle.Regular, GraphicsUnit.Pixel);
         TEXTMETRIC tm = new TEXTMETRIC();
         IntPtr hDC = e.Graphics.GetHdc();
         IntPtr hFont = font.ToHfont();
         IntPtr hFontPrev = SelectObject(hDC, hFont);
         bool bResults = GetTextMetrics(hDC, tm);
         SelectObject(hDC, hFontPrev);
         DeleteObject(hFont);
         e.Graphics.ReleaseHdc(hDC);
      }

Open in new window

Avatar of graber

ASKER

Am I too assume that this matter is closed.  The question as asking for "Getting and using TextMetrics".  We're not using it yet.
Gregg
Sorry, didn't see that last post. Try the following, as a test, and see if it returns true:
            System.Windows.Forms.Label label = new System.Windows.Forms.Label();
            Graphics g = Graphics.FromHwnd(label.Handle);

            API.TEXTMETRIC metric = new API.TEXTMETRIC();
            bool result = API.GetTextMetrics(g.GetHdc(), metric);

Open in new window

Avatar of graber

ASKER

Thanks carl for responding.  I had to alter it a bit to work with the stub.  See if this is ok.  As it runs right now it is still returning false. Bummer.  
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetTextMetricsTest
{
   public partial class Form1 : Form
   {
      public struct TEXTMETRIC
      {
         public int tmHeight; 
         public int tmAscent; 
         public int tmDescent; 
         public int tmInternalLeading; 
         public int tmExternalLeading; 
         public int tmAveCharWidth; 
         public int tmMaxCharWidth; 
         public int tmWeight; 
         public int tmOverhang; 
         public int tmDigitizedAspectX; 
         public int tmDigitizedAspectY; 
         public char tmFirstChar; 
         public char tmLastChar; 
         public char tmDefaultChar; 
         public char tmBreakChar; 
         public char tmItalic; 
         public char tmUnderlined; 
         public char tmStruckOut; 
         public char tmPitchAndFamily; 
         public char tmCharSet; 
      }

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool GetTextMetrics(IntPtr hDC, TEXTMETRIC lptm);

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

      [DllImport("Gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool DeleteObject(IntPtr hdc);

      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern UInt32 GetLastError();


      public Form1()
      {
         InitializeComponent();
      }

      private void Form1_Paint(object sender, PaintEventArgs e)
      {
         System.Windows.Forms.Label label = new System.Windows.Forms.Label();
         Graphics g = Graphics.FromHwnd(label.Handle);
         TEXTMETRIC tm = new TEXTMETRIC();
         bool result = GetTextMetrics(g.GetHdc(), tm); 
         //Font font = new Font(Font.FontFamily, 10, FontStyle.Regular, GraphicsUnit.Pixel);
         //TEXTMETRIC tm = new TEXTMETRIC();
         //IntPtr hDC = e.Graphics.GetHdc();
         //IntPtr hFont = font.ToHfont();
         //IntPtr hFontPrev = SelectObject(hDC, hFont);
         //bool bResults = GetTextMetrics(hDC, tm);
         //SelectObject(hDC, hFontPrev);
         //DeleteObject(hFont);
         //e.Graphics.ReleaseHdc(hDC);
      }
   }
}

Open in new window

Avatar of graber

ASKER

Carl ... Do you own and operate your own business?...
Ok, that should be working. There must be something in your form, or elsewhere that is causing GetTextMetrics to return false. I would try that block of code by itself in a simple winforms app, but don't put the code in the Paint event.

On a side note, I don't run my own business, but I do do the occasional freelance project.
Avatar of graber

ASKER

How about a C# console application?
You can do it as a console app, but you will need to add references to the System.Windows.Forms and System.Drawing assemblies, as they won't be included by default.
Avatar of graber

ASKER

Will do.  Thanks again carl.
Avatar of graber

ASKER

The code as it stands is still returning false.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace ConsoleGetTextMetrics
{
   class Program
   {
      public struct TEXTMETRIC
      {
         public int tmHeight; 
         public int tmAscent; 
         public int tmDescent; 
         public int tmInternalLeading; 
         public int tmExternalLeading; 
         public int tmAveCharWidth; 
         public int tmMaxCharWidth; 
         public int tmWeight; 
         public int tmOverhang; 
         public int tmDigitizedAspectX; 
         public int tmDigitizedAspectY; 
         public char tmFirstChar; 
         public char tmLastChar; 
         public char tmDefaultChar; 
         public char tmBreakChar; 
         public char tmItalic; 
         public char tmUnderlined; 
         public char tmStruckOut; 
         public char tmPitchAndFamily; 
         public char tmCharSet; 
      }

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool GetTextMetrics(IntPtr hDC, TEXTMETRIC lptm);
      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
      [DllImport("Gdi32.dll", CharSet = CharSet.Auto)]
      public static extern bool DeleteObject(IntPtr hdc);
      [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
      public static extern UInt32 GetLastError();

      static void Main(string[] args)
      {

         System.Windows.Forms.Label label = new System.Windows.Forms.Label();
         Graphics g = Graphics.FromHwnd(label.Handle);
         TEXTMETRIC tm = new TEXTMETRIC();
         bool result = GetTextMetrics(g.GetHdc(), tm); 
      }
   }
}

Open in new window

Avatar of graber

ASKER

Sorry about the extra DllImports they weren't necessary and should have been removed.
Avatar of graber

ASKER

I found this out on .Net Framework Developement Center
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/1bc0166b-8a68-4067-a44b-e11ff7d55720
And it appears to work.  I'm using visual studio 2005 on vista OS with a reference for vjslib (com.ms.win32)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using com.ms.win32;

namespace GetTextMetricsAttempt3
{
   public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
      }

      private void button1_Click(object sender, EventArgs e)
      {
         int hDC = User32.GetDC((int)this.Handle);
         TEXTMETRIC tm = new TEXTMETRIC();
         foreach (FontFamily FF in FontFamily.Families)
         {
            try
            {
               this.Font = new Font(FF, 10);
            }
            catch(Exception ex)
            {
               Console.WriteLine(ex.ToString());
            }
            Gdi32.GetTextMetrics(hDC, tm);
            Console.WriteLine(FF.Name + " " + tm.tmPitchAndFamily.ToString());
         }
      }
   }
}

Open in new window

Oh well, as long as its working for you now. Although I can't see any reason why your other version shouldn't have worked.
ASKER CERTIFIED SOLUTION
Avatar of graber
graber
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial