【发布时间】:2015-01-13 16:15:48
【问题描述】:
我用 C# 编写了一个启用多个全局热键的程序,并根据按下的热键激活 chrome、firefox、记事本、计算器等窗口。注册全局热键后,我有一个无限的时间-使应用程序保持活动状态的循环。运行程序后,热键突然停止工作。这有时会在几个小时后发生。经过长时间测试我的每一段代码后,我发现了问题。问题是主线程突然停止工作。该程序仍然存在并在内存中。热键似乎是在另一个活动的线程中注册的,即使包含 while 循环的主线程死了,它也能保持程序运行。
然后我使用了一个后台工作程序并在后台工作程序中移动了 while 循环。它再次发生,这意味着后台工作人员在热键仍在注册时突然停止。这不是我第一次使用 backgroudworker,而且我从未遇到过这样的事情,即 backgroundworker 会自行退出。
发生这种情况时,类似这样的消息会出现在 Visual Studio 的输出窗口中:
The thread 0x1b24 has exited with code 0 (0x0)
线程是否有任何时间限制,以便它们在此之后退出? 您对这是如何发生的以及如何解决它有什么建议吗?
对于全局热键,我使用此处列出的代码:
http://stackoverflow.com/a/3654821/3179989
这是我剩下的代码:
public static void HotKeyPressed(object sender, HotKeyEventArgs e)
{
string PressedHotkey = e.Modifiers.ToString() + " " + e.Key.ToString();
switch (PressedHotkey)
{
case "Alt D1":
mActivateWindow(mEnumApplications.Chrome);
break;
case "Alt D3":
mActivateWindow(mEnumApplications.CintaNotes);
break;
default:
break;
}
}
private void button1_Click(object sender, EventArgs e)
{
bgWkrHotkey.WorkerSupportsCancellation = true;
bgWkrHotkey.WorkerReportsProgress = true;
bgWkrHotkey.RunWorkerAsync();
}
private void bgWkrHotkey_DoWork(object sender, DoWorkEventArgs e)
{
mHotKeyManager.RegisterHotKey(Keys.Oemtilde, KeyModifiers.Alt);
mHotKeyManager.RegisterHotKey(Keys.D1, KeyModifiers.Alt);
mHotKeyManager.RegisterHotKey(Keys.D3, KeyModifiers.Alt);
mHotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyPressed);
while (true)
{
Thread.Sleep(50);
}
}
//@@@@@@@@@@@@@@@@@@@@ DLL IMPORTS @@@@@@@@@@@@@@@@@@@@
#region DLL IMPORTS
[DllImport("User32.dll")]
private static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);
[DllImport("USER32.DLL")]
static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
[DllImport("USER32.DLL")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("USER32.DLL")]
static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("USER32.DLL")]
static extern IntPtr GetShellWindow();
#endregion DLL IMPORTS
public static IDictionary<IntPtr, string> mGetOpenWindows()
{
IntPtr ipShellWindow = GetShellWindow();
Dictionary<IntPtr, string> ipWindows = new Dictionary<IntPtr, string>();
EnumWindows(delegate(IntPtr hWnd, int lParam)
{
if (hWnd == ipShellWindow) return true;
//if (!IsWindowVisible(hWnd)) return true;
int lLength = GetWindowTextLength(hWnd);
if (lLength == 0) return true;
StringBuilder lBuilder = new StringBuilder(lLength);
GetWindowText(hWnd, lBuilder, lLength + 1);
ipWindows[hWnd] = lBuilder.ToString();
return true;
}, 0);
return ipWindows;
}
public static string mGetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return "";
}
public static bool mActivateWindow(IntPtr ipHandle, string strWindowTitle)
{
StringBuilder Buff = new StringBuilder(256);
SetForegroundWindow(ipHandle);
Stopwatch swTimeout = new Stopwatch();
swTimeout.Start();
while (swTimeout.Elapsed < TimeSpan.FromSeconds(2))
{
ipHandle = GetForegroundWindow();
if ((GetWindowText(ipHandle, Buff, 256) > 0) && (Buff.ToString().ToLower().Contains(strWindowTitle.ToLower())))
return true;
else
{
SetForegroundWindow(ipHandle);
Thread.Sleep(50);
}
}
swTimeout.Stop();
return false;
}
public static bool mActivateWindow(mEnumApplications enumApp)
{
string strWindowTitle = "";
switch (enumApp)
{
case mEnumApplications.Chrome:
strWindowTitle = "Google Chrome";
break;
case mEnumApplications.CintaNotes:
strWindowTitle = "CintaNotes";
break;
default:
break;
}
IntPtr ipHandle = IntPtr.Zero;
string strExactTitle = "";
StringBuilder Buff = new StringBuilder(256);
foreach (KeyValuePair<IntPtr, string> ipWindow in mGetOpenWindows())
{
ipHandle = ipWindow.Key;
strExactTitle = ipWindow.Value;
if (strExactTitle.ToLower().Contains(strWindowTitle.ToLower()))
if (mActivateWindow(ipHandle, strWindowTitle))
return true;
}
return false;
}
public enum mEnumApplications
{
Null,
Chrome,
CintaNotes,
};
感谢您的帮助。 谢谢
【问题讨论】:
-
您的主线程发生了无法解释的崩溃,因此您将热键移至
BackgroundWorker?似乎您应该诊断出主线程崩溃。转到BackgroundWorker只是使问题翻了一番(至少)。也就是说,我怀疑您的热键按下处理程序中的某些东西正在引发异常。在它周围放置一个 try/catch 并记录你得到的任何异常。 -
此外,我会仔细查看您的
EnumWindows回调。为您的StringBuilder分配内存是可疑的,特别是因为您将其分配给lLength,但随后将lLength+1传递给GetWindowText。这很可能会尝试覆盖您不拥有的内存,并导致线程崩溃。GetWindowTextLength没有具体说明返回值是否包含空终止符。很可能将返回值加 1 并使用结果初始化您的StringBuilder将解决问题。 -
感谢您的 cmets。那部分代码实际上不是我自己的代码,我只是从互联网上复制的 (blog.tcx.be/2006/05/getting-list-of-all-open-windows.html)。对不起,我应该在我的主要帖子中引用这一点。您能否更改代码并将其作为答案发送,因为我不确定您的意思?谢谢
-
在
EnumWindows调用中,将此new StringBuilder(lLength);更改为new StringBuilder(lLength+1); -
我改变了它。现在它正在运行。一旦我确定问题是否解决,我会回复。谢谢。
标签: c# multithreading hotkeys