Global hooks (experts)

V

Víctor

Hello,

I'm doing a Taskbar like app and I need to show open application's buttons.
I've chosen to use a global hook due to elevate resource comsumptions by
using a timer that looks up running processes. I'm trying with the
SetWindowEventHook API and it works fine until I open four or five windows.
Below, I show source code and exception stack trace. I'm grateful with any
solution or idea.

In class constructor:

....
IniciaHook();
....

Hook initialization:

private void IniciaHook()
{
API.Win32.SetWinEventHook((int)API.Win32.HookEventConstants.EVENT_OBJECT_CREATE,
(int)API.Win32.HookEventConstants.EVENT_OBJECT_CREATE, 0, new
API.Win32.WinEventProc(WinEventProcedure), 0,0,
(int)API.Win32.HookFlags.WINEVENT_OUTOFCONTEXT);
}

Delegate linked function:

private int WinEventProcedure(int hWinEventHook, int idEvent, int hwnd, int
idObject, int idChild, int dwEventThread, int dwmsEventTime)
{
int pId;
try
{
int length = API.Win32.GetWindowTextLength((IntPtr) hwnd);
if(length > 0)
{
if(idObject==(int)API.Win32.HookObjId.OBJID_WINDOW)
{
StringBuilder sb = new StringBuilder(length + 1);
API.Win32.GetWindowText((IntPtr) hwnd, sb, sb.Capacity);
if(hwnd!=0)
{
API.Win32.GetWindowThreadProcessId((IntPtr) hwnd, out pId);
if(!arLst.Contains(pId))
{
arLst.Add(pId);
Process p=Process.GetProcessById(pId);
addProcess(p.Id, p.MainWindowTitle, p.MainModule.FileName, p.StartTime);
}
}
}
}
}
catch(Exception exc)
{
MessageBox.Show(exc.Message);
}
return 0;
}

Method which add button to taskBar:
public void addProcess(int idProc, string windowName, string exeName,
DateTime pCreate)
{
try
{
XDesktop.TaskBarButton btn=new TaskBarButton();
btn.Height=panel3.Height-4;
btn.ProcessId=idProc;
btn.WindowName=windowName;
btn.Font=new Font(btn.Font.Name,9);
btn.ForeColor=Color.White;
btn.ContextMenu=cMenuButton;
btn.executableName=exeName;
btn.FechaCreacion=pCreate;
this.InsertButton(btn);
if(panel3.Controls.Count<=10)
{
panel3.Controls.Add(btn);
redimensionaBotones();
}
else
{
etbFrm.AddButton(btn);
}
btnMas.Visible=(btCol.Count > panel3.Controls.Count);
}
catch(Exception exc)
{
MessageBox.Show(exc.Message + "\n" + exc.Source + "\n" + exc.StackTrace);
}
}

