Kernel32 VirtualAllocEx间歇性地返回IntPtr.Zero

时间:2014-09-06 09:13:36

标签: c# interop tooltip intptr

我们正在尝试从系统托盘图标中读取工具提示并且代码正在运行但是间歇性地为下面的方法返回零,调用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;

似乎工作得很好然后突然停止工作并一直返回IntPtr.Zero。检查Marshal.GetLastWin32Error()时,它返回8(内存不足)。以下是完整代码:

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;
  }
}

1 个答案:

答案 0 :(得分:0)

好的,如果我打电话释放内存,问题就解决了。

    const uint MEM_RELEASE = 0x8000;

    UIntPtr uintPtr = UIntPtr.Zero;
    var successfullyReleased = Kernel32.VirtualFreeEx(hProcess, ipRemoteBuffer, uintPtr, MEM_RELEASE);
    if (!successfullyReleased)
    {

    }