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;
}
}
7 Réponses :
Je pense que vous devez avoir besoin de p / invoquer < Code> getModulehandle code> et utilisez la poignée qu'elle renvoie pour le troisième paramètre de Si cela ne fonctionne pas pour vous, SetwindowshookeX code>. Je crois aussi
0 code> est correct pour le quatrième paramètre, car vous ne souhaitez pas accrocher à un thread spécifique dans l'application tiers. P>
SetWindowshookex code>
sur MSDN pourrait vous pointer dans la bonne direction. P>
GetModulehandle (string lpmodulename); Qu'est-ce que je passe? Le nom EXE?
Pass null code> et il apportera la poignée du processus d'appel (votre exécutable.)
Setwindowshookex Spécifie les deux derniers paramètres Ainsi: p>
hmod code> li>
ul>
[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. p>
blockQuote>
-
dwthreadide code> li>
ul>
[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. P>
blockQuote>
Je ne suis pas sûr que vous puissiez utiliser une DLL .NET dans la manière requise, mais vous pouvez certainement essayer. P>
grab hmod code> via Marshal.GethInstance (typeof (form1) .Module) et dwthread indicateur code> via Process.Threads . Alternativement, définissez dwtheadid code> à 0 si vous souhaitez un crochet global (c.-à-d. Un crochet pour tous getMessage () code> appels dans le bureau actuel) mais méfiez-vous des pénalités de performance. < / p>
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 code> 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é.
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. p>
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 code> et
intptr code>
Ce qui suit suggère cela ne fonctionnera pas: p>
"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." P> blockQuote>
de "Comment définir un crochet Windows dans Visual C # .NET" A > p>
Il y a une solution de contournement: codeProject.com / Articles / 18638 / ... Je suppose qu'il est préférable d'écrire 2 dlls en C ++.
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); } }
Hooktype.whw_keyboard_llboard = 13
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