How can I detect when a process that I'm not controlling is flashing due to some notification in it. I've seen only solutions that focus on an application that you have control over. In my case, there might be multiple instances of said process active at once and just one of them might be blinking.
This is my attempt:
using (Process process = Process.GetProcesses().FirstOrDefault(p => p.ProcessName.ToLower() == "..."))
using (ProcessModule module = process.MainModule)
{
var a = GetModuleHandleEx(0x00000004, module.ModuleName, out var hModule);
var hHook = SetWindowsHookEx(HookType.WH_SHELL, (code, param, lParam) =>
{
//test
return IntPtr.Zero;
}, hModule, 0);
}
Where the DLL imports are as follows:
public enum HookType : int
{
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
}
delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GetModuleHandleEx(UInt32 dwFlags, string lpModuleName, out IntPtr phModule);
The problem here is that GetModuleHandleEx
doesn't successfully return the proper handle, probably because I don't have the process is external and I don't have it loaded in mine (this is not possible).
I'm using win 10 64bit and the process that I'm targeting is 64 bit as well.
It is not possible to implement a global hook in the .net Framework, except for the WH_KEYBOARD_LL and the WH_MOUSE_LL low-level hooks. Global hooks for another types should be declared as C-style, that is not supported by the .NET Framework.
As a workaround it is possible to implement global hook in a native (unmanaged) DLL and transfer a callback (delegate) to a function that will be called each time, when the required message is received. Therefore, even if you fix the problem of calling the GetModuleHandleEx() you will receive only WH_SHELL messages related to your current application.
I was going to leave this as a comment, but I wanted to provide some code to elaborate what I meant.
You said that there may be multiple instances of the process. In your code, you performed a FirstOrDefault, grabbing the first instance that you find that matches your process name. Is there any chance that the process name repeats? For example, I fired up the F# Interactive and ran the following:
open System.Diagnostics;;
Process.GetProcesses() |> Array.map(fun(p) -> p.ProcessName);;
[|"chrome"; "fsiAnyCpu"; "svchost"; "InteractiveHost64"; "conhost"; "conhost"; "ServiceHub.RoslynCodeAnalysisService32"; "conhost"; "conhost"; ...|]
"conhost" repeated several times, meaning that the ProcessName can be repeated. I suggest trying the following, removing the FirstOrDefault with a Where, making sure you grab every Process that matches your criteria.
// First, lets grab all of the processes that match the desired name
var flashingProcesses = Process.GetProcesses().Where(p => p.ProcessName.ToLower() == "...")
// Next, lets Select what we want from these processes
.Select(process =>
{
using (process)
{
using (ProcessModule module = process.MainModule)
{
var moduleHandle = GetModuleHandleEx(0x00000004, module.ModuleName, out var hModule);
var hHook = SetWindowsHookEx(HookType.WH_SHELL, (code, param, lParam) =>
{
//test
return IntPtr.Zero;
}, hModule, 0);
return hHook;
}
}
})
// Finally, lets filter out the non-flashing proceses
.Where(ptr => ptr != IntPtr.Zero);
var count = flashingProcesses.Count();
Console.WriteLine($"There are ${count} flashing processes");
This may not be the exact answer, but I hope it helps.
User contributions licensed under CC BY-SA 3.0