使用WH_JOURNALRECORD和cancel似乎返回WM_CANCELJOURNAL

时间:2012-02-16 18:41:12

标签: c# windows winapi setwindowshookex

我正在使用C#,我已经使用SetWindowsHookEx WH_JOURNALRECORD成功记录了日记邮件。

我的问题出现了,是时候停下来了。文档显示,如果用户按下CTRL-ESC或CTRL-ALT-DELETE,将发布WM_CANCELJOURNAL消息,我可以查看该消息何时停止。我的应用程序取消了,但我似乎永远不会得到WM_CANCELJOURNAL

我有两个挂钩设置。一个钩子用于记录日志记录,另一个用于检查取消消息:

IntPtr hinstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]);

JournalRecordProcedure = JournalRecordProc;
journalHook = SetWindowsHookEx(WH_JOURNALRECORD, JournalRecordProcedure, hinstance, 0);

GetMessageProcedure = GetMessageProc;
messageHook = SetWindowsHookEx(WH_GETMESSAGE, GetMessageProcedure, hinstance, 0); 


------

public static int JournalRecordProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode < 0) return CallNextHookEx(journalHook, nCode, wParam, lParam);

    EventMsgStruct msg = (EventMsgStruct) Marshal.PtrToStructure(lParam, typeof (EventMsgStruct));

    script.Add(msg); //just a quick way to record for now

    return CallNextHookEx(journalHook, nCode, wParam, lParam);
}

public static int GetMessageProc(int code, IntPtr wParam, IntPtr lParam)
{

    //it comes here but how do I test if it's WM_CANCELJOURNAL ??
    //code always seems to be equal to zero.. I must be missing something


    return CallNextHookEx(journalHook, code, wParam, lParam);
}

1 个答案:

答案 0 :(得分:1)

我想你在documentation

中引用了这一部分
  

此角色作为停止日志记录的信号意味着无法记录CTRL + BREAK组合键。由于CTRL + C组合键不具有日记信号的作用,因此可以记录它。还有另外两个无法记录的组合键:CTRL + ESC和CTRL + ALT + DEL。这两个组合键会导致系统停止所有日记活动(记录或回放),删除所有日记记录挂钩,并将WM_CANCELJOURNAL消息发布到日记应用程序。

问题是WM_CANCELJOURNAL message 已发送到您使用SetWindowsHookEx安装的回调函数。但与其他WM_*消息不同,它也不是由窗口过程(WinForms中的WndProc)处理,因为它被发布到线程的消息队列中,与任何特定窗口无关。

相反,文档建议必须在应用程序的主循环中或使用WH_GETMESSAGE hook处理它:

  

此消息不返回值。它应该从应用程序的主循环或GetMessage钩子过程中处理,而不是从窗口过程中处理。

     

[。 。 。 ]

     

WM_CANCELJOURNAL消息具有NULL窗口句柄,因此无法将其分派给窗口过程。应用程序有两种方法可以查看WM_CANCELJOURNAL消息:如果应用程序在其自己的主循环中运行,则必须在其对GetMessagePeekMessage的调用与其之间捕获消息致电DispatchMessage。如果应用程序未在其自己的主循环中运行,则必须设置GetMsgProc挂钩过程(通过调用SetWindowsHookEx指定WH_GETMESSAGE挂钩类型)来监视消息。 / p>

在托管的WinForms代码中,您显然无法访问或控制应用程序的主循环。我不确定您的应用程序adding a message filter是否会让您处理此消息:我没有尝试过。如果它会,那可能是你想要的路线,考虑替代方案,即安装第二个钩子WH_GETMESSAGE,然后在该钩子程序中,听取{{ 1}}消息。


<强>更新

GetMessageProc callback function中,WM_CANCELJOURNAL参数只是告诉您钩子过程是否应该处理消息。几乎所有的时间,它都是0,相当于符号常量code。如果HC_ACTION参数小于0,则挂钩过程应该只调用code函数而不执行任何进一步处理。这与CallNextHookEx回调函数基本完全相同。

窗口消息将在MSG structure中找到,指针将作为JournalRecordProc参数传递给回调函数。但那是Win32的东西。不要乱用.NET中的原始指针,让P / Invoke编组程序为您处理所有这些脏东西。原生lParam结构等同于托管System.Windows.Forms.Message structure(与MSG方法使用的相同),因此如果您声明这样的WndProc回调函数,事情将会更简单:

GetMessageProc

然后,Windows消息被发现为public delegate int GetMessageProc(int code, IntPtr wParam, ref Message lParam); 结构的Msg member。这是您要与Message进行比较的值:

WM_CANCELJOURNAL

请注意,要使public static int GetMessageProc(int code, IntPtr wParam, ref Message lParam) { if (code >= 0) { if (lParam.Msg == WM_CANCELJOURNAL) { // do something } } return CallNextHookEx(messageHook, code, wParam, ref lParam); } 的上述调用有效,您还必须提供与CallNextHookEx回调的签名匹配的CallNextHookEx函数的重载定义功能:

GetMessageProc