1517 lines
63 KiB
C#
1517 lines
63 KiB
C#
|
// 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 [....]. 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;
|
||
|
}
|
||
|
}
|
||
|
}
|