SetWindowsHookEx в C#

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

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





}

6 ответов


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

  • hMod

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

  • dwThreadId

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

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

схватила hMod через Маршал.GetHINSTANCE (typeof (Form1).Модуль) и dwThreadId via


далее предполагает, что это не сработает:

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

с "как установить крючок Windows в Visual C# .NET"


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


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

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


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

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

эта работа для меня 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);
            }
        }