2017-05-03 22 views
0

我試圖從層次結構中的每個控件獲取文本。如果我使用unsafe方法,下面的代碼運行正常。但是,使用非託管版本似乎打破hWnd,結果hWnd = GetAncestor(hWnd, GetAncestorFlags.GA_PARENT)抱怨:C#中這個非託管代碼有什麼問題?

System.AccessViolationException:'試圖讀取或寫入受保護的內存。這往往表明其他內存已經損壞。「

我已經檢查hWndGetWindowTextRaw函數返回後沒有改變,如果我在這個功能不會造成問題註釋掉第二SendMessage(雖然它顯然不會得到窗口文本)。

(PS:我在使用的NuGet PInvoke.User32)

// using static PInvoke.User32; 

public static string GetWindowTextRaw(IntPtr hWnd) { 
    // Allocate correct string length first 
    int length = (int)SendMessage(hWnd, WindowMessage.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero); 
    char[] buff = new char[length + 1]; 
    IntPtr iptr = Marshal.AllocHGlobal(buff.Length); 
    SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)(length + 1), iptr); 
    Marshal.Copy(iptr, buff, 0, length + 1); 
    Marshal.FreeHGlobal(iptr); 
    //unsafe 
    //{ 
    // fixed (char* p = buff) 
    //  SendMessage(hWnd, WindowMessage.WM_GETTEXT, (IntPtr)(length + 1), (IntPtr)p); 
    //} 
    return new string(buff).TrimEnd('\0'); 
} 

private void button1_Click(object sender, EventArgs { 
    POINT p; 
    IntPtr hWnd; 
    //while (true) 
    if (GetCursorPos(out p)) { 
     hWnd = WindowFromPoint(p); ; 
     Debug.Print($"{p.x} {p.y} 0x{(int)hWnd:x8}"); 
     while (hWnd != IntPtr.Zero) { 
      Debug.Print($"{GetWindowTextRaw(hWnd)}"); 
      hWnd = GetAncestor(hWnd, GetAncestorFlags.GA_PARENT); 
     } 
     Thread.Sleep(500); 
    } 
} 
+0

您可能會考慮將C++/CLI用於interop代碼。 –

+0

[試圖讀取或寫入受保護的內存。這通常表明其他內存已損壞](http://stackoverflow.com/questions/4074585/attempted-to-read-or-write-protected-memory-this-is-often-an-indication-that- ot) – ThePerplexedOne

+0

@多如何?任何參考?謝謝! –

回答

3
IntPtr iptr = Marshal.AllocHGlobal(buff.Length); 

尺寸錯誤,你需要buff.Length * sizeof(char)。它現在分配的數量是它的兩倍。正如所寫,代碼破壞了操作系統使用的同一堆,接下來可能會發生任何事情。 AVE是一個正常和快樂的結果,但不能保證。

+0

謝謝!這完全解決了這個問題!我專注於'hWnd'本身的價值,但從未想過它可能會溢出!更糟糕的是,我在編組方面的經驗很少,而其他許多文章都是'AllocHGlobal' - 字節,不需要乘數,所以我沒有想過大小。非常感謝您的大力幫助! –