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
Download Visual Studio Add-In

SB_GETTEXT (user32)
 
.
Summary
I started trying to figure out how to use SB_GETTEXT many years ago when I was still new to C#. pInvoke in particular was always pretty confusing to me back then because of all the different C++ types. When does it matter whether I use int, uint, IntPtr, etc when they all seem to work?! Well I know now but that's another story... I was looking through my code archive and noticed my unfinished SB_GETTEXT code so I took another look and decided that it wasn't so confusing anymore (5 years later). I was never able to find good C# examples of SB_GETTEXT so I thought I'd share mine. Have fun!
Summary
TODO - a short description

C# Signature:

  [DllImport("user32.dll")]
  private static extern UInt32 SendMessage(
      IntPtr hWnd,
      UInt32 wMsg,
      IntPtr wParam,
      IntPtr lParam
      );

C++ Signature:

  lResult = SendMessage(  // returns LRESULT in lResult
     (HWND) hWndControl,  // handle to destination control
     (UINT) SB_GETTEXT,   // message ID
     (WPARAM) wParam,     // = (WPARAM) (INT) iPart;
     (LPARAM) lParam      // = (LPARAM) (LPSTR) szText;
      );

Sample Code:

using System;
using System.Runtime.InteropServices;

Notes:

I started trying to figure out how to use SB_GETTEXT many years ago when I was still new to C#. pInvoke in particular was always pretty confusing to me back then because of all the different C++ types. When does it matter whether I use int, uint, IntPtr, etc when they all seem to work?! Well I know now but that's another story... I was looking through my code archive and noticed my unfinished SB_GETTEXT code so I took another look and decided that it wasn't so confusing anymore (5 years later). I was never able to find good C# examples of SB_GETTEXT so I thought I'd share mine. Have fun!

namespace BBooth
{
    public class StatusBar
    {
    #region Members
    private IntPtr _handle;
    private string[] _captions;
    private int _panelCount;
    private int _pid;
    #endregion

Sample Code:

using System;
using System.Runtime.InteropServices;

    #region Constructor
    public StatusBar(IntPtr hWnd)
    {
        this._handle = hWnd;
        this._panelCount = -1;
        this._pid = -1;
    }
namespace BBooth
{
    public class StatusBar
    {
    #region Members
    private IntPtr _handle;
    private string[] _captions;
    private int _panelCount;
    private int _pid;
    #endregion

    #region Imports
    [DllImport("kernel32.dll")]
    private static extern IntPtr OpenProcess(
        ProcessAccessTypes desiredAccess,
        Boolean inheritHandle,
        Int32 processId
        );
    #region Constructor
    public StatusBar(IntPtr hWnd)
    {
        this._handle = hWnd;
        this._panelCount = -1;
        this._pid = -1;
    }
    #endregion

