Interaction with UI from windows service


Interaction with UI from windows service

Introduction

Windows service has no UI and it has never been easy to prompt users with some notifications from windows service.
To interact with UI from windows service, we used to opt, allow service to interact with desktop and by launching another process from the windows service. But it is not expected to work with windows vista and upwards.
So now the question is how to implement this in newer versions of windows i.e. windows 8, windows 10 etc.
Here is the answer:
Display a dialog box in the user's session using the WTSSendMessage function.
It can be used to display messages from windows service on all supported windows operating systems.

WTSSendMessage

Displays a message box on the client desktop of a specified Remote Desktop Services session.

Syntax

BOOL WTSSendMessageA(
  IN HANDLE hServer,
  IN DWORD  SessionId,
  LPSTR     pTitle,
  IN DWORD  TitleLength,
  LPSTR     pMessage,
  IN DWORD  MessageLength,
  IN DWORD  Style,
  IN DWORD  Timeout,
  DWORD     *pResponse,
  IN BOOL   bWait
);

Parameters

HServer

A handle to an RD Session Host server. Specify a handle opened by the WTSOpenServer function, or specifyWTS_CURRENT_SERVER_HANDLE to indicate the RD Session Host server on which your application is running.

SessionId

A Remote Desktop Services session identifier. To indicate the current session, specify WTS_CURRENT_SESSION. You can use the WTSEnumerateSessions function to retrieve the identifiers of all sessions on a specified RD Session Host server.

pTitle

A pointer to a null-terminated string for the title bar of the message box.

TitleLength

The length, in bytes, of the title bar string.

pMessage

A pointer to a null-terminated string that contains the message to display.

MessageLength

The length, in bytes, of the message string.

Style

The contents and behavior of the message box. This value is typically MB_OK. For a complete list of values, see the uType parameter of the MessageBox function.

Timeout

The time, in seconds, that the WTSSendMessage function waits for the user's response. If the user does not respond within the time-out interval, the pResponse parameter returns IDTIMEOUT. If the Timeout parameter is zero, WTSSendMessage waits indefinitely for the user to respond.

pResponse

A pointer to a variable that receives the user's response.

Code

class NotifyService
    {
        [DllImport("wtsapi32.dll", SetLastError = true)]
        static extern bool WTSSendMessage(
                IntPtr hServer,
                [MarshalAs(UnmanagedType.I4)] int SessionId,
                String pTitle,
                [MarshalAs(UnmanagedType.U4)] int TitleLength,
                String pMessage,
                [MarshalAs(UnmanagedType.U4)] int MessageLength,
                [MarshalAs(UnmanagedType.U4)] int Style,
                [MarshalAs(UnmanagedType.U4)] int Timeout,
                [MarshalAs(UnmanagedType.U4)] out int pResponse,
                bool bWait);
        public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
        //public static int WTS_CURRENT_SESSION = 1;
        public void Start(int lastRebootDaysDiff)
        {
                    try
                    {
                        bool result = false;
                        String title = "Support";
                        int tlen = title.Length;
                       //  lastRebootDaysDiff = 0;
                        if (lastRebootDaysDiff >= 0)
                        {
                            string msg = lastRebootDaysDiff +
                                         "days have passed since you have rebooted your machine. Would you like to reboot your system now?";
                            int mlen = msg.Length;
                            int resp = 7;
                            //result = WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, user_session, title, tlen, msg, mlen, 4,
                            //    0, out resp, true);
                            result = WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, 1, title, tlen, msg, mlen, 4,
                                0, out resp, false);
                    int err = Marshal.GetLastWin32Error();
                            if (err == 0)
                            {
                                if (result) //user responded to box
                                {
                                    if (resp == 7) //user clicked no
                                    {

                                    }
                                    else if (resp == 6) //user clicked yes
                                    {
                                       // write your functionality here
                                    }

                                    //  Debug.WriteLine("user_session:" + user_session + " err:" + err + " resp:" + resp);
                                }
                              
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                       // Debug.WriteLine("no such thread exists", ex);
                    }
                 

        }
      
    }

Comments

Popular posts from this blog

.Net Basic terminology

Basics of .Net