2023-02-05 08:53:12 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
|
|
|
|
namespace PCRobot.Utils
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 微信激活帮助类
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class WeChatActivateHelperV2
|
|
|
|
|
{
|
|
|
|
|
#region WIN32 API函数
|
|
|
|
|
[DllImport("User32.dll", EntryPoint = "SendMessage")]
|
|
|
|
|
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 聚焦
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="hWnd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
[DllImport("user32.dll", EntryPoint = "SetFocus")]
|
|
|
|
|
private static extern IntPtr SetFocus(IntPtr hWnd);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 判断是否最小化
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="hWnd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
[DllImport("user32.dll")]
|
|
|
|
|
private static extern bool IsIconic(IntPtr hWnd);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 判断是否可见
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="hWnd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
[DllImport("user32.dll")]
|
|
|
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
|
|
|
private static extern bool IsWindowVisible(IntPtr hWnd);
|
|
|
|
|
|
|
|
|
|
[DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
|
|
|
|
|
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 附加线程输入
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="idAttach">当前线程</param>
|
|
|
|
|
/// <param name="idAttachTo">目标线程</param>
|
|
|
|
|
/// <param name="fAttach"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "AttachThreadInput", ExactSpelling = true, SetLastError = true)]
|
|
|
|
|
private static extern bool AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, bool fAttach);
|
|
|
|
|
|
|
|
|
|
//通过句柄获取线程ID
|
|
|
|
|
[DllImport("User32.dll", CharSet = CharSet.Auto)]
|
|
|
|
|
private static extern IntPtr GetWindowThreadProcessId(IntPtr hwnd, IntPtr id);
|
|
|
|
|
|
|
|
|
|
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
|
|
|
|
private static extern IntPtr FindWindowExA(IntPtr parentHandle, IntPtr childAfter, string lpClassName, string lpWindowName);
|
|
|
|
|
|
|
|
|
|
[System.Runtime.InteropServices.DllImport("USER32.DLL")]
|
|
|
|
|
private static extern bool SetForegroundWindow(IntPtr hWnd);
|
|
|
|
|
|
|
|
|
|
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
|
|
|
|
private static extern bool SetActiveWindow(IntPtr hWnd);
|
|
|
|
|
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
|
|
|
|
|
private static extern IntPtr GetCurrentThreadId();
|
|
|
|
|
|
|
|
|
|
public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
|
|
|
|
|
public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
|
|
|
|
|
public const int SWP_NOSIZE = 0x1;
|
|
|
|
|
public const int SWP_NOMOVE = 0x2;
|
|
|
|
|
[DllImport("user32.dll")]
|
|
|
|
|
public static extern IntPtr GetForegroundWindow();
|
|
|
|
|
|
|
|
|
|
[DllImport("user32.dll")]
|
|
|
|
|
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndlnsertAfter, int x, int y, int cx, int cy, uint flags);
|
|
|
|
|
|
|
|
|
|
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
|
|
|
|
public static extern bool BringWindowToTop(IntPtr hWnd);
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 激活相关代码
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 置顶窗口
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="hwnd"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private static bool SetForegroundWindowCustom(IntPtr hwnd)
|
|
|
|
|
{
|
|
|
|
|
IntPtr currentWindow = GetForegroundWindow();
|
|
|
|
|
if (currentWindow == hwnd)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
|
|
|
|
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
|
|
|
|
|
|
|
|
|
return SetForegroundWindow(hwnd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 激活窗口
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void ActivateWindow(string lpClassName, string lpWindowName)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//主窗口句柄
|
|
|
|
|
var handle = IntPtr.Zero;
|
|
|
|
|
var handleList = new List<IntPtr>();
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
//优先休眠,防止continue未休眠
|
|
|
|
|
Thread.Sleep(1000);
|
|
|
|
|
|
|
|
|
|
//查找窗口句柄并筛选
|
|
|
|
|
handle = FindWindowExA(IntPtr.Zero, handle, lpClassName, lpWindowName);
|
|
|
|
|
if (handle == IntPtr.Zero)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (handleList.Contains(handle))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleList.Add(handle);
|
|
|
|
|
var isIconic = IsIconic(handle);
|
|
|
|
|
|
|
|
|
|
//窗体不可见,视为最小化了
|
|
|
|
|
var isWindowVisible = IsWindowVisible(handle);
|
|
|
|
|
if (!isWindowVisible)
|
|
|
|
|
{
|
|
|
|
|
isIconic = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//窗体不可见,或者最小化了
|
|
|
|
|
if (isIconic)
|
|
|
|
|
{
|
|
|
|
|
ShowWindow(handle, 1);
|
|
|
|
|
Thread.Sleep(3000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//var thisHandel = Process.GetCurrentProcess().MainWindowHandle;
|
|
|
|
|
//获取自己的线程ID
|
|
|
|
|
|
|
|
|
|
//如果这里报错,请添加引用PresentationFramework
|
|
|
|
|
var cur = _mSynchronizationContext;
|
|
|
|
|
|
|
|
|
|
if (cur == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("当前线程信息获取失败");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var handle1 = handle;
|
|
|
|
|
//用主线程的上下文
|
|
|
|
|
cur.Send((e) =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
//var thisThreadId = GetCurrentThreadId();// AppDomain.GetCurrentThreadId();
|
|
|
|
|
var thisThreadId = GetCurrentThreadId();
|
|
|
|
|
var targetThreadId = GetWindowThreadProcessId(handle1, IntPtr.Zero);
|
|
|
|
|
//附加线程
|
|
|
|
|
var attachThreadStart = AttachThreadInput(targetThreadId, thisThreadId, true);
|
|
|
|
|
|
|
|
|
|
//置顶
|
|
|
|
|
var bringWindowToTop = BringWindowToTop(handle1);
|
|
|
|
|
|
|
|
|
|
//置焦点(输入框可获得光标)
|
|
|
|
|
SetFocus(handle1);
|
|
|
|
|
|
|
|
|
|
//置前台
|
|
|
|
|
var setForegroundWindowResult = SetForegroundWindowCustom(handle1);
|
|
|
|
|
|
|
|
|
|
//激活
|
|
|
|
|
var setActiveWindow = SetActiveWindow(handle1);
|
|
|
|
|
|
|
|
|
|
//分离线程
|
|
|
|
|
var attachThreadEnd = AttachThreadInput(targetThreadId, thisThreadId, false);
|
|
|
|
|
|
|
|
|
|
//log.Info($"完成微信激活!attachThreadStart={attachThreadStart} - bringWindowToTop={bringWindowToTop} - setForegroundWindowResult={setForegroundWindowResult} - setActiveWindow={setActiveWindow} - attachThreadEnd={attachThreadEnd}");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
{
|
|
|
|
|
//log.Error($"激活微信失败2:{exception.Message}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}, null);
|
|
|
|
|
|
|
|
|
|
//如果微信最小化了,重新让他最小化
|
|
|
|
|
|
|
|
|
|
if (isIconic)
|
|
|
|
|
{
|
|
|
|
|
Thread.Sleep(4000);
|
|
|
|
|
ShowWindow(handle, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//休眠
|
|
|
|
|
Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next(40000, 60000));
|
|
|
|
|
|
|
|
|
|
} while (true);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
//log.Error($"激活微信失败1:{e.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 屏蔽微信的更新功能
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void ShieldingWeChatUpdateFunction()
|
|
|
|
|
{
|
2023-03-06 00:49:40 +00:00
|
|
|
|
//SetHost("dldir1v6.qq.com", "127.0.0.1");
|
|
|
|
|
//SetHost("dldir1.qq.com", "127.0.0.1");
|
|
|
|
|
|
|
|
|
|
DelHost("dldir1v6.qq.com");
|
|
|
|
|
DelHost("dldir1.qq.com");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DelHost(string hosts_str)
|
|
|
|
|
{
|
|
|
|
|
string path = System.Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\drivers\\etc\\hosts";
|
|
|
|
|
if (File.GetAttributes(path) == (FileAttributes.ReadOnly | FileAttributes.Archive))
|
|
|
|
|
{
|
|
|
|
|
File.SetAttributes(path, FileAttributes.Archive);
|
|
|
|
|
}
|
|
|
|
|
string[] hosts = File.ReadAllLines(path);
|
|
|
|
|
List<string> list = hosts.ToList();
|
|
|
|
|
list.RemoveAll(x => x.Contains(hosts_str));
|
|
|
|
|
File.WriteAllLines(path, list.ToArray());
|
2023-02-05 08:53:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 激活微信
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void ActivateWeChat()
|
|
|
|
|
{
|
|
|
|
|
//CloseWindow("UpdateWnd", "升级");
|
|
|
|
|
ActivateWindow("WeChatMainWndForPC", "微信");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Thread _thread;
|
|
|
|
|
private static SynchronizationContext _mSynchronizationContext;
|
|
|
|
|
private static MouseHook _mouse;
|
|
|
|
|
private static DateTime _lastActiveTime = DateTime.MinValue;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化激活器
|
|
|
|
|
/// 注:请务必在主线程调用,不要再子线程
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="forcedRunHours">强制运行小时</param>
|
|
|
|
|
/// <param name="maxCount">总激活次数(0表示无限制)</param>
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
|
|
|
|
public static bool Init(int forcedRunHours = 2, int maxCount = 0)
|
|
|
|
|
{
|
|
|
|
|
//log.Info("初始化");
|
|
|
|
|
if (_thread != null && _thread.IsAlive)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("当前线程尚未结束,请勿重复初始化");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////检测鼠标是否有操作界面
|
|
|
|
|
//if (_mouse == null)
|
|
|
|
|
//{
|
|
|
|
|
// _mouse = new MouseHook();
|
|
|
|
|
// _mouse.OnMouseActivity += _mouse_OnMouseActivity;
|
|
|
|
|
// _mouse.Start();
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
_mSynchronizationContext = SynchronizationContext.Current;
|
|
|
|
|
if (_mSynchronizationContext == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("获取主线程失败,请不要再子线程执行");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_thread = new Thread(() =>
|
|
|
|
|
{
|
|
|
|
|
int index = 0;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//操作鼠标键盘时间较短
|
|
|
|
|
var curTime = DateTime.Now;
|
|
|
|
|
var isNext = false;
|
|
|
|
|
//超过2小时没有激活过,强制激活一次
|
|
|
|
|
if ((curTime - _lastActiveTime).TotalHours > forcedRunHours)
|
|
|
|
|
{
|
|
|
|
|
isNext = true;
|
|
|
|
|
}
|
|
|
|
|
//超过了一定时间,没有操作鼠标
|
|
|
|
|
else if (_mouse != null)
|
|
|
|
|
{
|
|
|
|
|
var time = TimeSpan.FromMinutes(30);
|
|
|
|
|
var interval = curTime - _mouseHeartbeatTime;
|
|
|
|
|
if (interval > time)
|
|
|
|
|
{
|
|
|
|
|
_mouseHeartbeatTime = DateTime.Now;
|
|
|
|
|
isNext = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isNext)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//log.Info("开始激活");
|
|
|
|
|
index++;
|
|
|
|
|
_lastActiveTime = DateTime.Now;
|
|
|
|
|
ActivateWeChat();
|
|
|
|
|
//log.Info("激活完成");
|
|
|
|
|
if (maxCount != 0 && index >= maxCount)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"激活窗口发生异常:{e.Message}");
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
Thread.Sleep(TimeSpan.FromMinutes(1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
IsBackground = true
|
|
|
|
|
};
|
|
|
|
|
_thread.Start();
|
|
|
|
|
|
|
|
|
|
//屏蔽微信的更新功能
|
|
|
|
|
ShieldingWeChatUpdateFunction();
|
|
|
|
|
|
|
|
|
|
//开启自动关闭微信更新进程
|
|
|
|
|
StartCheckUpdateThread();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static bool _isStartCheckUpdateThread = false;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 定时检测,关闭微信自动更新
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void StartCheckUpdateThread()
|
|
|
|
|
{
|
|
|
|
|
if (_isStartCheckUpdateThread)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_isStartCheckUpdateThread = true;
|
|
|
|
|
|
|
|
|
|
var th = new Thread(() =>
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var process = Process.GetProcessesByName("WeChatUpdate");
|
|
|
|
|
foreach (var pro in process)
|
|
|
|
|
{
|
|
|
|
|
pro.Kill();
|
|
|
|
|
Thread.Sleep(5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
// ignored
|
|
|
|
|
}
|
|
|
|
|
Thread.Sleep(1000 * 5);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
IsBackground = true
|
|
|
|
|
};
|
|
|
|
|
th.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static DateTime _mouseHeartbeatTime = DateTime.Now;
|
|
|
|
|
private static void _mouse_OnMouseActivity(object sender, MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
_mouseHeartbeatTime = DateTime.Now;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置HOST文件
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="domain">域名</param>
|
|
|
|
|
/// <param name="ip">IP地址</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private static bool SetHost(string domain, string ip)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
string path = Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\drivers\\etc\\hosts";
|
|
|
|
|
if (File.GetAttributes(path) == (FileAttributes.ReadOnly | FileAttributes.Archive))
|
|
|
|
|
{
|
|
|
|
|
File.SetAttributes(path, FileAttributes.Archive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string[] hosts = File.ReadAllLines(path);
|
|
|
|
|
List<string> list = hosts.ToList();
|
|
|
|
|
string temp = hosts.ToList().FirstOrDefault(x => x.Contains(domain));
|
|
|
|
|
if (string.IsNullOrEmpty(temp))
|
|
|
|
|
{
|
|
|
|
|
list.Add($"{ip} {domain}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list.Count <= 0)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
File.WriteAllLines(path, list.ToArray());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 公共代码
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取文件MD5(大写)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="fileName"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="Exception"></exception>
|
|
|
|
|
private static string GetMD5HashFromFile(string fileName)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
FileStream file = new FileStream(fileName, FileMode.Open);
|
|
|
|
|
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
|
|
|
|
|
byte[] retVal = md5.ComputeHash(file);
|
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
for (int i = 0; i < retVal.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
sb.Append(retVal[i].ToString("X2"));
|
|
|
|
|
}
|
|
|
|
|
return sb.ToString();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
|
|
|
|
|
private static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal class MouseHook
|
|
|
|
|
{
|
|
|
|
|
private const int WM_MOUSEMOVE = 0x200;
|
|
|
|
|
private const int WM_LBUTTONDOWN = 0x201;
|
|
|
|
|
private const int WM_RBUTTONDOWN = 0x204;
|
|
|
|
|
private const int WM_MBUTTONDOWN = 0x207;
|
|
|
|
|
private const int WM_LBUTTONUP = 0x202;
|
|
|
|
|
private const int WM_RBUTTONUP = 0x205;
|
|
|
|
|
private const int WM_MBUTTONUP = 0x208;
|
|
|
|
|
private const int WM_LBUTTONDBLCLK = 0x203;
|
|
|
|
|
private const int WM_RBUTTONDBLCLK = 0x206;
|
|
|
|
|
private const int WM_MBUTTONDBLCLK = 0x209;
|
|
|
|
|
|
|
|
|
|
//全局的事件
|
|
|
|
|
public event MouseEventHandler OnMouseActivity;
|
|
|
|
|
|
|
|
|
|
static int hMouseHook = 0; //鼠标钩子句柄
|
|
|
|
|
|
|
|
|
|
//鼠标常量
|
|
|
|
|
public const int WH_MOUSE_LL = 14; //mouse hook constant
|
|
|
|
|
|
|
|
|
|
HookProc MouseHookProcedure; //声明鼠标钩子事件类型.
|
|
|
|
|
|
|
|
|
|
//声明一个Point的封送类型
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
public class POINT
|
|
|
|
|
{
|
|
|
|
|
public int x;
|
|
|
|
|
public int y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//声明鼠标钩子的封送结构类型
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
|
|
|
public class MouseHookStruct
|
|
|
|
|
{
|
|
|
|
|
public POINT pt;
|
|
|
|
|
public int hWnd;
|
|
|
|
|
public int wHitTestCode;
|
|
|
|
|
public int dwExtraInfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//装置钩子的函数
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
|
|
|
|
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
|
|
|
|
|
|
|
|
|
|
//卸下钩子的函数
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
|
|
|
|
public static extern bool UnhookWindowsHookEx(int idHook);
|
|
|
|
|
|
|
|
|
|
//下一个钩挂的函数
|
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
|
|
|
|
|
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
|
|
|
|
|
|
|
|
|
|
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 墨认的构造函数构造当前类的实例.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public MouseHook()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//析构函数.
|
|
|
|
|
~MouseHook()
|
|
|
|
|
{
|
|
|
|
|
Stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Start()
|
|
|
|
|
{
|
|
|
|
|
//安装鼠标钩子
|
|
|
|
|
if (hMouseHook == 0)
|
|
|
|
|
{
|
|
|
|
|
//生成一个HookProc的实例.
|
|
|
|
|
MouseHookProcedure = new HookProc(MouseHookProc);
|
|
|
|
|
|
|
|
|
|
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);
|
|
|
|
|
|
|
|
|
|
//如果装置失败停止钩子
|
|
|
|
|
if (hMouseHook == 0)
|
|
|
|
|
{
|
|
|
|
|
Stop();
|
|
|
|
|
throw new Exception("SetWindowsHookEx failed.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Stop()
|
|
|
|
|
{
|
|
|
|
|
bool retMouse = true;
|
|
|
|
|
if (hMouseHook != 0)
|
|
|
|
|
{
|
|
|
|
|
retMouse = UnhookWindowsHookEx(hMouseHook);
|
|
|
|
|
hMouseHook = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//如果卸下钩子失败
|
|
|
|
|
if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
|
|
|
|
|
{
|
|
|
|
|
//如果正常运行并且用户要监听鼠标的消息
|
|
|
|
|
if ((nCode >= 0) && (OnMouseActivity != null))
|
|
|
|
|
{
|
|
|
|
|
MouseButtons button = MouseButtons.None;
|
|
|
|
|
int clickCount = 0;
|
|
|
|
|
|
|
|
|
|
switch (wParam)
|
|
|
|
|
{
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
button = MouseButtons.Left;
|
|
|
|
|
clickCount = 1;
|
|
|
|
|
break;
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
button = MouseButtons.Left;
|
|
|
|
|
clickCount = 1;
|
|
|
|
|
break;
|
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
|
|
|
button = MouseButtons.Left;
|
|
|
|
|
clickCount = 2;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
|
button = MouseButtons.Right;
|
|
|
|
|
clickCount = 1;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
|
button = MouseButtons.Right;
|
|
|
|
|
clickCount = 1;
|
|
|
|
|
break;
|
|
|
|
|
case WM_RBUTTONDBLCLK:
|
|
|
|
|
button = MouseButtons.Right;
|
|
|
|
|
clickCount = 2;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//从回调函数中得到鼠标的信息
|
|
|
|
|
MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
|
|
|
|
|
MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
|
|
|
|
|
//if(e.X>700)return 1;//如果想要限制鼠标在屏幕中的移动区域可以在此处设置
|
|
|
|
|
OnMouseActivity(this, e);
|
|
|
|
|
}
|
|
|
|
|
return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|