Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm trying to hook the creation of a windows in my C# app.

static IntPtr hhook = IntPtr.Zero;
static NativeMethods.HookProc hhookProc;

static void Main(string[] args)
{
    // Dummy.exe is a form with a button that opens a MessageBox when clicking on it.
    Process dummy = Process.Start(@"Dummy.exe");

    try
    {
        hhookProc = new NativeMethods.HookProc(Hook);
        IntPtr hwndMod = NativeMethods.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
        hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, hwndMod, (uint)AppDomain.GetCurrentThreadId());

        Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);

        while (!dummy.HasExited)
            dummy.WaitForExit(500);                
    }
    finally
    {
        if(hhook != IntPtr.Zero)
            NativeMethods.UnhookWindowsHookEx(hhook);
    }
}

static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
{
    Console.WriteLine("Hook()");
    return NativeMethods.CallNextHookEx(hhook, nCode, wParam, lParam);
}

Problem is, when clicking on my button (in Dummy.exe), I never enter in my Hook, what am I doing wrong?

Thanks.


EDIT

Program.cs

using System;
using System.Diagnostics;

namespace Hooker
{
    class Program
    {
        static IntPtr hhook = IntPtr.Zero;
        static NativeMethods.HookProc hhookProc;

        static void Main(string[] args)
        {
            Process dummy = Process.Start(@"Dummy.exe");

            try
            {
                hhookProc = new NativeMethods.HookProc(Hook);
                hhook = NativeMethods.SetWindowsHookEx(HookType.WH_CBT, hhookProc, IntPtr.Zero, 0);

                Console.WriteLine("hhook valid? {0}", hhook != IntPtr.Zero);

                while (!dummy.HasExited)
                    dummy.WaitForExit(500);                
            }
            finally
            {
                if(hhook != IntPtr.Zero)
                    NativeMethods.UnhookWindowsHookEx(hhook);
            }
        }

        static int Hook(int nCode, IntPtr wParam, IntPtr lParam)
        {
            Console.WriteLine("Hook()");
            return NativeMethods.CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
        }
    }
}

NativeMethods.cs

namespace Hooker
{
    using System;
    using System.Runtime.InteropServices;

    internal static class NativeMethods
    {
        public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, int dwThreadId);
        [DllImport("user32.dll")]
        public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int pid);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);
    }
}

For dummy, do a new Form with :

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        MessageBox.Show("CONTENT", "TITLE");
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
295 views
Welcome To Ask or Share your Answers For Others

1 Answer

Like most SetWindowsHookEx hooks, WH_CBT hooks require that the hook callback lives in a separate Win32 DLL that will get loaded into the target process. This essentially requires that the hook is written in C/C++, C# won't work here.

(Low-level mouse and keyboard hooks are two exceptions to this rule. It might also be possible to use other hooks in C# but only if you are hooking one of your own threads, so dwThreadId is the id of a thread in the current process, not 0. I haven't confirmed this, though. And you need to make sure you're using the Win32 threadid, so using GetCurrentThreadId is probably the best bet here.)

If you want to watch for new windows appearing from another app, an alternative C#-friendly approach is to use the SetWinEventHook API instead, specify WINEVENT_OUTOFCONTEXT (which is the magic flag that gets the events delivered to your own process, removing the need for a DLL and making C# usable here) and hook for the EVENT_OBJECT_CREATE and EVENT_OBJECT_SHOW events. You can listen to either your own process/thread's events, or to all processes/threads on the current desktop.

This will get you all sorts of "create" and show notifications, including those for child HWNDs within dialog, and even items within listboxes and similar; so you'll need to filter to extract only those for top-level HWNDs: eg. check that idObject==OBJID_WINDOW and idChild==0; that hwnd is visible (IsVisible()) and is top-level.

Note that using WinEvents requires that the thread that calls SetWinEventHook is pumping messages - which is typically the case anyway if it's a thread with UI. If not, you may need to add a message loop (GetMessage/TranslateMessage) manually. And you'll also want to use GC.KeepAlive() with the callback here also to prevent it from getting collected until after you call UnhookWinEvents.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...