namespace System.Workflow.ComponentModel.Compiler { #region Imports using System; using System.Collections; using System.Collections.Specialized; using System.Collections.Generic; using System.CodeDom; using System.ComponentModel; using System.ComponentModel.Design; using System.CodeDom.Compiler; using System.Reflection; using System.Xml; using System.Globalization; using System.IO; using System.Text; using System.Diagnostics; using System.Text.RegularExpressions; using Microsoft.CSharp; using Microsoft.VisualBasic; using System.Workflow.ComponentModel.Design; using System.Workflow.ComponentModel.Serialization; using Microsoft.Win32; using System.ComponentModel.Design.Serialization; using System.Configuration; using System.Runtime.InteropServices; using System.Workflow.Interop; using System.Diagnostics.CodeAnalysis; #endregion internal static class XomlCompilerHelper { #region Data members internal static object LineNumber = new object(); internal static object ColumnNumber = new object(); #endregion #region Main compilation helper internal static void InternalCompileFromDomBatch(string[] files, string[] codeFiles, WorkflowCompilerParameters parameters, WorkflowCompilerResults results, string localAssemblyPath) { // Check all the library paths are valid. foreach (string libraryPath in parameters.LibraryPaths) { if (!XomlCompilerHelper.CheckPathName(libraryPath)) { WorkflowCompilerError libPathError = new WorkflowCompilerError(string.Empty, 0, 0, ErrorNumbers.Error_LibraryPath.ToString(CultureInfo.InvariantCulture), string.Format(CultureInfo.CurrentCulture, SR.GetString(SR.LibraryPathIsInvalid), libraryPath)); libPathError.IsWarning = true; results.Errors.Add(libPathError); } } IList authorizedTypes = null; if (parameters.CheckTypes) { //If we dont find the list of authorized types then return. authorizedTypes = WorkflowCompilationContext.Current.GetAuthorizedTypes(); if (authorizedTypes == null) { ValidationError error = new ValidationError(SR.GetString(SR.Error_ConfigFileMissingOrInvalid), ErrorNumbers.Error_ConfigFileMissingOrInvalid); results.Errors.Add(CreateXomlCompilerError(error, parameters)); return; } } ITypeProvider typeProvider = WorkflowCompilationContext.Current.ServiceProvider.GetService(typeof(ITypeProvider)) as ITypeProvider; ArrayList activities = new ArrayList(); using (PDBReader pdbReader = new PDBReader(localAssemblyPath)) { // Validate all the compiled activities in the assembly. foreach (Type type in typeProvider.LocalAssembly.GetTypes()) { if (!TypeProvider.IsAssignable(typeof(Activity), type) || type.IsAbstract) continue; // Fetch file name. string fileName = string.Empty; WorkflowMarkupSourceAttribute[] sourceAttrs = (WorkflowMarkupSourceAttribute[])type.GetCustomAttributes(typeof(WorkflowMarkupSourceAttribute), false); if (sourceAttrs != null && sourceAttrs.Length > 0) { fileName = sourceAttrs[0].FileName; } else { ConstructorInfo ctorMethod = type.GetConstructor(Type.EmptyTypes); if (ctorMethod != null) { try { uint line = 0, column = 0; pdbReader.GetSourceLocationForOffset((uint)ctorMethod.MetadataToken, 0, out fileName, out line, out column); } catch { // We don't want errors if the user has written their own custom // activity and simply inherited the constructor } } // In case of VB, if the ctor is autogenerated the PDB will not have symbol // information. Use InitializeComponent method as the fallback. Bug 19085. if (String.IsNullOrEmpty(fileName)) { MethodInfo initializeComponent = type.GetMethod("InitializeComponent", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null); if (initializeComponent != null) { try { uint line = 0, column = 0; pdbReader.GetSourceLocationForOffset((uint)initializeComponent.MetadataToken, 0, out fileName, out line, out column); if (!String.IsNullOrEmpty(fileName)) { if (fileName.EndsWith(".designer.cs", StringComparison.OrdinalIgnoreCase)) fileName = fileName.Substring(0, fileName.Length - ".designer.cs".Length) + ".cs"; else if (fileName.EndsWith(".designer.vb", StringComparison.OrdinalIgnoreCase)) fileName = fileName.Substring(0, fileName.Length - ".designer.vb".Length) + ".vb"; } } catch { } } } } // Create the activity. Activity activity = null; try { try { Activity.ActivityType = type; activity = Activator.CreateInstance(type) as Activity; } finally { Activity.ActivityType = null; } activity.UserData[UserDataKeys.CustomActivity] = false; if (activity is CompositeActivity) { CompositeActivity compositeActivity = activity as CompositeActivity; if (compositeActivity.CanModifyActivities) results.Errors.Add(CreateXomlCompilerError(new ValidationError(SR.GetString(SR.Error_Missing_CanModifyProperties_False, activity.GetType().FullName), ErrorNumbers.Error_CustomActivityCantCreate), parameters)); } if (sourceAttrs.Length > 0) { DesignerSerializationManager manager = new DesignerSerializationManager(WorkflowCompilationContext.Current.ServiceProvider); Activity instance2 = null; using (manager.CreateSession()) { WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(manager); xomlSerializationManager.LocalAssembly = parameters.LocalAssembly; using (XmlReader reader = XmlReader.Create((sourceAttrs[0].FileName))) instance2 = new WorkflowMarkupSerializer().Deserialize(xomlSerializationManager, reader) as Activity; } if (instance2 is CompositeActivity) ActivityMarkupSerializer.ReplaceChildActivities(activity as CompositeActivity, instance2 as CompositeActivity); } } catch (TargetInvocationException tie) { // For TypeInitializationException, the message is available at the inner Exception if (tie.InnerException is TypeInitializationException && tie.InnerException.InnerException != null) results.Errors.Add(CreateXomlCompilerError(new ValidationError(SR.GetString(SR.Error_CustomActivityCantCreate, type.FullName, tie.InnerException.InnerException.ToString()), ErrorNumbers.Error_CustomActivityCantCreate), parameters)); else if (tie.InnerException.InnerException != null) results.Errors.Add(CreateXomlCompilerError(new ValidationError(tie.InnerException.InnerException.ToString(), ErrorNumbers.Error_CustomActivityCantCreate), parameters)); else results.Errors.Add(CreateXomlCompilerError(new ValidationError(SR.GetString(SR.Error_CustomActivityCantCreate, type.FullName, tie.InnerException.ToString()), ErrorNumbers.Error_CustomActivityCantCreate), parameters)); continue; } catch (Exception e) { results.Errors.Add(CreateXomlCompilerError(new ValidationError(SR.GetString(SR.Error_CustomActivityCantCreate, type.FullName, e.ToString()), ErrorNumbers.Error_CustomActivityCantCreate), parameters)); continue; } // Work around : another set of work arounds. activity.SetValue(ActivityCodeDomSerializer.MarkupFileNameProperty, fileName); activity.SetValue(WorkflowMarkupSerializer.XClassProperty, type.FullName); // Run the validators. ValidateActivity(activity, parameters, results); activities.Add(activity); } } // Add all type load errors to compiler results. foreach (KeyValuePair entry in typeProvider.TypeLoadErrors) { WorkflowCompilerError compilerError = new WorkflowCompilerError(string.Empty, 0, 0, ErrorNumbers.Error_TypeLoad.ToString(CultureInfo.InvariantCulture), entry.Value.Message); compilerError.IsWarning = true; results.Errors.Add(compilerError); } results.CompiledUnit = WorkflowCompilerInternal.GenerateCodeFromFileBatch(files, parameters, results); WorkflowCompilationContext context = WorkflowCompilationContext.Current; if (context == null) { throw new Exception(SR.GetString(SR.Error_MissingCompilationContext)); } // Fix standard namespaces and root namespace. WorkflowMarkupSerializationHelpers.ReapplyRootNamespace(results.CompiledUnit.Namespaces, context.RootNamespace, CompilerHelpers.GetSupportedLanguage(context.Language)); WorkflowMarkupSerializationHelpers.FixStandardNamespacesAndRootNamespace(results.CompiledUnit.Namespaces, context.RootNamespace, CompilerHelpers.GetSupportedLanguage(context.Language)); if (!results.Errors.HasErrors) { // ask activities to generate code for themselves CodeGenerationManager codeGenerationManager = new CodeGenerationManager(WorkflowCompilationContext.Current.ServiceProvider); codeGenerationManager.Context.Push(results.CompiledUnit.Namespaces); foreach (Activity activity in activities) { // Need to call code generators associated with the root activity. if (activity.Parent == null) { foreach (System.Workflow.ComponentModel.Compiler.ActivityCodeGenerator codeGenerator in codeGenerationManager.GetCodeGenerators(activity.GetType())) codeGenerator.GenerateCode(codeGenerationManager, activity); } } // If only ccu needed then return. if (!parameters.GenerateCodeCompileUnitOnly || parameters.CheckTypes) { // Convert all compile units to source files. SupportedLanguages language = CompilerHelpers.GetSupportedLanguage(parameters.LanguageToUse); CodeDomProvider codeDomProvider = CompilerHelpers.GetCodeDomProvider(language, parameters.CompilerVersion); ArrayList ccus = new ArrayList((ICollection)parameters.UserCodeCompileUnits); ccus.Add(results.CompiledUnit); ArrayList sourceFilePaths = new ArrayList(); sourceFilePaths.AddRange(codeFiles); sourceFilePaths.AddRange(XomlCompilerHelper.GenerateFiles(codeDomProvider, parameters, (CodeCompileUnit[])ccus.ToArray(typeof(CodeCompileUnit)))); // Finally give it to Code Compiler. CompilerResults results2 = codeDomProvider.CompileAssemblyFromFile(parameters, (string[])sourceFilePaths.ToArray(typeof(string))); results.AddCompilerErrorsFromCompilerResults(results2); results.PathToAssembly = results2.PathToAssembly; results.NativeCompilerReturnValue = results2.NativeCompilerReturnValue; if (!results.Errors.HasErrors && parameters.CheckTypes) { foreach (string referenceType in MetaDataReader.GetTypeRefNames(results2.CompiledAssembly.Location)) { bool authorized = false; foreach (AuthorizedType authorizedType in authorizedTypes) { if (authorizedType.RegularExpression.IsMatch(referenceType)) { authorized = (String.Compare(bool.TrueString, authorizedType.Authorized, StringComparison.OrdinalIgnoreCase) == 0); if (!authorized) break; } } if (!authorized) { ValidationError error = new ValidationError(SR.GetString(SR.Error_TypeNotAuthorized, referenceType), ErrorNumbers.Error_TypeNotAuthorized); results.Errors.Add(CreateXomlCompilerError(error, parameters)); } } } //this line was throwing for the delay sign case. besides, copying PathToAssembly should do the same... if (!results.Errors.HasErrors && !parameters.GenerateCodeCompileUnitOnly && parameters.GenerateInMemory && (string.IsNullOrEmpty(parameters.CompilerOptions) || !parameters.CompilerOptions.ToLower(CultureInfo.InvariantCulture).Contains("/delaysign"))) results.CompiledAssembly = results2.CompiledAssembly; } } } #endregion #region Service Helpers internal static string ProcessCompilerOptions(string options, out bool noCode, out bool checkTypes) { if (string.IsNullOrEmpty(options)) { noCode = false; checkTypes = false; } else { string compilerSwitchValue; noCode = ExtractCompilerOptionSwitch(ref options, WorkflowCompilerParameters.NoCodeSwitch, out compilerSwitchValue); checkTypes = ExtractCompilerOptionSwitch(ref options, WorkflowCompilerParameters.CheckTypesSwitch, out compilerSwitchValue); } return options; } static bool ExtractCompilerOptionSwitch(ref string options, string compilerSwitch, out string compilerSwitchValue) { int switchPos = options.IndexOf(compilerSwitch, StringComparison.OrdinalIgnoreCase); if (switchPos != -1) { int switchValueStart = switchPos + compilerSwitch.Length; int switchValueLength = 0; while ((switchValueStart + switchValueLength < options.Length) && !char.IsWhiteSpace(options[switchValueStart + switchValueLength])) { switchValueLength++; } if (switchValueLength > 0) { compilerSwitchValue = options.Substring(switchValueStart, switchValueLength); } else { compilerSwitchValue = string.Empty; } RemoveCompilerOptionSwitch(ref options, switchPos, compilerSwitch.Length + switchValueLength); return true; } else { compilerSwitchValue = string.Empty; return false; } } static void RemoveCompilerOptionSwitch(ref string options, int startPos, int length) { if ((startPos > 0) && char.IsWhiteSpace(options[startPos - 1])) { options = options.Remove(startPos - 1, length + 1); } else if ((startPos == 0) && (startPos + length + 1 < options.Length) && char.IsWhiteSpace(options[startPos + length + 1])) { options = options.Remove(startPos, length + 1); } else { options = options.Remove(startPos, length); } } internal static CompilerParameters CloneCompilerParameters(WorkflowCompilerParameters sourceParams) { bool noCode; bool checkTypes; CompilerParameters clonedParams = new CompilerParameters(); clonedParams.CompilerOptions = ProcessCompilerOptions(sourceParams.CompilerOptions, out noCode, out checkTypes); foreach (string embeddedResource in sourceParams.EmbeddedResources) clonedParams.EmbeddedResources.Add(embeddedResource); clonedParams.GenerateExecutable = sourceParams.GenerateExecutable; clonedParams.GenerateInMemory = sourceParams.GenerateInMemory; clonedParams.IncludeDebugInformation = sourceParams.IncludeDebugInformation; foreach (string linkedResource in sourceParams.LinkedResources) clonedParams.LinkedResources.Add(linkedResource); clonedParams.MainClass = sourceParams.MainClass; clonedParams.OutputAssembly = sourceParams.OutputAssembly; foreach (string referencedAssembly in sourceParams.ReferencedAssemblies) clonedParams.ReferencedAssemblies.Add(referencedAssembly); clonedParams.TreatWarningsAsErrors = sourceParams.TreatWarningsAsErrors; clonedParams.UserToken = sourceParams.UserToken; clonedParams.WarningLevel = sourceParams.WarningLevel; clonedParams.Win32Resource = sourceParams.Win32Resource; clonedParams.CoreAssemblyFileName = sourceParams.CoreAssemblyFileName; return clonedParams; } #endregion #region References helpers internal static void FixReferencedAssemblies(WorkflowCompilerParameters parameters, WorkflowCompilerResults results, StringCollection libraryPaths) { Debug.Assert(parameters.MultiTargetingInformation == null, "Shouldn't come here if opted to MT support"); // First add all WinOE assemblies foreach (string assemblyPath in XomlCompilerHelper.StandardAssemblies) { bool shouldAdd = true; //first check if also user referenced this standard WinOE assemblies foreach (string userAssembly in parameters.ReferencedAssemblies) { if (null != userAssembly && userAssembly.Length > 0) { string userAssemblyFileName = Path.GetFileName(userAssembly); string standardAssemblyFileName = Path.GetFileName(assemblyPath); if (null != userAssemblyFileName && null != standardAssemblyFileName && 0 == string.Compare(userAssemblyFileName, standardAssemblyFileName, StringComparison.OrdinalIgnoreCase)) { //we will use the user-provided assembly path instead of the standard one shouldAdd = false; break; } } } if (shouldAdd) parameters.ReferencedAssemblies.Add(assemblyPath); } // Resolve all the references. StringCollection resolvedAssemblyReferences = ResolveAssemblyReferences(parameters.ReferencedAssemblies, GetCompleteLibraryPaths(libraryPaths), results); parameters.ReferencedAssemblies.Clear(); foreach (string resolvedAssemblyReference in resolvedAssemblyReferences) { if (!parameters.ReferencedAssemblies.Contains(resolvedAssemblyReference)) parameters.ReferencedAssemblies.Add(resolvedAssemblyReference); } } private static StringCollection standardAssemblies = null; private static StringCollection StandardAssemblies { get { if (standardAssemblies == null) { StringCollection specialAssemblies = new StringCollection(); specialAssemblies.Add("System.Workflow.ComponentModel.dll"); specialAssemblies.Add("System.Workflow.Runtime.dll"); specialAssemblies.Add("System.Workflow.Activities.dll"); specialAssemblies.Add("System.dll"); specialAssemblies.Add("System.Transactions.dll"); specialAssemblies.Add("System.drawing.dll"); specialAssemblies.Add("System.Web.dll"); specialAssemblies.Add("System.Web.Services.dll"); standardAssemblies = specialAssemblies; } return standardAssemblies; } } private static char[] trimCharsArray = null; internal static string TrimDirectorySeparatorChar(string dir) { if (trimCharsArray == null) { trimCharsArray = new char[] { Path.DirectorySeparatorChar }; } return dir.TrimEnd(trimCharsArray); } private static StringCollection GetCompleteLibraryPaths(StringCollection userLibraryPaths) { StringCollection libraryPaths = new StringCollection(); // Add the current directory. libraryPaths.Add(Environment.CurrentDirectory); // Add the CLR system directory, for example: "C:\WINDOWS\Microsoft.NET\Framework\v1.2.30703" libraryPaths.Add(TrimDirectorySeparatorChar(System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory())); // Add /lib paths. string[] stringArray = new String[userLibraryPaths.Count]; userLibraryPaths.CopyTo(stringArray, 0); libraryPaths.AddRange(stringArray); // Add the LIB environment variable paths. string libLibraryPaths = Environment.GetEnvironmentVariable("LIB"); if ((libLibraryPaths != null) && (libLibraryPaths.Length > 0)) { string[] libLibraryPathsArray = Environment.GetEnvironmentVariable("LIB").Split(new char[] { ',', ';' }); libraryPaths.AddRange(libLibraryPathsArray); } return libraryPaths; } private static StringCollection ResolveAssemblyReferences(StringCollection originalReferences, StringCollection libraryPaths, WorkflowCompilerResults results) { StringCollection resolvedReferences = new StringCollection(); // Resolve listed references. foreach (string reference in originalReferences) { string fullReferenceName; if (CheckFileNameUsingPaths(reference, libraryPaths, out fullReferenceName)) resolvedReferences.Add(fullReferenceName); else { WorkflowCompilerError compilerError = new WorkflowCompilerError(string.Empty, 0, 0, ErrorNumbers.Error_InvalidReferencedAssembly.ToString(CultureInfo.InvariantCulture), SR.GetString(SR.Error_ReferencedAssemblyIsInvalid, reference)); results.Errors.Add(compilerError); } } return resolvedReferences; } private static void ResolveReferencedAssemblies(CompilerParameters parameters, CodeCompileUnit cu) { if (cu.ReferencedAssemblies.Count > 0) foreach (string assemblyName in cu.ReferencedAssemblies) if (!parameters.ReferencedAssemblies.Contains(assemblyName)) parameters.ReferencedAssemblies.Add(assemblyName); } private static bool CheckFileNameUsingPaths(string fileName, StringCollection paths, out string fullFileName) { fullFileName = null; string realFileName = fileName.Trim(new char[] { '"' }); FileInfo info = new FileInfo(realFileName); // If some path is specified, it should resolve to the file. if (realFileName.Length != info.Name.Length) { if (info.Exists) fullFileName = info.FullName; return info.Exists; } else { // Just a file name is specified, look under all directories in paths. foreach (string path in paths) { string trialFileName = path + Path.DirectorySeparatorChar + realFileName; FileInfo trialInfo = new FileInfo(trialFileName); if (trialInfo.Exists) { fullFileName = trialFileName; return true; } } } return false; } internal static bool CheckPathName(string pathName) { string fullPathName = pathName.Trim(new char[] { '"' }); fullPathName = fullPathName.TrimEnd(new char[] { Path.DirectorySeparatorChar }); return Directory.Exists(fullPathName); } #endregion #region Error helpers internal static WorkflowCompilerError CreateXomlCompilerError(ValidationError error, WorkflowCompilerParameters parameters) { WorkflowCompilerError compilerError; compilerError = new WorkflowCompilerError(GetFileName(error), (int)GetValue(error, XomlCompilerHelper.LineNumber), (int)GetValue(error, XomlCompilerHelper.ColumnNumber), string.Empty, GetPrettifiedErrorText(error)); if (!parameters.TreatWarningsAsErrors) compilerError.IsWarning = error.IsWarning; compilerError.ErrorNumber = "WF" + error.ErrorNumber.ToString(CultureInfo.InvariantCulture); if (error.UserData != null) { foreach (DictionaryEntry entry in error.UserData) { if (entry.Key == (object)typeof(Activity) && entry.Value is Activity) compilerError.UserData[entry.Key] = ((Activity)entry.Value).QualifiedName; else compilerError.UserData[entry.Key] = entry.Value; } } return compilerError; } internal static ValidationErrorCollection MorphIntoFriendlyValidationErrors(IEnumerable errors) { ValidationErrorCollection friendlyErrors = new ValidationErrorCollection(); foreach (ValidationError error in errors) { if (error == null) continue; if (error.GetType() == typeof(ValidationError)) { ValidationError error2 = new ValidationError(GetPrettifiedErrorText(error), error.ErrorNumber, error.IsWarning); friendlyErrors.Add(error2); } else { friendlyErrors.Add(error); } } return friendlyErrors; } private static string GetFileName(ValidationError error) { Activity activity = error.UserData[typeof(Activity)] as Activity; while (activity != null && activity.Parent != null) activity = activity.Parent; string fileName = string.Empty; if (activity != null) fileName = activity.GetValue(ActivityCodeDomSerializer.MarkupFileNameProperty) as string; if (fileName == null) fileName = string.Empty; return fileName; } private static string GetPrettifiedErrorText(ValidationError error) { string errorText = error.ErrorText; Activity activity = error.UserData[typeof(Activity)] as Activity; if (activity != null) { // get the ID string identifier = (Helpers.GetRootActivity(activity) != activity) ? activity.QualifiedName : activity.GetType().Name; if ((identifier == null) || (identifier.Length == 0)) identifier = SR.GetString(SR.EmptyValue); // prettify error text if (error.IsWarning) errorText = SR.GetString(SR.Warning_ActivityValidation, identifier) + " " + errorText; else errorText = SR.GetString(SR.Error_ActivityValidation, identifier) + " " + errorText; } return errorText; } private static uint GetValue(ValidationError error, object key) { Activity activity = error.UserData[typeof(Activity)] as Activity; while (activity != null && activity.Parent != null) activity = activity.Parent; uint value = 0; if (activity != null && activity.UserData[key] != null) value = (uint)activity.UserData[key]; return value; } internal static bool HasCodeWithin(Activity rootActivity) { bool hasCodeWithin = false; Walker documentWalker = new Walker(); documentWalker.FoundActivity += delegate(Walker walker, WalkerEventArgs e) { Activity currentActivity = e.CurrentActivity; if (!currentActivity.Enabled) { e.Action = WalkerAction.Skip; return; } CodeTypeMemberCollection codeCollection = currentActivity.GetValue(WorkflowMarkupSerializer.XCodeProperty) as CodeTypeMemberCollection; if (codeCollection != null && codeCollection.Count != 0) { hasCodeWithin = true; e.Action = WalkerAction.Abort; return; } }; documentWalker.Walk(rootActivity as Activity); return hasCodeWithin; } internal static void ValidateActivity(Activity activity, WorkflowCompilerParameters parameters, WorkflowCompilerResults results) { ValidationErrorCollection errors = null; ValidationManager validationManager = new ValidationManager(WorkflowCompilationContext.Current.ServiceProvider); foreach (Validator validator in validationManager.GetValidators(activity.GetType())) { // Validate recursively. try { errors = validator.Validate(validationManager, activity); foreach (ValidationError error in errors) { if (!error.UserData.Contains(typeof(Activity))) error.UserData[typeof(Activity)] = activity; results.Errors.Add(CreateXomlCompilerError(error, parameters)); } } catch (TargetInvocationException tie) { Exception e = tie.InnerException ?? tie; ValidationError error = new ValidationError(SR.GetString(SR.Error_ValidatorThrewException, e.GetType().FullName, validator.GetType().FullName, activity.Name, e.ToString()), ErrorNumbers.Error_ValidatorThrewException); results.Errors.Add(CreateXomlCompilerError(error, parameters)); } catch (Exception e) { ValidationError error = new ValidationError(SR.GetString(SR.Error_ValidatorThrewException, e.GetType().FullName, validator.GetType().FullName, activity.Name, e.ToString()), ErrorNumbers.Error_ValidatorThrewException); results.Errors.Add(CreateXomlCompilerError(error, parameters)); } } } #endregion #region Code generation Helpers internal static string[] GenerateFiles(CodeDomProvider codeDomProvider, CompilerParameters parameters, CodeCompileUnit[] ccus) { CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BracingStyle = "C"; string[] filenames = new string[ccus.Length]; for (int i = 0; i < ccus.Length; i++) { ResolveReferencedAssemblies(parameters, ccus[i]); filenames[i] = parameters.TempFiles.AddExtension(i + codeDomProvider.FileExtension); Stream temp = new FileStream(filenames[i], FileMode.Create, FileAccess.Write, FileShare.Read); try { using (StreamWriter sw = new StreamWriter(temp, Encoding.UTF8)) { codeDomProvider.GenerateCodeFromCompileUnit(ccus[i], sw, options); sw.Flush(); } } finally { temp.Close(); } } return filenames; } #endregion } #region Class MetaDataReader // The GUIDs, enums, structs and interface definitions in this class are from // cor.h and corhdr.h in the SDK\v2.0\include folder of the .net Framework SDK. internal static class MetaDataReader { private static class Guids { public const string CLSID_MetaDataDispenser = "E5CB7A31-7512-11d2-89CE-0080C792E5D8"; public const string IID_IMetaDataDispenser = "809C652E-7396-11d2-9771-00A0C9B4D50C"; public const string IID_IMetaDataImport = "7DAC8207-D3AE-4c75-9B67-92801A497D44"; public const string IID_IMetaDataAssemblyImport = "EE62470B-E94B-424e-9B7C-2F00C9249F93"; } enum MetadataTokenType { ModuleRef = 0x1a000000, AssemblyRef = 0x23000000 } [StructLayout(LayoutKind.Sequential)] struct OsInfo { uint osPlatformId; uint osMajorVersion; uint osMinorVersion; } [StructLayout(LayoutKind.Sequential)] struct AssemblyMetadata { public ushort majorVersion; public ushort minorVersion; public ushort buildNumber; public ushort revisionNumber; [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources", Justification = "This points to memory and not to a native handle. So leaking will result in a memory leak at worst")] public IntPtr locale; public uint localeSize; public IntPtr processorIds; public uint processorIdCount; public IntPtr osInfo; public uint osInfoCount; }; [ComImport(), Guid(Guids.CLSID_MetaDataDispenser)] private class MetaDataDispenser { } [ComImport(), Guid(Guids.IID_IMetaDataDispenser), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IMetaDataDispenser { void DefineScope(); int OpenScope([In, MarshalAs(UnmanagedType.LPWStr)]string scopeName, uint openFlags, [In]ref Guid riid, [Out, MarshalAs(UnmanagedType.IUnknown)] out object unknown); void OpenScopeOnMemory(); } [ComImport(), Guid(Guids.IID_IMetaDataImport), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IMetaDataImport { void CloseEnum([In] IntPtr enumHandle); void CountEnum(); void ResetEnum(); void EnumTypeDefs(); void EnumInterfaceImpls(); int EnumTypeRefs([In, Out] ref IntPtr enumHandle, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] uint[] rTypeRefs, uint cMax, ref uint typeRefs); void FindTypeDefByName(); void GetScopeProps(); void GetModuleFromScope(); void GetTypeDefProps(); void GetInterfaceImplProps(); int GetTypeRefProps([In] uint typeRefToken, [Out] out uint resolutionScopeToken, IntPtr typeRefName, uint nameLength, [Out] out uint actualLength); /*....*/ } [ComImport(), Guid(Guids.IID_IMetaDataAssemblyImport), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IMetaDataAssemblyImport { void GetAssemblyProps(); int GetAssemblyRefProps([In] uint assemblyRefToken, [Out] out IntPtr publicKeyOrToken, [Out] out uint sizePublicKeyOrToken, IntPtr assemblyName, [In] uint assemblyNameBufferSize, [Out] out uint assemblyNameSize, [Out] out AssemblyMetadata assemblyMetaData, [Out] out IntPtr hashValueBlob, [Out] out uint hashValueSize, [Out] out uint assemblyRefFlags); /*....*/ } private static MetadataTokenType TokenTypeFromToken(uint token) { return (MetadataTokenType)(token & 0xff000000); } internal static IEnumerable GetTypeRefNames(string assemblyLocation) { IMetaDataDispenser metaDataDispenser = new MetaDataDispenser() as IMetaDataDispenser; if (metaDataDispenser == null) { throw new InvalidOperationException(String.Format(SR.GetString(SR.Error_MetaDataInterfaceMissing), assemblyLocation, "IMetaDataDispenser")); } Guid guidMetaDataImport = new Guid(Guids.IID_IMetaDataImport); object metaDataImportObj = null; NativeMethods.ThrowOnFailure(metaDataDispenser.OpenScope(assemblyLocation, 0, ref guidMetaDataImport, out metaDataImportObj)); IMetaDataImport metaDataImport = metaDataImportObj as IMetaDataImport; if (metaDataImport == null) { throw new InvalidOperationException(String.Format(SR.GetString(SR.Error_MetaDataInterfaceMissing), assemblyLocation, "IMetaDataImport")); } IntPtr enumHandle = new IntPtr(); uint[] typeRefs = new uint[20]; uint typeRefCount = 0; try { do { NativeMethods.ThrowOnFailure((metaDataImport.EnumTypeRefs(ref enumHandle, typeRefs, (uint)typeRefs.Length, ref typeRefCount))); for (int typeRefIndex = 0; typeRefIndex < typeRefCount; typeRefIndex++) { IntPtr typeRefNamePtr = IntPtr.Zero; uint typeRefNameLength; uint resolutionScopeToken; NativeMethods.ThrowOnFailure(metaDataImport.GetTypeRefProps(typeRefs[typeRefIndex], out resolutionScopeToken, typeRefNamePtr, 0, out typeRefNameLength)); if (typeRefNameLength > 0) { string typeRefName = String.Empty; typeRefNamePtr = Marshal.AllocCoTaskMem((int)(2 * (typeRefNameLength + 1))); try { NativeMethods.ThrowOnFailure(metaDataImport.GetTypeRefProps(typeRefs[typeRefIndex], out resolutionScopeToken, typeRefNamePtr, typeRefNameLength, out typeRefNameLength)); } finally { typeRefName = Marshal.PtrToStringUni(typeRefNamePtr); Marshal.FreeCoTaskMem(typeRefNamePtr); } IMetaDataAssemblyImport metaDataAssemblyImport = metaDataImportObj as IMetaDataAssemblyImport; if (metaDataAssemblyImport == null) { throw new InvalidOperationException(String.Format(SR.GetString(SR.Error_MetaDataInterfaceMissing), assemblyLocation, "IMetaDataAssemblyImport")); } if (TokenTypeFromToken(resolutionScopeToken) == MetadataTokenType.AssemblyRef) { AssemblyMetadata assemblyMetadata; IntPtr publicKeyOrToken = IntPtr.Zero; uint publicKeyOrTokenSize; IntPtr assemblyName = IntPtr.Zero; uint assemblyNameSize; IntPtr hashValueBlob = IntPtr.Zero; uint hashValueSize; uint assemblyRefFlags; NativeMethods.ThrowOnFailure(metaDataAssemblyImport.GetAssemblyRefProps(resolutionScopeToken, out publicKeyOrToken, out publicKeyOrTokenSize, assemblyName, 0, out assemblyNameSize, out assemblyMetadata, out hashValueBlob, out hashValueSize, out assemblyRefFlags)); if (assemblyNameSize > 0) assemblyName = Marshal.AllocCoTaskMem((int)(2 * (assemblyNameSize + 1))); if (assemblyMetadata.localeSize > 0) assemblyMetadata.locale = Marshal.AllocCoTaskMem((int)(2 * (assemblyMetadata.localeSize + 1))); try { if (assemblyNameSize > 0 || assemblyMetadata.localeSize > 0) { NativeMethods.ThrowOnFailure(metaDataAssemblyImport.GetAssemblyRefProps(resolutionScopeToken, out publicKeyOrToken, out publicKeyOrTokenSize, assemblyName, assemblyNameSize, out assemblyNameSize, out assemblyMetadata, out hashValueBlob, out hashValueSize, out assemblyRefFlags)); } String publicKeyString = String.Empty; for (int pos = 0; pos < publicKeyOrTokenSize; pos++) { publicKeyString += String.Format("{0}", Marshal.ReadByte(publicKeyOrToken, pos).ToString("x2")); } yield return String.Format("{0}, {1}, Version={2}.{3}.{4}.{5}, Culture={6}, PublicKeyToken={7}", typeRefName, Marshal.PtrToStringUni(assemblyName), assemblyMetadata.majorVersion, assemblyMetadata.minorVersion, assemblyMetadata.buildNumber, assemblyMetadata.revisionNumber, String.IsNullOrEmpty(Marshal.PtrToStringUni(assemblyMetadata.locale)) ? "neutral" : Marshal.PtrToStringUni(assemblyMetadata.locale), String.IsNullOrEmpty(publicKeyString) ? "null" : publicKeyString); } finally { if (assemblyName != IntPtr.Zero && assemblyNameSize > 0) { Marshal.FreeCoTaskMem(assemblyName); assemblyName = IntPtr.Zero; } if (assemblyMetadata.locale != IntPtr.Zero && assemblyMetadata.localeSize > 0) { Marshal.FreeCoTaskMem(assemblyMetadata.locale); assemblyMetadata.locale = IntPtr.Zero; } } } } } } while (typeRefCount > 0); } finally { metaDataImport.CloseEnum(enumHandle); } yield break; } } #endregion }