File: Shared\CompModHelpers.cs
Project: ndp\cdf\src\WF\Common\System.Workflow.ComponentModel.csproj (System.Workflow.ComponentModel)
// Copyright (c) Microsoft Corporation. All rights reserved. 
//  
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
// WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
// WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. 
// THE ENTIRE RISK OF USE OR RESULTS IN CONNECTION WITH THE USE OF THIS CODE 
// AND INFORMATION REMAINS WITH THE USER. 
 
 
/*********************************************************************
 * NOTE: A copy of this file exists at: WF\Activities\Common
 * The two files must be kept in sync.  Any change made here must also
 * be made to WF\Activities\Common\CompModHelpers.cs
*********************************************************************/
namespace System.Workflow.ComponentModel.Design
{
    using System;
    using System.CodeDom;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.ComponentModel.Design;
    using System.ComponentModel.Design.Serialization;
    using System.Workflow.ComponentModel.Serialization;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Windows.Forms;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Compiler;
    using System.Text;
    using System.Reflection;
    using System.Xml;
    using System.Globalization;
    using Microsoft.Win32;
    using System.Runtime.InteropServices;
    using System.Diagnostics.CodeAnalysis;
 
    #region Class Helpers
    internal static class Helpers
    {
        private static readonly string VSExtensionProductRegistrySubKey = "Visual Studio Ext for Windows Workflow";
        // 
 
        internal static readonly string ProductRootRegKey = @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v4.0\Setup\Windows Workflow Foundation";
        internal static readonly string ProductInstallDirectory = GetInstallDirectory(false);
        internal static readonly string ProductSDKInstallDirectory = GetInstallDirectory(true);
        internal static readonly string TypeProviderAssemblyRegValueName = "References";
 
        private static readonly string ProductRootRegKey30 = @"SOFTWARE\Microsoft\Net Framework Setup\NDP\v3.0\Setup\Windows Workflow Foundation";
        internal static readonly string ProductInstallDirectory30 = GetInstallDirectory30();
 
        private const string ProductCode = "{B644FB52-BB3D-4C43-80EC-57644210536A}";
        private const string ProductSDKCode = "{C8A7718A-FF6D-4DDC-AE36-BBF968D6799B}";
        private const string INSTALLPROPERTY_INSTALLLOCATION = "InstallLocation";
 
        internal const int FILENAME_MAX = 260; //"stdio.h"
 
        [SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", Justification = "LastIndexOf(\"\\\") not a security issue.")]
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string PerUserRegistryKey
        {
            get
            {
                string keyPath = String.Empty;
                using (RegistryKey userRegistryKey = Application.UserAppDataRegistry)
                {
                    keyPath = userRegistryKey.ToString().Substring(Registry.CurrentUser.ToString().Length + 1);
                    keyPath = keyPath.Substring(0, keyPath.LastIndexOf("\\"));
                    keyPath += "\\" + VSExtensionProductRegistrySubKey;
                }
                return keyPath;
            }
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private static string TypeProviderRegistryKeyPath
        {
            get
            {
                return PerUserRegistryKey + "\\TypeProvider";
            }
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool IsFileNameValid(string fileName)
        {
            int length = Path.GetInvalidPathChars().GetLength(0) + 5;
            char[] invalidChars = new char[length];
            Path.GetInvalidPathChars().CopyTo(invalidChars, 0);
            invalidChars[length - 5] = ':';
            invalidChars[length - 4] = '?';
            invalidChars[length - 3] = '*';
            invalidChars[length - 2] = '/';
            invalidChars[length - 1] = '\\';
 
            return (fileName != null &&
                    fileName.Length != 0 &&
                    fileName.Length <= FILENAME_MAX &&
                    fileName.IndexOfAny(invalidChars) == -1);
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool AreAllActivities(ICollection c)
        {
            if (c == null)
                throw new ArgumentNullException("c");
 
            foreach (object obj in c)
            {
                if (!(obj is Activity))
                    return false;
            }
            return true;
        }
 
        // this will return IDictionary, whose keys are parent and value is arraylist of child activities
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static IDictionary PairUpCommonParentActivities(ICollection activities)
        {
            if (activities == null)
                throw new ArgumentNullException("activities");
 
            Hashtable commonParentActivities = new Hashtable();
            foreach (Activity activity in activities)
            {
                if (activity.Parent != null)
                {
                    ArrayList childActivities = (ArrayList)commonParentActivities[activity.Parent];
                    if (childActivities == null)
                    {
                        childActivities = new ArrayList();
                        commonParentActivities.Add(activity.Parent, childActivities);
                    }
                    childActivities.Add(activity);
                }
            }
            return commonParentActivities;
        }
 
        // this will remove any activity from the collection whose parent is already there in the collection
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity[] GetTopLevelActivities(ICollection activities)
        {
            if (activities == null)
                throw new ArgumentNullException("activities");
 
            List<Activity> filteredActivities = new List<Activity>();
            foreach (object obj in activities)
            {
                Activity activity = obj as Activity;
                if (activity != null)
                {
                    bool foundParent = false;
                    Activity parentActivity = activity.Parent;
                    while (parentActivity != null && !foundParent)
                    {
                        foreach (object obj2 in activities)
                        {
                            if (obj2 == parentActivity)
                            {
                                foundParent = true;
                                break;
                            }
                        }
                        parentActivity = parentActivity.Parent;
                    }
 
                    if (!foundParent)
                        filteredActivities.Add(activity);
                }
            }
            return filteredActivities.ToArray();
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity[] GetNestedActivities(CompositeActivity compositeActivity)
        {
 
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");
 
            IList<Activity> childActivities = null;
            ArrayList nestedActivities = new ArrayList();
            Queue compositeActivities = new Queue();
            compositeActivities.Enqueue(compositeActivity);
            while (compositeActivities.Count > 0)
            {
                CompositeActivity compositeActivity2 = (CompositeActivity)compositeActivities.Dequeue();
                childActivities = compositeActivity2.Activities;
 
                foreach (Activity activity in childActivities)
                {
                    nestedActivities.Add(activity);
                    if (activity is CompositeActivity)
                        compositeActivities.Enqueue(activity);
                }
            }
            return (Activity[])nestedActivities.ToArray(typeof(Activity));
        }
 
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static IList GetIdentifiersInCompositeActivity(CompositeActivity compositeActivity)
        {
            ArrayList identifiers = new ArrayList();
            if (compositeActivity != null)
            {
                identifiers.Add(compositeActivity.Name);
                IList<Activity> allChildren = GetAllNestedActivities(compositeActivity);
                foreach (Activity activity in allChildren)
                    identifiers.Add(activity.Name);
            }
            return ArrayList.ReadOnly(identifiers);
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity[] GetAllNestedActivities(CompositeActivity compositeActivity)
        {
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");
 
            ArrayList nestedActivities = new ArrayList();
 
            // Note: GetAllNestedActivities will not check for black box activities.
            // This is to allow it to be invoked from within the activity's 
            // constructor.
            //if(Helpers.IsCustomActivity(compositeActivity))
            //return (Activity[])nestedActivities.ToArray(typeof(Activity));
 
            Queue compositeActivities = new Queue();
            compositeActivities.Enqueue(compositeActivity);
            while (compositeActivities.Count > 0)
            {
                CompositeActivity compositeActivity2 = (CompositeActivity)compositeActivities.Dequeue();
                if (compositeActivity2 == compositeActivity || !Helpers.IsCustomActivity(compositeActivity2))
                {
                    foreach (Activity activity in compositeActivity2.Activities)
                    {
                        nestedActivities.Add(activity);
                        if (activity is CompositeActivity)
                            compositeActivities.Enqueue(activity);
                    }
 
                    foreach (Activity activity in compositeActivity2.EnabledActivities)
                    {
                        if (!nestedActivities.Contains(activity))
                        {
                            nestedActivities.Add(activity);
                            if (activity is CompositeActivity)
                                compositeActivities.Enqueue(activity);
                        }
                    }
                }
            }
            return (Activity[])nestedActivities.ToArray(typeof(Activity));
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string MergeNamespaces(string primaryNs, string secondaryNs)
        {
            string newNs = primaryNs;
            if (secondaryNs != null && secondaryNs.Length > 0)
            {
                if (newNs != null && newNs.Length > 0)
                    newNs += ("." + secondaryNs);
                else
                    newNs = secondaryNs;
            }
 
            if (newNs == null)
                newNs = string.Empty;
            return newNs;
        }
 
        internal static Activity GetRootActivity(Activity activity)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");
 
            while (activity.Parent != null)
                activity = activity.Parent;
 
            return activity;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Stream SerializeDesignersToStream(ICollection activities)
        {
            Stream stateStream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stateStream);
 
            Queue<IComponent> serializedComponents = new Queue<IComponent>();
            foreach (IComponent activity in activities)
                serializedComponents.Enqueue(activity);
 
            while (serializedComponents.Count > 0)
            {
                IComponent component = serializedComponents.Dequeue();
                if (component != null && component.Site != null)
                {
                    IDesignerHost designerHost = component.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
                    if (designerHost == null)
                        throw new InvalidOperationException(
                            SR.GetString(SR.General_MissingService, typeof(IDesignerHost).Name));
 
                    ActivityDesigner activityDesigner = designerHost.GetDesigner(component) as ActivityDesigner;
                    if (activityDesigner != null)
                    {
                        try
                        {
                            ((IPersistUIState)activityDesigner).SaveViewState(writer);
 
                            CompositeActivity compositeActivity = component as CompositeActivity;
                            if (compositeActivity != null)
                            {
                                foreach (IComponent childActivity in compositeActivity.Activities)
                                {
                                    serializedComponents.Enqueue(childActivity);
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }
            }
 
            return stateStream;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static void DeserializeDesignersFromStream(ICollection activities, Stream stateStream)
        {
            if (stateStream.Length == 0)
                return;
 
            BinaryReader reader = new BinaryReader(stateStream);
            stateStream.Seek(0, SeekOrigin.Begin);
 
            Queue<IComponent> serializedComponents = new Queue<IComponent>();
            foreach (IComponent component in activities)
                serializedComponents.Enqueue(component);
 
            while (serializedComponents.Count > 0)
            {
                IComponent component = serializedComponents.Dequeue();
                if (component != null && component.Site != null)
                {
                    IDesignerHost designerHost = component.Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
                    if (designerHost == null)
                        throw new InvalidOperationException(
                            SR.GetString(SR.General_MissingService, typeof(IDesignerHost).Name));
 
                    ActivityDesigner activityDesigner = designerHost.GetDesigner(component) as ActivityDesigner;
                    if (activityDesigner != null)
                    {
                        try
                        {
                            ((IPersistUIState)activityDesigner).LoadViewState(reader);
 
                            CompositeActivity compositeActivity = component as CompositeActivity;
                            if (compositeActivity != null)
                            {
                                foreach (IComponent childActivity in compositeActivity.Activities)
                                {
                                    serializedComponents.Enqueue(childActivity);
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string GetBaseIdentifier(Activity activity)
        {
            string baseIdentifier = activity.GetType().Name;
            StringBuilder b = new StringBuilder(baseIdentifier.Length);
            for (int i = 0; i < baseIdentifier.Length; i++)
            {
                if (Char.IsUpper(baseIdentifier[i]) && (i == 0 || i == baseIdentifier.Length - 1 || Char.IsUpper(baseIdentifier[i + 1])))
                {
                    b.Append(Char.ToLowerInvariant(baseIdentifier[i]));
                }
                else
                {
                    b.Append(baseIdentifier.Substring(i));
                    break;
                }
            }
            return b.ToString();
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string GetRootNamespace(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");
 
            string rootNs = string.Empty;
            IWorkflowCompilerOptionsService compilerOptionsService = (IWorkflowCompilerOptionsService)serviceProvider.GetService(typeof(IWorkflowCompilerOptionsService));
            if (compilerOptionsService != null && compilerOptionsService.RootNamespace != null)
                rootNs = compilerOptionsService.RootNamespace; //e.g. WorkflowApp1
            return rootNs;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Type GetDataSourceClass(Activity activity, IServiceProvider serviceProvider)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");
 
            Type activityType = null;
            string className = null;
            if (activity == GetRootActivity(activity))
                className = activity.GetValue(WorkflowMarkupSerializer.XClassProperty) as String;
 
            if (!String.IsNullOrEmpty(className))
            {
                ITypeProvider typeProvider = (ITypeProvider)serviceProvider.GetService(typeof(ITypeProvider));
                if (typeProvider == null)
                    throw new InvalidOperationException(
                        SR.GetString(SR.General_MissingService, typeof(ITypeProvider).Name));
 
                activityType = typeProvider.GetType(className);
            }
            else
            {
                return activity.GetType();
            }
 
            return activityType;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity GetDataSourceActivity(Activity activity, string inputName, out string name)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");
            if (string.IsNullOrEmpty(inputName))
                throw new ArgumentException("inputName");
 
            name = inputName;
            if (inputName.IndexOf('.') == -1)
                return activity;
 
            int indexOfDot = inputName.LastIndexOf('.');
            string scopeID = inputName.Substring(0, indexOfDot);
            name = inputName.Substring(indexOfDot + 1);
 
            Activity contextActivity = Helpers.ParseActivityForBind(activity, scopeID);
            if (contextActivity == null)
                contextActivity = Helpers.ParseActivity(Helpers.GetRootActivity(activity), scopeID);
 
            // activity can be either the qualified id of the scope activity or the qualified id of the custom activity.
            return contextActivity;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static void GetNamespaceAndClassName(string fullQualifiedName, out string namespaceName, out string className)
        {
            namespaceName = String.Empty;
            className = String.Empty;
 
            if (fullQualifiedName == null)
                return;
 
            int indexOfDot = fullQualifiedName.LastIndexOf('.');
            if (indexOfDot != -1)
            {
                namespaceName = fullQualifiedName.Substring(0, indexOfDot);
                className = fullQualifiedName.Substring(indexOfDot + 1);
            }
            else
            {
                className = fullQualifiedName;
            }
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static CodeTypeDeclaration GetCodeNamespaceAndClass(CodeNamespaceCollection namespaces, string namespaceName, string className, out CodeNamespace codeNamespace)
        {
            codeNamespace = null;
            foreach (CodeNamespace ns in namespaces)
            {
                if (ns.Name == namespaceName)
                {
                    codeNamespace = ns;
                    break;
                }
            }
 
            CodeTypeDeclaration codeTypeDeclaration = null;
            if (codeNamespace != null)
            {
                foreach (CodeTypeDeclaration typeDecl in codeNamespace.Types)
                {
                    if (typeDecl.Name == className)
                    {
                        codeTypeDeclaration = typeDecl;
                        break;
                    }
                }
            }
            return codeTypeDeclaration;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string GetClassName(string fullQualifiedName)
        {
            if (fullQualifiedName == null)
                return null;
 
            string className = fullQualifiedName;
            int indexOfDot = fullQualifiedName.LastIndexOf('.');
            if (indexOfDot != -1)
                className = fullQualifiedName.Substring(indexOfDot + 1);
            return className;
        }
 
 
        [DllImport("msi.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
        private static extern int MsiGetProductInfoW(string szProduct, string szProperty, StringBuilder lpValueBuf, ref int pcchValueBuf);
        private static string GetInstallDirectory(bool getSDKDir)
        {
            string path = string.Empty;
            try
            {
                //ERROR_UNKNOWN_PROPERTY           1608L
                //ERROR_INVALID_PARAMETER          87L
                int length = FILENAME_MAX + 1;
                StringBuilder location = new StringBuilder(length);
                int hr = MsiGetProductInfoW(getSDKDir ? ProductSDKCode : ProductCode, INSTALLPROPERTY_INSTALLLOCATION, location, ref length);
                int error = Marshal.GetLastWin32Error();
                if (hr == 0)
                {
                    path = location.ToString();
                }
                else
                {
                    Debug.WriteLine("Error loading install directory: " + error.ToString(CultureInfo.CurrentCulture));
                }
 
            }
            catch
            {
            }
 
            if (string.IsNullOrEmpty(path))
            {
                try
                {
                    if (!getSDKDir)
                    {
                        using (RegistryKey key = Registry.LocalMachine.OpenSubKey(ProductRootRegKey))
                        {
                            if (key != null)
                                path = (string)key.GetValue("InstallDir");
                        }
                    }
                }
                catch
                {
                }
            }
 
            // 
            if (string.IsNullOrEmpty(path))
                path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
 
            return path;
        }
 
        private static string GetInstallDirectory30()
        {
            string path = string.Empty;
            try
            {
                //ERROR_UNKNOWN_PROPERTY           1608L
                //ERROR_INVALID_PARAMETER          87L
                int length = FILENAME_MAX + 1;
                StringBuilder location = new StringBuilder(length);
                int hr = MsiGetProductInfoW(ProductCode, INSTALLPROPERTY_INSTALLLOCATION, location, ref length);
                int error = Marshal.GetLastWin32Error();
                if (hr == 0)
                {
                    path = location.ToString();
                }
                else
                {
                    Debug.WriteLine("Error loading 3.0 install directory: " + error.ToString(CultureInfo.CurrentCulture));
                }
 
            }
            catch
            {
            }
 
            if (string.IsNullOrEmpty(path))
            {
                try
                {
                    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(ProductRootRegKey30))
                    {
                        if (key != null)
                        {
                            path = (string)key.GetValue("InstallDir");
                        }
                    }
                }
                catch
                {
                }
            }
 
            return path;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Type GetBaseType(PropertyInfo property, object owner, IServiceProvider serviceProvider)
        {
            //When we are emitting code for the dynamic properties we might get the propertyinfo as null
            if (owner == null)
                throw new ArgumentNullException("owner");
 
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");
 
            if (property != null)
            {
                IDynamicPropertyTypeProvider basetypeProvider = owner as IDynamicPropertyTypeProvider;
                if (basetypeProvider != null)
                {
                    Type type = basetypeProvider.GetPropertyType(serviceProvider, property.Name);
                    if (type != null)
                        return type;
                }
 
                return property.PropertyType;
            }
 
            return null;
        }
 
        //
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static AccessTypes GetAccessType(PropertyInfo property, object owner, IServiceProvider serviceProvider)
        {
            //When we are emitting code for the dynamic properties we might get the propertyinfo as null
            if (owner == null)
                throw new ArgumentNullException("owner");
 
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");
 
            if (property != null)
            {
                IDynamicPropertyTypeProvider basetypeProvider = owner as IDynamicPropertyTypeProvider;
                if (basetypeProvider != null)
                    return basetypeProvider.GetAccessType(serviceProvider, property.Name);
            }
 
            return AccessTypes.Read;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool IsChildActivity(CompositeActivity parent, Activity activity)
        {
            foreach (Activity containedActivity in parent.Activities)
            {
                if (activity == containedActivity)
                    return true;
 
                if (containedActivity is CompositeActivity &&
                    Helpers.IsChildActivity(containedActivity as CompositeActivity, activity))
                    return true;
            }
 
            return false;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool TypesEqual(CodeTypeReference typeLeft, Type typeRight)
        {
            if (typeRight.IsArray && typeLeft.ArrayRank != typeRight.GetArrayRank()) return false;
            // 
            if (!typeLeft.BaseType.Equals(typeRight.FullName)) return false;
 
            if (typeLeft.ArrayRank > 0)
                return TypesEqual(typeLeft.ArrayElementType, typeRight.GetElementType());
            return true;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool TypesEqual(CodeTypeReference typeLeft, CodeTypeReference typeRight)
        {
            if (typeLeft.ArrayRank != typeRight.ArrayRank) return false;
            if (!typeLeft.BaseType.Equals(typeRight.BaseType)) return false;
 
            if (typeLeft.ArrayRank > 0)
                return TypesEqual(typeLeft.ArrayElementType, typeRight.ArrayElementType);
            return true;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static DesignerSerializationVisibility GetSerializationVisibility(MemberInfo memberInfo)
        {
 
            if (memberInfo == null)
                throw new ArgumentNullException("memberInfo");
 
            DesignerSerializationVisibility designerSerializationVisibility = DesignerSerializationVisibility.Visible;
 
            // Calling GetCustomAttributes on PropertyInfo or EventInfo when the inherit parameter of GetCustomAttributes 
            // is true does not walk the type hierarchy. But System.Attribute.GetCustomAttributes causes perf issues.
            object[] attributes = memberInfo.GetCustomAttributes(typeof(DesignerSerializationVisibilityAttribute), true);
            if (attributes.Length > 0)
                designerSerializationVisibility = (attributes[0] as DesignerSerializationVisibilityAttribute).Visibility;
            else if (Attribute.IsDefined(memberInfo, typeof(DesignerSerializationVisibilityAttribute)))
                designerSerializationVisibility = (Attribute.GetCustomAttribute(memberInfo, typeof(DesignerSerializationVisibilityAttribute)) as DesignerSerializationVisibilityAttribute).Visibility;
 
            return designerSerializationVisibility;
        }
 
        // Method parameters must match exactly
        // 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static MethodInfo GetMethodExactMatch(Type type, string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
        {
            MethodInfo foundMethod = null;
            MethodInfo[] methods = type.GetMethods(bindingAttr);
            foreach (MethodInfo method in methods)
            {
                bool matchName = ((bindingAttr & BindingFlags.IgnoreCase) == BindingFlags.IgnoreCase) ? string.Compare(method.Name, name, StringComparison.OrdinalIgnoreCase) == 0 : string.Compare(method.Name, name, StringComparison.Ordinal) == 0;
                if (matchName)
                {
                    bool mismatch = false;
                    if (types != null)
                    {
                        ParameterInfo[] parameters = method.GetParameters();
                        if (parameters.GetLength(0) == types.Length)
                        {
                            for (int index = 0; !mismatch && index < parameters.Length; index++)
                                mismatch = (parameters[index].ParameterType == null) || (!parameters[index].ParameterType.IsAssignableFrom(types[index]));
                        }
                        else
                            mismatch = true;
                    }
                    if (!mismatch)
                    {
                        foundMethod = method;
                        break;
                    }
                }
            }
 
            return foundMethod;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static T GetAttributeFromObject<T>(object attributeObject) where T : Attribute
        {
            if (attributeObject is AttributeInfoAttribute)
                return (T)((AttributeInfoAttribute)attributeObject).AttributeInfo.CreateAttribute();
 
            if (attributeObject is T)
                return (T)attributeObject;
 
            return null;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Type GetDelegateFromEvent(EventInfo eventInfo)
        {
            if (eventInfo.EventHandlerType != null)
                return eventInfo.EventHandlerType;
 
            return TypeProvider.GetEventHandlerType(eventInfo);
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static void AddTypeProviderAssembliesFromRegistry(TypeProvider typeProvider, IServiceProvider serviceProvider)
        {
            if (typeProvider == null)
                throw new ArgumentNullException("typeProvider");
            if (serviceProvider == null)
                throw new ArgumentNullException("serviceProvider");
 
            RegistryKey referenceKey = Registry.CurrentUser.OpenSubKey(TypeProviderRegistryKeyPath);
            if (referenceKey != null)
            {
                ITypeProviderCreator typeProviderCreator = serviceProvider.GetService(typeof(ITypeProviderCreator)) as ITypeProviderCreator;
                foreach (string assemblyName in ((string[])referenceKey.GetValue(TypeProviderAssemblyRegValueName)))
                {
                    try
                    {
                        if (typeProviderCreator != null)
                        {
                            bool addAssembly = true;
                            Assembly assembly = typeProviderCreator.GetTransientAssembly(AssemblyName.GetAssemblyName(assemblyName));
                            // Check to see if a copy of the assembly is already added.
                            if (assembly != null)
                            {
                                foreach (Type type in assembly.GetTypes())
                                {
                                    if (typeProvider.GetType(type.AssemblyQualifiedName) != null)
                                        addAssembly = false;
                                    break;
                                }
                                if (addAssembly)
                                    typeProvider.AddAssembly(assembly);
                            }
                        }
                        else
                            // AddAssemblyReference should take care of duplicates.
                            typeProvider.AddAssemblyReference(assemblyName);
 
                    }
                    catch
                    {
                        // Continue loading.
                    }
                }
 
                referenceKey.Close();
            }
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static void UpdateTypeProviderAssembliesRegistry(string assemblyName)
        {
            RegistryKey referenceKey = Registry.CurrentUser.CreateSubKey(TypeProviderRegistryKeyPath);
            if (referenceKey != null)
            {
                try
                {
                    ArrayList references = null;
                    if (referenceKey.ValueCount > 0)
                        references = new ArrayList((string[])referenceKey.GetValue(TypeProviderAssemblyRegValueName));
                    else
                        references = new ArrayList();
 
                    if (!references.Contains(assemblyName))
                    {
                        references.Add(assemblyName);
                        referenceKey.SetValue(TypeProviderAssemblyRegValueName, ((string[])references.ToArray(typeof(string))));
                    }
                }
                catch
                {
                    //We eat the exception
                }
                finally
                {
                    referenceKey.Close();
                }
            }
        }
 
        internal static CompositeActivity GetDeclaringActivity(Activity activity)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");
 
            CompositeActivity parent = activity.Parent;
            while (parent != null)
            {
                // This will be the root
                if (parent.Parent == null)
                    return parent;
 
                // Any custom activity found is the declaring activity
                if (IsCustomActivity(parent))
                    return parent;
 
                parent = parent.Parent;
            }
            return null;
        }
 
        internal static bool IsActivityLocked(Activity activity)
        {
            if (activity == null)
                throw new ArgumentNullException("activity");
 
            CompositeActivity parent = activity.Parent;
            while (parent != null)
            {
                // If root, not locked
                if (parent.Parent == null)
                    return false;
 
                // Any custom activity found, then locked
                if (IsCustomActivity(parent))
                    return true;
 
                parent = parent.Parent;
            }
 
            return false;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity GetEnclosingActivity(Activity activity)
        {
            Activity enclosingActivity;
 
            if (IsActivityLocked(activity))
                enclosingActivity = Helpers.GetDeclaringActivity(activity);
            else
                enclosingActivity = GetRootActivity(activity);
 
            return enclosingActivity;
        }
 
        // This function returns all the executable activities including secondary flow activities.
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        public static IList<Activity> GetAllEnabledActivities(CompositeActivity compositeActivity)
        {
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");
 
            List<Activity> allActivities = new List<Activity>(compositeActivity.EnabledActivities);
            foreach (Activity childActivity in compositeActivity.Activities)
            {
                if (childActivity.Enabled &&
                        IsFrameworkActivity(childActivity))
                    allActivities.Add(childActivity);
            }
            return allActivities;
        }
        public static bool IsFrameworkActivity(Activity activity)
        {
            return (activity is CancellationHandlerActivity ||
                        activity is CompensationHandlerActivity ||
                        activity is FaultHandlersActivity);
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static MethodInfo GetInterfaceMethod(Type interfaceType, string methodName)
        {
            MethodInfo methodInfo = null;
            string interfaceName = String.Empty;
            string method = String.Empty;
 
            if (methodName.LastIndexOf('.') > 0)
            {
                interfaceName = methodName.Substring(0, methodName.LastIndexOf('.'));
                method = methodName.Substring(methodName.LastIndexOf('.') + 1);
            }
 
            if (!String.IsNullOrEmpty(interfaceName))
            {
                foreach (Type inheritedInterface in interfaceType.GetInterfaces())
                {
                    if (String.Compare(inheritedInterface.FullName, interfaceName, StringComparison.Ordinal) == 0)
                    {
                        methodInfo = inheritedInterface.GetMethod(method);
                        break;
                    }
                }
            }
            else
            {
                methodInfo = interfaceType.GetMethod(methodName);
            }
 
            return methodInfo;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static XmlWriter CreateXmlWriter(object output)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = ("\t");
            settings.OmitXmlDeclaration = true;
            settings.CloseOutput = true;
 
            if (output is string)
                return XmlWriter.Create(output as string, settings);
            else if (output is TextWriter)
                return XmlWriter.Create(output as TextWriter, settings);
            else
            {
                Debug.Assert(false, "Invalid argument type.  'output' must either be string or TextWriter.");
                return null;
            }
        }
 
        #region DesignTimeType Support
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static string GetDesignTimeTypeName(object owner, object key)
        {
            string typeName = null;
            DependencyObject dependencyObject = owner as DependencyObject;
            if (dependencyObject != null && key != null)
            {
                if (dependencyObject.UserData.Contains(UserDataKeys.DesignTimeTypeNames))
                {
                    Hashtable typeNames = dependencyObject.UserData[UserDataKeys.DesignTimeTypeNames] as Hashtable;
                    if (typeNames != null && typeNames.ContainsKey(key))
                        typeName = typeNames[key] as string;
                }
            }
            return typeName;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static void SetDesignTimeTypeName(object owner, object key, string value)
        {
            DependencyObject dependencyObject = owner as DependencyObject;
            if (dependencyObject != null && key != null)
            {
                if (!dependencyObject.UserData.Contains(UserDataKeys.DesignTimeTypeNames))
                    dependencyObject.UserData[UserDataKeys.DesignTimeTypeNames] = new Hashtable();
 
                Hashtable typeNames = dependencyObject.UserData[UserDataKeys.DesignTimeTypeNames] as Hashtable;
                typeNames[key] = value;
            }
        }
        #endregion
 
        #region Helpers from ExecutableCompModHelpers
        // This only works for composite activity.
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool IsCustomActivity(CompositeActivity compositeActivity)
        {
            if (compositeActivity == null)
                throw new ArgumentNullException("compositeActivity");
 
            if (compositeActivity.UserData.Contains(UserDataKeys.CustomActivity))
            {
                return (bool)(compositeActivity.UserData[UserDataKeys.CustomActivity]);
            }
            else
            {
                try
                {
                    CompositeActivity activity = Activator.CreateInstance(compositeActivity.GetType()) as CompositeActivity;
                    if (activity != null && activity.Activities.Count > 0)
                    {
                        compositeActivity.UserData[UserDataKeys.CustomActivityDefaultName] = activity.Name;
                        compositeActivity.UserData[UserDataKeys.CustomActivity] = true; //
                        return true;
                    }
                }
                catch
                {
                    // 
                }
            }
 
            compositeActivity.UserData[UserDataKeys.CustomActivity] = false; //
            return false;
        }
 
        [SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", Justification = "IndexOf(\".\") not a security issue.")]
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity ParseActivity(Activity parsingContext, string activityName)
        {
            if (parsingContext == null)
                throw new ArgumentNullException("parsingContext");
            if (activityName == null)
                throw new ArgumentNullException("activityName");
 
            string currentAtivityName = activityName;
            string nextActivityName = string.Empty;
            int indexOfDot = activityName.IndexOf(".");
            if (indexOfDot != -1)
            {
                currentAtivityName = activityName.Substring(0, indexOfDot);
                nextActivityName = activityName.Substring(indexOfDot + 1);
                if (nextActivityName.Length == 0)
                    return null;
            }
 
            Activity currentActivity = GetActivity(parsingContext, currentAtivityName);
            if (currentActivity != null)
            {
                if (nextActivityName.Length > 0)
                {
                    if (!(currentActivity is CompositeActivity) || !IsCustomActivity(currentActivity as CompositeActivity))
                        // current activity must be a custom activity, otherwise there should be no dots in the name.
                        return null;
 
                    string[] names = nextActivityName.Split('.');
                    for (int i = 0; i < names.Length; i++)
                    {
                        Activity nextActivity = GetActivity(currentActivity, names[i]);
                        if (nextActivity == null || !Helpers.IsActivityLocked(nextActivity))
                            return null;
 
                        CompositeActivity declaringActivity = GetDeclaringActivity(nextActivity);
                        if (currentActivity != declaringActivity)
                            return null;
 
                        currentActivity = nextActivity;
                    }
 
                    return currentActivity;
                }
                else
                {
                    // This activity should always be unlocked, unless if GetChildActivity() is called from
                    // within the custom activity's companion class, then we don't have the full qualified ID available
                    // at that time.  We allow this to succeed only if the declaring activity is the same as the declaring
                    // activity of the context activity passed in.
                    if (Helpers.IsActivityLocked(currentActivity))//.IsLocked)
                    {
                        if (!IsDeclaringActivityMatchesContext(currentActivity, parsingContext))
                            return null;
                    }
 
                    return currentActivity;
                }
            }
 
            return null;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static Activity ParseActivityForBind(Activity context, string activityName)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            if (activityName == null)
                throw new ArgumentNullException("activityName");
 
            if (string.Equals(activityName, "/Self", StringComparison.Ordinal))
            {
                return context;
            }
            else if (activityName.StartsWith("/Parent", StringComparison.OrdinalIgnoreCase))
            {
                Activity activity = context;
                string[] paths = activityName.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < paths.Length && activity != null; i++)
                {
                    string parent = paths[i].Trim();
                    activity = (string.Equals(parent, "Parent", StringComparison.OrdinalIgnoreCase)) ? activity.Parent : null;
                }
                return activity;
            }
            else if (Helpers.IsActivityLocked(context))
            {
                // Look for the matching activity inside the custom activity context first.  This is because if a bind
                // is coming from a custom activity, it's activity ref ID may not match the qualified ID of the
                // the activity.
                Activity activity = null;
                Activity declaringActivity = Helpers.GetDeclaringActivity(context);
                Guid currentContextGuid = GetRuntimeContextGuid(context);
                Guid declaringContextGuid = GetRuntimeContextGuid(declaringActivity);
 
                Activity currentContextActivity = context;
                Activity parentContextActivity = context.Parent;
                Guid parentContextGuid = GetRuntimeContextGuid(parentContextActivity);
                while (activity == null && declaringContextGuid != currentContextGuid)
                {
                    // WinOE Bug 17931: if the context id is different, it means that this activity is running in a child context (such as 
                    // the children of a replicator or a while).  we need to resolve the activity within the child context
                    // first.  If we go up to the declaring activity, we'd be finding children of the template instead of
                    // the actual running instance.
                    while (parentContextActivity != null && parentContextGuid == currentContextGuid)
                    {
                        currentContextActivity = parentContextActivity;
                        parentContextActivity = parentContextActivity.Parent;
                        parentContextGuid = GetRuntimeContextGuid(parentContextActivity);
                    }
 
                    activity = Helpers.ParseActivity(currentContextActivity, activityName);
                    currentContextGuid = parentContextGuid;
                }
 
                if (activity == null)
                {
                    // Check the declaring activity
                    activity = Helpers.ParseActivity(declaringActivity, activityName);
                }
 
                // Nothing found, let's see if this is bind to the custom activity itself.
                if (activity == null)
                {
                    if (!declaringActivity.UserData.Contains(UserDataKeys.CustomActivityDefaultName))
                    {
                        //we need to activate a new instance of the declaringActivity's type and check if its name equals to the one we are looking for
                        Activity newCustomActivity = Activator.CreateInstance(declaringActivity.GetType()) as Activity;
                        declaringActivity.UserData[UserDataKeys.CustomActivityDefaultName] = newCustomActivity.Name;
                    }
 
                    if (((string)declaringActivity.UserData[UserDataKeys.CustomActivityDefaultName]) == activityName)
                        activity = declaringActivity;
                }
 
                // if this is a locked activity, its bind reference must be within its declaring activity. We should not try
                // to resolve it beyond that scope.
                return activity;
            }
 
            Activity targetActivity = null;
            Activity parentActivity = context;
 
            //if it's a custom activity and it has parent, start looking for the target activity at the parent level
            //otherwise we'll get children of the custom activity
            bool mayLookInside = false; //we may look inside the custom activity if the target is not found outside
            CompositeActivity compositeParentActivity = parentActivity as CompositeActivity;
            if (compositeParentActivity != null && parentActivity.Parent != null && IsCustomActivity(compositeParentActivity))
            {
                mayLookInside = true;
                parentActivity = parentActivity.Parent;
            }
 
            while (targetActivity == null && parentActivity != null)
            {
                targetActivity = parentActivity.GetActivityByName(activityName, true);
                parentActivity = parentActivity.Parent;
            }
 
            if (mayLookInside && targetActivity == null)
            {
                //if we have not found an appropriate activity at the parent level, try looking inside
                //we dont need to look outside (loop while parent is not null) - it has already been done above
                parentActivity = context;
                targetActivity = parentActivity.GetActivityByName(activityName, true);
            }
 
 
            return (targetActivity == null) ? Helpers.ParseActivity(Helpers.GetRootActivity(context), activityName) : targetActivity;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private static Guid GetRuntimeContextGuid(Activity currentActivity)
        {
            Activity contextActivity = currentActivity;
            Guid contextGuid = (Guid)contextActivity.GetValue(Activity.ActivityContextGuidProperty);
            while (contextGuid == Guid.Empty && contextActivity.Parent != null)
            {
                contextActivity = contextActivity.Parent;
                contextGuid = (Guid)contextActivity.GetValue(Activity.ActivityContextGuidProperty);
            }
            return contextGuid;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private static bool IsDeclaringActivityMatchesContext(Activity currentActivity, Activity context)
        {
            CompositeActivity declaringContext = context as CompositeActivity;
 
            CompositeActivity declaringActivityOfCurrent = Helpers.GetDeclaringActivity(currentActivity);
 
            // If the context activity is locked and it is a primitive activity
            // or NOT a custom activity then we need to find its enclosing 
            // custom activity.
            if (Helpers.IsActivityLocked(context) &&
                    (declaringContext == null || !Helpers.IsCustomActivity(declaringContext))
                )
                declaringContext = Helpers.GetDeclaringActivity(context);
 
            if (declaringContext == declaringActivityOfCurrent)
                return true;
            else
                return false;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal static bool IsAlternateFlowActivity(Activity activity)
        {
            if (activity == null)
                return false;
 
            bool isAlternateFlowActivityAttribute = false;
            //dont want to use reflection to check for the alternate flow attribute
            //this is a fix for a perf issue - use of reflection in a ui loop
            if (!activity.UserData.Contains(typeof(AlternateFlowActivityAttribute)))
            {
                isAlternateFlowActivityAttribute = activity.GetType().GetCustomAttributes(typeof(AlternateFlowActivityAttribute), true).Length != 0;
                activity.UserData[typeof(AlternateFlowActivityAttribute)] = isAlternateFlowActivityAttribute;
            }
            else
            {
                isAlternateFlowActivityAttribute = (bool)activity.UserData[typeof(AlternateFlowActivityAttribute)];
            }
 
            return isAlternateFlowActivityAttribute;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        private static Activity GetActivity(Activity containerActivity, string id)
        {
            if (containerActivity != null)
            {
                Queue activities = new Queue();
                activities.Enqueue(containerActivity);
                while (activities.Count > 0)
                {
                    Activity activity = (Activity)activities.Dequeue();
                    if (activity.Enabled)
                    {
                        if (activity.Name == id)
                            return activity;
 
                        if (activity is CompositeActivity)
                        {
                            foreach (Activity child in ((CompositeActivity)activity).Activities)
                                activities.Enqueue(child);
                        }
                    }
                }
            }
            return null;
        }
        #endregion
    }
    #endregion
 
    #region Class TypeDescriptorContext (SHARED WITH ACTIVITIES, ORCHESTRATIONDESIGNER)
    [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses",
        Justification = "Not all assemblies that include this file instantiate the class.")]
    internal sealed class TypeDescriptorContext : ITypeDescriptorContext
    {
        private IServiceProvider serviceProvider;
        private PropertyDescriptor propDesc;
        private object instance;
 
        public TypeDescriptorContext(IServiceProvider serviceProvider, PropertyDescriptor propDesc, object instance)
        {
            this.serviceProvider = serviceProvider;
            this.propDesc = propDesc;
            this.instance = instance;
        }
 
        public IContainer Container
        {
            get
            {
                return (IContainer)this.serviceProvider.GetService(typeof(IContainer));
            }
        }
        public object Instance
        {
            get
            {
                return this.instance;
            }
        }
        public PropertyDescriptor PropertyDescriptor
        {
            get
            {
                return this.propDesc;
            }
        }
        public object GetService(Type serviceType)
        {
            return this.serviceProvider.GetService(serviceType);
        }
 
        public bool OnComponentChanging()
        {
            IComponentChangeService componentChangeService = (IComponentChangeService)this.serviceProvider.GetService(typeof(IComponentChangeService));
            if (componentChangeService != null)
            {
                try
                {
                    componentChangeService.OnComponentChanging(this.instance, this.propDesc);
                }
                catch (CheckoutException ce)
                {
                    if (ce == CheckoutException.Canceled)
                        return false;
                    throw ce;
                }
            }
 
            return true;
        }
        public void OnComponentChanged()
        {
            IComponentChangeService componentChangeService = (IComponentChangeService)this.serviceProvider.GetService(typeof(IComponentChangeService));
            if (componentChangeService != null)
                componentChangeService.OnComponentChanged(this.instance, this.propDesc, null, null);
        }
    }
    #endregion
 
    // This class has been added as a fix for bug 18214 in order to 
    // create an independent code-path for debugger's use of ParseActivity functionality.
    // The GetActivity method of this class uses QualifiedName instead of Name property
    // for finding activities.
    internal static class DebuggerHelpers
    {
        [SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", Justification = "IndexOf(\".\") not a security issue.")]
        internal static Activity ParseActivity(Activity parsingContext, string activityName)
        {
            if (parsingContext == null)
                throw new ArgumentNullException("parsingContext");
            if (activityName == null)
                throw new ArgumentNullException("activityName");
 
            string currentAtivityName = activityName;
            string nextActivityName = string.Empty;
            int indexOfDot = activityName.IndexOf(".");
            if (indexOfDot != -1)
            {
                currentAtivityName = activityName.Substring(0, indexOfDot);
                nextActivityName = activityName.Substring(indexOfDot + 1);
                if (nextActivityName.Length == 0)
                    return null;
            }
 
            Activity currentActivity = null;
            currentActivity = GetActivity(parsingContext, currentAtivityName);
 
            // The check for parsingContext.Parent != null is added here because IsCustomActivity returns true for root activities.
            if (currentActivity == null && (parsingContext is CompositeActivity) && parsingContext.Parent != null && Helpers.IsCustomActivity(parsingContext as CompositeActivity))
                currentActivity = GetActivity(parsingContext, parsingContext.QualifiedName + "." + currentAtivityName);
 
            if (currentActivity != null)
            {
                if (nextActivityName.Length > 0)
                {
                    if (!(currentActivity is CompositeActivity) || !Helpers.IsCustomActivity(currentActivity as CompositeActivity))
                        // current activity must be a custom activity, otherwise there should be no dots in the name.
                        return null;
 
                    string[] names = nextActivityName.Split('.');
                    for (int i = 0; i < names.Length; i++)
                    {
                        Activity nextActivity = GetActivity(currentActivity, currentActivity.QualifiedName + "." + names[i]);
                        if (nextActivity == null || !Helpers.IsActivityLocked(nextActivity))
                            return null;
 
                        CompositeActivity declaringActivity = Helpers.GetDeclaringActivity(nextActivity);
                        if (currentActivity != declaringActivity)
                            return null;
 
                        currentActivity = nextActivity;
                    }
 
                    return currentActivity;
                }
                else
                {
                    // This activity should always be unlocked, unless if GetChildActivity() is called from
                    // within the custom activity's companion class, then we don't have the full qualified ID available
                    // at that time.  We allow this to succeed only if the declaring activity is the same as the declaring
                    // activity of the context activity passed in.
                    if (Helpers.IsActivityLocked(currentActivity))//.IsLocked)
                    {
                        if (!IsDeclaringActivityMatchesContext(currentActivity, parsingContext))
                            return null;
                    }
 
                    return currentActivity;
                }
            }
 
            return null;
        }
 
        private static Activity GetActivity(Activity containerActivity, string id)
        {
            if (containerActivity != null)
            {
                Queue activities = new Queue();
                activities.Enqueue(containerActivity);
                while (activities.Count > 0)
                {
                    Activity activity = (Activity)activities.Dequeue();
                    if (activity.Enabled)
                    {
                        if (activity.QualifiedName == id)
                            return activity;
 
                        if (activity is CompositeActivity)
                        {
                            foreach (Activity child in ((CompositeActivity)activity).Activities)
                                activities.Enqueue(child);
                        }
                    }
                }
            }
            return null;
        }
 
        private static bool IsDeclaringActivityMatchesContext(Activity currentActivity, Activity context)
        {
            CompositeActivity declaringContext = context as CompositeActivity;
 
            CompositeActivity declaringActivityOfCurrent = Helpers.GetDeclaringActivity(currentActivity);
 
            // If the context activity is locked and it is a primitive activity
            // or NOT a custom activity then we need to find its enclosing 
            // custom activity.
            if (Helpers.IsActivityLocked(context) &&
                    (declaringContext == null || !Helpers.IsCustomActivity(declaringContext))
                )
                declaringContext = Helpers.GetDeclaringActivity(context);
 
            if (declaringContext == declaringActivityOfCurrent)
                return true;
            else
                return false;
        }
    }
}