-- UPDATE --
You could use SetWindowsHookEx to monitor the current Desktop, but this doesn't work in managed code. Instead, you must use SetWinEventHook.
You had asked how to use the SetWinEventHook p/Invoke method. Here is your answer:
First make sure this line is at the top of your code file:
Imports System.Runtime.InteropServices
Next, declare all that you need to invoke the call:
Public Const WINEVENT_OUTOFCONTEXT = &H0
'' Events are ASYNC
Public Const WINEVENT_SKIPOWNTHREAD = &H1
'' Don't call back for events on installer's thread
Public Const WINEVENT_SKIPOWNPROCESS = &H2
'' Don't call back for events on installer's process
Public Const WINEVENT_INCONTEXT = &H4
'' Events are SYNC, this causes your dll to be injected into every process
Public Declare Function SetWinEventHook Lib "user32.dll" _
(eventMin As UInteger, _
eventMax As UInteger, _
hmodWinEventProc As IntPtr, _
lpfnWinEventProc As IntPtr, _
idProcess As UInteger, _
idThread As UInteger, _
dwflags As UInteger) As IntPtr
Public Declare Function UnhookWinEvent Lib "user32.dll" _
(hWinEventHook As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
Public Delegate Sub WinEventProc( _
hWinEventHook As IntPtr, _
[event] As UInteger, _
hwnd As IntPtr, _
idObject As Integer, _
idChild As Integer, _
dwEventThread As UInteger, _
dwmsEventTime As UInteger)
Next, you declare a function and a new variable as a function with an address to that function:
Public Sub EventCallBack( _
hWinEventHook As IntPtr, _
[event] As UInteger, _
hwnd As IntPtr, _
idObject As Integer, _
idChild As Integer, _
dwEventThread As UInteger, _
dwmsEventTime As UInteger)
' Some code goes here
End Sub
Private eventProc As New WinEventProc(AddressOf EventCallBack)
Private hEventHook As IntPtr
Finally, you tie it all together, and you pass the following line of code to create your hook (0 and 255 are arbitrary numbers, replace them with the min and max message codes you want to watch):
hEventHook = SetWinEventHook(0, _
255, _
IntPtr.Zero, _
Marshal.GetFunctionPointerForDelegate(eventProc), _
0, _
0, _
WINEVENT_OUTOFCONTEXT)
And when your program has finished add the following line to an Application termination event, or the form's Dispose or Finalize methods:
UnhookWinEvent(hEventHook)
And this runs as expected on my test application.