Windows services when interacting with Desktop works fine in XP but when we change the application to Vista or greater than XP, it does not work as we expect.
Problem
When we migrate the solution to Windows 7 operating system, it runs in session 0. So you get a message:
blocked by Interactive Service Dialog Detection
This article can be one solution for the above problem.
Question
1) Why do I want the Windows service to interact with Desktop, it's not what they are made for?
Answer: Yes, Exactly! the Windows services are not make to interact with Desktop. But after introducing WCF services which can be hosted in Windows services, we may have the requirement to run the EXE file from the WCF services.
But before going through this article, please read:
Note
Before implementing this solution, please be aware of your requirements and handle all the security problems.
Introduction
Windows Services
Microsoft Windows services, formerly known as NT services, enables you to create long-running executable applications that run in their own Windows sessions. These services can be automatically started when the computer boots, can be paused and restarted, and do not show any user interface. These features make services ideal for use on a server or whenever you need long-running functionality that does not interfere with other users who are working on the same computer. You can also run services in the security context of a specific user account that is different from the logged-on user or the default computer account. For more information about services and Windows sessions:
Step 1
- Open Visual Studio 2010
- File -> New -> Project ->
- Template VisualC# -> Windows
- Project -> Windows Service
- Name : InteractDesktopDemo
- Ok ß
Step 2
Open Service1.cs, right Click in designer mode and Select AddInstaller .
Set the Properties of the installers, by default we get:
serviceProcessInstaller
serviceInstaller1
Go to Solution Explorer project.
Installer.designer.cs
Add the following code:
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
if (System.Environment.OSVersion.Version.Major <= 5)
this.serviceProcessInstaller1.Account =
System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
this.serviceInstaller1.ServiceName = "Service1";
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
}
Explanation
It will check for operating system version and if the operating system is greater than Windows XP, then it will ask for username and password and after entering the credentials, the service runs under that system account. If its XP or lesser than XP, the Windows service will run under local system account.
Step 3
Add an installer
Go to Solution Explorer, right click add new item Installer.cs:
And add the following code:
protected override void OnCommitted(IDictionary savedState)
{
base.OnCommitted(savedState);
try
{
ServiceController nService = new ServiceController("Service1");
nService.Start();
}
catch (Exception ie)
{
StreamWriter sw;
sw = File.AppendText("C:\\sashidhar.txt");
sw.WriteLine(ie.Message);
sw.Close();
}
}
Explanation
The above code handles the oncommitted event which fires after the installation of the EXE file/Windows service. It helps the service to start automatically after installation.
Step 4
Add reference to Microsoft.Win32.TaskScheduler
which is useful to create the task scheduler.
DLL can be found at http://taskscheduler.codeplex.com/.
protected override void OnStart(string[] args)
{
try
{
if (System.Environment.OSVersion.Version.Major > 5)
{
TaskService ts = new TaskService();
TaskDefinition td = ts.NewTask();
td.Principal.RunLevel = TaskRunLevel.Highest;
td.RegistrationInfo.Description = "Does something";
td.Triggers.Add(new RegistrationTrigger { Delay = TimeSpan.FromSeconds(1) });
td.Actions.Add(new ExecAction("notepad"));
ts.RootFolder.RegisterTaskDefinition(@"ssd", td);
}
else
{
ServiceDesktopPermission();
System.Diagnostics.Process.Start("notepad.exe");
}
}
catch (Exception ie)
{
StreamWriter sw;
sw = File.AppendText("C:\\Sashidhar.txt");
sw.WriteLine(ie.Message);
sw.Close();
}
}
Explanation
The above code behaves differently depending on the operating system, for operating system lesser than XP or XP. Windows Service will run in the localsystem account and interacting with desktop is checked. While in windows 7, it creates a task in the task scheduller and the task scheduler interacts with desktop. Make sure you run the Windows service in administrator account or the account which has the right to run the task in the task scheduler.
static public void ServiceDesktopPermission()
{
try
{
ConnectionOptions coOptions = new ConnectionOptions();
coOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope mgmtScope = new ManagementScope(@"root\CIMV2", coOptions);
mgmtScope.Connect();
ManagementObject wmiService;
wmiService = new ManagementObject("Win32_Service.Name='" + "Service1" + "'");
ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");
InParam["DesktopInteract"] = true;
wmiService.InvokeMethod("Change", InParam, null);
}
catch (Exception ex)
{
StreamWriter sw;
sw = File.AppendText("C:\\Sashidhar.txt");
sw.WriteLine("Trying to open Service");
sw.Close();
}
}
Explanation
For making the Windows service interact with desktop for operating system Windows XP or lesser.
Installing
Open Visual Studio command prompt and type:
installutil <Path of the exe File>
When installing, provide the administrator credentials as shown below:
Uninstalling
Open Visual studio command prompt and type:
installutil/u <Path of the exe File>
References
To be continued! Working with WCF services and WindowServices!