I am trying to create a project that can detect when a taskbar icon is flashing. You typically do this by creating a hook into the application and checking for the appropriate message. In this case, the message can be detected by creating a WH_SHELL hook into the application, waiting for a HSHELL_REDRAW message and checking the lParam variable for TRUE.
According to the documents, if the lParam value is true, then the window referenced by the window handle in the wParam variable is flashing. Great.
The problem is I cannot, for the life of me, figure out how to actually create a WH_SHELL hook. The code to create a hook seems fairly straightforward:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
class Flashy {
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
protected static extern IntPtr SetWindowsHookEx(int code, HookProc func, IntPtr hInstance, int threadID);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
private int WH_SHELL = 10;
static IntPtr hHook;
public void doStuff() {
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
IntPtr hModule = GetModuleHandle(module.ModuleName);
MyDLL.Class1.hHook = SetWindowsHookEx(WH_SHELL, MyDLL.Class1.MyHookProc, hModule, 0);
}
}
}
Now, from what I've read, the WH_SHELL requires a dll. So mine looks like:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace FlashyDLL
{
public class Class1
{
//This is the Import for the CallNextHookEx function.
//Use this function to pass the hook information to the next hook procedure in chain.
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
public static IntPtr hHook;
public static int MyHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
return CallNextHookEx(hHook, nCode, wParam, lParam);
switch (nCode)
{
case 6: //HSHELL_REDRAW
break;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
}
So what am I doing wrong? Thanks!
*Edit:
Here's the final bits of code that worked. It's basically the code from the accepted answer with a few minor additions. I'm posting it this way because I hate trying to piece together bits of code from various portions of the thread and I figure other people do, too.
Note that this is a global shell hook, not an application specific one, so you have to check the lParam handle against the handle you're looking for to ensure the flash message is about the correct window.
Step 1: window to pick up messages:
using System;
using System.Windows.Forms;
public class TestAlertForm : Form
{
private IntPtr myWindow;
private int uMsgNotify = 0;
readonly IntPtr HSHELL_FLASH = new IntPtr(0x8006);
protected override void WndProc(ref Message m)
{
if (m.Msg == uMsgNotify)
{
if (m.WParam == HSHELL_FLASH)
{
if (m.LParam == myWindow)
{
MessageBox.Show("FLASH!");
}
}
}
base.WndProc(ref m);
}
}
Step 2: PInvokes:
public class Win32 {
[DllImport("user32.dll", EntryPoint = "RegisterWindowMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int RegisterWindowMessage(string lpString);
[DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int RegisterShellHookWindow(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern System.IntPtr FindWindowByCaption(int ZeroOnly, string lpWindowName);
}
Step 3: Activate the hook:
var taf = new TestAlertForm();
myWindow = FindWindowByCaption(0, "My Window Title");
uMsgNotify = RegisterWindowMessage("SHELLHOOK");
Win32.RegisterShellHookWindow(taf.Handle);
C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...
Open Visual Studio, and choose Create a new project in the Start window. In the Create a new project window, select All languages, and then choose C# from the dropdown list. Choose Windows from the All platforms list, and choose Console from the All project types list.
The C# programming language was designed by Anders Hejlsberg from Microsoft in 2000 and was later approved as an international standard by Ecma (ECMA-334) in 2002 and ISO/IEC (ISO/IEC 23270) in 2003. Microsoft introduced C# along with .NET Framework and Visual Studio, both of which were closed-source.
OK, turns out this is a bit tricky in .Net -- but it is possible.
You can use SetWindowsHookEx
to hook directly to a single thread by ID, but this way is a bit simpler and easier to match to a window.
Caveat: This relies on an internal USER32.dll
call.
Step 1: window to pick up messages:
using System;
using System.Windows.Forms;
public class TestAlertForm : Form
{
readonly IntPtr HSHELL_FLASH = new IntPtr(0x8006);
protected override void WndProc(ref Message m)
{
if (m.WParam == HSHELL_FLASH)
{
// TODO: DO WORK HERE
// m.LParam <-- A handle to the window that is 'flashing'
// You should be able to match this to your target.
MessageBox.Show("FLASH!");
}
base.WndProc(ref m);
}
}
Step 2: PInvokes:
public class Win32 {
[DllImport("user32.dll")]
public static extern bool RegisterShellHookWindow(IntPtr handle);
}
Step 3: Activate the hook:
var taf = new TestAlertForm();
Win32.RegisterShellHookWindow(taf.Handle);
After all that, you should see a message box for every flash. This is only a quick hack and I haven't tested it much.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With