我有一段与这个问题非常相似的代码,在Windows托盘应用程序中运行。即使使用来自该问题的完全相同代码,我也会得到相同的行为。它在经典的Windows应用程序(如Firefox、Chrome、Windows Explorer等)上都能正常工作。然而,当鼠标焦点到达UWP应用程序(如Edge、Calendar或Mail)时,滚动变得抖动,并且在执行几十次滚动后,我的应用程序会挂起,甚至无法从任务管理器中终止(权限被拒绝),这种行为非常容易重现。
我将在此处粘贴来自该问题的代码:
有没有可能这是windows中的一个bug?有什么指针可以帮我找出问题所在?
更新:
我已经用C++创建了一个测试Win32应用程序,以更轻松地重现/演示这个问题。问题在于SendCommand,当它被执行时,只要任何经典应用程序处于焦点状态,就能正常工作。但是,当它被执行时,如果一个UWP应用程序或者甚至是Windows的启动/开始菜单处于焦点状态,调用应用程序(我的应用程序)将会挂起并一直卡住,直到Windows被重新启动。
对于这个问题的一个有效的解决方法是在处理钩子回调的线程中从另一个线程执行SendCommand调用。立即启动执行SendCommand的线程,并从钩子回调返回能够产生期望的行为并且不会引起任何问题。
我将在此处粘贴来自该问题的代码:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace EnableMacScrolling
{
class InterceptMouse
{
const int INPUT_MOUSE = 0;
const int MOUSEEVENTF_WHEEL = 0x0800;
const int WH_MOUSE_LL = 14;
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
if (_hookID == null)
{
MessageBox.Show("SetWindowsHookEx Failed");
return;
}
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.mouseData);
if (hookStruct.flags != -1) //prevents recursive call to self
{
INPUT input;
input = new INPUT();
input.type = INPUT_MOUSE;
input.mi.dx = 0;
input.mi.dy = 0;
input.mi.dwFlags = MOUSEEVENTF_WHEEL;
input.mi.time = 0;
input.mi.dwExtraInfo = 0;
input.mi.mouseData = -(hookStruct.mouseData >> 16);
try
{
SendInput(1, ref input, Marshal.SizeOf(input));
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
return (IntPtr)1;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private enum MouseMessages
{
WM_MOUSEWHEEL = 0x020A
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
public struct INPUT
{
public int type;
public MOUSEINPUT mi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public uint dwFlags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("User32.dll", SetLastError = true)]
public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize);
} }
有没有可能这是windows中的一个bug?有什么指针可以帮我找出问题所在?
更新:
我已经用C++创建了一个测试Win32应用程序,以更轻松地重现/演示这个问题。问题在于SendCommand,当它被执行时,只要任何经典应用程序处于焦点状态,就能正常工作。但是,当它被执行时,如果一个UWP应用程序或者甚至是Windows的启动/开始菜单处于焦点状态,调用应用程序(我的应用程序)将会挂起并一直卡住,直到Windows被重新启动。
对于这个问题的一个有效的解决方法是在处理钩子回调的线程中从另一个线程执行SendCommand调用。立即启动执行SendCommand的线程,并从钩子回调返回能够产生期望的行为并且不会引起任何问题。