10
votes

Setwindowshookex en C #

J'essaie de gérer une application tierce de 3e partie afin que je puisse dessiner à son écran. Dessin à l'écran est facile, et je n'ai besoin d'aucune aide avec elle, mais je semble avoir des problèmes avec l'utilisation de Setwindowshookex code> pour gérer wh_getmessage code>. Je ne peux pas comprendre ce qu'il faut passer pour les deux derniers paramètres.

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


0 commentaires

7 Réponses :


3
votes

Je pense que vous devez avoir besoin de p / invoquer < Code> getModulehandle et utilisez la poignée qu'elle renvoie pour le troisième paramètre de SetwindowshookeX . Je crois aussi 0 est correct pour le quatrième paramètre, car vous ne souhaitez pas accrocher à un thread spécifique dans l'application tiers.

Si cela ne fonctionne pas pour vous, SetWindowshookex sur MSDN pourrait vous pointer dans la bonne direction.


2 commentaires

GetModulehandle (string lpmodulename); Qu'est-ce que je passe? Le nom EXE?


Pass null et il apportera la poignée du processus d'appel (votre exécutable.)



15
votes

Setwindowshookex Spécifie les deux derniers paramètres Ainsi:

  • hmod

    [in] poignée à la DLL contenant le Procédure de crochet pointée par la LPFN paramètre. Le paramètre HMOD doit être se mettre sur null si le DWthreadId paramètre spécifie un thread créé par le processus actuel et si le crochet la procédure est dans le code associé au processus actuel.

    • dwthreadide

      [in] Spécifie l'identifiant de la fil avec lequel la procédure de crochet doit être associé. Si ce paramètre est zéro, la procédure de crochet est associé à tous les threads existants courir dans le même bureau que le Appelant le fil.

      Je ne suis pas sûr que vous puissiez utiliser une DLL .NET dans la manière requise, mais vous pouvez certainement essayer.

      grab hmod via Marshal.GethInstance (typeof (form1) .Module) et dwthread indicateur via Process.Threads . Alternativement, définissez dwtheadid à 0 si vous souhaitez un crochet global (c.-à-d. Un crochet pour tous getMessage () appels dans le bureau actuel) mais méfiez-vous des pénalités de performance. < / p>


5 commentaires

J'ai modifié le code ci-dessus pour refléter votre idée. Je reçois toujours Setwindowshookeex (Wh_getMessage, PaintHookProcoDure, Hmod, Threadid) == 0;


Il existe une possibilité distincte que vous devez emballer votre painthookprocédrique dans une DLL séparée; qui empêche l'utilisation de .NET. Prenez le code de message d'erreur avec GetLasterRor (), et voyez quel est le problème.


Et par getlasterror () je veux dire marshal.getlastwin32Error (); p / invoquant getlasterror () est directement peu fiable.


GetLasterRor retourne 1428. C'est un HMOD invalide. Des idées?


Vérifiez si le retour de marshal.Gethinstance est -1. Si tel est le cas, vous devez déplacer votre processus de crochet dans une DLL, ce qui signifie que vous devez l'écrire dans un code non géré.



3
votes

Je ne sais pas, mais si vous utilisez des valeurs de paramètre qui spécifient que vous souhaitez, comme l'aide de l'API indique, "injecte une DLL dans un autre processus", alors pour tout ce que je sais que cela ne fonctionnerait que si vous écrivez. une DLL non gérée de laquelle l'appeller.


0 commentaires

3
votes

Je sais que c'est une vieille question mais j'espère qu'il y a toujours quelqu'un qui trouvera cela utile. Je pense que vous mélangez int et intptr xxx


0 commentaires

9
votes

Ce qui suit suggère cela ne fonctionnera pas:

"Les crochets globaux ne sont pas pris en charge dans la framework .NET. À l'exception du crochet de bas niveau WH_Keyboard_LL et du crochet de faible niveau WH_Keyboard_LL, vous ne pouvez pas implémenter des crochets globaux dans le cadre Microsoft .NET."

de "Comment définir un crochet Windows dans Visual C # .NET"



1
votes

Ce travail pour moi utilisez 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);
            }
        }


1 commentaires

Hooktype.whw_keyboard_llboard = 13



1
votes
  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
  }
Global hooks are not supported in the .NET FrameworkExcept for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework.To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export.The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically.Low-level hook procedures are called on the thread that installed the hook. Low-level hooks do not require that the hook procedure be implemented in a DLL.See also:
Snoop - The WPF Spy UtilityOr my WPF => WF => Win32 LL_Keyboard Hook Proxy w/ Gestures

0 commentaires