    #region Imports
    [DllImport("kernel32.dll")]
    private static extern int CloseHandle(
        IntPtr hObject
    private static extern IntPtr OpenProcess(
        ProcessAccessTypes desiredAccess,
        Boolean inheritHandle,
        Int32 processId
        );

    [DllImport("kernel32.dll")]
    private static extern IntPtr VirtualAllocEx(
        IntPtr hProcess,
        IntPtr address,
        UInt32 size,
        VirtualAllocExTypes allocationType,
        AccessProtectionFlags flags
    private static extern int CloseHandle(
        IntPtr hObject
        );

    [DllImport("kernel32.dll")]
    private static extern bool VirtualFreeEx(
    private static extern IntPtr VirtualAllocEx(
        IntPtr hProcess,
        IntPtr address,
        UInt32 size,
        VirtualAllocExTypes dwFreeType
        VirtualAllocExTypes allocationType,
        AccessProtectionFlags flags
        );

    [DllImport("kernel32.dll")]
    private static extern bool ReadProcessMemory(
    private static extern bool VirtualFreeEx(
        IntPtr hProcess,
        IntPtr baseAddress,
        byte[] buffer,
        UInt32 dwSize,
        out UInt32 numberOfBytesRead
        IntPtr address,
        UInt32 size,
        VirtualAllocExTypes dwFreeType
        );

    [DllImport("user32.dll")]
    private static extern int GetWindowThreadProcessId(
        IntPtr hWnd,
        out Int32 lpdwProcessId
    [DllImport("kernel32.dll")]
    private static extern bool ReadProcessMemory(
        IntPtr hProcess,
        IntPtr baseAddress,
        byte[] buffer,
        UInt32 dwSize,
        out UInt32 numberOfBytesRead
        );

    [DllImport("user32.dll")]
    private static extern uint SendMessage(
    private static extern int GetWindowThreadProcessId(
        IntPtr hWnd,
        UInt32 wMsg,
        IntPtr wParam,
        IntPtr lParam
        out Int32 lpdwProcessId
        );

    [DllImport("user32.dll")]
    private static extern uint SendMessage(
        IntPtr hWnd,
        UInt32 wMsg,
        UInt32 wParam,
        UInt32 lParam
        IntPtr wParam,
        IntPtr lParam
        );
    #endregion

    #region Constants
    private const uint WM_USER      = 0x0400;
    private const uint SB_SETPARTS      = WM_USER + 4;
    private const uint SB_GETPARTS      = WM_USER + 6;
    private const uint SB_GETTEXTLENGTH = WM_USER + 12;
    private const uint SB_GETTEXT       = WM_USER + 13;
    [DllImport("user32.dll")]
    private static extern uint SendMessage(
        IntPtr hWnd,
        UInt32 wMsg,
        UInt32 wParam,
        UInt32 lParam
        );
    #endregion

    #region Constants
    private const uint WM_USER      = 0x0400;
    private const uint SB_SETPARTS      = WM_USER + 4;
    private const uint SB_GETPARTS      = WM_USER + 6;
    private const uint SB_GETTEXTLENGTH = WM_USER + 12;
    private const uint SB_GETTEXT       = WM_USER + 13;
    #endregion

    #region Enumerations
    private enum ProcessAccessTypes
    {
        PROCESS_TERMINATE     = 0x00000001,
        PROCESS_CREATE_THREAD     = 0x00000002,
        PROCESS_SET_SESSIONID     = 0x00000004,
        PROCESS_VM_OPERATION      = 0x00000008,
        PROCESS_VM_READ       = 0x00000010,
        PROCESS_VM_WRITE      = 0x00000020,
        PROCESS_DUP_HANDLE    = 0x00000040,
        PROCESS_CREATE_PROCESS    = 0x00000080,
        PROCESS_SET_QUOTA     = 0x00000100,
        PROCESS_SET_INFORMATION   = 0x00000200,
        PROCESS_QUERY_INFORMATION = 0x00000400,
        STANDARD_RIGHTS_REQUIRED  = 0x000F0000,
        SYNCHRONIZE = 0x00100000,
        PROCESS_ALL_ACCESS = PROCESS_TERMINATE | PROCESS_CREATE_THREAD | PROCESS_SET_SESSIONID | PROCESS_VM_OPERATION |
          PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE | PROCESS_CREATE_PROCESS | PROCESS_SET_QUOTA |
          PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION | STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE
    }

    private enum VirtualAllocExTypes
    {
        WRITE_WATCH_FLAG_RESET = 0x00000001, // Win98 only
        MEM_COMMIT         = 0x00001000,
        MEM_RESERVE        = 0x00002000,
        MEM_COMMIT_OR_RESERVE  = 0x00003000,
        MEM_DECOMMIT       = 0x00004000,
        MEM_RELEASE        = 0x00008000,
        MEM_FREE           = 0x00010000,
        MEM_PUBLIC         = 0x00020000,
        MEM_MAPPED         = 0x00040000,
        MEM_RESET          = 0x00080000, // Win2K only
        MEM_TOP_DOWN       = 0x00100000,
        MEM_WRITE_WATCH    = 0x00200000, // Win98 only
        MEM_PHYSICAL       = 0x00400000, // Win2K only
        //MEM_4MB_PAGES    = 0x80000000, // ??
        SEC_IMAGE          = 0x01000000,
        MEM_IMAGE          = SEC_IMAGE
    }

    private enum AccessProtectionFlags
    {
        PAGE_NOACCESS      = 0x001,
        PAGE_READONLY      = 0x002,
        PAGE_READWRITE     = 0x004,
        PAGE_WRITECOPY     = 0x008,
        PAGE_EXECUTE       = 0x010,
        PAGE_EXECUTE_READ      = 0x020,
        PAGE_EXECUTE_READWRITE = 0x040,
        PAGE_EXECUTE_WRITECOPY = 0x080,
        PAGE_GUARD         = 0x100,
        PAGE_NOCACHE       = 0x200,
        PAGE_WRITECOMBINE      = 0x400
    }
    #endregion

    #region Private Methods
    private int GetPanelCount()
    {
        if (this._handle != IntPtr.Zero)
        return (int)SendMessage(this._handle, SB_GETPARTS, 0, 0);

        return 0;
    }
    private string[] GetCaptions()
    {
        int count = this.PanelCount;
        string[] captions = new string[count];

        for (uint i = 0; i < count; i++)
        captions[i] = this.GetCaption(i);

        return captions;
    }
    private string GetCaption(uint index)
    {
        uint length = (uint)SendMessage(this._handle, SB_GETTEXTLENGTH, index, 0);

        // Low part is the count. High part is the window type. Mask out the high bits.
        // The returned text will also be unicode so double the length to accomodate our buffer
        length = (length & 0x0000ffff) * 2;

        IntPtr hProcess = IntPtr.Zero;
        IntPtr allocated = IntPtr.Zero;

        try
        {
        hProcess = StatusBar.OpenProcess(ProcessAccessTypes.PROCESS_ALL_ACCESS, false, this.OwningPID);
        if (hProcess != IntPtr.Zero)
        {
            // Allocate memory in the remote process
            allocated = StatusBar.VirtualAllocEx(hProcess, IntPtr.Zero, length, (VirtualAllocExTypes.MEM_COMMIT_OR_RESERVE), AccessProtectionFlags.PAGE_READWRITE);

            if (allocated != IntPtr.Zero)
            {
            uint bytesRead = 0;
            byte[] buffer = new byte[length];

            // SB_GETTEXT tells the remote process to write out text to the remote memory we allocated.
            StatusBar.SendMessage(this._handle, SB_GETTEXT, (IntPtr)index, allocated);

            // Now we need to read that memory from the remote process into a local buffer.
            bool success = StatusBar.ReadProcessMemory(hProcess, allocated, buffer, length, out bytesRead);

            if (success)
            {
                // Each char takes 2 bytes.
                char[] characters = new char[length / 2];

                for (int i = 0; i < buffer.Length; i = i + 2)
                {
                // Even though the second byte will probably always be 0 for en-us let's so a bit shift
                // then "or" the first and second bytes together before casting to char.
                uint a = (uint)buffer[i];
                uint b = (uint)buffer[i + 1] << 8;

                characters[i / 2] = (char)(a | b);
                }

                return new string(characters);
            }
            }
        }
        }
        finally
        {
        if (hProcess != IntPtr.Zero)
        {
            if (allocated != IntPtr.Zero)
            {
            // Free the memory in the remote process
            StatusBar.VirtualFreeEx(hProcess, allocated, 0, VirtualAllocExTypes.MEM_RELEASE);
            }

            // Close the process handle
            StatusBar.CloseHandle(hProcess);
        }
        }

        return string.Empty;
    }
    private int GetOwningPid()
    {
        int pid = 0;

        if (this._handle != IntPtr.Zero)
        StatusBar.GetWindowThreadProcessId(this._handle, out pid);

        return pid;
    }
    #endregion

    #region Public Methods
    public void SetCaptions(int index, string caption)
    {
        if (index == -1)
        {
        string[] oldParts = this.Captions;
        string[] newParts = caption.Split(new string[] { " | " }, StringSplitOptions.None);

        if ((oldParts.Length == newParts.Length) && (newParts.Length > 0))
        {
            for (int i = 0; i < oldParts.Length; i++)
            {
            if (oldParts[i] != newParts[i])
                this.SetCaption(i, newParts[i]);
            }
        }
        }
        else
        {
        this.SetCaption(index, caption);
        }
    }
    private void SetCaption(int index, string caption)
    {
        throw new NotImplementedException("Sorry... You'll have to figure out SB_SETTEXT.");
    }
    #endregion

    #region Properties
    public string[] Captions
    {
        get
        {
        if (this._captions == null)
            this._captions = this.GetCaptions();

        return this._captions;
        }
    }
    public string Caption
    {
        get { return string.Join(" | ", this.Captions); }
        set { this.SetCaptions(-1, value); }
    }
    public int PanelCount
    {
        get
        {
        if (this._panelCount == -1)
            this._panelCount = this.GetPanelCount();

        return this._panelCount;
        }
    }
    public int OwningPID
    {
        get
        {
        if (this._pid == -1)
            this._pid = this.GetOwningPid();

        return this._pid;
        }
    }
    #endregion
    }
}

Documentation
SB_GETTEXT 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