Pregunta

Estoy intentando enganchar una aplicación de terceros para poder dibujar en su pantalla. Dibujar a la pantalla es fácil, y no necesito ayuda con eso, pero parece que tengo problemas con el uso de SetWindowsHookEx para manejar WH_GETMESSAGE . No puedo averiguar qué pasar por los dos últimos parámetros.

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;
    }
}
¿Fue útil?

Solución

SetWindowsHookEx especifica los dos últimos parámetros por lo tanto :

  • hMod
  

[in] Manejar a la DLL que contiene el   procedimiento de gancho apuntado por el lpfn   parámetro. El parámetro hMod debe ser   establecer en NULL si el dwThreadId   parámetro especifica un hilo creado   por el proceso actual y si el gancho   el procedimiento está dentro del código   asociado con el proceso actual.

  • dwThreadId
  

[in] Especifica el identificador de la   Hilo con el que el procedimiento de gancho.   es estar asociado. Si este parametro   es cero, el procedimiento de gancho es   asociado con todos los hilos existentes   corriendo en el mismo escritorio que el   hilo de llamada.

No estoy seguro de que puedas usar un archivo .NET de la manera requerida, pero puedes intentarlo.

Agarre hMod a través de Marshal.GetHINSTANCE (typeof (Form1) .Module) y dwThreadId a través de Process.Threads . Alternativamente, configure dwThreadId en 0 si desea un enlace global (es decir, un enlace para todas las llamadas de GetMessage () en el escritorio actual) pero tenga cuidado con las penalizaciones de rendimiento.

Otros consejos

Lo siguiente sugiere que esto no funcionará:

  

" Los enlaces globales no son compatibles con .NET Framework. Excepto por el gancho de bajo nivel WH_KEYBOARD_LL y el gancho de bajo nivel WH_MOUSE_LL, no puede implementar ganchos globales en Microsoft .NET Framework. & Quot;

De " Cómo establecer un enlace de Windows en Visual C # .NET "

Creo que necesitas P / Invocar < código> GetModuleHandle y use el identificador que devuelve para el tercer parámetro de SetWindowsHookEx . También creo que 0 es correcto para el cuarto parámetro, ya que no desea enganchar ningún hilo específico en la aplicación de terceros.

Si esto no funciona para usted, SetWindowsHookEx en MSDN puede apuntarle en la dirección correcta.

No lo sé, pero si estás usando valores de parámetros que especifican que quieres, como dice la API, "inyectar una DLL en otro proceso", entonces, por lo que sé, podría funcionar solo si escriba un archivo DLL no administrado desde el que lo llame.

Sé que esta es una pregunta antigua, pero espero que todavía haya alguien que la encuentre útil. Creo que estás mezclando int y IntPtr

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

Este trabajo para mí usa 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);
            }
        }
  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
  }

Los enlaces globales no son compatibles con .NET Framework

Excepto por el enlace de bajo nivel WH_KEYBOARD_LL y el enlace de bajo nivel WH_MOUSE_LL, no puede implementar enlaces globales en Microsoft .NET Framework.

Para instalar un enlace global, un enlace debe tener una exportación DLL nativa para inyectarse en otro proceso que requiera una función consistente y válida a la que llamar. Este comportamiento requiere una exportación de DLL.

.NET Framework no admite exportaciones de DLL. El código administrado no tiene un concepto de valor consistente para un puntero de función porque estos punteros de función son proxies que se crean dinámicamente.

Los procedimientos de enganche de bajo nivel se llaman en el hilo que instaló el enganche. Los enganches de bajo nivel no requieren que el procedimiento de enganche se implemente en una DLL.

Ver también: Snoop : la utilidad de espionaje de WPF

O mi WPF = > WF = > Win32 LL_Keyboard Hook Proxy w / Gestures

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top