//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Activities.Runtime { using System; using System.Activities.DynamicUpdate; using System.Collections.ObjectModel; using System.Runtime; using System.Runtime.Serialization; using System.Security; // can't add FuncCompletionCallbackWrapper since we don't know what to close the generic with [KnownType(typeof(ActivityCompletionCallbackWrapper))] [KnownType(typeof(DelegateCompletionCallbackWrapper))] [DataContract] abstract class CompletionCallbackWrapper : CallbackWrapper { static Type completionCallbackType = typeof(CompletionCallback); static Type[] completionCallbackParameters = new Type[] { typeof(NativeActivityContext), typeof(ActivityInstance) }; bool checkForCancelation; bool needsToGatherOutputs; protected CompletionCallbackWrapper(Delegate callback, ActivityInstance owningInstance) : base(callback, owningInstance) { } protected bool NeedsToGatherOutputs { get { return this.needsToGatherOutputs; } set { this.needsToGatherOutputs = value; } } [DataMember(EmitDefaultValue = false, Name = "checkForCancelation")] internal bool SerializedCheckForCancelation { get { return this.checkForCancelation; } set { this.checkForCancelation = value; } } [DataMember(EmitDefaultValue = false, Name = "needsToGatherOutputs")] internal bool SerializedNeedsToGatherOutputs { get { return this.needsToGatherOutputs; } set { this.needsToGatherOutputs = value; } } public void CheckForCancelation() { this.checkForCancelation = true; } protected virtual void GatherOutputs(ActivityInstance completedInstance) { // No-op in the base class } internal WorkItem CreateWorkItem(ActivityInstance completedInstance, ActivityExecutor executor) { // We use the property to guard against the virtual method call // since we don't need it in the common case if (this.NeedsToGatherOutputs) { this.GatherOutputs(completedInstance); } CompletionWorkItem workItem; if (this.checkForCancelation) { workItem = new CompletionWithCancelationCheckWorkItem(this, completedInstance); } else { workItem = executor.CompletionWorkItemPool.Acquire(); workItem.Initialize(this, completedInstance); } if (completedInstance.InstanceMap != null) { completedInstance.InstanceMap.AddEntry(workItem); } return workItem; } [Fx.Tag.SecurityNote(Critical = "Because any implementation will be calling EnsureCallback", Safe = "Safe because the method needs to be part of an Activity and we are casting to the callback type and it has a very specific signature. The author of the callback is buying into being invoked from PT.")] [SecuritySafeCritical] protected internal abstract void Invoke(NativeActivityContext context, ActivityInstance completedInstance); [DataContract] public class CompletionWorkItem : ActivityExecutionWorkItem, ActivityInstanceMap.IActivityReference { CompletionCallbackWrapper callbackWrapper; ActivityInstance completedInstance; // Called by the Pool. public CompletionWorkItem() { this.IsPooled = true; } // Only used by non-pooled base classes. protected CompletionWorkItem(CompletionCallbackWrapper callbackWrapper, ActivityInstance completedInstance) : base(callbackWrapper.ActivityInstance) { this.callbackWrapper = callbackWrapper; this.completedInstance = completedInstance; } protected ActivityInstance CompletedInstance { get { return this.completedInstance; } } [DataMember(Name = "callbackWrapper")] internal CompletionCallbackWrapper SerializedCallbackWrapper { get { return this.callbackWrapper; } set { this.callbackWrapper = value; } } [DataMember(Name = "completedInstance")] internal ActivityInstance SerializedCompletedInstance { get { return this.completedInstance; } set { this.completedInstance = value; } } public void Initialize(CompletionCallbackWrapper callbackWrapper, ActivityInstance completedInstance) { base.Reinitialize(callbackWrapper.ActivityInstance); this.callbackWrapper = callbackWrapper; this.completedInstance = completedInstance; } protected override void ReleaseToPool(ActivityExecutor executor) { base.ClearForReuse(); this.callbackWrapper = null; this.completedInstance = null; executor.CompletionWorkItemPool.Release(this); } public override void TraceCompleted() { if (TD.CompleteCompletionWorkItemIsEnabled()) { TD.CompleteCompletionWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id, this.completedInstance.Activity.GetType().ToString(), this.completedInstance.Activity.DisplayName, this.completedInstance.Id); } } public override void TraceScheduled() { if (TD.ScheduleCompletionWorkItemIsEnabled()) { TD.ScheduleCompletionWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id, this.completedInstance.Activity.GetType().ToString(), this.completedInstance.Activity.DisplayName, this.completedInstance.Id); } } public override void TraceStarting() { if (TD.StartCompletionWorkItemIsEnabled()) { TD.StartCompletionWorkItem(this.ActivityInstance.Activity.GetType().ToString(), this.ActivityInstance.Activity.DisplayName, this.ActivityInstance.Id, this.completedInstance.Activity.GetType().ToString(), this.completedInstance.Activity.DisplayName, this.completedInstance.Id); } } public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) { NativeActivityContext context = executor.NativeActivityContextPool.Acquire(); Fx.Assert(this.completedInstance.Activity != null, "Activity definition should always be associated with an activity instance."); try { context.Initialize(this.ActivityInstance, executor, bookmarkManager); this.callbackWrapper.Invoke(context, this.completedInstance); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } this.ExceptionToPropagate = e; } finally { context.Dispose(); executor.NativeActivityContextPool.Release(context); if (this.ActivityInstance.InstanceMap != null) { this.ActivityInstance.InstanceMap.RemoveEntry(this); } } return true; } Activity ActivityInstanceMap.IActivityReference.Activity { get { return this.completedInstance.Activity; } } void ActivityInstanceMap.IActivityReference.Load(Activity activity, ActivityInstanceMap instanceMap) { if (this.completedInstance.Activity == null) { ((ActivityInstanceMap.IActivityReference)this.completedInstance).Load(activity, instanceMap); } } } [DataContract] class CompletionWithCancelationCheckWorkItem : CompletionWorkItem { public CompletionWithCancelationCheckWorkItem(CompletionCallbackWrapper callbackWrapper, ActivityInstance completedInstance) : base(callbackWrapper, completedInstance) { } public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager) { if (this.CompletedInstance.State != ActivityInstanceState.Closed && this.ActivityInstance.IsPerformingDefaultCancelation) { this.ActivityInstance.MarkCanceled(); } return base.Execute(executor, bookmarkManager); } } } }