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);
}
}