250 lines
8.3 KiB
C#
250 lines
8.3 KiB
C#
using System;
|
|
using System.Windows.Forms;
|
|
using System.Collections;
|
|
using System.Threading;
|
|
using System.Drawing;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace DevComponents.DotNetBar
|
|
{
|
|
/// <summary>
|
|
/// Summary description for MessageHandler.
|
|
/// </summary>
|
|
internal class NonClientHook
|
|
{
|
|
private static ArrayList m_Clients = new ArrayList();
|
|
private static Hashtable m_FilterOnThread = new Hashtable();
|
|
private static ReaderWriterLock rwClientsListLock;
|
|
private static MouseProc m_MouseHook = null;
|
|
|
|
private delegate IntPtr MouseProc(int nCode, IntPtr wParam, IntPtr lParam);
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
private static extern IntPtr SetWindowsHookEx(int hookid, MouseProc pfnhook, IntPtr hinst, int threadid);
|
|
|
|
//[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, EntryPoint = "SetWindowsHookEx")]
|
|
//private static extern IntPtr SetWindowsHookExKeyboard(int hookid, KeyboardProc pfnhook, IntPtr hinst, int threadid);
|
|
|
|
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
|
|
private static extern bool UnhookWindowsHookEx(IntPtr hhook);
|
|
|
|
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
|
|
private static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wparam, IntPtr lparam);
|
|
[DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
|
|
private static extern int GetCurrentThreadId();
|
|
|
|
private const int WH_MOUSE = 7;
|
|
private const int HC_ACTION = 0;
|
|
private const int WH_CALLWNDPROCRET = 12;
|
|
private const int WH_CALLWNDPROC = 4;
|
|
|
|
// Methods
|
|
static NonClientHook()
|
|
{
|
|
NonClientHook.rwClientsListLock = new ReaderWriterLock();
|
|
m_MouseHook = new MouseProc(OnMouseHook);
|
|
}
|
|
|
|
public static void RegisterHook(ISkinHook client)
|
|
{
|
|
if (m_Clients.Contains(client))
|
|
return;
|
|
|
|
if (!m_FilterOnThread.ContainsKey(System.Threading.Thread.CurrentThread.GetHashCode()))
|
|
HookThread();
|
|
|
|
LockCookie cookie1 = new LockCookie();
|
|
bool readerLockHeld = NonClientHook.rwClientsListLock.IsReaderLockHeld;
|
|
|
|
if (readerLockHeld)
|
|
{
|
|
cookie1 = NonClientHook.rwClientsListLock.UpgradeToWriterLock(-1);
|
|
}
|
|
else
|
|
{
|
|
NonClientHook.rwClientsListLock.AcquireWriterLock(-1);
|
|
}
|
|
|
|
try
|
|
{
|
|
m_Clients.Add(client);
|
|
}
|
|
finally
|
|
{
|
|
if (readerLockHeld)
|
|
{
|
|
NonClientHook.rwClientsListLock.DowngradeFromWriterLock(ref cookie1);
|
|
}
|
|
else
|
|
{
|
|
NonClientHook.rwClientsListLock.ReleaseWriterLock();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void UnregisterHook(ISkinHook client)
|
|
{
|
|
if (m_Clients.Contains(client))
|
|
{
|
|
LockCookie cookie1 = new LockCookie();
|
|
bool readerLockHeld = NonClientHook.rwClientsListLock.IsReaderLockHeld;
|
|
|
|
if (readerLockHeld)
|
|
{
|
|
cookie1 = NonClientHook.rwClientsListLock.UpgradeToWriterLock(-1);
|
|
}
|
|
else
|
|
{
|
|
NonClientHook.rwClientsListLock.AcquireWriterLock(-1);
|
|
}
|
|
|
|
try
|
|
{
|
|
m_Clients.Remove(client);
|
|
if (m_Clients.Count == 0)
|
|
UnHookThread();
|
|
}
|
|
finally
|
|
{
|
|
if (readerLockHeld)
|
|
{
|
|
NonClientHook.rwClientsListLock.DowngradeFromWriterLock(ref cookie1);
|
|
}
|
|
else
|
|
{
|
|
NonClientHook.rwClientsListLock.ReleaseWriterLock();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void HookThread()
|
|
{
|
|
if (m_FilterOnThread.ContainsKey(System.Threading.Thread.CurrentThread.GetHashCode()))
|
|
return;
|
|
|
|
int id = GetCurrentThreadId();
|
|
IntPtr hook = SetWindowsHookEx(WH_MOUSE, m_MouseHook, IntPtr.Zero, id);
|
|
m_FilterOnThread.Add(System.Threading.Thread.CurrentThread.GetHashCode(), hook);
|
|
}
|
|
|
|
private static void UnHookThread()
|
|
{
|
|
if (!m_FilterOnThread.ContainsKey(System.Threading.Thread.CurrentThread.GetHashCode()))
|
|
return;
|
|
IntPtr hook = (IntPtr)m_FilterOnThread[System.Threading.Thread.CurrentThread.GetHashCode()];
|
|
UnhookWindowsHookEx(hook);
|
|
m_FilterOnThread.Remove(System.Threading.Thread.CurrentThread.GetHashCode());
|
|
}
|
|
|
|
private static ISkinHook[] GetMessageClients()
|
|
{
|
|
ISkinHook[] messageClients;
|
|
NonClientHook.rwClientsListLock.AcquireReaderLock(-1);
|
|
try
|
|
{
|
|
messageClients = (ISkinHook[])m_Clients.ToArray(typeof(ISkinHook));
|
|
}
|
|
finally
|
|
{
|
|
NonClientHook.rwClientsListLock.ReleaseReaderLock();
|
|
}
|
|
|
|
return messageClients;
|
|
}
|
|
|
|
private static unsafe IntPtr OnMouseHook(int nCode, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
try
|
|
{
|
|
if (nCode == HC_ACTION)
|
|
{
|
|
int wParamInt = WinApi.ToInt(wParam);
|
|
if (wParamInt == (int)WinApi.WindowsMessages.WM_MOUSEMOVE)
|
|
{
|
|
MOUSEHOOKSTRUCT* ws = (MOUSEHOOKSTRUCT*)lParam;
|
|
PostMouseMove(ws->hwnd, ws->pt.ToPoint());
|
|
}
|
|
if (wParamInt == (int)WinApi.WindowsMessages.WM_LBUTTONUP)
|
|
{
|
|
MOUSEHOOKSTRUCT* ws = (MOUSEHOOKSTRUCT*)lParam;
|
|
PostMouseUp(ws->hwnd, ws->pt.ToPoint());
|
|
}
|
|
//CWPRETSTRUCT* ws = (CWPRETSTRUCT*)lParam;
|
|
//if (ws->message == (uint)WinApi.WindowsMessages.WM_MOUSEMOVE || ws->message == 0x118)
|
|
//{
|
|
// PostMouseMove(ws->hwnd, ws->wParam, ws->lParam);
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
|
|
IntPtr h = (IntPtr)m_FilterOnThread[System.Threading.Thread.CurrentThread.GetHashCode()];
|
|
IntPtr res = CallNextHookEx(h, nCode, wParam, lParam);
|
|
|
|
return res;
|
|
}
|
|
catch
|
|
{ }
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
public static bool PostMouseMove(IntPtr hWnd, Point mousePos)
|
|
{
|
|
ISkinHook[] messageClients = GetMessageClients();
|
|
foreach (ISkinHook client in messageClients)
|
|
{
|
|
client.PostMouseMove(hWnd, mousePos);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool PostMouseUp(IntPtr hWnd, Point mousePos)
|
|
{
|
|
ISkinHook[] messageClients = GetMessageClients();
|
|
foreach (ISkinHook client in messageClients)
|
|
{
|
|
client.PostMouseUp(hWnd, mousePos);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private struct POINT
|
|
{
|
|
public POINT(int x, int y)
|
|
{
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
public int x;
|
|
public int y;
|
|
|
|
public Point ToPoint()
|
|
{
|
|
return new Point(x, y);
|
|
}
|
|
}
|
|
private struct MOUSEHOOKSTRUCT
|
|
{
|
|
public MOUSEHOOKSTRUCT(POINT pt, IntPtr hwnd, ushort wHitTestCode, IntPtr dwExtraInfo)
|
|
{
|
|
this.pt = pt;
|
|
this.hwnd = hwnd;
|
|
this.wHitTestCode = wHitTestCode;
|
|
this.dwExtraInfo = dwExtraInfo;
|
|
}
|
|
public POINT pt;
|
|
public IntPtr hwnd;
|
|
public ushort wHitTestCode;
|
|
public IntPtr dwExtraInfo;
|
|
}
|
|
}
|
|
|
|
internal interface ISkinHook
|
|
{
|
|
void PostMouseMove(IntPtr hWnd, Point mousePos);
|
|
void PostMouseUp(IntPtr hWnd, Point mousePos);
|
|
}
|
|
}
|