Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Support Forum
Download Visual Studio Add-In

Terms of Use
Privacy Policy
textout (gdi32)
 
.
Summary

C# Signature:

[DllImport("gdi32.dll", CharSet = CharSet.Auto)]
static extern bool TextOut(IntPtr hdc, int nXStart, int nYStart,
   string lpString, int cbString); (Please see note for CharSet in tips)

VB.NET Signature:

    <DllImport("gdi32")> _
    Shared Function TextOut(ByVal hdc As IntPtr, ByVal x As Integer, _
      ByVal y As Integer, ByVal textstring As String, _
      ByVal charCount As Integer) As Boolean
    End Function

Tips & Tricks:

TextOut, unlike the Text property, have to be called every time Windows asks for a control to repaint. By using the Graphics.CopyFromScreen method one can copy the output of a Textout command and use that for repainting.

Unlike graphics.drawstring, Textout can work with fonts other than True Type, Open Type, and PostScript fonts. If you have a font that's supported by Windows but not .net you can most likely use this command to draw it.

[CharSet = CharSet.Auto] According to my experience this parameter should be used when using a LOGFONT structure and the CreateFontIndirect fuction, otherwise the selected font will not be displayed. All flags will be done (lfItalic, lfUnderline ...) but not the lfFaceName string.

Sample Code:

   // Paste this at the beginning of your file if not present:
   using System.Drawing;
   using System.Runtime.InteropServices;

   //Create a class that subclass Control and paste these methods into it.
   //Then place the new control on a form.

   [DllImport("gdi32.dll")]
   static extern bool TextOut(IntPtr hdc, int nXStart, int nYStart,
       string lpString, int cbString);
   [DllImport("gdi32.dll")]
   static extern bool GetTextExtentPoint(IntPtr hdc, string lpString,
       int cbString, ref Size lpSize);
   [DllImport("gdi32.dll")]
   public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
   [DllImport("GDI32.dll")]
   public static extern bool DeleteObject(IntPtr objectHandle);

    #region Font

   protected override void OnKeyPress(KeyPressEventArgs e)
   {
       Text += e.KeyChar.ToString();

       //Note, painting should not be done in the OnKeyPress method, instead:
       Refresh();

       //You may want to meassure the string's size for layout purposes.
       using(Graphics g = base.CreateGraphics())
       {

       //Do the GetHdc(), GetTextExtentPoint, etc, here. Remember that you have
       //to delete related objects such as fonts and call ReleaseHdc on graphics
       //afterwards. If you for some reason don't want to do this you can use a
       //SafeHandle (needs to be subclassed) which does this for you.

       //Remember to use HandleRef when appropriate. For instance if you create
       //a color that you set through SelectObject the .net garbage collector will
       //happily delete the color unless you refere to it after the drawing call or
       //use a HandleRef.

       //In this example we used the base class font and therefore need not worry
       //about the GC deleting the Font in mid drawing.    

       //Also keep in mind that all graphics objects _you_ create must be disposed,
       //which is done through the using clause in this example. It can also be done
       //by calling g.Dispose() in a finally clause (to guarantee that it's executed)
       }
   }

   protected override void OnPaint(PaintEventArgs e)
   {
    IntPtr HDC = e.Graphics.GetHdc();

    //We have to use SelectObject to set the font, color and other properties.
    IntPtr last_font = SelectObject(HDC, Font.ToHfont());

    Size MeasureSize = new Size(0, 0);
    int y_pos = 0;
    int x_pos = 2;

    //Tasks such as these should not be done in the drawing loop as they
    //slow down the drawing.
    String[] lines = Text.Split(new char[] { '\n' });        

    try
    {  
        //We draw out each line of text.
        for(int c=0; c < lines.Length; c++)
        {
             String line = lines[c];
            TextOut(HDC, x_pos, y_pos, line, line.Length);

            //Unless you change the font, the line height never
            //changes so measuring the text at each draw call is
            //inefficient. Also it measure empty lines at 0 height
            //so pressing multiple enters will not move the text down.
             GetTextExtentPoint(HDC, line, line.Length, ref MeasureSize);

             y_pos += MeasureSize.Height;

            //You can use the MeasureSize.Width property to implement
            //word wrapping.
        }
    }
    finally
    {
        //Put here to make sure we don't get a memory leak.

        DeleteObject(SelectObject(HDC, last_font));
        e.Graphics.ReleaseHdc(HDC);
        //Don't call dispose() on the Graphics object unless you createded it.
    }
   }

Vb.net Sample:

Imports System.Runtime.InteropServices

Public Class Form1

    Declare Function SetTextCharacterExtra Lib "gdi32" Alias "SetTextCharacterExtra" (ByVal hDC As Integer, ByVal nCharExtra As Integer) As Integer
    <DllImport("gdi32")> _
    Private Shared Function TextOut(ByVal hdc As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal textstring As String, ByVal charCount As Integer) As Boolean
    End Function
    <DllImport("gdi32")> _
    Private Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hgdiobj As IntPtr) As IntPtr
    End Function
    <DllImport("gdi32")> _
    Private Shared Function DeleteObject(ByVal objectHandle As IntPtr) As Boolean
    End Function
    <DllImport("gdi32")> _
    Private Shared Function SetBkColor(ByVal hdc As IntPtr, ByVal crColor As Integer) As UInt32
    End Function
    <DllImport("gdi32")> _
    Private Shared Function SetTextColor(ByVal hdc As IntPtr, ByVal crColor As Integer) As UInt32
    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Using G = Graphics.FromHwnd(Me.Handle)
        Using myFont As New System.Drawing.Font("Arial", 20, FontStyle.Regular, GraphicsUnit.Pixel)
        'Regular Way
        Dim LeftEdge = 20
        G.DrawString("Hello", myFont, Brushes.Red, LeftEdge, 40)

        'If you want kerning
        Dim Kerning As Integer = 6 'I think this is twips
        Dim Hdc As IntPtr
        Dim FontPtr As IntPtr
        Try
            'Grab the Graphic object's handle
            Hdc = G.GetHdc()
            'Set the current GDI font
            FontPtr = SelectObject(Hdc, myFont.ToHfont())
            'Set the drawing surface background color
            SetBkColor(Hdc, ColorTranslator.ToWin32(Me.BackColor))
            'Set the text color
            SetTextColor(Hdc, ColorTranslator.ToWin32(Color.Red))
            'Set the kerning
            SetTextCharacterExtra(Hdc, Kerning)
            Dim Text = "Hello"
            'Draw the text at (20,60), Kerning will be applied so reset the left edge to half of kerning
            TextOut(Hdc, LeftEdge + (Kerning \ 2), 60, Text, Text.Length)
        Catch ex As Exception

        Finally
            'Release the font
            DeleteObject(FontPtr)
            'Release the handle on the graphics object
            G.ReleaseHdc()
        End Try
        End Using
    End Using
    End Sub

End Class

Alternative Managed API:

Graphics.DrawString
Graphics.MeasureString
Graphics.MeasureCharacterRanges

Documentation
TextOut on MSDN

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Edit This Page
Find References
Show Printable Version
Revisions