简体   繁体   English

当 UWP 桌面应用程序失焦时,不会调用全局低级鼠标挂钩

[英]Global low-level mouse hook doesn't get called when UWP desktop app is out of focus

I'm creating a desktop UWP app and I need to set a global low level mouse hook to detect and change the position of it when it is moved to certain locations of the screen.我正在创建一个桌面 UWP 应用程序,我需要设置一个全局低级鼠标钩子来检测和更改它移动到屏幕的某些位置时的位置。

It works fine while my app's window is in focus and the values get logged correctly to the output window(meaning that the hook is working correctly).当我的应用程序窗口处于焦点并且值被正确记录到输出窗口时它工作正常(意味着钩子工作正常)。

This UWP app isn't going to be on the store and will only be used on a Windows 10 desktop (1903+).此 UWP 应用不会在商店中出现,只会在 Windows 10 桌面 (1903+) 上使用。

I've tried calling SetWindowsHookEx on a different thread (which didn't do anything).我试过在不同的线程上调用SetWindowsHookEx (它没有做任何事情)。 Tried also passing a thread ID when calling SetWindowsHookEx to no avail.在调用SetWindowsHookEx时也尝试传递线程 ID 无济于事。 Also tried using the following restricted capabilities to prevent the app to suspend when not on focus: extendedExecutionUnconstrained and extendedBackgroundTaskTime along with the PreventFromSuspending method shown here .还尝试使用以下受限功能来防止应用程序在未聚焦时挂起: extendedExecutionUnconstrainedextendedBackgroundTaskTime以及此处显示的PreventFromSuspending方法。 Another thing I tried was to set uiAccess to true on the app manifest, which also didn't work.我尝试的另一件事是在应用程序清单uiAccess设置为 true,这也不起作用。

The global hook is supposed to work even when the app isn't in the foreground, but instead it just works when it has the active window focus.即使应用程序不在前台,全局钩子也应该可以工作,但它只在具有活动窗口焦点时工作。

#region Structures

[StructLayout(LayoutKind.Sequential)]
/* MSLLHOOKSTRUCT */
public struct NativeMouseLowLevelHook
{
    public override string ToString()
    {
        return $"{nameof(Point)}: {Point}, {nameof(MouseData)}: {MouseData}, {nameof(Flags)}: {Flags}";
    }

    public NativePoint Point;
    public int MouseData;
    public int Flags;
    public int Time;
    public UIntPtr ExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public class NativePoint
{
    public override string ToString()
    {
        return $"{nameof(X)}: {X}, {nameof(Y)}: {Y}";
    }

    public int X;
    public int Y;
}

#endregion
#region Hook

public class ManagedMouseHook : SafeHandleZeroOrMinusOneIsInvalid
{
    public static List<ManagedMouseHook> KnownHooks { get; set; } = new List<ManagedMouseHook>();

    public HookProc HookImpl { get; set; }

    public ManagedMouseHook() : base(true)
    {
        Hook();
    }

    private void Hook()
    {
        HookImpl = NativeHookCallback;
        KnownHooks.Add(this);
        using (var curProcess = Process.GetCurrentProcess())
        using (var curModule = curProcess.MainModule)
        {
            DoHook(curModule);
        }
    }

    private void DoHook(ProcessModule curModule)
    {
        SetHandle(SetWindowsHookEx(14 /*WH_MOUSE_LL*/, HookImpl, GetModuleHandle(curModule.ModuleName), 0));
    }

    private bool UnHook()
    {
        var result = UnhookWindowsHookEx(DangerousGetHandle());
        KnownHooks.Remove(this);
        HookImpl = null;
        return result;
    }

    /* LowLevelMouseProc */
    private IntPtr NativeHookCallback(int code, IntPtr wparam, IntPtr lparam)
    {
        if (code >= 0)
        {
            var info = (NativeMouseLowLevelHook) Marshal.PtrToStructure(lparam,
                typeof(NativeMouseLowLevelHook));

            Debug.WriteLine(info); //Output example: Point: X: 408, Y: 535, MouseData: 0, Flags: 0
            return new IntPtr(-1);
        }

        return CallNextHookEx(IntPtr.Zero, code, wparam, lparam);
    }

    protected override bool ReleaseHandle()
    {
        return UnHook();
    }
}

#endregion
#region Interop

public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, ulong dwThreadId);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);

[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,
    IntPtr lParam);

#endregion

Then, to start using it:然后,开始使用它:

public ManagedMouseHook MouseHook { get; set; }
MouseHook/*property*/ = new ManagedMouseHook();

And to unhook:并解开:

MouseHook/*property*/.Close();

UWP apps are running in the sandbox, so that doesn't sound strange. UWP 应用程序在沙箱中运行,所以这听起来并不奇怪。 If you think a bit it is a security problem if the app can receive such an input and as 'Security' is listed as No.1 characteristic of the UWP this behavior is expected.如果您认为如果应用程序可以接收这样的输入并且“安全”被列为 UWP 的第一特征,那么这是一个安全问题,这种行为是正常的。

我在评论的帮助下决定,最好的方法是使用我的 UWP 应用程序作为前端,并使用 win32 应用程序来实现挂钩功能本身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM