DebugController.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / RunTime / DebugEngine / DebugController.cs / 1407647 / DebugController.cs

                            // Copyright (c) Microsoft Corp., 2004. All rights reserved. 
#region Using directives

using System;
using System.IO; 
using System.Xml;
using System.Text; 
using System.Threading; 
using System.Reflection;
using System.Collections; 
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Runtime.Serialization;
using System.Workflow.Runtime; 
using System.Workflow.Runtime.Hosting; 
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Channels; 
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Serialization; 
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting.Channels.Ipc; 
using System.Configuration; 
using System.Security.Permissions;
using System.Globalization; 
using Microsoft.Win32;
using System.Security.AccessControl;
using System.Security.Principal;
#endregion 

namespace System.Workflow.Runtime.DebugEngine 
{ 
    internal static class RegistryKeys
    { 
        //
        internal static readonly string ProductRootRegKey = @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4.0\Setup\Windows Workflow Foundation";
        internal static readonly string DebuggerSubKey = ProductRootRegKey + @"\Debugger";
    } 

    public sealed class DebugController : MarshalByRefObject 
    { 
        #region Data members
 
        private Guid programId;
        private string hostName;
        private int attachTimeout;
        private ProgramPublisher programPublisher; 
        private DebugControllerThread debugControllerThread;
        private Timer attachTimer; 
        private WorkflowRuntime serviceContainer; 
        private IpcChannel channel;
 		private IWorkflowDebugger controllerConduit; 
        private bool isZombie;
        private bool isAttached;
        private ManualResetEvent eventConduitAttached;
        private InstanceTable instanceTable; 
        private Dictionary typeToGuid;
        private Dictionary xomlHashToGuid; 
        bool isServiceContainerStarting; 
        private const string rootExecutorGuid = "98fcdc7a-8ab4-4fb7-92d4-20f437285729";
        private object eventLock; 
        private object syncRoot = new object();
		private static readonly string ControllerConduitTypeName = "ControllerConduitTypeName";

        #endregion 
		
		#region Security related methods 
 		private delegate void ExceptionNotification(Exception e); 

		internal static void InitializeProcessSecurity() 
 		{
 			// Spawn off a separate thread to that does RevertToSelf and adjusts DACLs.
			// This is because RevertToSelf terminates client impersonation on the thread
 			// that calls it. We do not want to change that on the current thread when 
			// the runtime is hosted inside ASP.net for example.
			Exception workerThreadException = null; 
            ProcessSecurity processSecurity = new ProcessSecurity(); 
            Thread workerThread = new Thread(new ThreadStart(processSecurity.Initialize));
 
            processSecurity.exceptionNotification += delegate(Exception e)
			{
 				workerThreadException = e;
			}; 
 			
            workerThread.Start(); workerThread.Join(); 
 			if (workerThreadException != null) 
				throw workerThreadException;
 		} 

		private class ProcessSecurity
		{
			internal ExceptionNotification exceptionNotification; 

 			internal void Initialize() 
			{ 
 				try
 				{ 
					// This is needed if the thread calling the method is impersonating
 					// a client call (ASP.net hosting scenarios).
					if (!NativeMethods.RevertToSelf())
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 

					// Get the DACL for process token. Add TOKEN_QUERY permissions for the Administrators group. 
 					// Set the updated DACL for process token. 
					RawAcl tokenDacl = GetCurrentProcessTokenDacl();
 					CommonAce adminsGroupAceForToken = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, NativeMethods.TOKEN_QUERY, new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), false, null); 
 					int i = FindIndexInDacl(adminsGroupAceForToken, tokenDacl);
					if (i != -1)
 						tokenDacl.InsertAce(i, adminsGroupAceForToken);
					SetCurrentProcessTokenDacl(tokenDacl); 
				}
				catch (Exception e) 
 				{ 
					// Communicate any exceptions from this thread back to the thread
 					// that spawned it. 
 					if (exceptionNotification != null)
						exceptionNotification(e);
 				}
			} 

			private RawAcl GetCurrentProcessTokenDacl() 
			{ 
 				IntPtr hProcess = IntPtr.Zero;
				IntPtr hProcessToken = IntPtr.Zero; 
 				IntPtr securityDescriptorPtr = IntPtr.Zero;

 				try
				{ 
 					hProcess = NativeMethods.GetCurrentProcess();
 
					if (!NativeMethods.OpenProcessToken(hProcess, NativeMethods.TOKEN_ALL_ACCESS, out hProcessToken)) 
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 
					// Get security descriptor associated with the kernel object, read the DACL and return
 					// that to the caller.
					uint returnLength;
 
 					NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, IntPtr.Zero, 0, out returnLength);
 					int lasterror = Marshal.GetLastWin32Error();//#pragma warning disable 56523 doesnt recognize 56523 
 
					securityDescriptorPtr = Marshal.AllocCoTaskMem((int)returnLength);
 					 
					if (!NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, securityDescriptorPtr, returnLength, out returnLength))
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

					byte[] sdBytes = new byte[returnLength]; 
 					Marshal.Copy(securityDescriptorPtr, sdBytes, 0, (int)returnLength);
 
					RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor(sdBytes, 0); 

