We are trying to read the ToolTips from system tray icons and the code is working but is returning zero intermittently for the the method below calling Kernel32.VirtualAllocEx
IntPtr ipRemoteBuffer = Kernel32.VirtualAllocEx(
hProcess,
IntPtr.Zero,
new UIntPtr(BUFFER_SIZE),
MemAllocationType.COMMIT,
MemoryProtection.PAGE_READWRITE);
if (ipRemoteBuffer == IntPtr.Zero)
return String.Empty;
It seems to work absolutely fine then suddenly stops working and returns IntPtr.Zero consistently. When checking Marshal.GetLastWin32Error() it returns 8 (not enough memory). Below is the full code:
public static string GetTooltip(string search)
{
IntPtr _ToolbarWindowHandle = GetSystemTrayHandle();
UInt32 count = User32.SendMessage(_ToolbarWindowHandle, TB.BUTTONCOUNT, 0, 0);
List<string> tooltips = new List<string>();
for (int i = 0; i < count; i++)
{
TBBUTTON tbButton = new TBBUTTON();
string text = String.Empty;
IntPtr ipWindowHandle = IntPtr.Zero;
text = GetTBButtonText(_ToolbarWindowHandle, i, ref tbButton, ref text, ref ipWindowHandle);
if (!String.IsNullOrWhiteSpace(text) && text.ToLowerInvariant().Contains(search.ToLowerInvariant()))
return text;
}
return String.Empty;
}
static unsafe string GetTBButtonText(IntPtr hToolbar, int i, ref TBBUTTON tbButton, ref string text, ref IntPtr ipWindowHandle)
{
const int BUFFER_SIZE = 0x1000;
byte[] localBuffer = new byte[BUFFER_SIZE];
UInt32 processId = 0;
UInt32 threadId = User32.GetWindowThreadProcessId(hToolbar, out processId);
IntPtr hProcess = Kernel32.OpenProcess(ProcessRights.ALL_ACCESS, false, processId);
if (hProcess == IntPtr.Zero)
return String.Empty;
IntPtr ipRemoteBuffer = Kernel32.VirtualAllocEx(
hProcess,
IntPtr.Zero,
new UIntPtr(BUFFER_SIZE),
MemAllocationType.COMMIT,
MemoryProtection.PAGE_READWRITE);
if (ipRemoteBuffer == IntPtr.Zero)
{
var error = Marshal.GetLastWin32Error();
return String.Empty;
}
// TBButton
fixed (TBBUTTON* pTBButton = &tbButton)
{
IntPtr ipTBButton = new IntPtr(pTBButton);
int b = (int)User32.SendMessage(hToolbar, TB.GETBUTTON, (IntPtr)i, ipRemoteBuffer);
if (b == 0)
return String.Empty;
// this is fixed
Int32 dwBytesRead = 0;
IntPtr ipBytesRead = new IntPtr(&dwBytesRead);
bool b2 = Kernel32.ReadProcessMemory(
hProcess,
ipRemoteBuffer,
ipTBButton,
new UIntPtr((uint)sizeof(TBBUTTON)),
ipBytesRead);
if (!b2)
return String.Empty;
}
// button text
fixed (byte* pLocalBuffer = localBuffer)
{
IntPtr ipLocalBuffer = new IntPtr(pLocalBuffer);
int chars = (int)User32.SendMessage(hToolbar, TB.GETBUTTONTEXTW, (IntPtr)tbButton.idCommand, ipRemoteBuffer);
if (chars == -1) { Debug.Assert(false); return ""; }
// this is fixed
Int32 dwBytesRead = 0;
IntPtr ipBytesRead = new IntPtr(&dwBytesRead);
bool b4 = Kernel32.ReadProcessMemory(
hProcess,
ipRemoteBuffer,
ipLocalBuffer,
new UIntPtr(BUFFER_SIZE),
ipBytesRead);
if (!b4)
return String.Empty;
text = Marshal.PtrToStringUni(ipLocalBuffer, chars);
return text;
}
}
OK if I make a call to release the memory like so the problem is solved.
const uint MEM_RELEASE = 0x8000;
UIntPtr uintPtr = UIntPtr.Zero;
var successfullyReleased = Kernel32.VirtualFreeEx(hProcess, ipRemoteBuffer, uintPtr, MEM_RELEASE);
if (!successfullyReleased)
{
}