SB_GETTEXT (user32)
Last changed: -12.190.158.6

.
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!

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;

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

    #region Constructor
    public StatusBar(IntPtr hWnd)
    {
        this._handle = hWnd;
        this._panelCount = -1;
        this._pid = -1;
    }
    #endregion

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

    [DllImport("kernel32.dll")]
    private static extern int CloseHandle(
        IntPtr hObject
        );

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

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

    [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 int GetWindowThreadProcessId(
        IntPtr hWnd,
        out Int32 lpdwProcessId
        );

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

    [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