Salve a tutti!

Una delle più importanti e vistose novità di Vista e Windows 7 è la Session 0 isolation. Questa novità, è una delle più impattanti dal punto di vista della compatibilità delle applicazioni, in quanto una applicazione che gira come servizio o una applicazione eseguita da un servizio, non è più accedibile direttamente e non può comunicare con le altre applicazioni che girano sul Desktop. Lo switch “Allow this service to interact with desktop” non serve più.

Application Compatibility: Session 0 Isolation, http://msdn.microsoft.com/en-us/library/bb756986.aspx, spiega il perchè esattamente.

Se vogliamo quindi creare un evento da un servizio che sia poi accedibile da una sessione utente, dobbiamo crearlo usando il prefisso “Global\” e dobbiamo crearlo con il descrittore della sicurezza impostato, perchè per default solo gli Administrators possono accedere agli oggetti definiti “Global\” e deve essere appunto globale per poter essere “visibile” al di fuori della sessione 0, quella dei servizi.

Questo piccolo esempio mostra come fare a creare un evento globale accedibile a tutti gli utenti da un servizio:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Security.AccessControl;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace EventRightsServiceTest
{
public partial class Service1 : ServiceBase
{
public Service1()
{
Trace.Listeners.Add(new TextWriterTraceListener(string.Format(@"C:\Logs\MyService.log", DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"))));
Trace.AutoFlush = true;

InitializeComponent();
}

private Thread _worker = null;

protected override void OnStart(string[] args)
{
if (_worker == null)
{
_worker = new Thread(new ThreadStart(ThreadFunction));
_worker.Start();
}
}

protected override void OnStop()
{
if (_worker != null)
{
_worker.Abort();
}
}

private EventWaitHandle _event;

private void ThreadFunction()
{
bool created;
try
{
System.Security.Principal.SecurityIdentifier sid = new System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.WorldSid, null);
System.Security.Principal.NTAccount acct = sid.Translate(typeof(System.Security.Principal.NTAccount)) as System.Security.Principal.NTAccount;

EventWaitHandleSecurity sec = new EventWaitHandleSecurity();
sec.AddAccessRule(new EventWaitHandleAccessRule(acct, EventWaitHandleRights.FullControl, AccessControlType.Allow));
EventWaitHandle myEvent = new EventWaitHandle(true, EventResetMode.ManualReset, "Global\\SampleEvent", out created, sec);

Trace.WriteLine("EventWaitHandle 'Global\\SampleEvent' new: " + created);
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
}

}
}
}

 
 
Per testare se l’evento è visibile, una volta avviato il servizio, potete realizzare una veloce Console application con questo codice:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading;

namespace EventRightsTestConsole
{
class Program
{
static void Main(string[] args)
{
try
{

EventWaitHandle handle = EventWaitHandle.OpenExisting("Global\\SampleEvent", EventWaitHandleRights.Synchronize);

Console.WriteLine("Successfully opened");
}
catch (Exception ex)
{
Console.WriteLine("Open failed");
Console.WriteLine(ex.ToString());
Console.ReadLine();
}

}
}
}

Gli eventi sono utili per sincronizzare il funzionamento di applicazioni diverse, quali ad esempio proprio un servizio e una applicazione user mode.
 
Alla prossima!

Mario Raccagni
Senior Support Engineer
Platform Development Support Team