[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Getting and using TextMetrics from dgi32.dll

Posted on 2010-01-04
18
Medium Priority
?
1,028 Views
Last Modified: 2013-12-17
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

0
Comment
Question by:graber
  • 12
  • 6
18 Comments
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 26178446
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.
0
 
LVL 2

Author Comment

by:graber
ID: 26181983
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
0
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 26183155
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.
0
Get your Conversational Ransomware Defense e‑book

This e-book gives you an insight into the ransomware threat and reviews the fundamentals of top-notch ransomware preparedness and recovery. To help you protect yourself and your organization. The initial infection may be inevitable, so the best protection is to be fully prepared.

 
LVL 2

Author Comment

by:graber
ID: 26190116
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 :)
0
 
LVL 2

Author Comment

by:graber
ID: 26194906
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

0
 
LVL 2

Author Comment

by:graber
ID: 26286250
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
0
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 26287482
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

0
 
LVL 2

Author Comment

by:graber
ID: 26287745
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

0
 
LVL 2

Author Comment

by:graber
ID: 26287796
Carl ... Do you own and operate your own business?...
0
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 26288026
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.
0
 
LVL 2

Author Comment

by:graber
ID: 26288089
How about a C# console application?
0
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 26288108
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.
0
 
LVL 2

Author Comment

by:graber
ID: 26288518
Will do.  Thanks again carl.
0
 
LVL 2

Author Comment

by:graber
ID: 26288983
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

0
 
LVL 2

Author Comment

by:graber
ID: 26289088
Sorry about the extra DllImports they weren't necessary and should have been removed.
0
 
LVL 2

Author Comment

by:graber
ID: 26289406
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

0
 
LVL 52

Expert Comment

by:Carl Tawn
ID: 26291048
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.
0
 
LVL 2

Accepted Solution

by:
graber earned 0 total points
ID: 26293942
I am not sure of the differences internally.  But it did entail a switch for gdi32.dll to vjslib.dll.  This may not be the solution though.  One of the comments on the sight mentioned, "I wouldn't trust the TEXTMETRIC as an indicator of PitchAndFamily no matter how it was obtained.   It might work today and not tomorrow."  So there are still some questions.  At best, for the time being, this code will be suspect.  I want to thank you carl for responding to the post and your help.  I'm going to shut this tread down.  I was under the presumption that GetTextMetrics was the correct approach.  The correct question now is "How do you properly measure text in a C# application"
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Recently while returning home from work my wife (another .NET developer) was murmuring something. On further poking she said that she has been assigned a task where she has to serialize and deserialize objects and she is afraid of serialization. Wha…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signal…
Despite its rising prevalence in the business world, "the cloud" is still misunderstood. Some companies still believe common misconceptions about lack of security in cloud solutions and many misuses of cloud storage options still occur every day. …
Suggested Courses

872 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question