Session 0 isolation e gli oggetti “Global” o “Local”

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