2 out of 7 rated this helpful - Rate this topic

WTSRegisterSessionNotification function

Applies to: desktop apps only

Registers the specified window to receive session change notifications.

Syntax

BOOL WTSRegisterSessionNotification(
  __in  HWND hWnd,
  __in  DWORD dwFlags
);

Parameters

hWnd [in]

Handle of the window to receive session change notifications.

dwFlags [in]

Specifies which session notifications are to be received. This parameter can be one of the following values.

ValueMeaning
NOTIFY_FOR_THIS_SESSION

Only session notifications involving the session attached to by the window identified by the hWnd parameter value are to be received.

NOTIFY_FOR_ALL_SESSIONS

All session notifications are to be received.

 

Return value

If the function succeeds, the return value is TRUE. Otherwise, it is FALSE. To get extended error information, call GetLastError.

Remarks

If this function is called before the dependent services of Remote Desktop Services have started, an RPC_S_INVALID_BINDING error code may be returned. When the Global\\TermSrvReadyEvent global event is set, all dependent services have started and this function can be successfully called.

Session change notifications are sent in the form of a WM_WTSSESSION_CHANGE message. These notifications are sent only to the windows that have registered for them using this function.

When a window no longer requires these notifications, it must call WTSUnRegisterSessionNotification before being destroyed. For every call to this function, there must be a corresponding call to WTSUnRegisterSessionNotification.

If the window handle passed in this function is already registered, the value of the dwFlags parameter is ignored.

To receive session change notifications from a service, use the HandlerEx function.

Requirements

Minimum supported client

Windows XP

Minimum supported server

Windows Server 2003

Header

Wtsapi32.h

Library

Wtsapi32.lib

DLL

Wtsapi32.dll

See also

HandlerEx
WTSRegisterSessionNotificationEx
WTSUnRegisterSessionNotification
WTSGetActiveConsoleSessionId
WM_WTSSESSION_CHANGE
WTSSESSION_NOTIFICATION

 

 

Send comments about this topic to Microsoft

Build date: 3/7/2012

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Call to WTSRegisterSessionNotification is WPF
When you use WTSRegisterSessionNotification in a WPF Window you will receive twice notifications.
That's because WPF Windows are already registered to receive WM_WTSSESSION_CHANGE in NOTIFY_FOR_THIS_SESSION mode.

So if in WPF you need to receive NOTIFY_FOR_THIS_SESSION - WM_WTSSESSION_CHANGE you don't need to call WTSRegisterSessionNotification.

But if you need to receive NOTIFY_FOR_ALL_SESSIONS - WM_WTSSESSION_CHANGE you first need to Call WTSUnRegisterSessionNotification and then register the Window calling WTSRegisterSessionNotification with NOTIFY_FOR_ALL_SESSIONS flag.

I've written a couple of blog articles about WTSRegisterSessionNotification, follow this links:

http://juank.black-byte.com/csharp-notificaciones-sesion-cambios/
http://juank.black-byte.com/csharp-notificacion-cambio-sesion-forms/
http://juank.black-byte.com/csharp-notificacion-cambio-sesion-wpf/
NOTIFY_FOR_THIS_SESSION flags has problems
It seems that NOTIFY_FOR_THIS_SESSION flag of this function doesnot do what it is meant to under certain conditions. This problem was seen in Windows XP SP2 but has not been tested in any other Windows OS versions.

Scenario 1 (Where it works as it is supposed to):
Try calling WTSRegisterSessionNotification() with NOTIFY_FOR_THIS_SESSION flag set in your program. Then goto 'Start->Log Off' then click on 'Switch User'. Now select a new user. Then keeping this new account open (which will be required to be so for scenario 2) switch back to your original user account. You will have received WTS_SESSION_LOCK and WTS_SESSION_UNLOCK as expected; both events related to the session from where your code is running.

Scenario 2 (Where it fails to work as it is supposed to):
Now restart your program and again goto 'Start->Log Off' then 'Switch User'. This time unlock the new account you had locked earlier. Again switch to your original account to see what messages your window has got. This time too WTS_SESSION_LOCK and WTS_SESSION_UNLOCK will have been caught. But there is a problem. WTS_SESSION_LOCK is fired correctly for the original session but WTS_SESSION_UNLOCK will have been fired while unlocking the new account and no event will have fired when the user is unlocking the session where your program is running (whom you asked to be notified for its lock/unlock event).

This problem is easily confirmed if you call WTSGetActiveConsoleSessionId() when lock and unlock events are caught in your code. You will see that you get different session ids in Scenario 2 instead of being same.


Solution
:
To be notified correctly of session change events concerning only your session, save session id of your process by calling GetCurrentProcessId() and ProcessIdToSessionId() function in a variable. Also, call WTSRegisterSessionNotification() with NOTIFY_FOR_ALL_SESSIONS (Even a process running under guest account can receive notifications of global session change under Windows XP SP2; not tested in any otherOS vers). When you receive WM_WTSSESSION_CHANGE message in your windows procedure, see if WTSGetActiveConsoleSessionId() and session id of your process (which you saved earlier in a variable) are equal or not. If they are equal then this event is concerned with your session.

Happy Coding,
Sanje2v
Visual Basic 8 declaration
Private Declare Function WTSRegisterSessionNotification Lib "Wtsapi32" (ByVal hWnd As IntPtr, ByVal THISSESS As Integer) As Integer

Private Const NOTIFY_FOR_ALL_SESSIONS As Integer = 1
Private Const NOTIFY_FOR_THIS_SESSION As Integer = 0

Usage:

  

After regustering owerride your WndProc anc catch WM_WTSSESSION_CHANGE message like this:

Private Const WM_WTSSESSION_CHANGE As Integer = &H2B1

Private Enum WTS
CONSOLE_CONNECT = 1
CONSOLE_DISCONNECT = 2
REMOTE_CONNECT = 3
REMOTE_DISCONNECT = 4
SESSION_LOGON = 5
SESSION_LOGOFF = 6
SESSION_LOCK = 7
SESSION_UNLOCK = 8
SESSION_REMOTE_CONTROL = 9
End Enum
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Select Case m.Msg
Case WM_WTSSESSION_CHANGE
Select Case m.WParam.ToInt32
Case WTS.CONSOLE_CONNECT
Debug.Print("A session was connected to the console session.")
Case WTS.CONSOLE_DISCONNECT
Debug.Print("A session was disconnected from the console session.")
Case WTS.REMOTE_CONNECT
Debug.Print("A session was connected to the remote session.")
Case WTS.REMOTE_DISCONNECT
Debug.Print("A session was disconnected from the remote session.")
Case WTS.SESSION_LOGON
Debug.Print("A user has logged on to the session.")
Case WTS.SESSION_LOGOFF
Debug.Print("A user has logged off the session.")
Case WTS.SESSION_LOCK
Debug.Print("A session has been locked.")
Case WTS.SESSION_UNLOCK
Debug.Print("A session has been unlocked.")
Case WTS.SESSION_REMOTE_CONTROL
Debug.Print("A session has changed its remote controlled status. To determine the status, call GetSystemMetrics and check the SM_REMOTECONTROL metric.")
End Select
End Select
MyBase.WndProc(m)
End Sub


Beware. You cannot check Global\\TermSrvReadyEvent status on a limited user account
At least not on XP SP2 or SP3 on XP Home. If you try

HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, _T("Global\\TermSrvReadyEvent"));

hEvent is set to NULL, and GetLastError returns 5 (access denied).

You can do this on Vista Business on a limited user account though.