mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
尝试使用EasyHook实现完善光标映射
This commit is contained in:
parent
70e89d5787
commit
16fdb53c18
21 changed files with 569 additions and 38 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -10,6 +10,11 @@
|
|||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# EasyHook
|
||||
EasyHook*.dll
|
||||
EasyHook*.exe
|
||||
EasyLoad*.dll
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
|
|
|
|||
67
CursorHook/CursorHook.csproj
Normal file
67
CursorHook/CursorHook.csproj
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{983647DC-E3C2-4658-852B-FF4D146F8134}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CursorHook</RootNamespace>
|
||||
<AssemblyName>CursorHook</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\build\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="EasyHook, Version=2.7.7097.0, Culture=neutral, PublicKeyToken=4b580fca19d0b0c5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EasyHook.2.7.7097\lib\net40\EasyHook.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Remoting" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="InjectionEntryPoint.cs" />
|
||||
<Compile Include="NativeMethods.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ServerInterface.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="EasyHook32.dll" />
|
||||
<Content Include="EasyHook32Svc.exe" />
|
||||
<Content Include="EasyHook64.dll" />
|
||||
<Content Include="EasyHook64Svc.exe" />
|
||||
<Content Include="EasyLoad32.dll" />
|
||||
<Content Include="EasyLoad64.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
141
CursorHook/InjectionEntryPoint.cs
Normal file
141
CursorHook/InjectionEntryPoint.cs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Magpie.CursorHook {
|
||||
/// <summary>
|
||||
/// EasyHook will look for a class implementing <see cref="EasyHook.IEntryPoint"/> during injection. This
|
||||
/// becomes the entry point within the target process after injection is complete.
|
||||
/// </summary>
|
||||
public class InjectionEntryPoint : EasyHook.IEntryPoint {
|
||||
/// <summary>
|
||||
/// Reference to the server interface within FileMonitor
|
||||
/// </summary>
|
||||
private ServerInterface _server = null;
|
||||
|
||||
/// <summary>
|
||||
/// Message queue of all files accessed
|
||||
/// </summary>
|
||||
private Queue<string> _messageQueue = new Queue<string>();
|
||||
|
||||
private IntPtr _hwndHost;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// EasyHook requires a constructor that matches <paramref name="context"/> and any additional parameters as provided
|
||||
/// in the original call to <see cref="EasyHook.RemoteHooking.Inject(int, EasyHook.InjectionOptions, string, string, object[])"/>.
|
||||
///
|
||||
/// Multiple constructors can exist on the same <see cref="EasyHook.IEntryPoint"/>, providing that each one has a corresponding Run method (e.g. <see cref="Run(EasyHook.RemoteHooking.IContext, string)"/>).
|
||||
/// </summary>
|
||||
/// <param name="context">The RemoteHooking context</param>
|
||||
/// <param name="channelName">The name of the IPC channel</param>
|
||||
public InjectionEntryPoint(
|
||||
EasyHook.RemoteHooking.IContext context,
|
||||
string channelName, IntPtr hwndHost) {
|
||||
_hwndHost = hwndHost;
|
||||
|
||||
// Connect to server object using provided channel name
|
||||
_server = EasyHook.RemoteHooking.IpcConnectClient<ServerInterface>(channelName);
|
||||
|
||||
// If Ping fails then the Run method will be not be called
|
||||
_server.Ping();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for our logic once injected within the target process.
|
||||
/// This is where the hooks will be created, and a loop will be entered until host process exits.
|
||||
/// EasyHook requires a matching Run method for the constructor
|
||||
/// </summary>
|
||||
/// <param name="context">The RemoteHooking context</param>
|
||||
/// <param name="channelName">The name of the IPC channel</param>
|
||||
public void Run(
|
||||
EasyHook.RemoteHooking.IContext context,
|
||||
string channelName, IntPtr hwndHost) {
|
||||
|
||||
// Injection is now complete and the server interface is connected
|
||||
_server.IsInstalled(EasyHook.RemoteHooking.GetCurrentProcessId());
|
||||
|
||||
// Install hooks
|
||||
|
||||
// SetCursor https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursor
|
||||
var setCursorHook = EasyHook.LocalHook.Create(
|
||||
EasyHook.LocalHook.GetProcAddress("user32.dll", "SetCursor"),
|
||||
new SetCursor_Delegate(SetCursor_Hook),
|
||||
this);
|
||||
|
||||
// Activate hooks on all threads except the current thread
|
||||
setCursorHook.ThreadACL.SetExclusiveACL(new int[] { 0 });
|
||||
|
||||
_server.ReportMessage("SetCursor钩子安装成功");
|
||||
|
||||
|
||||
NativeMethods.EnumChildWindows(IntPtr.Zero, (IntPtr hWnd, int lParam) => {
|
||||
NativeMethods.SetClassLong(hWnd, NativeMethods.GCLP_HCURSOR,
|
||||
NativeMethods.LoadCursor(IntPtr.Zero, NativeMethods.IDC_ARROW));
|
||||
|
||||
NativeMethods.EnumChildWindows(hWnd, (IntPtr hWnd1, int lParam1) => {
|
||||
NativeMethods.SetClassLong(hWnd, NativeMethods.GCLP_HCURSOR,
|
||||
NativeMethods.LoadCursor(IntPtr.Zero, NativeMethods.IDC_ARROW));
|
||||
return true;
|
||||
}, 0);
|
||||
return true;
|
||||
}, 0);
|
||||
NativeMethods.SetCursor(NativeMethods.LoadCursor(IntPtr.Zero, NativeMethods.IDC_ARROW));
|
||||
|
||||
try {
|
||||
// Loop until FileMonitor closes (i.e. IPC fails)
|
||||
while (true) {
|
||||
Thread.Sleep(500);
|
||||
|
||||
string[] queued = null;
|
||||
|
||||
lock (_messageQueue) {
|
||||
queued = _messageQueue.ToArray();
|
||||
_messageQueue.Clear();
|
||||
}
|
||||
|
||||
// Send newly monitored file accesses to FileMonitor
|
||||
if (queued != null && queued.Length > 0) {
|
||||
_server.ReportMessages(queued);
|
||||
} else {
|
||||
_server.Ping();
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ping() or ReportMessages() will raise an exception if host is unreachable
|
||||
}
|
||||
|
||||
// Remove hooks
|
||||
setCursorHook.Dispose();
|
||||
|
||||
// Finalise cleanup of hooks
|
||||
EasyHook.LocalHook.Release();
|
||||
}
|
||||
|
||||
|
||||
// The SetCursor delegate, this is needed to create a delegate of our hook function
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
delegate IntPtr SetCursor_Delegate(IntPtr hCursor);
|
||||
|
||||
|
||||
// The SetCursor hook function. This will be called instead of the original SetCursor once hooked.
|
||||
IntPtr SetCursor_Hook(IntPtr hCursor) {
|
||||
_server.ReportMessage("SetCursor前:" + hCursor.ToString());
|
||||
if (!NativeMethods.PostMessage(_hwndHost, NativeMethods.WM_COPYDATA, hCursor, IntPtr.Zero)) {
|
||||
_server.ReportMessage("error: " + Marshal.GetLastWin32Error().ToString());
|
||||
}
|
||||
|
||||
var r = NativeMethods.SetCursor(hCursor);
|
||||
|
||||
NativeMethods.PostMessage(_hwndHost, NativeMethods.WM_COPYDATA, NativeMethods.GetCursor(), IntPtr.Zero);
|
||||
_server.ReportMessage("SetCursor后:" + NativeMethods.GetCursor().ToString());
|
||||
return r;
|
||||
//return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
58
CursorHook/NativeMethods.cs
Normal file
58
CursorHook/NativeMethods.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Magpie.CursorHook {
|
||||
// Win32 API
|
||||
public static class NativeMethods {
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SetCursor(IntPtr hCursor);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr GetCursor();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName);
|
||||
|
||||
public readonly static IntPtr IDC_ARROW = new IntPtr(32512);
|
||||
public readonly static IntPtr IDC_HAND = new IntPtr(32649);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SetClassLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
|
||||
|
||||
public readonly static int GCLP_HCURSOR = -12;
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int ShowCursor(bool bShow);
|
||||
|
||||
|
||||
public delegate bool EnumWindowsProc(IntPtr hwnd, int lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, int lParam);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
public readonly static uint WM_COPYDATA = 0x004A + 1;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct POINT {
|
||||
public int x;
|
||||
public int y;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CURSORINFO {
|
||||
public int cbSize;
|
||||
public int flags;
|
||||
public IntPtr hCursor;
|
||||
public POINT ptScreenPos;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern bool GetCursorInfo(ref CURSORINFO pci);
|
||||
}
|
||||
}
|
||||
36
CursorHook/Properties/AssemblyInfo.cs
Normal file
36
CursorHook/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("CursorHook")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("CursorHook")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("983647dc-e3c2-4658-852b-ff4d146f8134")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
55
CursorHook/ServerInterface.cs
Normal file
55
CursorHook/ServerInterface.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Magpie.CursorHook {
|
||||
/// <summary>
|
||||
/// Provides an interface for communicating from the client (target) to the server (injector)
|
||||
/// </summary>
|
||||
public class ServerInterface : MarshalByRefObject {
|
||||
public void IsInstalled(int clientPID) {
|
||||
Console.WriteLine("Hook 成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Output messages to the console.
|
||||
/// </summary>
|
||||
/// <param name="clientPID"></param>
|
||||
/// <param name="fileNames"></param>
|
||||
public void ReportMessages(string[] messages) {
|
||||
for (int i = 0; i < messages.Length; i++) {
|
||||
Console.WriteLine(messages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReportMessage(string message) {
|
||||
Console.WriteLine(message);
|
||||
|
||||
unsafe {
|
||||
var ci = new NativeMethods.CURSORINFO {
|
||||
cbSize = sizeof(NativeMethods.CURSORINFO)
|
||||
};
|
||||
|
||||
NativeMethods.GetCursorInfo(ref ci);
|
||||
|
||||
Console.WriteLine("另一进程:" + ci.hCursor.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Report exception
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
public void ReportException(Exception e) {
|
||||
Console.WriteLine("IPC出错:" + e.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to confirm that the IPC channel is still open / host application has not closed
|
||||
/// </summary>
|
||||
public void Ping() {
|
||||
}
|
||||
}
|
||||
}
|
||||
4
CursorHook/packages.config
Normal file
4
CursorHook/packages.config
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="EasyHook" version="2.7.7097" targetFramework="net472" />
|
||||
</packages>
|
||||
20
Magpie.sln
20
Magpie.sln
|
|
@ -10,30 +10,50 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Magpie", "Magpie\Magpie.csp
|
|||
{8FC22A64-6D09-478B-9980-608D27601EF2} = {8FC22A64-6D09-478B-9980-608D27601EF2}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CursorHook", "CursorHook\CursorHook.csproj", "{983647DC-E3C2-4658-852B-FF4D146F8134}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Debug|x64.Build.0 = Debug|x64
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Debug|x86.Build.0 = Debug|Win32
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Release|x64.ActiveCfg = Release|x64
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Release|x64.Build.0 = Release|x64
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8FC22A64-6D09-478B-9980-608D27601EF2}.Release|x86.Build.0 = Release|Win32
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Debug|Any CPU.ActiveCfg = Debug|x86
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Debug|x64.Build.0 = Debug|x64
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Debug|x86.Build.0 = Debug|x86
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Release|Any CPU.ActiveCfg = Release|x86
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Release|x64.ActiveCfg = Release|x64
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Release|x64.Build.0 = Release|x64
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Release|x86.ActiveCfg = Release|x86
|
||||
{C75EC8D6-FF40-4307-9B46-EA760DC5E4C9}.Release|x86.Build.0 = Release|x86
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Release|x64.Build.0 = Release|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{983647DC-E3C2-4658-852B-FF4D146F8134}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
41
Magpie/CursorHookInjector.cs
Normal file
41
Magpie/CursorHookInjector.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Remoting;
|
||||
using EasyHook;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Magpie.CursorHook;
|
||||
using System.Runtime.Remoting.Channels.Ipc;
|
||||
|
||||
namespace Magpie {
|
||||
public class CursorHookInjector {
|
||||
private string channelName = null;
|
||||
private readonly int targetPID;
|
||||
private IpcServerChannel ipcServer;
|
||||
|
||||
public CursorHookInjector(int targetPID, IntPtr hwndSrc) {
|
||||
Debug.Assert(targetPID > 0);
|
||||
|
||||
this.targetPID = targetPID;
|
||||
|
||||
// Create the IPC server using the FileMonitorIPC.ServiceInterface class as a singleton
|
||||
ipcServer = RemoteHooking.IpcCreateServer<ServerInterface>(ref channelName, WellKnownObjectMode.Singleton);
|
||||
|
||||
// Get the full path to the assembly we want to inject into the target process
|
||||
string injectionLibrary = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "CursorHook.dll");
|
||||
|
||||
EasyHook.RemoteHooking.Inject(
|
||||
targetPID, // ID of process to inject into
|
||||
injectionLibrary, // 32-bit library to inject (if target is 32-bit)
|
||||
injectionLibrary, // 64-bit library to inject (if target is 64-bit)
|
||||
channelName, // the parameters to pass into injected library
|
||||
hwndSrc // ...
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -64,11 +64,15 @@
|
|||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="EasyHook, Version=2.7.7097.0, Culture=neutral, PublicKeyToken=4b580fca19d0b0c5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\EasyHook.2.7.7097\lib\net40\EasyHook.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Gma.System.MouseKeyHook, Version=5.6.130.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MouseKeyHook.5.6.0\lib\net40\Gma.System.MouseKeyHook.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Runtime.Remoting" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
|
@ -80,6 +84,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CursorHookInjector.cs" />
|
||||
<Compile Include="MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
|
@ -119,7 +124,31 @@
|
|||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="EasyHook32.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="EasyHook32Svc.exe">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="EasyHook64.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="EasyHook64Svc.exe">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="EasyLoad32.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="EasyLoad64.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="logo.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CursorHook\CursorHook.csproj">
|
||||
<Project>{983647dc-e3c2-4658-852b-ff4d146f8134}</Project>
|
||||
<Name>CursorHook</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
2
Magpie/MainForm.Designer.cs
generated
2
Magpie/MainForm.Designer.cs
generated
|
|
@ -104,7 +104,7 @@ namespace Magpie {
|
|||
this.tkbFrameRate.TabIndex = 3;
|
||||
this.tkbFrameRate.TickFrequency = 10;
|
||||
this.tkbFrameRate.Value = 60;
|
||||
this.tkbFrameRate.ValueChanged += new System.EventHandler(this.TkbFrameRate_ValueChanged);
|
||||
this.tkbFrameRate.Scroll += new System.EventHandler(this.TkbFrameRate_Scroll);
|
||||
//
|
||||
// lblFrameRate
|
||||
//
|
||||
|
|
|
|||
|
|
@ -17,13 +17,12 @@ namespace Magpie {
|
|||
{
|
||||
""effect"": ""scale"",
|
||||
""type"": ""mitchell"",
|
||||
""scale"": [0,0],
|
||||
""useSharperVersion"": true
|
||||
""scale"": [0,0]
|
||||
},
|
||||
{
|
||||
""effect"": ""sharpen"",
|
||||
""type"": ""adaptive"",
|
||||
""curveHeight"": 0.2
|
||||
""curveHeight"": 0.3
|
||||
}
|
||||
]";
|
||||
private static readonly string CommonEffectJson = @"[
|
||||
|
|
@ -44,6 +43,8 @@ namespace Magpie {
|
|||
|
||||
IKeyboardMouseEvents keyboardEvents = null;
|
||||
|
||||
CursorHookInjector cursorHookInjector = null;
|
||||
|
||||
public MainForm() {
|
||||
InitializeComponent();
|
||||
|
||||
|
|
@ -78,6 +79,11 @@ namespace Magpie {
|
|||
Settings.Default.Save();
|
||||
}
|
||||
|
||||
private void TkbFrameRate_Scroll(object sender, EventArgs e) {
|
||||
lblFrameRate.Text = tkbFrameRate.Value.ToString();
|
||||
Settings.Default.FrameRate = (uint)tkbFrameRate.Value;
|
||||
}
|
||||
|
||||
private void TxtHotkey_TextChanged(object sender, EventArgs e) {
|
||||
keyboardEvents?.Dispose();
|
||||
keyboardEvents = Hook.GlobalEvents();
|
||||
|
|
@ -94,7 +100,12 @@ namespace Magpie {
|
|||
if(!NativeMethods.HasMagWindow()) {
|
||||
if(!NativeMethods.CreateMagWindow(frameRate, effectJson, false)) {
|
||||
MessageBox.Show("创建全屏窗口失败:" + NativeMethods.GetLastErrorMsg());
|
||||
return;
|
||||
}
|
||||
|
||||
int pid = NativeMethods.GetSrcPID();
|
||||
IntPtr hwndHost = NativeMethods.GetHostWnd();
|
||||
cursorHookInjector = new CursorHookInjector(pid, hwndHost);
|
||||
} else {
|
||||
NativeMethods.DestroyMagWindow();
|
||||
}
|
||||
|
|
@ -145,10 +156,5 @@ namespace Magpie {
|
|||
tsmiMainForm.PerformClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void TkbFrameRate_ValueChanged(object sender, EventArgs e) {
|
||||
lblFrameRate.Text = tkbFrameRate.Value.ToString();
|
||||
Settings.Default.FrameRate = (uint)tkbFrameRate.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ namespace Magpie {
|
|||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||
public static extern int RegisterWindowMessage(string message);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr SetCursor(IntPtr hCursor);
|
||||
|
||||
|
||||
[DllImport("Runtime", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern bool CreateMagWindow(
|
||||
|
|
@ -44,5 +47,14 @@ namespace Magpie {
|
|||
public static string GetLastErrorMsg() {
|
||||
return Marshal.PtrToStringUni(GetLastErrorMsgNative());
|
||||
}
|
||||
|
||||
[DllImport("Runtime", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern int GetSrcPID();
|
||||
|
||||
[DllImport("Runtime", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern IntPtr GetSrcWnd();
|
||||
|
||||
[DllImport("Runtime", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern IntPtr GetHostWnd();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="EasyHook" version="2.7.7097" targetFramework="net472" />
|
||||
<package id="MouseKeyHook" version="5.6.0" targetFramework="net472" />
|
||||
</packages>
|
||||
|
|
@ -19,7 +19,7 @@ public:
|
|||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
*ppOutput = new Anime4KUpscaleDenoiseConvReduceTransform();
|
||||
|
||||
return S_OK;
|
||||
|
|
|
|||
|
|
@ -17,21 +17,20 @@ public:
|
|||
_cursorSize.cx = GetSystemMetrics(SM_CXCURSOR);
|
||||
_cursorSize.cy = GetSystemMetrics(SM_CYCURSOR);
|
||||
|
||||
_d2dBmpNormalCursor = _CursorToD2DBitmap(LoadCursor(NULL, IDC_ARROW));
|
||||
_d2dBmpHandCursor = _CursorToD2DBitmap(LoadCursor(NULL, IDC_HAND));
|
||||
|
||||
|
||||
if (!noDisturb) {
|
||||
// 保存替换之前的 arrow 光标图像
|
||||
ComPtr<ID2D1Bitmap> arrowImg = _CursorToD2DBitmap(LoadCursor(NULL, IDC_ARROW));
|
||||
|
||||
HCURSOR tptCursor = _CreateTransparentCursor();
|
||||
|
||||
Debug::ThrowIfWin32Failed(
|
||||
SetSystemCursor(CopyCursor(tptCursor), OCR_HAND),
|
||||
L"ÉèÖà OCR_HAND ʧ°Ü"
|
||||
);
|
||||
Debug::ThrowIfWin32Failed(
|
||||
SetSystemCursor(tptCursor, OCR_NORMAL),
|
||||
SetSystemCursor(_CreateTransparentCursor(), OCR_NORMAL),
|
||||
L"设置 OCR_NORMAL 失败"
|
||||
);
|
||||
// tptCursor ±»Ïú»Ù
|
||||
|
||||
_hCursorArrow = LoadCursor(NULL, IDC_ARROW);
|
||||
_cursorMap.emplace(_hCursorArrow, arrowImg);
|
||||
|
||||
// 限制鼠标在窗口内
|
||||
RECT r{ lroundf(srcRect.left), lroundf(srcRect.top), lroundf(srcRect.right), lroundf(srcRect.bottom) };
|
||||
|
|
@ -69,7 +68,10 @@ public:
|
|||
void DrawCursor() {
|
||||
CURSORINFO ci{};
|
||||
ci.cbSize = sizeof(ci);
|
||||
Debug::ThrowIfWin32Failed(GetCursorInfo(&ci), L"GetCursorInfo ʧ°Ü");
|
||||
Debug::ThrowIfWin32Failed(
|
||||
GetCursorInfo(&ci),
|
||||
L"GetCursorInfo 失败"
|
||||
);
|
||||
|
||||
if (ci.hCursor == NULL) {
|
||||
return;
|
||||
|
|
@ -98,18 +100,33 @@ public:
|
|||
targetScreenPos.y + _cursorSize.cy - ii.yHotspot
|
||||
};
|
||||
|
||||
if (ci.hCursor == LoadCursor(NULL, IDC_ARROW)) {
|
||||
_d2dDC->DrawBitmap(_d2dBmpNormalCursor.Get(), &cursorRect);
|
||||
} else if (ci.hCursor == LoadCursor(NULL, IDC_HAND)) {
|
||||
_d2dDC->DrawBitmap(_d2dBmpHandCursor.Get(), &cursorRect);
|
||||
auto it = _cursorMap.find(ci.hCursor);
|
||||
if (it != _cursorMap.end()) {
|
||||
_d2dDC->DrawBitmap(it->second.Get(), &cursorRect);
|
||||
} else {
|
||||
Debug::WriteLine(L"未找到");
|
||||
try {
|
||||
ComPtr<ID2D1Bitmap> c = _CursorToD2DBitmap(ci.hCursor);
|
||||
_d2dDC->DrawBitmap(c.Get(), &cursorRect);
|
||||
} catch (magpie_exception) {
|
||||
ComPtr<ID2D1Bitmap> cursorBmp = _CursorToD2DBitmap(ci.hCursor);
|
||||
_d2dDC->DrawBitmap(cursorBmp.Get(), &cursorRect);
|
||||
|
||||
// 添加进表
|
||||
_cursorMap[ci.hCursor] = cursorBmp;
|
||||
} catch (...) {
|
||||
// 如果出错,只绘制普通光标
|
||||
Debug::WriteLine(L"_CursorToD2DBitmap 出错");
|
||||
_d2dDC->DrawBitmap(_d2dBmpNormalCursor.Get(), &cursorRect);
|
||||
|
||||
it = _cursorMap.find(_hCursorArrow);
|
||||
if (it == _cursorMap.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cursorRect = {
|
||||
targetScreenPos.x,
|
||||
targetScreenPos.y,
|
||||
targetScreenPos.x + _cursorSize.cx,
|
||||
targetScreenPos.y + _cursorSize.cy
|
||||
};
|
||||
_d2dDC->DrawBitmap(it->second.Get(), &cursorRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -167,8 +184,8 @@ private:
|
|||
IWICImagingFactory2* _wicImgFactory;
|
||||
ID2D1DeviceContext* _d2dDC;
|
||||
|
||||
ComPtr<ID2D1Bitmap> _d2dBmpNormalCursor = nullptr;
|
||||
ComPtr<ID2D1Bitmap> _d2dBmpHandCursor = nullptr;
|
||||
HCURSOR _hCursorArrow{};
|
||||
std::map<HCURSOR, ComPtr<ID2D1Bitmap>> _cursorMap;
|
||||
|
||||
SIZE _cursorSize{};
|
||||
|
||||
|
|
|
|||
|
|
@ -65,3 +65,28 @@ API_DECLSPEC void WINAPI DestroyMagWindow() {
|
|||
API_DECLSPEC const WCHAR* WINAPI GetLastErrorMsg() {
|
||||
return Debug::GetLastErrorMessage().c_str();
|
||||
}
|
||||
|
||||
|
||||
API_DECLSPEC HWND WINAPI GetSrcWnd() {
|
||||
if (MagWindow::$instance == nullptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MagWindow::$instance->GetSrcWnd();
|
||||
}
|
||||
|
||||
API_DECLSPEC UINT32 WINAPI GetSrcPID() {
|
||||
HWND hwndSrc = GetSrcWnd();
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(hwndSrc, &pid);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
API_DECLSPEC HWND WINAPI GetHostWnd() {
|
||||
if (MagWindow::$instance == nullptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MagWindow::$instance->GetHostWnd();
|
||||
}
|
||||
|
|
@ -38,6 +38,14 @@ public:
|
|||
CoUninitialize();
|
||||
}
|
||||
|
||||
HWND GetSrcWnd() {
|
||||
return _hwndSrc;
|
||||
}
|
||||
|
||||
HWND GetHostWnd() {
|
||||
return _hwndHost;
|
||||
}
|
||||
|
||||
private:
|
||||
MagWindow(
|
||||
HINSTANCE hInstance,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
// Mitchell-Netravali 缩放算法,一种双三次插值,可以获得平滑的边缘
|
||||
// 可选是否使用更锐利的版本,默认为否
|
||||
// (经测试两种版本几乎没有区别)
|
||||
class MitchellNetravaliScaleEffect : public EffectBase {
|
||||
public:
|
||||
IFACEMETHODIMP Initialize(
|
||||
|
|
@ -50,7 +51,7 @@ public:
|
|||
|
||||
enum PROPS {
|
||||
PROP_SCALE = 0,
|
||||
PROP_USE_SHARPER_VERSION = 1
|
||||
PROP_USE_SHARPER_VERSION = 0
|
||||
};
|
||||
|
||||
static HRESULT Register(_In_ ID2D1Factory1* pFactory) {
|
||||
|
|
|
|||
|
|
@ -241,7 +241,9 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="common.hlsli" />
|
||||
<None Include="common.hlsli">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
</None>
|
||||
<None Include="cpp.hint" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
|
|
@ -262,9 +264,6 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelShader.hlsl">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KUpscaleConv4x3x3x1Shader.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
|
||||
|
|
@ -411,6 +410,12 @@
|
|||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelShader.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Pixel</ShaderType>
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<FxCompile Include="Anime4KDeblurKernelShader.hlsl">
|
||||
<Filter>着色器\缩放\Anime4K</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KUpscaleConv4x3x3x1Shader.hlsl">
|
||||
<Filter>着色器\缩放\Anime4K</Filter>
|
||||
</FxCompile>
|
||||
|
|
@ -67,6 +64,9 @@
|
|||
<FxCompile Include="Lanczos6ScaleShader.hlsl">
|
||||
<Filter>着色器\缩放</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="Anime4KDeblurKernelShader.hlsl">
|
||||
<Filter>着色器\缩放\Anime4K</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="GUIDs.cpp">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue