SetWindowsHookEx을 사용하면 (특정) Windows 메시지를 수신하기 위해 낮은 수준의 후크를 설정할 수 있습니다. 특히 이러한 후크 ID는 모니터링을 위해 재미있을 수 있습니다
는
WH_CALLWNDPROC
(4) 시스템이 대상 창 프로 시저로 전송하기 전에 메시지를 을 모니터링하는 후크 프로 시저를 설치합니다. 에 대한 자세한 내용은 CallWndProc 후크 절차를 참조하십시오.
WH_CALLWNDPROCRET
(12) 메시지가 대상 창 절차에 의해 처리 된 후이를 모니터링하는 후크 프로 시저를 설치합니다. 자세한 내용은 CallWndRetProc 후크 절차를 참조하십시오.
구현 한 지 오래되었지만 예를 들어 특정 메시지를 연결하는 데 사용하는 기본 클래스를 게시했습니다. (예를 들어, 글로벌 마우스 휠 트래퍼에서 사용하여 winforms 앱이 인터넷 익스플로러와 똑같이 작동하는지 확인합니다 : 활성 컨트롤 대신 커서 아래로 스크롤하십시오).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Subro.Win32;
namespace Subro
{
/// <summary>
/// Base class to relatively safely register global windows hooks
/// </summary>
public abstract class GlobalHookTrapper : FinalizerBase
{
[DllImport("user32", EntryPoint = "SetWindowsHookExA")]
static extern IntPtr SetWindowsHookEx(int idHook, Delegate lpfn, IntPtr hmod, IntPtr dwThreadId);
[DllImport("user32", EntryPoint = "UnhookWindowsHookEx")]
private static extern int UnhookWindowsHookEx(IntPtr hHook);
[DllImport("user32", EntryPoint = "CallNextHookEx")]
static extern int CallNextHook(IntPtr hHook, int ncode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThreadId();
IntPtr hook;
public readonly int HookId;
public readonly GlobalHookTypes HookType;
public GlobalHookTrapper(GlobalHookTypes Type):this(Type,false)
{
}
public GlobalHookTrapper(GlobalHookTypes Type, bool OnThread)
{
this.HookType = Type;
this.HookId = (int)Type;
del = ProcessMessage;
if (OnThread)
hook = SetWindowsHookEx(HookId, del, IntPtr.Zero, GetCurrentThreadId());
else
{
var hmod = IntPtr.Zero; // Marshal.GetHINSTANCE(GetType().Module);
hook = SetWindowsHookEx(HookId, del, hmod, IntPtr.Zero);
}
if (hook == IntPtr.Zero)
{
int err = Marshal.GetLastWin32Error();
if (err != 0)
OnHookFailed(err);
}
}
protected virtual void OnHookFailed(int Error)
{
throw Win32Functions.TranslateError(Error);
}
private const int HC_ACTION = 0;
[MarshalAs(UnmanagedType.FunctionPtr)]
private MessageDelegate del;
private delegate int MessageDelegate(int code, IntPtr wparam, IntPtr lparam);
private int ProcessMessage(int hookcode, IntPtr wparam, IntPtr lparam)
{
if (HC_ACTION == hookcode)
{
try
{
if (Handle(wparam, lparam)) return 1;
}
catch { }
}
return CallNextHook(hook, hookcode, wparam, lparam);
}
protected abstract bool Handle(IntPtr wparam, IntPtr lparam);
protected override sealed void OnDispose()
{
UnhookWindowsHookEx(hook);
AfterDispose();
}
protected virtual void AfterDispose()
{
}
}
public enum GlobalHookTypes
{
BeforeWindow = 4, //WH_CALLWNDPROC
AfterWindow = 12, //WH_CALLWNDPROCRET
KeyBoard = 2, //WH_KEYBOARD
KeyBoard_Global = 13, //WH_KEYBOARD_LL
Mouse = 7, //WH_MOUSE
Mouse_Global = 14, //WH_MOUSE_LL
JournalRecord = 0, //WH_JOURNALRECORD
JournalPlayback = 1, //WH_JOURNALPLAYBACK
ForeGroundIdle = 11, //WH_FOREGROUNDIDLE
SystemMessages = 6, //WH_SYSMSGFILTER
MessageQueue = 3, //WH_GETMESSAGE
ComputerBasedTraining = 5, //WH_CBT
Hardware = 8, //WH_HARDWARE
Debug = 9, //WH_DEBUG
Shell = 10, //WH_SHELL
}
public abstract class FinalizerBase : IDisposable
{
protected readonly AppDomain domain;
public FinalizerBase()
{
System.Windows.Forms.Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
domain = AppDomain.CurrentDomain;
domain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
domain.DomainUnload += new EventHandler(domain_DomainUnload);
}
private bool disposed;
public bool IsDisposed{get{return disposed;}}
public void Dispose()
{
if (!disposed)
{
GC.SuppressFinalize(this);
if (domain != null)
{
domain.ProcessExit -= new EventHandler(CurrentDomain_ProcessExit);
domain.DomainUnload -= new EventHandler(domain_DomainUnload);
System.Windows.Forms.Application.ApplicationExit -= new EventHandler(Application_ApplicationExit);
}
disposed = true;
OnDispose();
}
}
void Application_ApplicationExit(object sender, EventArgs e)
{
Dispose();
}
void domain_DomainUnload(object sender, EventArgs e)
{
Dispose();
}
void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
Dispose();
}
protected abstract void OnDispose();
/// Destructor
~FinalizerBase()
{
Dispose();
}
}
}
# 할 수 없습니다. C++은 가능합니다. – Alex
@alex - 왜 이렇게 할 수 없습니까? –
@ DanielA.White 플랫폼 메시지 대기열은 내가 이해하는 한 원시 코드에서만 처리 할 수 있으므로 C#이 처리 할 수있는 것처럼 들리지는 않습니다 (관리되고 모든 것) ... 나는 더 행복 할 것 같습니다. 만약 내가 틀렸다면 다른 것을 알고 있다면 당신은 (내가 꽤 오랫동안 소용이없는 주제를 직접 연구 해왔다.) – Alex