【问题标题】:C# Win32 Interop Crashes when Enumerating Window Handles枚举窗口句柄时 C# Win32 互操作崩溃
【发布时间】:2014-06-23 17:39:54
【问题描述】:

我有一些涉及窗口句柄的 Win32 操作的 C# 包装器,但是当我调用 Win32 函数时,我遇到了意外崩溃,没有详细信息。

有趣的是,整个代码示例在构造类时(在应用程序初始化时)运行良好,但随后在调用相同的 buildCache() 方法时会失败。

以下是相关代码:

public delegate bool CallBack(int hWnd, int lParam);

public class Win32Interop {
    private Dictionary<int, string> windowCache = new Dictionary<int, string>();

    public Win32Interop() {
        buildCache();
    }

    public void buildCache() {
        windowCache.Clear();

        CallBack hWndCacher = new CallBack(saveHWndHandler);
        EnumWindows(hWndCacher, 0);
    }

    public void doThings(string title, uint message, bool rebuildCache = false) {
    //Use the window title to get its handle
        int hWnd = titleToHWnd(title, rebuildCache);
        SendMessage(hWnd, message, 0, 0);
    }

    private bool saveHWndHandler(int hWnd, int lParam) {
        if(IsWindow(hWnd) != 0) {       / ***** CRASHES HERE ***** /
            int length = GetWindowTextLength(hWnd);
            StringBuilder title = new StringBuilder(length + 1);

            GetWindowText(hWnd, title, title.Capacity);
            string formatted = title.ToString().Trim();

            windowCache.Add(hWnd, formatted);
        }

        return true;
    }

    private int titleToHWnd(string title, bool rebuildCache = false) {
        if(rebuildCache)
            buildCache();

        if(windowCache.ContainsValue(title)) {
            return windowCache.FirstOrDefault(x => x.Value.Contains(title)).Key;
        } else {
            throw new KeyNotFoundException(string.Format("\"{0}\" is not a window title which is available in the cache.", title));
        }
    }

    #region Win32 API Functions
    [DllImport("user32.dll")]
    private static extern int EnumWindows(CallBack lpEnumFunc, int lParam);

    [DllImport("user32.dll")]
    private static extern int GetWindowText(int hWnd, StringBuilder lpString, int maxCount);

    [DllImport("user32.dll")]
    private static extern int GetWindowTextLength(int hWnd);

    [DllImport("user32.dll")]
    private static extern int IsWindow(int hWnd);

    [DllImport("user32.lib")]
    private static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
    #endregion
}

saveHWndHandler() 方法中,我已经标记了调试器显示执行停止的行。有趣的是,EnumWindows() 通常会返回大约 300 个窗口句柄,并且它总是在迭代次数 45 或 46 时崩溃。它崩溃的窗口句柄是一个合理的值,例如 12345。

根据MSDNIsWindow() 应该返回0,如果窗口没有与句柄相关联,则不会使线程崩溃。

有人知道为什么会这样吗? Windows 事件日志中没有引发异常或任何详细信息。

谢谢。

对于那些不想弄清楚 buildCache() 过程是否有效的人: (1.) 当buildCache() 被调用时,&lt;HWnd, Title&gt; 值的字典被清除。 (2.) 调用Win32函数EnumWindows(),它为每个窗口句柄调用saveHWndHandler()方法。 (3.)saveHWndHandler() 将检查当前窗口句柄是否仍然存在,调用另一个 Win32 函数从句柄中获取窗口标题。 (4.) 标题和窗口句柄被添加到字典中。

【问题讨论】:

  • @ScottChamberlain 也许,但处理程序在第 45-46 次迭代的第一次 Win32 API 调用时停止执行。这似乎太一致了,不可能是 GC 的行为。
  • @AdamMaras 你在哪里对,我删除了我不正确的 cmets。
  • @ScottChamberlain 别担心,朋友。
  • 你的进程是32位还是64位?

标签: c# .net winapi interop pinvoke


【解决方案1】:

我无法重现您的问题,但一个可能的问题是您的所有 P/Invoke 签名都是错误的。 HWNDLPARAMWPARAM数据类型至少需要映射到P/Invoke代码中的IntPtr

private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString,
    int nMaxCount);

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowTextLength(IntPtr hWnd);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindow(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam,
    IntPtr lParam);

您需要更改相应的实例方法签名和用法以匹配这些正确的签名。

【讨论】:

  • 现在正在研究...返回类型呢?在您的代码中,您有 intIntPtr 返回类型。
  • @spryno724 GetWindowTextGetWindowTextLength 返回 实际整数值(字符串长度),而 SendMessage 返回一个 LRESULT,它可以是任何值(整数值,一个指针,一个错误代码)。如有疑问,请查看 MSDN 文档以了解 Win32 函数返回的内容。
猜你喜欢
  • 2010-09-05
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-13
相关资源
最近更新 更多