 					return rawSecurityDescriptor.DiscretionaryAcl; 
 				}
				finally
 				{
					if (hProcess != IntPtr.Zero && hProcess != (IntPtr)(-1)) 
						if(!NativeMethods.CloseHandle(hProcess))
							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
 
 					if (hProcessToken != IntPtr.Zero)
						if(!NativeMethods.CloseHandle(hProcessToken)) 
 							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

 					if (securityDescriptorPtr != IntPtr.Zero)
						Marshal.FreeCoTaskMem(securityDescriptorPtr); 
 				}
			} 
			private void SetCurrentProcessTokenDacl(RawAcl dacl) 
			{
 				IntPtr hProcess = IntPtr.Zero; 
				IntPtr hProcessToken = IntPtr.Zero;
 				IntPtr securityDescriptorPtr = IntPtr.Zero;
 				try
				{ 
 					hProcess = NativeMethods.GetCurrentProcess();
 
					if (!NativeMethods.OpenProcessToken(hProcess, NativeMethods.TOKEN_ALL_ACCESS, out hProcessToken)) 
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 
					// Get security descriptor associated with the kernel object and modify it.
 					uint returnLength;

					NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, IntPtr.Zero, 0, out returnLength); 
 					int lasterror = Marshal.GetLastWin32Error();//#pragma warning disable 56523 doesnt recognize 56523
 
 					securityDescriptorPtr = Marshal.AllocCoTaskMem((int)returnLength); 

					if (!NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, securityDescriptorPtr, returnLength, out returnLength)) 
 						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

					byte[] sdBytes = new byte[returnLength];
					Marshal.Copy(securityDescriptorPtr, sdBytes, 0, (int)returnLength); 

					RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor(sdBytes, 0); 
 					rawSecurityDescriptor.DiscretionaryAcl = dacl; 

					sdBytes = new byte[rawSecurityDescriptor.BinaryLength]; 
 					rawSecurityDescriptor.GetBinaryForm(sdBytes, 0);
 					Marshal.FreeCoTaskMem(securityDescriptorPtr);
					securityDescriptorPtr = Marshal.AllocCoTaskMem(rawSecurityDescriptor.BinaryLength);
 					Marshal.Copy(sdBytes, 0, securityDescriptorPtr, rawSecurityDescriptor.BinaryLength); 

					if (!NativeMethods.SetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, securityDescriptorPtr)) 
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
				}
 				finally 
				{
 					if (hProcess != IntPtr.Zero && hProcess != (IntPtr)(-1))
 						if(!NativeMethods.CloseHandle(hProcess))
							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 

 					if (hProcessToken != IntPtr.Zero) 
						if(!NativeMethods.CloseHandle(hProcessToken)) 
							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 
					if (securityDescriptorPtr != IntPtr.Zero)
 						Marshal.FreeCoTaskMem(securityDescriptorPtr);

				} 
 			}
 
 			// The preferred order in which ACEs are added to DACLs is 
			// documented here: http://search.msdn.microsoft.com/search/results.aspx?qu=Order+of+ACEs+in+a+DACL&View=msdn&st=b.
 			// This routine follows that logic to determine the position of an ACE in the DACL. 
			private int FindIndexInDacl(CommonAce newAce, RawAcl dacl)
			{
				int i = 0;
 				for (i = 0; i < dacl.Count; i++) 
				{
 					if (dacl[i] is CommonAce && ((CommonAce)dacl[i]).SecurityIdentifier.Value == newAce.SecurityIdentifier.Value && dacl[i].AceType == newAce.AceType) 
 					{ 
						i = -1;
 						break; 
					}

					if (newAce.AceType == AceType.AccessDenied && dacl[i].AceType == AceType.AccessDenied && !newAce.IsInherited && !dacl[i].IsInherited)
						continue; 

 					if (newAce.AceType == AceType.AccessDenied && !newAce.IsInherited) 
						break; 

 					if (newAce.AceType == AceType.AccessAllowed && dacl[i].AceType == AceType.AccessAllowed && !newAce.IsInherited && !dacl[i].IsInherited) 
 						continue;

					if (newAce.AceType == AceType.AccessAllowed && !newAce.IsInherited)
 						break; 

				} 
 
				return i;
			} 
 		}
		#endregion

        #region Constructor and Lifetime methods 

        internal DebugController(WorkflowRuntime serviceContainer, string hostName) 
        { 
 			if (serviceContainer == null)
 				throw new ArgumentNullException("serviceContainer"); 

            try
            {
                this.programPublisher = new ProgramPublisher(); 
            }
            catch 
            { 
                // If we are unable to create the ProgramPublisher, this means that VS does not exist on this machine, so we can't debug.
                return; 
            }

            this.serviceContainer = serviceContainer;
            this.programId = Guid.Empty; 
            this.controllerConduit = null;
            this.channel = null; 
            this.isZombie = false; 
            this.hostName = hostName;
 
            AppDomain.CurrentDomain.ProcessExit += OnDomainUnload;
            AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;

            this.serviceContainer.Started += this.Start; 
            this.serviceContainer.Stopped += this.Stop;
        } 
 
        public override object InitializeLifetimeService()
        { 
            // We can't use a sponser because VS doesn't like to be attached when the lease renews itself - the
            // debugee gets an Access Violation and VS freezes. Returning null implies that the proxy shim will be
            // deleted only when the App Domain unloads. However, we will have disconnected the shim so no
            // one will be able to attach to it and the same proxy is used everytime a debugger attaches. 
            return null;
        } 
 
        #endregion
 
        #region Attach and Detach methods

        internal void Attach(Guid programId, int attachTimeout, int detachPingInterval, out string hostName, out string uri, out int controllerThreadId, out bool isSynchronousAttach)
        { 
			Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.Attach(): programId = {0}", programId));
 			lock (this.syncRoot) 
			{ 
				hostName = String.Empty;
				uri = String.Empty; 
 				controllerThreadId = 0;
				isSynchronousAttach = false;

 				// Race condition: 
 				// During the call to Attach() if Uninitialize() is also called, we should ignore the call to Attach() and
				// just return. The Zombie flag and lock(this) help us recognize the ----. 
 				if (this.isZombie) 
					return;
 

				// Race condition:
				// The isAttached flat along with lock(this) catch the ---- where a debugger may have detached which
 				// we haven't detected yet and another debugger may have attached, so we force detach from the first 
				// debugger.
 				if (this.isAttached) 
 					Detach(); 

 
				this.isAttached = true;

 				this.programId = programId;
				this.debugControllerThread = new DebugControllerThread(); 
				this.instanceTable = new InstanceTable(this.debugControllerThread.ManagedThreadId);
				this.typeToGuid = new Dictionary(); 
 				this.xomlHashToGuid = new Dictionary((IEqualityComparer)new DigestComparer()); 

				this.debugControllerThread.RunThread(this.instanceTable); 

 				// Publish our MBR object.
 				IDictionary providerProperties = new Hashtable();
				providerProperties["typeFilterLevel"] = "Full"; 
 				BinaryServerFormatterSinkProvider sinkProvider = new BinaryServerFormatterSinkProvider(providerProperties, null);
 
				Hashtable channelProperties = new Hashtable(); 
				channelProperties["name"] = string.Empty;
				channelProperties["portName"] = this.programId.ToString(); 
 				SecurityIdentifier si = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
				IdentityReference idRef = si.Translate(typeof(NTAccount));
 				channelProperties["authorizedGroup"] = idRef.ToString();
 				this.channel = new IpcChannel(channelProperties, null, sinkProvider); 
				ChannelServices.RegisterChannel(this.channel, true);
 
 				ObjRef o = RemotingServices.Marshal(this, this.programId.ToString()); 
				hostName = this.hostName;
 
				uri = this.channel.GetUrlsForUri(this.programId.ToString())[0];
				controllerThreadId = this.debugControllerThread.ThreadId;
 				isSynchronousAttach = !this.isServiceContainerStarting;
 
				this.attachTimeout = attachTimeout;
 				this.attachTimer = new Timer(AttachTimerCallback, null, attachTimeout, detachPingInterval); 
 			} 
        }
 
        private void Detach()
        {
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.Detach():"));
 
            using(new DebuggerThreadMarker())
            { 
                lock (this.syncRoot) 
                {
 
                    AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;

                    // See comments in Attach().
                    if (this.isZombie || !this.isAttached) 
                        return;
 
                    this.isAttached = false; 

                    // Undone: AkashS - At this point wait for all event handling to complete to avoid exceptions. 

                    this.programId = Guid.Empty;

                    if (this.debugControllerThread != null) 
					{
                        this.debugControllerThread.StopThread(); 
                        this.debugControllerThread = null; 
                    }
 
                    if (this.attachTimer != null)
                    {
                        this.attachTimer.Change(Timeout.Infinite, Timeout.Infinite);
                        this.attachTimer = null; 
                    }
 
                    RemotingServices.Disconnect(this); 
                    if (this.channel != null)
                    { 
                        ChannelServices.UnregisterChannel(this.channel);
                        this.channel = null;
                    }
 
                    this.controllerConduit = null;
 
                    this.eventConduitAttached.Reset(); 
                    this.instanceTable = null;
                    this.typeToGuid = null; 
                    this.xomlHashToGuid = null;

                    // Do this only after we perform the previous cleanup! Otherwise
                    // we may get exceptions from the runtime that may cause the cleanup 
                    // to not happen.
 
                    if (!this.serviceContainer.IsZombie) 
                    {
 						foreach (WorkflowInstance instance in this.serviceContainer.GetLoadedWorkflows()) 
						{
							WorkflowExecutor executor = instance.GetWorkflowResourceUNSAFE();
							using (executor.ExecutorLock.Enter())
 							{ 
								if (executor.IsInstanceValid)
 									executor.WorkflowExecutionEvent -= OnInstanceEvent; 
 							} 
						}
 
                        this.serviceContainer.WorkflowExecutorInitializing -= InstanceInitializing;
                        this.serviceContainer.DefinitionDispenser.WorkflowDefinitionLoaded -= ScheduleTypeLoaded;
                    }
                } 
            }
        } 
 
        private void AttachTimerCallback(object state)
        { 
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.AttachTimerCallback():"));

            try
            { 
                lock (this.syncRoot)
                { 
                    // See comments in Attach(). 
                    if (this.isZombie || !this.isAttached)
                        return; 

                    if (!Debugger.IsAttached)
                    {
                        // The debugger had attached and has now detached, so cleanup, or Attach() was called on the 
                        // Program Node, but the process of attach failed thereafter and so we were never actually
                        // debugged. 
                        this.attachTimer.Change(Timeout.Infinite, Timeout.Infinite); 
                        Detach();
                    } 
                }
            }
            catch
            { 
                // Avoid throwing unhandled exceptions!
            } 
        } 

        private void OnDomainUnload(object sender, System.EventArgs e) 
        {
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.OnDomainUnload():"));

            Stop(null, default(WorkflowRuntimeEventArgs)); 
        }
 
        #endregion 

        #region Methods for the DE 

        public void AttachToConduit(Uri url)
        {
            if (url == null) 
                throw new ArgumentNullException("url");
 
            try 
            {
                using (new DebuggerThreadMarker()) 
                {
 					try
					{
						RegistryKey debugEngineSubKey = Registry.LocalMachine.OpenSubKey(RegistryKeys.DebuggerSubKey); 
						if (debugEngineSubKey != null)
 						{ 
							string controllerConduitTypeName = debugEngineSubKey.GetValue(ControllerConduitTypeName, String.Empty) as string; 
 							if (!String.IsNullOrEmpty(controllerConduitTypeName) && Type.GetType(controllerConduitTypeName) != null)
 								this.controllerConduit = Activator.GetObject(Type.GetType(controllerConduitTypeName), url.AbsolutePath) as IWorkflowDebugger; 
						}
 					}
					catch {}
					finally 
					{
 						if (this.controllerConduit == null) 
							this.controllerConduit = Activator.GetObject(Type.GetType("Microsoft.Workflow.DebugEngine.ControllerConduit, Microsoft.Workflow.DebugController, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"), url.AbsolutePath) as IWorkflowDebugger; 
 					}
 					Debug.Assert(this.controllerConduit != null, "Failed to create Controller Conduit"); 
					if (this.controllerConduit == null)
 						return;

                    this.eventLock = new object(); 

                    // Race Condition: 
                    // We hook up to the AssemblyLoad event, the Schedule events and Instance events handler 
                    // before we iterate over all loaded assemblies. This means that we need to deal with duplicates in the
                    // debugee. 

                    // Race Condition:
                    // Further the order in which we hook up handlers/iterate is important to avoid ----s if the events fire
                    // before the iterations complete. We need to hook and iterate over the assemblies, then the schedule 
                    // types and finally the instances. This guarantees that we always have all the assemblies when we load
                    // schedules types and we always have all the schedule types when we load instances. 
 
                    AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
                    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 
                    {
                        if (   !assembly.IsDynamic
                            && !(assembly is System.Reflection.Emit.AssemblyBuilder)
                            && !(string.IsNullOrEmpty(assembly.Location))) 
                        {
                            this.controllerConduit.AssemblyLoaded(this.programId, assembly.Location, assembly.GlobalAssemblyCache); 
                        } 
                    }
                    this.serviceContainer.DefinitionDispenser.WorkflowDefinitionLoaded += ScheduleTypeLoaded; 

                    // In here we load all schedule types defined as they are - with no dynamic updates
                    ReadOnlyCollection types;
                    ReadOnlyCollection values; 
                    this.serviceContainer.DefinitionDispenser.GetWorkflowTypes(out types, out values);
                    for (int i = 0; i < types.Count; i++) 
                    { 
                        Type scheduleType = types[i];
                        Activity rootActivity = values[i]; 
                        LoadExistingScheduleType(GetScheduleTypeId(scheduleType), scheduleType, false, rootActivity);
                    }

                    ReadOnlyCollection keys; 
                    this.serviceContainer.DefinitionDispenser.GetWorkflowDefinitions(out keys, out values);
                    for (int i = 0; i < keys.Count; i++) 
                    { 
                        byte[] scheduleDefHash = keys[i];
                        Activity rootActivity = values[i]; 
                        Activity workflowDefinition = (Activity)rootActivity.GetValue(Activity.WorkflowDefinitionProperty);
                        ArrayList changeActions = null;
                        if (workflowDefinition != null)
                            changeActions = (ArrayList)workflowDefinition.GetValue(WorkflowChanges.WorkflowChangeActionsProperty); 
                        LoadExistingScheduleType(GetScheduleTypeId(scheduleDefHash), rootActivity.GetType(), (changeActions != null && changeActions.Count != 0), rootActivity);
                    } 
 
                    this.serviceContainer.WorkflowExecutorInitializing += InstanceInitializing;
 
                    foreach (WorkflowInstance instance in this.serviceContainer.GetLoadedWorkflows())
                    {
                        WorkflowExecutor executor = instance.GetWorkflowResourceUNSAFE();
                        using (executor.ExecutorLock.Enter()) 
                        {
                            LoadExistingInstance(instance, true); 
                        } 
                    }
 
                    this.eventConduitAttached.Set();
                }
            }
            catch (Exception e) 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel. 
				Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: Failure in DebugController.AttachToConduit: {0}, Call stack:{1}", e.Message, e.StackTrace));
			} 

        }

        #endregion 

        #region Methods for the Runtime 
 
        private void Start(object source, WorkflowRuntimeEventArgs e)
        { 
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.ServiceContainerStarted():"));

            this.isZombie = false;
            this.isAttached = false; 
            this.eventConduitAttached = new ManualResetEvent(false);
            this.isServiceContainerStarting = true; 
 
            bool published = this.programPublisher.Publish(this);
 
            // If the debugger is already attached, then the DE will invoke AttachToConduit() on a separate thread.
            // We need to wait for that to happen to prevent new instances being created and causing a ----. See
            // comments in ControllerConduit.ProgramCreated(). However, if the DE never calls AttachToConduit(),
            // and the detaches instead, we set a wait timeout to that of our Attach Timer. 
            // Note that when we publish the program node, if the debugger is attached, isAttached will be set to true
            // when the debugger calls Attach() on the Program Node! 
 
            while (published && this.isAttached && !this.eventConduitAttached.WaitOne(attachTimeout, false)) ;
            this.isServiceContainerStarting = false; 
        }

        private void Stop(object source, WorkflowRuntimeEventArgs e)
        { 
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.ServiceContainerStopped():"));
 
            try 
            {
                lock (this.syncRoot) 
                {
                    Detach();
                    this.programPublisher.Unpublish();
 
                    // See comments in Attach().
                    this.isZombie = true; 
                } 
            }
            catch 
            {
                // Do not throw exceptions back!
            }
        } 

        internal void Close() 
        { 
            //Unregister from Appdomain event to remove ourselves from GCRoot.
            AppDomain.CurrentDomain.ProcessExit -= OnDomainUnload; 
            AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;

            if (!this.isZombie)
            { 
                Stop(null, new WorkflowRuntimeEventArgs(false));
            } 
        } 

 
        private void OnInstanceEvent(object sender, WorkflowExecutor.WorkflowExecutionEventArgs e)
        {
            switch (e.EventType)
            { 
                case WorkflowEventInternal.Completed:
                    InstanceCompleted(sender, new WorkflowEventArgs(((WorkflowExecutor)sender).WorkflowInstance)); 
                    break; 
                case WorkflowEventInternal.Terminated:
                    InstanceTerminated(sender, new WorkflowEventArgs(((WorkflowExecutor)sender).WorkflowInstance)); 
                    break;
                case WorkflowEventInternal.Unloaded:
                    InstanceUnloaded(sender, new WorkflowEventArgs(((WorkflowExecutor)sender).WorkflowInstance));
                    break; 
                case WorkflowEventInternal.Changed:
                    OnWorkflowChanged(sender, e); 
                    break; 
                case WorkflowEventInternal.HandlerInvoking:
                    OnHandlerInvoking(sender, e); 
                    break;
                case WorkflowEventInternal.HandlerInvoked:
                    OnHandlerInvoked(sender, e);
                    break; 
                case WorkflowEventInternal.ActivityStatusChange:
                    OnActivityStatusChanged(sender, (WorkflowExecutor.ActivityStatusChangeEventArgs)e); 
                    break; 
                case WorkflowEventInternal.ActivityExecuting:
                    OnActivityExecuting(sender, (WorkflowExecutor.ActivityExecutingEventArgs)e); 
                    break;
                default:
                    return;
            } 
        }
 
 
        private void InstanceInitializing(object sender, WorkflowRuntime.WorkflowExecutorInitializingEventArgs e)
        { 
            try
            {
                if (e.Loading)
                    LoadExistingInstance(((WorkflowExecutor)sender).WorkflowInstance, true); 
                else
                    LoadExistingInstance(((WorkflowExecutor)sender).WorkflowInstance, false); 
            } 
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel.
            }
        } 

        private void InstanceCompleted(object sender, WorkflowEventArgs args) 
        { 
            try
            { 
                UnloadExistingInstance(args.WorkflowInstance);
            }
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel. 
            } 
        }
 
        private void InstanceTerminated(object sender, WorkflowEventArgs args)
        {
            try
            { 
                UnloadExistingInstance(args.WorkflowInstance);
            } 
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            }
        }
 
        private void InstanceUnloaded(object sender, WorkflowEventArgs args)
        { 
            // Treat this as if the instance completed so that it won't show up in the UI anymore. 
            try
            { 
                UnloadExistingInstance(args.WorkflowInstance);
            }
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel. 
            } 
        }
 
        private void ScheduleTypeLoaded(object sender, WorkflowDefinitionEventArgs args)
        {
            try
            { 
                if (args.WorkflowType != null)
                { 
                    Activity rootActivity = ((WorkflowRuntime)sender).DefinitionDispenser.GetWorkflowDefinition(args.WorkflowType); 
                    LoadExistingScheduleType(GetScheduleTypeId(args.WorkflowType), args.WorkflowType, false, rootActivity);
                } 
                else
                {
                    Activity rootActivity = ((WorkflowRuntime)sender).DefinitionDispenser.GetWorkflowDefinition(args.WorkflowDefinitionHashCode);
                    LoadExistingScheduleType(GetScheduleTypeId(args.WorkflowDefinitionHashCode), rootActivity.GetType(), false, rootActivity); 
                }
            } 
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            }
        }
 
        private void OnActivityExecuting(object sender, WorkflowExecutor.ActivityExecutingEventArgs eventArgs)
        { 
            if (this.isZombie || !this.isAttached) 
                return;
 
            try
            {
                lock (this.eventLock)
                { 
                    IWorkflowCoreRuntime workflowCoreRuntime = (IWorkflowCoreRuntime)sender;
                    Guid scheduleTypeId = GetScheduleTypeId(workflowCoreRuntime); 
 
                    // When the activity starts executing, update its handler list for stepping.
                    EnumerateEventHandlersForActivity(scheduleTypeId, eventArgs.Activity); 
                    this.controllerConduit.BeforeActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity));
                    this.controllerConduit.ActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity));
                }
            } 
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            } 
        }

        private void OnActivityStatusChanged(object sender, WorkflowExecutor.ActivityStatusChangeEventArgs eventArgs)
        { 
            if (this.isZombie || !this.isAttached)
                return; 
 
            try
            { 
                lock (this.eventLock)
                {
                    // We will receive an event when Activity.Execute() is about to be called.
                    if (eventArgs.Activity.ExecutionStatus == ActivityExecutionStatus.Executing) 
                        return;
 
                    IWorkflowCoreRuntime workflowCoreRuntime = (IWorkflowCoreRuntime)sender; 
                    Guid scheduleTypeId = GetScheduleTypeId(workflowCoreRuntime);
 
                    // When the activity starts executing, update its handler list for stepping.
                    if (eventArgs.Activity.ExecutionStatus == ActivityExecutionStatus.Executing)
                        EnumerateEventHandlersForActivity(scheduleTypeId, eventArgs.Activity);
 
                    this.controllerConduit.BeforeActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity));
                    this.controllerConduit.ActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity)); 
                } 
            }
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel.
            } 
        }
 
		private void OnHandlerInvoking(object sender, EventArgs eventArgs) 
        {
 			// Undone: AkashS - We need to remove EnumerateHandlersForActivity() and set the CPDE 
			// breakpoints from here. This is handle the cases where event handlers are modified
 			// at runtime.
 		}
 
        private void OnHandlerInvoked(object sender, EventArgs eventArgs)
        { 
            if (this.isZombie || !this.isAttached) 
                return;
 
            try
            {
                lock (this.eventLock)
                { 
                    IWorkflowCoreRuntime workflowCoreRuntime = sender as IWorkflowCoreRuntime;
                    this.controllerConduit.HandlerInvoked(this.programId, workflowCoreRuntime.InstanceID, NativeMethods.GetCurrentThreadId(), GetHierarchicalId(workflowCoreRuntime.CurrentActivity)); 
                } 
            }
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel.
            } 
        }
 
        private void OnWorkflowChanged(object sender, EventArgs eventArgs) 
        {
            if (this.isZombie || !this.isAttached) 
                return;

            try
            { 
                lock (this.eventLock)
                { 
                    IWorkflowCoreRuntime workflowCoreRuntime = (IWorkflowCoreRuntime)sender; 

                    // Get cached old root activity. 
                    Activity oldRootActivity = this.instanceTable.GetRootActivity(workflowCoreRuntime.InstanceID);

                    Guid scheduleTypeId = workflowCoreRuntime.InstanceID; // From now on we will treat the instance id as a dynamic schedule type id.
                    LoadExistingScheduleType(scheduleTypeId, oldRootActivity.GetType(), true, oldRootActivity); 

                    // And now reload the instance. 
                    this.instanceTable.UpdateRootActivity(workflowCoreRuntime.InstanceID, oldRootActivity); 

                    // The DE will update the schedule type on the thread that is running the instance. 
                    // DE should be called after the instance table entry is replaced.
                    this.controllerConduit.InstanceDynamicallyUpdated(this.programId, workflowCoreRuntime.InstanceID, scheduleTypeId);
                }
            } 
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            } 
        }

        #endregion
 
        #region Helper methods and properties
 
        // Callers of this method should acquire the executor lock only if they 
        // are not being called in the runtime thread.(bug 17231).
        private void LoadExistingInstance(WorkflowInstance instance, bool attaching) 
        {
            WorkflowExecutor executor = instance.GetWorkflowResourceUNSAFE();
            if (!executor.IsInstanceValid)
                return; 
            IWorkflowCoreRuntime runtimeService = (IWorkflowCoreRuntime)executor;
            Activity rootActivity = runtimeService.RootActivity; 
            Guid scheduleTypeId = GetScheduleTypeId(runtimeService); 

            // If we are just attaching, need to LoadExistingScheduleType with the dynamic definition and type 
            // since the OnDynamicUpdateEvent has never been executed.
            if (attaching && runtimeService.IsDynamicallyUpdated)
                LoadExistingScheduleType(scheduleTypeId, rootActivity.GetType(), true, rootActivity);
 
            // Add to the InstanceTable before firing the DE event !
            this.instanceTable.AddInstance(instance.InstanceId, rootActivity); 
 
            this.controllerConduit.InstanceCreated(this.programId, instance.InstanceId, scheduleTypeId);
 
            // Take a lock so that SetInitialActivityStatus is always called before next status events.
            lock (this.eventLock)
            {
                executor.WorkflowExecutionEvent += OnInstanceEvent; 
                foreach(Activity activity in DebugController.WalkActivityTree(rootActivity))
                { 
#if false 
                    //
                    ReplicatorActivity replicator = activity as ReplicatorActivity; 
                    if (replicator != null)
                    {
                        foreach (Activity queuedChildActivity in replicator.DynamicActivities)
                            activityQueue.Enqueue(queuedChildActivity); 
                    }
                    else 
#endif 
					UpdateActivityStatus(scheduleTypeId, instance.InstanceId, activity);
 
                }

 				ActivityExecutionContext rootExecutionContext = new ActivityExecutionContext(rootActivity);
				foreach(ActivityExecutionContext executionContext in DebugController.WalkExecutionContextTree(rootExecutionContext)) 
				{
					Activity instanceActivity = executionContext.Activity; 
 					foreach (Activity childInstance in DebugController.WalkActivityTree(instanceActivity)) 
                    {
						UpdateActivityStatus(scheduleTypeId, instance.InstanceId, childInstance); 
                    }
 				}
            }
        } 

 		private void UpdateActivityStatus(Guid scheduleTypeId, Guid instanceId, Activity activity) 
		{ 
 			if (activity == null)
				throw new ArgumentNullException("activity"); 

			// first update its handler list
			if (activity.ExecutionStatus == ActivityExecutionStatus.Executing)
 				EnumerateEventHandlersForActivity(scheduleTypeId, activity); 

			//report only states different from the initialized 
 			if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized) 
 			{
				Activity contextActivity = ContextActivityUtils.ContextActivity(activity); 
 				int context = ContextActivityUtils.ContextId(contextActivity);
				this.controllerConduit.SetInitialActivityStatus(this.programId, scheduleTypeId, instanceId, activity.QualifiedName, GetHierarchicalId(activity), activity.ExecutionStatus, context);
			}
 
		}
 
 		private static IEnumerable WalkActivityTree(Activity rootActivity) 
		{
 			if (rootActivity == null || !rootActivity.Enabled) 
 				yield break;

			// Return self
 			yield return rootActivity; 

			// Go through the children as well 
			if (rootActivity is CompositeActivity) 
			{
 				foreach (Activity childActivity in ((CompositeActivity)rootActivity).Activities) 
				{
 					foreach (Activity nestedChild in WalkActivityTree(childActivity))
 						yield return nestedChild;
				} 
 			}
		} 
 
		private static IEnumerable WalkExecutionContextTree(ActivityExecutionContext rootContext)
		{ 
 			if (rootContext == null)
				yield break;

 			yield return rootContext; 

 			foreach (ActivityExecutionContext executionContext in rootContext.ExecutionContextManager.ExecutionContexts) 
			{ 
 				foreach(ActivityExecutionContext nestedContext in WalkExecutionContextTree(executionContext))
					yield return nestedContext; 
			}
			yield break;
 		}
 
        private void UnloadExistingInstance(WorkflowInstance instance)
        { 
            // Fire DE event before removing from the InstanceTable! 
            this.controllerConduit.InstanceCompleted(this.programId, instance.InstanceId);
            this.instanceTable.RemoveInstance(instance.InstanceId); 
        }

        private void LoadExistingScheduleType(Guid scheduleTypeId, Type scheduleType, bool isDynamic, Activity rootActivity)
        { 
            if (rootActivity == null)
                throw new InvalidOperationException(); 
 
            using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            { 
                using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(stringWriter))
                {
                    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
                    serializer.Serialize(xmlWriter, rootActivity); 
                    string fileName = null;
                    string md5Digest = null; 
                    Attribute[] attributes = scheduleType.GetCustomAttributes(typeof(WorkflowMarkupSourceAttribute), false) as Attribute[]; 
                    if (attributes != null && attributes.Length == 1)
                    { 
                        fileName = ((WorkflowMarkupSourceAttribute)attributes[0]).FileName;
                        md5Digest = ((WorkflowMarkupSourceAttribute)attributes[0]).MD5Digest;
                    }
 
                    this.controllerConduit.ScheduleTypeLoaded(this.programId, scheduleTypeId, scheduleType.Assembly.FullName, fileName, md5Digest, isDynamic, scheduleType.FullName, scheduleType.Name, stringWriter.ToString());
                } 
            } 
        }
 
        private string GetHierarchicalId(Activity activity)
        {
            string id = string.Empty;
            while (activity != null) 
            {
                string iterationId = string.Empty; 
 
                Activity contextActivity = ContextActivityUtils.ContextActivity(activity);
                int context = ContextActivityUtils.ContextId(contextActivity); 
                iterationId = activity.Name + ((context > 1 && activity == contextActivity) ? "(" + context + ")" : string.Empty);

                id = (id.Length > 0) ? iterationId + "." + id : iterationId;
 
                activity = activity.Parent;
            } 
 
            return id;
        } 

        private int GetContextId(Activity activity)
        {
            Activity contextActivity = ContextActivityUtils.ContextActivity(activity); 
            return ContextActivityUtils.ContextId(contextActivity);
        } 
 
        private Guid GetScheduleTypeId(IWorkflowCoreRuntime workflowCoreRuntime)
        { 
            Activity rootActivity = workflowCoreRuntime.RootActivity;

            if (workflowCoreRuntime.IsDynamicallyUpdated)
                return workflowCoreRuntime.InstanceID; 
            else if (string.IsNullOrEmpty(rootActivity.GetValue(Activity.WorkflowXamlMarkupProperty) as string))
                return GetScheduleTypeId(rootActivity.GetType()); 
            else 
                return GetScheduleTypeId(rootActivity.GetValue(WorkflowDefinitionDispenser.WorkflowDefinitionHashCodeProperty) as byte[]);
        } 

        private Guid GetScheduleTypeId(Type scheduleType)
        {
            // We cannot use the GUID from the type because that is not guaranteed to be unique, especially when 
            // multiple versions are loaded and the stamps a GuidAttribute.
            lock (this.typeToGuid) 
            { 
                if (!this.typeToGuid.ContainsKey(scheduleType))
                    this.typeToGuid[scheduleType] = Guid.NewGuid(); 

                return (Guid)this.typeToGuid[scheduleType];
            }
        } 

        private Guid GetScheduleTypeId(byte[] scheduleDefHashCode) 
        { 
            // We use the same hashtable to store schedule definition to Guid mapping.
            lock (this.xomlHashToGuid) 
            {
                if (!this.xomlHashToGuid.ContainsKey(scheduleDefHashCode))
                    this.xomlHashToGuid[scheduleDefHashCode] = Guid.NewGuid();
 
                return (Guid)this.xomlHashToGuid[scheduleDefHashCode];
            } 
        } 

        private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) 
        {
            // Call assembly load on the conduit for assemblies loaded from disk.
            if (args.LoadedAssembly.Location != String.Empty)
            { 
                try
                { 
                    this.controllerConduit.AssemblyLoaded(this.programId, args.LoadedAssembly.Location, args.LoadedAssembly.GlobalAssemblyCache); 
                }
                catch 
                {
                    // Don't throw exceptions to the CLR. Ignore exceptions that may occur if the debugger detaches
                    // and closes the remoting channel.
                } 
            }
        } 
 
        private void EnumerateEventHandlersForActivity(Guid scheduleTypeId, Activity activity)
        { 
			List handlerMethods = new List();
            MethodInfo getInvocationListMethod = activity.GetType().GetMethod("System.Workflow.ComponentModel.IDependencyObjectAccessor.GetInvocationList", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);

            foreach (EventInfo eventInfo in activity.GetType().GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy)) 
            {
                DependencyProperty dependencyEvent = DependencyProperty.FromName(eventInfo.Name, activity.GetType()); 
 
                if (dependencyEvent != null)
                { 
                    try
                    {
                        MethodInfo boundGetInvocationListMethod = getInvocationListMethod.MakeGenericMethod(new Type[] { dependencyEvent.PropertyType });
                        foreach (Delegate handler in (boundGetInvocationListMethod.Invoke(activity, new object[] { dependencyEvent }) as Delegate[])) 
                        {
                            MethodInfo handlerMethodInfo = handler.Method; 
 							ActivityHandlerDescriptor handlerMethod; 
                            handlerMethod.Name = handlerMethodInfo.DeclaringType.FullName + "." + handlerMethodInfo.Name;
                            handlerMethod.Token = handlerMethodInfo.MetadataToken; 
                            handlerMethods.Add(handlerMethod);
                        }
                    }
                    catch 
                    {
                    } 
                } 
            }
 
            this.controllerConduit.UpdateHandlerMethodsForActivity(this.programId, scheduleTypeId, activity.QualifiedName, handlerMethods);
        }

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corp., 2004. All rights reserved. 
#region Using directives

using System;
using System.IO; 
using System.Xml;
using System.Text; 
using System.Threading; 
using System.Reflection;
using System.Collections; 
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Runtime.Serialization;
using System.Workflow.Runtime; 
using System.Workflow.Runtime.Hosting; 
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Channels; 
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Serialization; 
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting.Channels.Ipc; 
using System.Configuration; 
using System.Security.Permissions;
using System.Globalization; 
using Microsoft.Win32;
using System.Security.AccessControl;
using System.Security.Principal;
#endregion 

namespace System.Workflow.Runtime.DebugEngine 
{ 
    internal static class RegistryKeys
    { 
        //
        internal static readonly string ProductRootRegKey = @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4.0\Setup\Windows Workflow Foundation";
        internal static readonly string DebuggerSubKey = ProductRootRegKey + @"\Debugger";
    } 

    public sealed class DebugController : MarshalByRefObject 
    { 
        #region Data members
 
        private Guid programId;
        private string hostName;
        private int attachTimeout;
        private ProgramPublisher programPublisher; 
        private DebugControllerThread debugControllerThread;
        private Timer attachTimer; 
        private WorkflowRuntime serviceContainer; 
        private IpcChannel channel;
 		private IWorkflowDebugger controllerConduit; 
        private bool isZombie;
        private bool isAttached;
        private ManualResetEvent eventConduitAttached;
        private InstanceTable instanceTable; 
        private Dictionary typeToGuid;
        private Dictionary xomlHashToGuid; 
        bool isServiceContainerStarting; 
        private const string rootExecutorGuid = "98fcdc7a-8ab4-4fb7-92d4-20f437285729";
        private object eventLock; 
        private object syncRoot = new object();
		private static readonly string ControllerConduitTypeName = "ControllerConduitTypeName";

        #endregion 
		
		#region Security related methods 
 		private delegate void ExceptionNotification(Exception e); 

		internal static void InitializeProcessSecurity() 
 		{
 			// Spawn off a separate thread to that does RevertToSelf and adjusts DACLs.
			// This is because RevertToSelf terminates client impersonation on the thread
 			// that calls it. We do not want to change that on the current thread when 
			// the runtime is hosted inside ASP.net for example.
			Exception workerThreadException = null; 
            ProcessSecurity processSecurity = new ProcessSecurity(); 
            Thread workerThread = new Thread(new ThreadStart(processSecurity.Initialize));
 
            processSecurity.exceptionNotification += delegate(Exception e)
			{
 				workerThreadException = e;
			}; 
 			
            workerThread.Start(); workerThread.Join(); 
 			if (workerThreadException != null) 
				throw workerThreadException;
 		} 

		private class ProcessSecurity
		{
			internal ExceptionNotification exceptionNotification; 

 			internal void Initialize() 
			{ 
 				try
 				{ 
					// This is needed if the thread calling the method is impersonating
 					// a client call (ASP.net hosting scenarios).
					if (!NativeMethods.RevertToSelf())
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 

					// Get the DACL for process token. Add TOKEN_QUERY permissions for the Administrators group. 
 					// Set the updated DACL for process token. 
					RawAcl tokenDacl = GetCurrentProcessTokenDacl();
 					CommonAce adminsGroupAceForToken = new CommonAce(AceFlags.None, AceQualifier.AccessAllowed, NativeMethods.TOKEN_QUERY, new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), false, null); 
 					int i = FindIndexInDacl(adminsGroupAceForToken, tokenDacl);
					if (i != -1)
 						tokenDacl.InsertAce(i, adminsGroupAceForToken);
					SetCurrentProcessTokenDacl(tokenDacl); 
				}
				catch (Exception e) 
 				{ 
					// Communicate any exceptions from this thread back to the thread
 					// that spawned it. 
 					if (exceptionNotification != null)
						exceptionNotification(e);
 				}
			} 

