Type a page name and press Enter. You'll jump to the page if it exists, or you can create it if it doesn't.
To create a page in a module other than user32, prefix the name with the module name and a period.
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
// 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;
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
}
}
An IntPtr is a pointer to a memory location (unmanaged) that adapts to the platform it is running on (64-bit, etc.) UNLIKE a standard int/Integer. You should always use this type for unmanaged calls that require it, even though an int will appear to work on your development machine.
1/13/2008 4:00:13 AM - Damon Carr-72.43.165.29
An IntPtr is a pointer to a memory location (unmanaged) that adapts to the platform it is running on (64-bit, etc.) UNLIKE a standard int/Integer. You should always use this type for unmanaged calls that require it, even though an int will appear to work on your development machine.
1/13/2008 4:00:13 AM - Damon Carr-72.43.165.29
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).