SetWindowsHookEx в C # - PullRequest
       29

SetWindowsHookEx в C #

10 голосов
/ 28 ноября 2009

Я пытаюсь подключить стороннее приложение, чтобы рисовать на его экране. Рисовать на экране легко, и мне не нужна помощь, но у меня, похоже, возникают проблемы с использованием SetWindowsHookEx для обработки WH_GETMESSAGE. Я не могу понять, что передать последним двум параметрам.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowDrawer
{
    public partial class Form1 : Form
    {
        private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
        static IntPtr hHook;
        IntPtr windowHandle;
        uint processHandle;

        HookProc PaintHookProcedure;     

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
        static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
        static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        // When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        [System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet =System.Runtime.InteropServices.CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        { 
            PaintHookProcedure = new HookProc(PaintHookProc);
            windowHandle = FindWindowByCaption(0, "Untitled - Notepad");
            uint threadID = GetWindowThreadProcessId(windowHandle, out processHandle);
            IntPtr hMod = System.Runtime.InteropServices.Marshal.GetHINSTANCE(typeof(Form1).Module);

            // HERE IS THE PROBLEM.  WHAT THE HECK DO I PASS INTO THE LAST 2 PARAMS?  I get a null pointer
            hHook = SetWindowsHookEx(WH_GETMESSAGE, PaintHookProcedure, hMod, threadID);
        }

        public int PaintHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
           // Do some painting here.
            return CallNextHookEx(hHook, nCode, wParam, lParam); 
        }

        private const int WM_PAINT = 15;
        private const int WH_GETMESSAGE = 3;
    }
}

Ответы [ 7 ]

15 голосов
/ 28 ноября 2009

SetWindowsHookEx , таким образом, определяет два последних параметра:

  • hMod

[in] Дескриптор библиотеки DLL, содержащей процедура подключения, на которую указывает lpfn параметр. Параметр hMod должен быть установить в NULL, если dwThreadId параметр указывает созданный поток текущим процессом и если хук процедура в коде связанный с текущим процессом.

  • dwThreadId

[in] Определяет идентификатор нить, с которой перехватывается процедура должен быть связан. Если этот параметр ноль, процедура подключения связан со всеми существующими потоками работает на том же рабочем столе, что и вызывающая нить.

Я не уверен, что вы можете использовать .NET dll требуемым образом, но вы, безусловно, можете попробовать.

Grab hMod через Marshal.GetHINSTANCE (typeof (Form1) .Module) и dwThreadId через Process.Threads . В качестве альтернативы, установите dwThreadId в 0, если вы хотите глобальную перехват (то есть перехват для всех вызовов GetMessage() на текущем рабочем столе), но остерегайтесь снижения производительности.

9 голосов
/ 27 марта 2013

Следующее предполагает, что это не будет работать:

"Глобальные хуки не поддерживаются в .NET Framework. За исключением низкоуровневой хуков WH_KEYBOARD_LL и низкоуровневой хуков WH_MOUSE_LL, вы не можете реализовать глобальные хуки в Microsoft .NET Framework."

С "Как установить хук Windows в Visual C # .NET"

3 голосов
/ 28 ноября 2009

Я не знаю, но если вы используете значения параметров, которые указывают, что вы хотите, как подсказывает API, «вставить DLL в другой процесс», то, насколько я знаю, это может сработать, только если вы напишитенеуправляемая DLL, из которой она вызывается.

3 голосов
/ 28 ноября 2009

Полагаю, вам нужно P / Invoke GetModuleHandle и использовать дескриптор, который он возвращает для третьего параметра SetWindowsHookEx. Я также считаю, что 0 является верным для четвертого параметра, поскольку вы не хотите подключать какой-либо конкретный поток в стороннем приложении.

Если это не работает для вас, SetWindowsHookEx на MSDN может указать вам правильное направление.

2 голосов
/ 03 января 2012

Я знаю, что это старый вопрос, но я надеюсь, что есть еще кто-то, кто найдет это полезным. Я думаю, что вы смешиваете int и IntPtr

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
1 голос
/ 18 ноября 2016

Эта работа для меня использовать 13 ...

 private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(13, proc,
                GetModuleHandle(curModule.ModuleName), 0);
            }
        }
0 голосов
/ 24 апреля 2019
  internal enum HookType : uint {
    WH_JOURNALRECORD = 0,
    WH_JOURNALPLAYBACK = 1,
    WH_KEYBOARD = 2,
    WH_GETMESSAGE = 3,
    WH_CALLWNDPROC = 4,
    WH_CBT = 5,
    WH_SYSMSGFILTER = 6,
    WH_MOUSE = 7,
    WH_HARDWARE = 8,
    WH_DEBUG = 9,
    WH_SHELL = 10,
    WH_FOREGROUNDIDLE = 11,
    WH_CALLWNDPROCRET = 12,
    WH_KEYBOARD_LL = 13,
    WH_MOUSE_LL = 14
  }

Глобальные хуки не поддерживаются в .NET Framework

За исключением низкоуровневого хука WH_KEYBOARD_LL и низкоуровневого хука WH_MOUSE_LL, вы не можете реализовать глобальные хуки в Microsoft .NET Framework.

Чтобы установить глобальный хук, хук должен иметь собственный экспорт DLL, чтобы внедрить себя в другой процесс, для которого требуется допустимая, согласованная функция для вызова. Это поведение требует экспорта DLL.

.NET Framework не поддерживает экспорт DLL. Управляемый код не имеет понятия согласованного значения для указателя на функцию, поскольку эти указатели на функции являются прокси, которые создаются динамически.

Процедуры низкоуровневого перехвата вызываются на нити, в которой установлен перехватчик. Низкоуровневые хуки не требуют, чтобы процедура хуков была реализована в DLL.

Смотри также: Snoop - Утилита WPF Spy

Или мой WPF => WF => Win32 LL_Keyboard Hook Proxy с жестами

...