API functions definition (enumeration definitions are omitted):
[DllImport("user32.dll", EntryPoint="SetWinEventHook", SetLastError=true,
CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
public static extern int SetWinEventHook(int eventMin, int eventMax, int
hmodWinEventProc,
WinEventProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);
public delegate int WinEventProc(int hWinEventHook, int idEvent, int hwnd,
int idObject, int idChild, int dwEventThread, int dwmsEventTime);

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER
ClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder
lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int
processId);

Stacktrace information:
Excepción no controlada: System.NullReferenceException: Referencia a objeto
no establecida como instancia de un objeto.
at API.WinEventProc.Invoke(Int32 hWinEventHook, Int32 idEvent, Int32 hwnd,
Int32 idObject, Int32 idChild, Int32 dwEventThread, Int32 dwmsEventTime)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef
hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at
System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at TaskBar.Inicio.Main() in c:\documents and settings\administrador\mis
documentos\visual studio projects\taskbar\inicio.cs:line 90El programa
'[3148] TaskBar.exe' terminó con código 0 (0x0).

I think, error is in delegate or in the associated function, but I'm not
able to find where the error is. I'm blocked and I can't go on.
Thanks.
 
P

Pete Davis

Can you show the code for API.WinEventProc?

Are you sure WinEventProc isn't null? Are you sure none of the handles
you're passing in are null?

Pete

Víctor said:
Hello,

I'm doing a Taskbar like app and I need to show open application's
buttons. I've chosen to use a global hook due to elevate resource
comsumptions by using a timer that looks up running processes. I'm trying
with the SetWindowEventHook API and it works fine until I open four or
five windows. Below, I show source code and exception stack trace. I'm
grateful with any solution or idea.

In class constructor:

...
IniciaHook();
...

Hook initialization:

private void IniciaHook()
{
API.Win32.SetWinEventHook((int)API.Win32.HookEventConstants.EVENT_OBJECT_CREATE,
(int)API.Win32.HookEventConstants.EVENT_OBJECT_CREATE, 0, new
API.Win32.WinEventProc(WinEventProcedure), 0,0,
(int)API.Win32.HookFlags.WINEVENT_OUTOFCONTEXT);
}

Delegate linked function:

private int WinEventProcedure(int hWinEventHook, int idEvent, int hwnd,
int
idObject, int idChild, int dwEventThread, int dwmsEventTime)
{
int pId;
try
{
int length = API.Win32.GetWindowTextLength((IntPtr) hwnd);
if(length > 0)
{
if(idObject==(int)API.Win32.HookObjId.OBJID_WINDOW)
{
StringBuilder sb = new StringBuilder(length + 1);
API.Win32.GetWindowText((IntPtr) hwnd, sb, sb.Capacity);
if(hwnd!=0)
{
API.Win32.GetWindowThreadProcessId((IntPtr) hwnd, out pId);
if(!arLst.Contains(pId))
{
arLst.Add(pId);
Process p=Process.GetProcessById(pId);
addProcess(p.Id, p.MainWindowTitle, p.MainModule.FileName, p.StartTime);
}
}
}
}
}
catch(Exception exc)
{
MessageBox.Show(exc.Message);
}
return 0;
}

Method which add button to taskBar:
public void addProcess(int idProc, string windowName, string exeName,
DateTime pCreate)
{
try
{
XDesktop.TaskBarButton btn=new TaskBarButton();
btn.Height=panel3.Height-4;
btn.ProcessId=idProc;
btn.WindowName=windowName;
btn.Font=new Font(btn.Font.Name,9);
btn.ForeColor=Color.White;
btn.ContextMenu=cMenuButton;
btn.executableName=exeName;
btn.FechaCreacion=pCreate;
this.InsertButton(btn);
if(panel3.Controls.Count<=10)
{
panel3.Controls.Add(btn);
redimensionaBotones();
}
else
{
etbFrm.AddButton(btn);
}
btnMas.Visible=(btCol.Count > panel3.Controls.Count);
}
catch(Exception exc)
{
MessageBox.Show(exc.Message + "\n" + exc.Source + "\n" + exc.StackTrace);
}
}

API functions definition (enumeration definitions are omitted):
[DllImport("user32.dll", EntryPoint="SetWinEventHook", SetLastError=true,
CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall)]
public static extern int SetWinEventHook(int eventMin, int eventMax, int
hmodWinEventProc,
WinEventProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);
public delegate int WinEventProc(int hWinEventHook, int idEvent, int hwnd,
int idObject, int idChild, int dwEventThread, int dwmsEventTime);

[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER
ClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder
lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int
processId);

Stacktrace information:
Excepción no controlada: System.NullReferenceException: Referencia a
objeto
no establecida como instancia de un objeto.
at API.WinEventProc.Invoke(Int32 hWinEventHook, Int32 idEvent, Int32 hwnd,
Int32 idObject, Int32 idChild, Int32 dwEventThread, Int32 dwmsEventTime)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg,
HandleRef
hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at
System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at TaskBar.Inicio.Main() in c:\documents and settings\administrador\mis
documentos\visual studio projects\taskbar\inicio.cs:line 90El programa
'[3148] TaskBar.exe' terminó con código 0 (0x0).

I think, error is in delegate or in the associated function, but I'm not
able to find where the error is. I'm blocked and I can't go on.
Thanks.
 
M

Mattias Sjögren

API.Win32.SetWinEventHook((int)API.Win32.HookEventConstants.EVENT_OBJECT_CREATE,
(int)API.Win32.HookEventConstants.EVENT_OBJECT_CREATE, 0, new
API.Win32.WinEventProc(WinEventProcedure), 0,0,
(int)API.Win32.HookFlags.WINEVENT_OUTOFCONTEXT);

You shouldn't create the callback delegate inline like this. You have
to keep a reference to it as long as the hook in active to prevent it
from being garbage collected.


Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top