我们必须通过安装一些全局键盘钩子SetWindowsHookEx
与WH_KEYBOARD_LL
看似随机获得由Windows脱钩.
我们验证了它们不再附加钩子,因为调用UnhookWindowsHookEx
句柄返回false
.(还验证了它true
在正常工作时返回)
似乎没有一致的repro,我听说他们可以因为超时或异常被抛出而脱钩,但我已经尝试了两个只是让它在处理方法中断点超过一分钟,以及抛出一个随机异常(C#),它似乎仍然有效.
在我们的回调中,我们快速发布到另一个线程,这可能不是问题.我已经阅读了Windows 7中的解决方案,用于在注册表中设置更高的超时,因为Windows 7显然更加积极地执行超时(我们都在这里运行Win7,所以不确定这是否发生在其他操作系统上),但这并不是看起来似乎是一个理想的解决方案.
我考虑过只运行一个后台线程来每隔一段时间刷新一次钩子,这很黑,但我不知道这样做有什么真正的负面后果,而且它似乎比改变全局Windows注册表设置更好.
还有其他建议或解决方案? 设置挂钩的类和它们所附加的委托都是静态的,因此它们不应该是GC.
编辑:通过调用验证GC.Collect();
他们仍然有效,因此他们没有被收集的垃圾.
我正在尝试在项目中使用Gma.UserActivityMonitor库,我遇到了一个我自己无法克服的错误.
在HookManager.Callbacks.cs
文件中有一个静态方法EnsureSubscribedToGlobalMouseEvents
,使用以下代码调用(或多或少):
var asm = Assembly.GetExecutingAssembly().GetModules()[0];
var mar = Marshal.GetHINSTANCE(asm);
s_MouseHookHandle = SetWindowsHookEx(
WH_MOUSE_LL,
s_MouseDelegate,
mar,
0);
//If SetWindowsHookEx fails.
if (s_MouseHookHandle == 0)
{
//Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
//Initializes and throws a new instance of the Win32Exception class with the specified error.
throw new Win32Exception(errorCode);
}
Run Code Online (Sandbox Code Playgroud)
将SetWindowsHookEx
始终返回0
和上面的代码中不断抛出与消息的异常 …
我在这个页面上发现了类似的问题,但我似乎无法弄清楚如何解释答案或弄清楚它们是否真的重复.
以下是我发现的可能重复项,并附有评论:
在32位计算机上编译.NET 4.0框架时,SetWindowsHookEx返回0
它似乎没有返回0我的,但我注意到崩溃时报告的句柄(32位上的.NET 4.0)与运行时报告的句柄不同(32位上的.NET 3.5),像崩溃句柄= 523727,工作句柄= 172738378.
在VS2008调试器中调用SetWindowsHookEx始终返回NULL
我可以在Visual Studio外部运行时重现我的问题
这似乎是最有希望的,除了对删除的答案的评论提到我应该使用LoadLibrary和GetProcAddress来加载.NET 4.0中的user32.dll,因为有关加载程序集的更改.但是,我很确定它是我自己无法找到的模块,但我不知道这是否适用.
Hans Passant对最后一个删除答案的评论如下:
你在使用.NET 4.0吗?它的CLR改变了程序集的加载方式,不再有LoadLibrary调用,也没有模块句柄.使用GetEntryAssembly()代替另一种修复. - 汉斯帕斯特5月5日19:43
那么,这里的字是什么?你在使用.NET 4.0吗?您是否尝试使用LoadLibrary("user32.dll")来获取可用的DLL句柄? - Hans Passant 5月6日15:43
我很确定我不需要这样做,但显然我不是百分百肯定.如果我需要更改它,我留下的问题是,为什么它适用于64位操作系统,在编译时Any CPU
,但在任何配置中都不适用于32位.
如果加载.NET程序集确实发生了一些变化,那么我没有得到类库的正确句柄,我有以下问题:
背景
我在.NET 4.0中构建了一个程序,它使用带有WH_KEYBOARD_LL钩子类型的SetWindowsHookEx来捕获按键.这在我的64位Windows 7上运行良好,但在32位Windows 7上安装键盘挂钩时崩溃时出现"找不到模块".
这是我尝试过的:
我宁愿不将我的代码切换到.NET 3.5,因为我使用了一些类库来简化工作,而最新的代码只在.NET 4.0中.
如果需要,可以下载包含Visual Studio 2010项目的.ZIP文件,也可以粘贴以下两个文件.
要重新创建是否要沿着该路线前进:
然后构建并运行,测试各种配置.
using System;
using HookLib;
namespace HookTest
{
class Program
{
static void Main() …
Run Code Online (Sandbox Code Playgroud) 我已经成功地安装一个WH_GETMESSAGE
带有钩SetWindowsHookEx
,我可以看到的WM_POINTERDOWN
,WM_POINTERUP
等应用程序接收消息.(它是在Windows 8.1上运行的32位桌面应用程序.)
现在,我不仅希望看到这些消息,而且还想删除其中一些消息.
GetMsgProc的文档说:
GetMsgProc挂钩过程可以检查或修改消息.在钩子过程将控制权返回给系统之后,GetMessage或PeekMessage函数将消息以及任何修改返回给最初调用它的应用程序.
有了WM_KEYUP
消息,这似乎工作正常.我可以将消息设置为WM_NULL
挂钩,并且键事件将消失.
WM_POINTER...
但是,对于消息,这似乎不起作用.应用程序仍然接收消息(在调试器中验证).
也许有其他方法来过滤/删除此类消息?
编辑:它必须使用未修改的第三方应用程序(因此使用钩子).
更新:我设法通过积极调用PeekMessage
钩子来阻止点击事件(从长远来看可能不是一个好主意).但是,我仍然无法阻止通过触摸滚动.
我正试图挂钩第三方应用程序,以便我可以绘制到它的屏幕.在屏幕上绘图是容易的,我需要它没有帮助,但我似乎有使用问题SetWindowsHookEx
来处理WH_GETMESSAGE
.我无法弄清楚最后两个参数传递的内容.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowDrawer
{
public partial class Form1 : Form
{
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
static IntPtr hHook;
IntPtr windowHandle;
uint processHandle;
HookProc PaintHookProcedure;
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint …
Run Code Online (Sandbox Code Playgroud) 在几句话:堵Win起来后Win+ Tab使Windows认为Win仍下降,所以然后按S与Win键向上例如会打开搜索的魅力,而不是在用户按下只需键入"S" ...... Win一次.不阻止它意味着Windows开始菜单将显示.我陷入了一个难题!
我可以使用Alt+ Tabusing LowLevelKeyboardHook
或Win+ Some Ubounded Keyusing 挂钩快捷方式RegisterHotKey
.只有使用Win密钥才会出现问题LowLevelKeyboardHook
.
在下面的示例中,我在检测到+ 组合Win时接管up事件.这导致使每个后续击键行为都像键仍然关闭一样.WinTabWin
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode != HC_ACTION)
return CallNextHookEx(_hookID, nCode, wParam, lParam);
var keyInfo = (Kbdllhookstruct)Marshal.PtrToStructure(lParam, typeof(Kbdllhookstruct));
if (keyInfo.VkCode == VK_LWIN)
{
if (wParam == (IntPtr)WM_KEYDOWN) {
_isWinDown …
Run Code Online (Sandbox Code Playgroud) c# windows keyboard-shortcuts keyboard-hook setwindowshookex
在Delphi XE应用程序中,我正在尝试设置一个全局挂钩来监视焦点更改.钩子是在一个DLL中创建的:
focusHook := SetWindowsHookEx( WH_CBT, @FocusHookProc, HInstance, 0 );
// dwThreadId (the last argument) set to 0 should create a global hook
Run Code Online (Sandbox Code Playgroud)
在同一个DLL中,我有一个将消息发布到主机应用程序窗口的钩子过程:
function FocusHookProc( code : integer; wParam: WPARAM; lParam: LPARAM ) : LResult; stdcall;
begin
if ( code < 0 ) then
begin
result := CallNextHookEx( focusHook, code, wParam, lParam );
exit;
end;
result := 0;
if ( code = HCBT_SETFOCUS ) then
begin
if ( hostHWND <> INVALID_HANDLE_VALUE ) then
PostMessage( hostHWND, cFOCUSMSGID, wParam, lParam ); …
Run Code Online (Sandbox Code Playgroud) 我正在准备一个Delphi模块,它在一个线程中设置一个钩子来记录一个宏:
FHandleRec := SetWindowsHookEx(WH_JOURNALRECORD, FRecordProc, HInstance, 0);
FHandlePlay := SetWindowsHookEx(WH_JOURNALPLAYBACK, FPlayProc, HInstance, 0);
Run Code Online (Sandbox Code Playgroud)
这在WinXP上工作正常,但在Vista/Windows 7上失败了ERROR_ACCESS_DENIED
.我在谷歌(这个)中找到了(那个).报价单:
较低权限进程不能:...使用Journal钩子来监视更高权限的进程.
尝试没有成功:
代码示例:
if LogonUser(PWideChar(sAdminUser), PWideChar(sDomain), PWideChar(sPwd),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken) then
begin
if not ImpersonateLoggedOnUser(hToken) then
raise Exception.Create('Error impersonating the user');
end;
FHandleRec := SetWindowsHookEx(WH_JOURNALRECORD, FRecordProc, HInstance, 0);
Run Code Online (Sandbox Code Playgroud)
LogonUser
并ImpersonateLoggedOnUser
执行没有错误.
尝试的其他可能性:
您能否在Visa/Windows 7下显示设置挂钩的代码或建议工作解决方案?
这个问题可能已经得到解答,但我一直无法找到正确的答案.我正试图在表单中按下F12键时切换调试开关.我无法使用onkeydown事件,因为我必须为每个字段设置一个单独的函数以及表单.所以我研究并发现了SetWindowsHookEx函数来设置键盘钩子.这个工作得很好,除了我得到两个指示F12键每次按下时都按下:
2014/05/21 14:16:43.334
Code: 0
Key: 123
KeyStroke: 5767169
KeyStroke to Hex: 00580001
2014/05/21 14:16:43.446
Code: 0
Key: 123
KeyStroke: -1067974655
KeyStroke to Hex: C0580001 Note: this should be the keystroke that reflects KEYDOWN
Run Code Online (Sandbox Code Playgroud)
我看到Keystroke是检查keydown的可能方法(WM_KEYDOWN $ 0100).我的问题是如何为WM_KEYDOWN测试击键?
这是我的回调函数:
function KeyboardHookProc(Code: Integer; Key: Word; KeyStroke: LongInt) : LongInt;
begin
Result := 0;
if Code = HC_NOREMOVE then exit;
Result := CallNextHookEx(FkbHook, Code,Key,KeyStroke);
if Code < 0 then exit;
{
WM_KEYDOWN
}
if (KeyStroke and WM_KEYDOWN) = 0 then { this is …
Run Code Online (Sandbox Code Playgroud) 我使用 SetWindowsHookEx 和 WH_CALLWNDPROC 来捕获所有 WndProc 消息 - 它工作正常。我想知道是否有一种方法可以将参数存储在回调函数可以读取和使用的地方。
我假设因为回调函数位于“其他”进程内部,所以与调用 SetWindowsHookEx 的进程没有连接,因此仅将值存储在静态变量中不会有任何好处。
例如:
void Hook(DWORD dwThread, int randomNumber)
{
MagicallyStore(randomNumber);
SetWindowsHookEx(WH_CALLWNDPROC, hookProc, GetModuleHandle(L"WNDProcHooks"), dwThread);
...
...
}
LRESULT CALLBACK hookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
int randomNumber = MagicallyRestore();
DoSomthing(randomNumber);
return CallNextHookEx(0, nCode, wParam, lParam);
}
Run Code Online (Sandbox Code Playgroud)
我已经考虑过让“MagicallyStore”函数将参数写入文件并在“MagicallyRestore”函数中读取一次 - 但必须有更好的方法..
提前致谢 :)