			private RawAcl GetCurrentProcessTokenDacl() 
			{ 
 				IntPtr hProcess = IntPtr.Zero;
				IntPtr hProcessToken = IntPtr.Zero; 
 				IntPtr securityDescriptorPtr = IntPtr.Zero;

 				try
				{ 
 					hProcess = NativeMethods.GetCurrentProcess();
 
					if (!NativeMethods.OpenProcessToken(hProcess, NativeMethods.TOKEN_ALL_ACCESS, out hProcessToken)) 
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 
					// Get security descriptor associated with the kernel object, read the DACL and return
 					// that to the caller.
					uint returnLength;
 
 					NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, IntPtr.Zero, 0, out returnLength);
 					int lasterror = Marshal.GetLastWin32Error();//#pragma warning disable 56523 doesnt recognize 56523 
 
					securityDescriptorPtr = Marshal.AllocCoTaskMem((int)returnLength);
 					 
					if (!NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, securityDescriptorPtr, returnLength, out returnLength))
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

					byte[] sdBytes = new byte[returnLength]; 
 					Marshal.Copy(securityDescriptorPtr, sdBytes, 0, (int)returnLength);
 
					RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor(sdBytes, 0); 

 					return rawSecurityDescriptor.DiscretionaryAcl; 
 				}
				finally
 				{
					if (hProcess != IntPtr.Zero && hProcess != (IntPtr)(-1)) 
						if(!NativeMethods.CloseHandle(hProcess))
							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
 
 					if (hProcessToken != IntPtr.Zero)
						if(!NativeMethods.CloseHandle(hProcessToken)) 
 							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

 					if (securityDescriptorPtr != IntPtr.Zero)
						Marshal.FreeCoTaskMem(securityDescriptorPtr); 
 				}
			} 
			private void SetCurrentProcessTokenDacl(RawAcl dacl) 
			{
 				IntPtr hProcess = IntPtr.Zero; 
				IntPtr hProcessToken = IntPtr.Zero;
 				IntPtr securityDescriptorPtr = IntPtr.Zero;
 				try
				{ 
 					hProcess = NativeMethods.GetCurrentProcess();
 
					if (!NativeMethods.OpenProcessToken(hProcess, NativeMethods.TOKEN_ALL_ACCESS, out hProcessToken)) 
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 
					// Get security descriptor associated with the kernel object and modify it.
 					uint returnLength;

					NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, IntPtr.Zero, 0, out returnLength); 
 					int lasterror = Marshal.GetLastWin32Error();//#pragma warning disable 56523 doesnt recognize 56523
 
 					securityDescriptorPtr = Marshal.AllocCoTaskMem((int)returnLength); 

					if (!NativeMethods.GetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, securityDescriptorPtr, returnLength, out returnLength)) 
 						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

					byte[] sdBytes = new byte[returnLength];
					Marshal.Copy(securityDescriptorPtr, sdBytes, 0, (int)returnLength); 

					RawSecurityDescriptor rawSecurityDescriptor = new RawSecurityDescriptor(sdBytes, 0); 
 					rawSecurityDescriptor.DiscretionaryAcl = dacl; 

					sdBytes = new byte[rawSecurityDescriptor.BinaryLength]; 
 					rawSecurityDescriptor.GetBinaryForm(sdBytes, 0);
 					Marshal.FreeCoTaskMem(securityDescriptorPtr);
					securityDescriptorPtr = Marshal.AllocCoTaskMem(rawSecurityDescriptor.BinaryLength);
 					Marshal.Copy(sdBytes, 0, securityDescriptorPtr, rawSecurityDescriptor.BinaryLength); 

					if (!NativeMethods.SetKernelObjectSecurity(hProcessToken, NativeMethods.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION, securityDescriptorPtr)) 
						Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 
				}
 				finally 
				{
 					if (hProcess != IntPtr.Zero && hProcess != (IntPtr)(-1))
 						if(!NativeMethods.CloseHandle(hProcess))
							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 

 					if (hProcessToken != IntPtr.Zero) 
						if(!NativeMethods.CloseHandle(hProcessToken)) 
							Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 
					if (securityDescriptorPtr != IntPtr.Zero)
 						Marshal.FreeCoTaskMem(securityDescriptorPtr);

				} 
 			}
 
 			// The preferred order in which ACEs are added to DACLs is 
			// documented here: http://search.msdn.microsoft.com/search/results.aspx?qu=Order+of+ACEs+in+a+DACL&View=msdn&st=b.
 			// This routine follows that logic to determine the position of an ACE in the DACL. 
			private int FindIndexInDacl(CommonAce newAce, RawAcl dacl)
			{
				int i = 0;
 				for (i = 0; i < dacl.Count; i++) 
				{
 					if (dacl[i] is CommonAce && ((CommonAce)dacl[i]).SecurityIdentifier.Value == newAce.SecurityIdentifier.Value && dacl[i].AceType == newAce.AceType) 
 					{ 
						i = -1;
 						break; 
					}

					if (newAce.AceType == AceType.AccessDenied && dacl[i].AceType == AceType.AccessDenied && !newAce.IsInherited && !dacl[i].IsInherited)
						continue; 

 					if (newAce.AceType == AceType.AccessDenied && !newAce.IsInherited) 
						break; 

 					if (newAce.AceType == AceType.AccessAllowed && dacl[i].AceType == AceType.AccessAllowed && !newAce.IsInherited && !dacl[i].IsInherited) 
 						continue;

					if (newAce.AceType == AceType.AccessAllowed && !newAce.IsInherited)
 						break; 

				} 
 
				return i;
			} 
 		}
		#endregion

        #region Constructor and Lifetime methods 

        internal DebugController(WorkflowRuntime serviceContainer, string hostName) 
        { 
 			if (serviceContainer == null)
 				throw new ArgumentNullException("serviceContainer"); 

            try
            {
                this.programPublisher = new ProgramPublisher(); 
            }
            catch 
            { 
                // If we are unable to create the ProgramPublisher, this means that VS does not exist on this machine, so we can't debug.
                return; 
            }

            this.serviceContainer = serviceContainer;
            this.programId = Guid.Empty; 
            this.controllerConduit = null;
            this.channel = null; 
            this.isZombie = false; 
            this.hostName = hostName;
 
            AppDomain.CurrentDomain.ProcessExit += OnDomainUnload;
            AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;

            this.serviceContainer.Started += this.Start; 
            this.serviceContainer.Stopped += this.Stop;
        } 
 
        public override object InitializeLifetimeService()
        { 
            // We can't use a sponser because VS doesn't like to be attached when the lease renews itself - the
            // debugee gets an Access Violation and VS freezes. Returning null implies that the proxy shim will be
            // deleted only when the App Domain unloads. However, we will have disconnected the shim so no
            // one will be able to attach to it and the same proxy is used everytime a debugger attaches. 
            return null;
        } 
 
        #endregion
 
        #region Attach and Detach methods

        internal void Attach(Guid programId, int attachTimeout, int detachPingInterval, out string hostName, out string uri, out int controllerThreadId, out bool isSynchronousAttach)
        { 
			Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.Attach(): programId = {0}", programId));
 			lock (this.syncRoot) 
			{ 
				hostName = String.Empty;
				uri = String.Empty; 
 				controllerThreadId = 0;
				isSynchronousAttach = false;

 				// Race condition: 
 				// During the call to Attach() if Uninitialize() is also called, we should ignore the call to Attach() and
				// just return. The Zombie flag and lock(this) help us recognize the ----. 
 				if (this.isZombie) 
					return;
 

				// Race condition:
				// The isAttached flat along with lock(this) catch the ---- where a debugger may have detached which
 				// we haven't detected yet and another debugger may have attached, so we force detach from the first 
				// debugger.
 				if (this.isAttached) 
 					Detach(); 

 
				this.isAttached = true;

 				this.programId = programId;
				this.debugControllerThread = new DebugControllerThread(); 
				this.instanceTable = new InstanceTable(this.debugControllerThread.ManagedThreadId);
				this.typeToGuid = new Dictionary(); 
 				this.xomlHashToGuid = new Dictionary((IEqualityComparer)new DigestComparer()); 

				this.debugControllerThread.RunThread(this.instanceTable); 

 				// Publish our MBR object.
 				IDictionary providerProperties = new Hashtable();
				providerProperties["typeFilterLevel"] = "Full"; 
 				BinaryServerFormatterSinkProvider sinkProvider = new BinaryServerFormatterSinkProvider(providerProperties, null);
 
				Hashtable channelProperties = new Hashtable(); 
				channelProperties["name"] = string.Empty;
				channelProperties["portName"] = this.programId.ToString(); 
 				SecurityIdentifier si = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
				IdentityReference idRef = si.Translate(typeof(NTAccount));
 				channelProperties["authorizedGroup"] = idRef.ToString();
 				this.channel = new IpcChannel(channelProperties, null, sinkProvider); 
				ChannelServices.RegisterChannel(this.channel, true);
 
 				ObjRef o = RemotingServices.Marshal(this, this.programId.ToString()); 
				hostName = this.hostName;
 
				uri = this.channel.GetUrlsForUri(this.programId.ToString())[0];
				controllerThreadId = this.debugControllerThread.ThreadId;
 				isSynchronousAttach = !this.isServiceContainerStarting;
 
				this.attachTimeout = attachTimeout;
 				this.attachTimer = new Timer(AttachTimerCallback, null, attachTimeout, detachPingInterval); 
 			} 
        }
 
        private void Detach()
        {
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.Detach():"));
 
            using(new DebuggerThreadMarker())
            { 
                lock (this.syncRoot) 
                {
 
                    AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;

                    // See comments in Attach().
                    if (this.isZombie || !this.isAttached) 
                        return;
 
                    this.isAttached = false; 

                    // Undone: AkashS - At this point wait for all event handling to complete to avoid exceptions. 

                    this.programId = Guid.Empty;

                    if (this.debugControllerThread != null) 
					{
                        this.debugControllerThread.StopThread(); 
                        this.debugControllerThread = null; 
                    }
 
                    if (this.attachTimer != null)
                    {
                        this.attachTimer.Change(Timeout.Infinite, Timeout.Infinite);
                        this.attachTimer = null; 
                    }
 
                    RemotingServices.Disconnect(this); 
                    if (this.channel != null)
                    { 
                        ChannelServices.UnregisterChannel(this.channel);
                        this.channel = null;
                    }
 
                    this.controllerConduit = null;
 
                    this.eventConduitAttached.Reset(); 
                    this.instanceTable = null;
                    this.typeToGuid = null; 
                    this.xomlHashToGuid = null;

                    // Do this only after we perform the previous cleanup! Otherwise
                    // we may get exceptions from the runtime that may cause the cleanup 
                    // to not happen.
 
                    if (!this.serviceContainer.IsZombie) 
                    {
 						foreach (WorkflowInstance instance in this.serviceContainer.GetLoadedWorkflows()) 
						{
							WorkflowExecutor executor = instance.GetWorkflowResourceUNSAFE();
							using (executor.ExecutorLock.Enter())
 							{ 
								if (executor.IsInstanceValid)
 									executor.WorkflowExecutionEvent -= OnInstanceEvent; 
 							} 
						}
 
                        this.serviceContainer.WorkflowExecutorInitializing -= InstanceInitializing;
                        this.serviceContainer.DefinitionDispenser.WorkflowDefinitionLoaded -= ScheduleTypeLoaded;
                    }
                } 
            }
        } 
 
        private void AttachTimerCallback(object state)
        { 
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.AttachTimerCallback():"));

            try
            { 
                lock (this.syncRoot)
                { 
                    // See comments in Attach(). 
                    if (this.isZombie || !this.isAttached)
                        return; 

                    if (!Debugger.IsAttached)
                    {
                        // The debugger had attached and has now detached, so cleanup, or Attach() was called on the 
                        // Program Node, but the process of attach failed thereafter and so we were never actually
                        // debugged. 
                        this.attachTimer.Change(Timeout.Infinite, Timeout.Infinite); 
                        Detach();
                    } 
                }
            }
            catch
            { 
                // Avoid throwing unhandled exceptions!
            } 
        } 

        private void OnDomainUnload(object sender, System.EventArgs e) 
        {
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.OnDomainUnload():"));

            Stop(null, default(WorkflowRuntimeEventArgs)); 
        }
 
        #endregion 

        #region Methods for the DE 

        public void AttachToConduit(Uri url)
        {
            if (url == null) 
                throw new ArgumentNullException("url");
 
            try 
            {
                using (new DebuggerThreadMarker()) 
                {
 					try
					{
						RegistryKey debugEngineSubKey = Registry.LocalMachine.OpenSubKey(RegistryKeys.DebuggerSubKey); 
						if (debugEngineSubKey != null)
 						{ 
							string controllerConduitTypeName = debugEngineSubKey.GetValue(ControllerConduitTypeName, String.Empty) as string; 
 							if (!String.IsNullOrEmpty(controllerConduitTypeName) && Type.GetType(controllerConduitTypeName) != null)
 								this.controllerConduit = Activator.GetObject(Type.GetType(controllerConduitTypeName), url.AbsolutePath) as IWorkflowDebugger; 
						}
 					}
					catch {}
					finally 
					{
 						if (this.controllerConduit == null) 
							this.controllerConduit = Activator.GetObject(Type.GetType("Microsoft.Workflow.DebugEngine.ControllerConduit, Microsoft.Workflow.DebugController, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"), url.AbsolutePath) as IWorkflowDebugger; 
 					}
 					Debug.Assert(this.controllerConduit != null, "Failed to create Controller Conduit"); 
					if (this.controllerConduit == null)
 						return;

                    this.eventLock = new object(); 

                    // Race Condition: 
                    // We hook up to the AssemblyLoad event, the Schedule events and Instance events handler 
                    // before we iterate over all loaded assemblies. This means that we need to deal with duplicates in the
                    // debugee. 

                    // Race Condition:
                    // Further the order in which we hook up handlers/iterate is important to avoid ----s if the events fire
                    // before the iterations complete. We need to hook and iterate over the assemblies, then the schedule 
                    // types and finally the instances. This guarantees that we always have all the assemblies when we load
                    // schedules types and we always have all the schedule types when we load instances. 
 
                    AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
                    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 
                    {
                        if (   !assembly.IsDynamic
                            && !(assembly is System.Reflection.Emit.AssemblyBuilder)
                            && !(string.IsNullOrEmpty(assembly.Location))) 
                        {
                            this.controllerConduit.AssemblyLoaded(this.programId, assembly.Location, assembly.GlobalAssemblyCache); 
                        } 
                    }
                    this.serviceContainer.DefinitionDispenser.WorkflowDefinitionLoaded += ScheduleTypeLoaded; 

                    // In here we load all schedule types defined as they are - with no dynamic updates
                    ReadOnlyCollection types;
                    ReadOnlyCollection values; 
                    this.serviceContainer.DefinitionDispenser.GetWorkflowTypes(out types, out values);
                    for (int i = 0; i < types.Count; i++) 
                    { 
                        Type scheduleType = types[i];
                        Activity rootActivity = values[i]; 
                        LoadExistingScheduleType(GetScheduleTypeId(scheduleType), scheduleType, false, rootActivity);
                    }

                    ReadOnlyCollection keys; 
                    this.serviceContainer.DefinitionDispenser.GetWorkflowDefinitions(out keys, out values);
                    for (int i = 0; i < keys.Count; i++) 
                    { 
                        byte[] scheduleDefHash = keys[i];
                        Activity rootActivity = values[i]; 
                        Activity workflowDefinition = (Activity)rootActivity.GetValue(Activity.WorkflowDefinitionProperty);
                        ArrayList changeActions = null;
                        if (workflowDefinition != null)
                            changeActions = (ArrayList)workflowDefinition.GetValue(WorkflowChanges.WorkflowChangeActionsProperty); 
                        LoadExistingScheduleType(GetScheduleTypeId(scheduleDefHash), rootActivity.GetType(), (changeActions != null && changeActions.Count != 0), rootActivity);
                    } 
 
                    this.serviceContainer.WorkflowExecutorInitializing += InstanceInitializing;
 
                    foreach (WorkflowInstance instance in this.serviceContainer.GetLoadedWorkflows())
                    {
                        WorkflowExecutor executor = instance.GetWorkflowResourceUNSAFE();
                        using (executor.ExecutorLock.Enter()) 
                        {
                            LoadExistingInstance(instance, true); 
                        } 
                    }
 
                    this.eventConduitAttached.Set();
                }
            }
            catch (Exception e) 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel. 
				Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: Failure in DebugController.AttachToConduit: {0}, Call stack:{1}", e.Message, e.StackTrace));
			} 

        }

        #endregion 

        #region Methods for the Runtime 
 
        private void Start(object source, WorkflowRuntimeEventArgs e)
        { 
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.ServiceContainerStarted():"));

            this.isZombie = false;
            this.isAttached = false; 
            this.eventConduitAttached = new ManualResetEvent(false);
            this.isServiceContainerStarting = true; 
 
            bool published = this.programPublisher.Publish(this);
 
            // If the debugger is already attached, then the DE will invoke AttachToConduit() on a separate thread.
            // We need to wait for that to happen to prevent new instances being created and causing a ----. See
            // comments in ControllerConduit.ProgramCreated(). However, if the DE never calls AttachToConduit(),
            // and the detaches instead, we set a wait timeout to that of our Attach Timer. 
            // Note that when we publish the program node, if the debugger is attached, isAttached will be set to true
            // when the debugger calls Attach() on the Program Node! 
 
            while (published && this.isAttached && !this.eventConduitAttached.WaitOne(attachTimeout, false)) ;
            this.isServiceContainerStarting = false; 
        }

        private void Stop(object source, WorkflowRuntimeEventArgs e)
        { 
            Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "WDE: DebugController.ServiceContainerStopped():"));
 
            try 
            {
                lock (this.syncRoot) 
                {
                    Detach();
                    this.programPublisher.Unpublish();
 
                    // See comments in Attach().
                    this.isZombie = true; 
                } 
            }
            catch 
            {
                // Do not throw exceptions back!
            }
        } 

        internal void Close() 
        { 
            //Unregister from Appdomain event to remove ourselves from GCRoot.
            AppDomain.CurrentDomain.ProcessExit -= OnDomainUnload; 
            AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;

            if (!this.isZombie)
            { 
                Stop(null, new WorkflowRuntimeEventArgs(false));
            } 
        } 

 
        private void OnInstanceEvent(object sender, WorkflowExecutor.WorkflowExecutionEventArgs e)
        {
            switch (e.EventType)
            { 
                case WorkflowEventInternal.Completed:
                    InstanceCompleted(sender, new WorkflowEventArgs(((WorkflowExecutor)sender).WorkflowInstance)); 
                    break; 
                case WorkflowEventInternal.Terminated:
                    InstanceTerminated(sender, new WorkflowEventArgs(((WorkflowExecutor)sender).WorkflowInstance)); 
                    break;
                case WorkflowEventInternal.Unloaded:
                    InstanceUnloaded(sender, new WorkflowEventArgs(((WorkflowExecutor)sender).WorkflowInstance));
                    break; 
                case WorkflowEventInternal.Changed:
                    OnWorkflowChanged(sender, e); 
                    break; 
                case WorkflowEventInternal.HandlerInvoking:
                    OnHandlerInvoking(sender, e); 
                    break;
                case WorkflowEventInternal.HandlerInvoked:
                    OnHandlerInvoked(sender, e);
                    break; 
                case WorkflowEventInternal.ActivityStatusChange:
                    OnActivityStatusChanged(sender, (WorkflowExecutor.ActivityStatusChangeEventArgs)e); 
                    break; 
                case WorkflowEventInternal.ActivityExecuting:
                    OnActivityExecuting(sender, (WorkflowExecutor.ActivityExecutingEventArgs)e); 
                    break;
                default:
                    return;
            } 
        }
 
 
        private void InstanceInitializing(object sender, WorkflowRuntime.WorkflowExecutorInitializingEventArgs e)
        { 
            try
            {
                if (e.Loading)
                    LoadExistingInstance(((WorkflowExecutor)sender).WorkflowInstance, true); 
                else
                    LoadExistingInstance(((WorkflowExecutor)sender).WorkflowInstance, false); 
            } 
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel.
            }
        } 

        private void InstanceCompleted(object sender, WorkflowEventArgs args) 
        { 
            try
            { 
                UnloadExistingInstance(args.WorkflowInstance);
            }
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel. 
            } 
        }
 
        private void InstanceTerminated(object sender, WorkflowEventArgs args)
        {
            try
            { 
                UnloadExistingInstance(args.WorkflowInstance);
            } 
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            }
        }
 
        private void InstanceUnloaded(object sender, WorkflowEventArgs args)
        { 
            // Treat this as if the instance completed so that it won't show up in the UI anymore. 
            try
            { 
                UnloadExistingInstance(args.WorkflowInstance);
            }
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel. 
            } 
        }
 
        private void ScheduleTypeLoaded(object sender, WorkflowDefinitionEventArgs args)
        {
            try
            { 
                if (args.WorkflowType != null)
                { 
                    Activity rootActivity = ((WorkflowRuntime)sender).DefinitionDispenser.GetWorkflowDefinition(args.WorkflowType); 
                    LoadExistingScheduleType(GetScheduleTypeId(args.WorkflowType), args.WorkflowType, false, rootActivity);
                } 
                else
                {
                    Activity rootActivity = ((WorkflowRuntime)sender).DefinitionDispenser.GetWorkflowDefinition(args.WorkflowDefinitionHashCode);
                    LoadExistingScheduleType(GetScheduleTypeId(args.WorkflowDefinitionHashCode), rootActivity.GetType(), false, rootActivity); 
                }
            } 
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            }
        }
 
        private void OnActivityExecuting(object sender, WorkflowExecutor.ActivityExecutingEventArgs eventArgs)
        { 
            if (this.isZombie || !this.isAttached) 
                return;
 
            try
            {
                lock (this.eventLock)
                { 
                    IWorkflowCoreRuntime workflowCoreRuntime = (IWorkflowCoreRuntime)sender;
                    Guid scheduleTypeId = GetScheduleTypeId(workflowCoreRuntime); 
 
                    // When the activity starts executing, update its handler list for stepping.
                    EnumerateEventHandlersForActivity(scheduleTypeId, eventArgs.Activity); 
                    this.controllerConduit.BeforeActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity));
                    this.controllerConduit.ActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity));
                }
            } 
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            } 
        }

        private void OnActivityStatusChanged(object sender, WorkflowExecutor.ActivityStatusChangeEventArgs eventArgs)
        { 
            if (this.isZombie || !this.isAttached)
                return; 
 
            try
            { 
                lock (this.eventLock)
                {
                    // We will receive an event when Activity.Execute() is about to be called.
                    if (eventArgs.Activity.ExecutionStatus == ActivityExecutionStatus.Executing) 
                        return;
 
                    IWorkflowCoreRuntime workflowCoreRuntime = (IWorkflowCoreRuntime)sender; 
                    Guid scheduleTypeId = GetScheduleTypeId(workflowCoreRuntime);
 
                    // When the activity starts executing, update its handler list for stepping.
                    if (eventArgs.Activity.ExecutionStatus == ActivityExecutionStatus.Executing)
                        EnumerateEventHandlersForActivity(scheduleTypeId, eventArgs.Activity);
 
                    this.controllerConduit.BeforeActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity));
                    this.controllerConduit.ActivityStatusChanged(this.programId, scheduleTypeId, workflowCoreRuntime.InstanceID, eventArgs.Activity.QualifiedName, GetHierarchicalId(eventArgs.Activity), eventArgs.Activity.ExecutionStatus, GetContextId(eventArgs.Activity)); 
                } 
            }
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel.
            } 
        }
 
		private void OnHandlerInvoking(object sender, EventArgs eventArgs) 
        {
 			// Undone: AkashS - We need to remove EnumerateHandlersForActivity() and set the CPDE 
			// breakpoints from here. This is handle the cases where event handlers are modified
 			// at runtime.
 		}
 
        private void OnHandlerInvoked(object sender, EventArgs eventArgs)
        { 
            if (this.isZombie || !this.isAttached) 
                return;
 
            try
            {
                lock (this.eventLock)
                { 
                    IWorkflowCoreRuntime workflowCoreRuntime = sender as IWorkflowCoreRuntime;
                    this.controllerConduit.HandlerInvoked(this.programId, workflowCoreRuntime.InstanceID, NativeMethods.GetCurrentThreadId(), GetHierarchicalId(workflowCoreRuntime.CurrentActivity)); 
                } 
            }
            catch 
            {
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches
                // and closes the remoting channel.
            } 
        }
 
        private void OnWorkflowChanged(object sender, EventArgs eventArgs) 
        {
            if (this.isZombie || !this.isAttached) 
                return;

            try
            { 
                lock (this.eventLock)
                { 
                    IWorkflowCoreRuntime workflowCoreRuntime = (IWorkflowCoreRuntime)sender; 

                    // Get cached old root activity. 
                    Activity oldRootActivity = this.instanceTable.GetRootActivity(workflowCoreRuntime.InstanceID);

                    Guid scheduleTypeId = workflowCoreRuntime.InstanceID; // From now on we will treat the instance id as a dynamic schedule type id.
                    LoadExistingScheduleType(scheduleTypeId, oldRootActivity.GetType(), true, oldRootActivity); 

                    // And now reload the instance. 
                    this.instanceTable.UpdateRootActivity(workflowCoreRuntime.InstanceID, oldRootActivity); 

                    // The DE will update the schedule type on the thread that is running the instance. 
                    // DE should be called after the instance table entry is replaced.
                    this.controllerConduit.InstanceDynamicallyUpdated(this.programId, workflowCoreRuntime.InstanceID, scheduleTypeId);
                }
            } 
            catch
            { 
                // Don't throw exceptions to the Runtime. Ignore exceptions that may occur if the debugger detaches 
                // and closes the remoting channel.
            } 
        }

        #endregion
 
        #region Helper methods and properties
 
        // Callers of this method should acquire the executor lock only if they 
        // are not being called in the runtime thread.(bug 17231).
        private void LoadExistingInstance(WorkflowInstance instance, bool attaching) 
        {
            WorkflowExecutor executor = instance.GetWorkflowResourceUNSAFE();
            if (!executor.IsInstanceValid)
                return; 
            IWorkflowCoreRuntime runtimeService = (IWorkflowCoreRuntime)executor;
            Activity rootActivity = runtimeService.RootActivity; 
            Guid scheduleTypeId = GetScheduleTypeId(runtimeService); 

            // If we are just attaching, need to LoadExistingScheduleType with the dynamic definition and type 
            // since the OnDynamicUpdateEvent has never been executed.
            if (attaching && runtimeService.IsDynamicallyUpdated)
                LoadExistingScheduleType(scheduleTypeId, rootActivity.GetType(), true, rootActivity);
 
            // Add to the InstanceTable before firing the DE event !
            this.instanceTable.AddInstance(instance.InstanceId, rootActivity); 
 
            this.controllerConduit.InstanceCreated(this.programId, instance.InstanceId, scheduleTypeId);
 
            // Take a lock so that SetInitialActivityStatus is always called before next status events.
            lock (this.eventLock)
            {
                executor.WorkflowExecutionEvent += OnInstanceEvent; 
                foreach(Activity activity in DebugController.WalkActivityTree(rootActivity))
                { 
#if false 
                    //
                    ReplicatorActivity replicator = activity as ReplicatorActivity; 
                    if (replicator != null)
                    {
                        foreach (Activity queuedChildActivity in replicator.DynamicActivities)
                            activityQueue.Enqueue(queuedChildActivity); 
                    }
                    else 
#endif 
					UpdateActivityStatus(scheduleTypeId, instance.InstanceId, activity);
 
                }

 				ActivityExecutionContext rootExecutionContext = new ActivityExecutionContext(rootActivity);
				foreach(ActivityExecutionContext executionContext in DebugController.WalkExecutionContextTree(rootExecutionContext)) 
				{
					Activity instanceActivity = executionContext.Activity; 
 					foreach (Activity childInstance in DebugController.WalkActivityTree(instanceActivity)) 
                    {
						UpdateActivityStatus(scheduleTypeId, instance.InstanceId, childInstance); 
                    }
 				}
            }
        } 

 		private void UpdateActivityStatus(Guid scheduleTypeId, Guid instanceId, Activity activity) 
		{ 
 			if (activity == null)
				throw new ArgumentNullException("activity"); 

			// first update its handler list
			if (activity.ExecutionStatus == ActivityExecutionStatus.Executing)
 				EnumerateEventHandlersForActivity(scheduleTypeId, activity); 

			//report only states different from the initialized 
 			if (activity.ExecutionStatus != ActivityExecutionStatus.Initialized) 
 			{
				Activity contextActivity = ContextActivityUtils.ContextActivity(activity); 
 				int context = ContextActivityUtils.ContextId(contextActivity);
				this.controllerConduit.SetInitialActivityStatus(this.programId, scheduleTypeId, instanceId, activity.QualifiedName, GetHierarchicalId(activity), activity.ExecutionStatus, context);
			}
 
		}
 
 		private static IEnumerable WalkActivityTree(Activity rootActivity) 
		{
 			if (rootActivity == null || !rootActivity.Enabled) 
 				yield break;

			// Return self
 			yield return rootActivity; 

			// Go through the children as well 
			if (rootActivity is CompositeActivity) 
			{
 				foreach (Activity childActivity in ((CompositeActivity)rootActivity).Activities) 
				{
 					foreach (Activity nestedChild in WalkActivityTree(childActivity))
 						yield return nestedChild;
				} 
 			}
		} 
 
		private static IEnumerable WalkExecutionContextTree(ActivityExecutionContext rootContext)
		{ 
 			if (rootContext == null)
				yield break;

 			yield return rootContext; 

 			foreach (ActivityExecutionContext executionContext in rootContext.ExecutionContextManager.ExecutionContexts) 
			{ 
 				foreach(ActivityExecutionContext nestedContext in WalkExecutionContextTree(executionContext))
					yield return nestedContext; 
			}
			yield break;
 		}
 
        private void UnloadExistingInstance(WorkflowInstance instance)
        { 
            // Fire DE event before removing from the InstanceTable! 
            this.controllerConduit.InstanceCompleted(this.programId, instance.InstanceId);
            this.instanceTable.RemoveInstance(instance.InstanceId); 
        }

        private void LoadExistingScheduleType(Guid scheduleTypeId, Type scheduleType, bool isDynamic, Activity rootActivity)
        { 
            if (rootActivity == null)
                throw new InvalidOperationException(); 
 
            using (StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture))
            { 
                using (XmlWriter xmlWriter = Helpers.CreateXmlWriter(stringWriter))
                {
                    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
                    serializer.Serialize(xmlWriter, rootActivity); 
                    string fileName = null;
                    string md5Digest = null; 
                    Attribute[] attributes = scheduleType.GetCustomAttributes(typeof(WorkflowMarkupSourceAttribute), false) as Attribute[]; 
                    if (attributes != null && attributes.Length == 1)
                    { 
                        fileName = ((WorkflowMarkupSourceAttribute)attributes[0]).FileName;
                        md5Digest = ((WorkflowMarkupSourceAttribute)attributes[0]).MD5Digest;
                    }
 
                    this.controllerConduit.ScheduleTypeLoaded(this.programId, scheduleTypeId, scheduleType.Assembly.FullName, fileName, md5Digest, isDynamic, scheduleType.FullName, scheduleType.Name, stringWriter.ToString());
                } 
            } 
        }
 
        private string GetHierarchicalId(Activity activity)
        {
            string id = string.Empty;
            while (activity != null) 
            {
                string iterationId = string.Empty; 
 
                Activity contextActivity = ContextActivityUtils.ContextActivity(activity);
                int context = ContextActivityUtils.ContextId(contextActivity); 
                iterationId = activity.Name + ((context > 1 && activity == contextActivity) ? "(" + context + ")" : string.Empty);

                id = (id.Length > 0) ? iterationId + "." + id : iterationId;
 
                activity = activity.Parent;
            } 
 
            return id;
        } 

        private int GetContextId(Activity activity)
        {
            Activity contextActivity = ContextActivityUtils.ContextActivity(activity); 
            return ContextActivityUtils.ContextId(contextActivity);
        } 
 
        private Guid GetScheduleTypeId(IWorkflowCoreRuntime workflowCoreRuntime)
        { 
            Activity rootActivity = workflowCoreRuntime.RootActivity;

            if (workflowCoreRuntime.IsDynamicallyUpdated)
                return workflowCoreRuntime.InstanceID; 
            else if (string.IsNullOrEmpty(rootActivity.GetValue(Activity.WorkflowXamlMarkupProperty) as string))
                return GetScheduleTypeId(rootActivity.GetType()); 
            else 
                return GetScheduleTypeId(rootActivity.GetValue(WorkflowDefinitionDispenser.WorkflowDefinitionHashCodeProperty) as byte[]);
        } 

        private Guid GetScheduleTypeId(Type scheduleType)
        {
            // We cannot use the GUID from the type because that is not guaranteed to be unique, especially when 
            // multiple versions are loaded and the stamps a GuidAttribute.
            lock (this.typeToGuid) 
            { 
                if (!this.typeToGuid.ContainsKey(scheduleType))
                    this.typeToGuid[scheduleType] = Guid.NewGuid(); 

                return (Guid)this.typeToGuid[scheduleType];
            }
        } 

        private Guid GetScheduleTypeId(byte[] scheduleDefHashCode) 
        { 
            // We use the same hashtable to store schedule definition to Guid mapping.
            lock (this.xomlHashToGuid) 
            {
                if (!this.xomlHashToGuid.ContainsKey(scheduleDefHashCode))
                    this.xomlHashToGuid[scheduleDefHashCode] = Guid.NewGuid();
 
                return (Guid)this.xomlHashToGuid[scheduleDefHashCode];
            } 
        } 

        private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) 
        {
            // Call assembly load on the conduit for assemblies loaded from disk.
            if (args.LoadedAssembly.Location != String.Empty)
            { 
                try
                { 
                    this.controllerConduit.AssemblyLoaded(this.programId, args.LoadedAssembly.Location, args.LoadedAssembly.GlobalAssemblyCache); 
                }
                catch 
                {
                    // Don't throw exceptions to the CLR. Ignore exceptions that may occur if the debugger detaches
                    // and closes the remoting channel.
                } 
            }
        } 
 
        private void EnumerateEventHandlersForActivity(Guid scheduleTypeId, Activity activity)
        { 
			List handlerMethods = new List();
            MethodInfo getInvocationListMethod = activity.GetType().GetMethod("System.Workflow.ComponentModel.IDependencyObjectAccessor.GetInvocationList", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy);

            foreach (EventInfo eventInfo in activity.GetType().GetEvents(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy)) 
            {
                DependencyProperty dependencyEvent = DependencyProperty.FromName(eventInfo.Name, activity.GetType()); 
 
                if (dependencyEvent != null)
                { 
                    try
                    {
                        MethodInfo boundGetInvocationListMethod = getInvocationListMethod.MakeGenericMethod(new Type[] { dependencyEvent.PropertyType });
                        foreach (Delegate handler in (boundGetInvocationListMethod.Invoke(activity, new object[] { dependencyEvent }) as Delegate[])) 
                        {
                            MethodInfo handlerMethodInfo = handler.Method; 
 							ActivityHandlerDescriptor handlerMethod; 
                            handlerMethod.Name = handlerMethodInfo.DeclaringType.FullName + "." + handlerMethodInfo.Name;
                            handlerMethod.Token = handlerMethodInfo.MetadataToken; 
                            handlerMethods.Add(handlerMethod);
                        }
                    }
                    catch 
                    {
                    } 
                } 
            }
 
            this.controllerConduit.UpdateHandlerMethodsForActivity(this.programId, scheduleTypeId, activity.QualifiedName, handlerMethods);
        }

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK