簡體   English   中英

Kernel32 VirtualAllocEx間歇返回IntPtr.Zero

[英]Kernel32 VirtualAllocEx returning IntPtr.Zero Intermittently

我們正在嘗試從系統任務欄圖標中讀取工具提示,並且代碼正在工作,但對於以下調用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;
  }
}

好,如果我打電話來釋放內存,這樣問題就解決了。

    const uint MEM_RELEASE = 0x8000;

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

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM