【发布时间】: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。
根据MSDN,IsWindow() 应该返回0,如果窗口没有与句柄相关联,则不会使线程崩溃。
有人知道为什么会这样吗? Windows 事件日志中没有引发异常或任何详细信息。
谢谢。
对于那些不想弄清楚 buildCache() 过程是否有效的人: (1.) 当
buildCache()被调用时,<HWnd, Title>值的字典被清除。 (2.) 调用Win32函数EnumWindows(),它为每个窗口句柄调用saveHWndHandler()方法。 (3.)saveHWndHandler()将检查当前窗口句柄是否仍然存在,调用另一个 Win32 函数从句柄中获取窗口标题。 (4.) 标题和窗口句柄被添加到字典中。
【问题讨论】:
-
@ScottChamberlain 也许,但处理程序在第 45-46 次迭代的第一次 Win32 API 调用时停止执行。这似乎太一致了,不可能是 GC 的行为。
-
@AdamMaras 你在哪里对,我删除了我不正确的 cmets。
-
@ScottChamberlain 别担心,朋友。
-
你的进程是32位还是64位?
标签: c# .net winapi interop pinvoke