File: Tool.cs
Project: ndp\cdf\src\WCF\Tools\comsvcutil\ComSvcConfig.csproj (ComSvcConfig)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace Microsoft.Tools.ServiceModel.ComSvcConfig
{
    using System;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Globalization;
    using System.Text;
    using System.Threading;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Security.Principal;
    using System.ServiceModel;
    using Microsoft.Tools.ServiceModel;
    using Microsoft.Tools.ServiceModel.SvcUtil;
    using System.Configuration;
 
    [ComImport]
    [Guid("33CAF1A1-FCB8-472b-B45E-967448DED6D8")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IServiceSysTxnConfig
    {
 
    }
 
    [ComImport]
    [Guid("ecabb0c8-7f19-11d2-978e-0000f8757e2a")]
    class CServiceConfig { }
    public static class Tool
    {
        static Options options;
        internal static Options Options { get { return options; } }
 
        // const string DefaultBindingName = "HttpDuplexWindowsSecurityBinding";
 
 
 
        internal static Exception CreateArgumentException(string command, string arg, string message, Exception innerException)
        {
            return new ArgumentException(SR.GetString(SR.InvalidArg, command, arg, message), innerException);
        }
 
        internal static Exception CreateException(string message, Exception innerException)
        {
            return new ApplicationException(message, innerException);
 
        }
 
        // returns whether help was displayed
        static void DisplayHelp(Mode mode)
        {
            if (options.Mode == Mode.NotSpecified)
            {
                DisplayUsage();
            }
            else if (options.Mode == Mode.Install)
            {
                ToolConsole.WriteLine(SR.GetString(SR.HelpUsage4, Cmd.Install, Abbr.Install));
                ToolConsole.WriteLine(SR.GetString(SR.HelpUsageExamples));
                ToolConsole.WriteLine("  ComSvcConfig.exe /install /application:TestApp /contract:* /hosting:complus");
                ToolConsole.WriteLine("  ComSvcConfig.exe /install /application:TestApp /contract:TestComponent,ITest /hosting:was /webDirectory:testdir /mex");
                ToolConsole.WriteLine("  ComSvcConfig.exe /install /application:TestApp /contract:TestComponent,ITest.{Method1} /hosting:was /webDirectory:testdir /mex");
                ToolConsole.WriteLine("  ComSvcConfig.exe /install /application:TestApp /contract:TestComponent,ITest.{Method2,Method3} /hosting:was /webDirectory:testdir /mex");
            }
            else if (options.Mode == Mode.Uninstall)
            {
                ToolConsole.WriteLine(SR.GetString(SR.HelpUsage5, Cmd.Uninstall, Abbr.Uninstall));
                ToolConsole.WriteLine(SR.GetString(SR.HelpUsageExamples));
                ToolConsole.WriteLine("  ComSvcConfig.exe /uninstall /application:OnlineStore /contract:* /hosting:complus");
                ToolConsole.WriteLine("  ComSvcConfig.exe /uninstall /application:OnlineStore /contract:* /hosting:was /mex");
                ToolConsole.WriteLine("  ComSvcConfig.exe /uninstall /application:OnlineStore /contract:TestComponent,ITest.{Method1} /hosting:was /mex");
                ToolConsole.WriteLine("  ComSvcConfig.exe /uninstall /application:OnlineStore /contract:TestComponent,ITest.{Method2,Method3} /hosting:was /mex");
 
            }
            else if (options.Mode == Mode.List)
            {
                ToolConsole.WriteLine(SR.GetString(SR.HelpUsage6, Cmd.List, Abbr.List));
                ToolConsole.WriteLine(SR.GetString(SR.HelpUsageExamples));
                ToolConsole.WriteLine("  ComSvcConfig.exe /list");
                ToolConsole.WriteLine("  ComSvcConfig.exe /list /hosting:complus");
                ToolConsole.WriteLine("  ComSvcConfig.exe /list /hosting:was");
 
            }
        }
 
 
        static void DisplayLogo()
        {
            // Using CommonResStrings.WcfTrademarkForCmdLine for the trademark: the proper resource for command line tools.
            Console.WriteLine(SR.GetString(SR.Logo, CommonResStrings.WcfTrademarkForCmdLine, ThisAssembly.InformationalVersion, CommonResStrings.CopyrightForCmdLine));
        }
 
        static void DisplayUsage()
        {
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage1));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage2, ThisAssembly.Title));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage3));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage4, Cmd.Install, Abbr.Install));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage5, Cmd.Uninstall, Abbr.Uninstall));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage6, Cmd.List, Abbr.List));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage7));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageApplication, Cmd.Application, Abbr.Application));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageInterface, Cmd.Contract, Abbr.Contract, "{", "}"));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageReferences, Cmd.AllowReferences, Abbr.AllowReferences));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageHosting, Cmd.Hosting, Abbr.Hosting));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageWebServer, Cmd.WebServer, Abbr.WebServer));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageWebDirectory, Cmd.WebDirectory, Abbr.WebDirectory));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageMexOption, Cmd.MetaData, Abbr.MetaData));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageGuidOption, Cmd.ID, Abbr.ID));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageNoLogo, Cmd.NoLogo, Abbr.NoLogo));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageVerbose, Cmd.Verbose, Abbr.Verbose));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsage8, "help"));
            ToolConsole.WriteLine(SR.GetString(SR.HelpUsageExamples));
            ToolConsole.WriteLine("  ComSvcConfig.exe /install /application:TestApp /contract:* /hosting:complus");
            ToolConsole.WriteLine("  ComSvcConfig.exe /install /application:TestApp /contract:TestComponent,ITest /hosting:was /webDirectory:testdir /mex");
            ToolConsole.WriteLine("  ComSvcConfig.exe /list");
            ToolConsole.WriteLine("  ComSvcConfig.exe /list /hosting:complus");
            ToolConsole.WriteLine("  ComSvcConfig.exe /list /hosting:was");
            ToolConsole.WriteLine("  ComSvcConfig.exe /uninstall /application:OnlineStore /contract:* /hosting:complus");
            ToolConsole.WriteLine("  ComSvcConfig.exe /uninstall /application:OnlineStore /contract:* /hosting:was");
            ToolConsole.WriteLine("");
        }
 
        static void DoInstall()
        {
            ValidateAddParams();
            ComAdminAppInfo appInfo = ComAdminWrapper.GetAppInfo(options.Application);
            if (appInfo == null)
            {
                throw CreateArgumentException(Cmd.Application, options.Application, SR.GetString(SR.ApplicationNotFound, options.Application), null);
            }
 
            ValidateApplication(appInfo, options.Hosting);
            Guid sourceAppId = appInfo.ID;
 
            EndpointConfigContainer container = null;
 
 
            if (options.Hosting == Hosting.Complus)
            {
                container = ComplusEndpointConfigContainer.Get(options.Application, true);
                if (container == null)
                {
                    throw CreateArgumentException(Cmd.Application, options.Application, SR.GetString(SR.ApplicationNotFound, options.Application), null);
                }
            }
            else if (options.Hosting == Hosting.Was)
            {
                string webServer = null;
                if (options.WebServer != null)
                {
                    webServer = options.WebServer;
                }
                else
                {
                    webServer = WasEndpointConfigContainer.DefaultWebServer;
                }
 
                container = WasEndpointConfigContainer.Get(webServer, options.WebDirectory, options.Application);
                if (container == null)
                {
                    throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.WebDirectoryNotFound, options.WebDirectory), null);
                }
            }
 
            IList<ComponentDefinition<Guid>> guidComponents = null;
            if (options.AllComponents)
            {
                GetAllComponentsForAdd(appInfo, options.Mex, out guidComponents);
            }
            else
            {
                GetComponentsFromInputForAdd(appInfo, options.Components, options.Mex, container.HasEndpointsForApplication(sourceAppId), out guidComponents);
            }
 
            if (guidComponents.Count == 0)
            {
                if (String.Empty != options.MexOnlyComponent)
                    throw Tool.CreateException(SR.GetString(SR.MexOnlyComponentHasNoExposedInterface, options.MexOnlyComponent), null);
                else
                    throw Tool.CreateException(SR.GetString(SR.NoneOfTheComponentsSatisfiedTheAddCriteria), null);
            }
 
            List<EndpointConfig> endpointConfigs = new List<EndpointConfig>();
 
            foreach (ComponentDefinition<Guid> component in guidComponents)
            {
                ComAdminClassInfo componentInfo = appInfo.FindClass(component.Component.ToString("B"));
                Debug.Assert(componentInfo != null, "No component Found");
                string bindingType = null;
                string bindingName = null;
                if (!componentInfo.SupportsTransactionFlow)
                {
                    bindingType = container.DefaultBindingType;
                    bindingName = container.DefaultBindingName;
                }
                else
                {
                    bindingType = container.DefaultTransactionalBindingType;
                    bindingName = container.DefaultTransactionalBindingName;
                }
                foreach (InterfaceDefination<Guid> iInterface in component.Interfaces)
                {
                    Guid iid = iInterface.Interface;
                    EndpointConfig ec = null;
                    if (iid != typeof(IMetadataExchange).GUID)
                    {
                        string address = container.DefaultEndpointAddress(sourceAppId, component.Component, iid);
                        ec = new EndpointConfig(sourceAppId,
                                                               component.Component,
                                                               iid,
                                                               bindingType,
                                                               bindingName,
                                                               new Uri(address, UriKind.RelativeOrAbsolute),
                                                               false,
                                                               (List<string>)iInterface.Methods);
                    }
                    else
                    {
                        ec = new EndpointConfig(sourceAppId,
                                                           component.Component,
                                                           typeof(IMetadataExchange).GUID,
                                                           container.DefaultMexBindingType,
                                                           container.DefaultMexBindingName,
                                                           new Uri(container.DefaultMexAddress(sourceAppId, component.Component), UriKind.RelativeOrAbsolute),
                                                           true,
                                                           null);
                    }
 
                    endpointConfigs.Add(ec);
                }
 
            }
 
 
 
            try
            {
                container.Add(endpointConfigs);
                container.PrepareChanges();         // containers can throw from this                
            }
            catch (Exception e)
            {
                if (e is NullReferenceException || e is SEHException)
                {
                    throw;
                }
                container.AbortChanges();
                throw CreateException(SR.GetString(SR.ErrorDuringAdd, options.Application), e);
            }
 
            container.CommitChanges();
        }
 
        // Assumption is that application, if present, is in curly Guids form
        static List<EndpointConfigContainer> GetContainersForQueryOrRemove(Hosting hosting, string application, string webServer, string webDirectory)
        {
            List<EndpointConfigContainer> containers = new List<EndpointConfigContainer>();
 
            // first, get any complus-hosted endpointConfigs
            if (hosting == Hosting.Complus || hosting == Hosting.NotSpecified)
            {
                if (!string.IsNullOrEmpty(application))
                {
                    EndpointConfigContainer container = ComplusEndpointConfigContainer.Get(application);
                    if (container == null)
                    {
                        throw CreateArgumentException(Cmd.Application, options.Application, SR.GetString(SR.ApplicationNotFound, options.Application), null);
                    }
 
                    containers.Add(container);
                }
                else
                {
                    // query for all complus-hosted apps
                    List<ComplusEndpointConfigContainer> comContainers = ComplusEndpointConfigContainer.Get();
                    if (comContainers != null)
                    {
                        foreach (ComplusEndpointConfigContainer comContainer in comContainers)
                        {
                            containers.Add(comContainer);
                        }
                    }
                }
            }
 
            // then, get any was-hosted endpointConfigs
            if (hosting == Hosting.Was || hosting == Hosting.NotSpecified)
            {
                // specific webDirectory
                if (!string.IsNullOrEmpty(webDirectory))
                {
                    if (string.IsNullOrEmpty(webServer))
                    {
                        webServer = WasEndpointConfigContainer.DefaultWebServer;
                    }
 
                    EndpointConfigContainer container = WasEndpointConfigContainer.Get(webServer, webDirectory, application);
                    if (container == null)
                    {
                        throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.WebDirectoryNotFound, options.WebDirectory), null);
                    }
 
                    if (string.IsNullOrEmpty(application))
                    {
                        containers.Add(container);
                    }
                    else
                    {
                        if (container.HasEndpointsForApplication(new Guid(application)))
                        {
                            containers.Add(container);
                        }
                    }
                }
                else
                {
                    // no webDirectory specified.
                    // we will therefore look in all webDirs, in all webServers (unless one is specified)
 
                    List<WasEndpointConfigContainer> wasContainers = null;
 
                    if (!string.IsNullOrEmpty(webServer))
                    {
                        wasContainers = WasEndpointConfigContainer.Get(webServer, application); // all webDirs in a specific server
                    }
                    else
                    {
                        wasContainers = WasEndpointConfigContainer.Get(application);  // all webDirs in all servers
                    }
 
                    if (wasContainers != null)
                    {
                        foreach (WasEndpointConfigContainer container in wasContainers)
                        {
                            if (string.IsNullOrEmpty(application))
                            {
                                containers.Add(container);
                            }
                            else
                            {
                                if (container.HasEndpointsForApplication(new Guid(application)))
                                {
                                    containers.Add(container);
                                }
                            }
                        }
                    }
                }
            }
 
            return containers;
        }
 
        static void DisplayEndpointConfig(EndpointConfig config)
        {
            List<string> baseAddresses = null;
 
            if (config.Container != null)
            {
                baseAddresses = config.Container.GetBaseAddresses(config);
            }
 
            if (null == baseAddresses || 0 == baseAddresses.Count)
            {
                if (config.IsMexEndpoint)
                    ToolConsole.WriteQueryLine("          " + SR.GetString(SR.MexEndpointExposed, config.Address));
                else
                {
                    ToolConsole.WriteQueryLine("             " + SR.GetString(SR.BindingType, config.BindingType));
                    ToolConsole.WriteQueryLine("             " + SR.GetString(SR.BindingConfigurationName, config.BindingName));
                    ToolConsole.WriteQueryLine("             " + SR.GetString(SR.Address, config.Address));
                }
            }
            else
            {
                foreach (string s in baseAddresses)
                {
                    string addr = s + @"/" + config.Address;
 
                    if (config.IsMexEndpoint)
                        ToolConsole.WriteQueryLine("          " + SR.GetString(SR.MexEndpointExposed, addr));
                    else
                    {
                        ToolConsole.WriteQueryLine("             " + SR.GetString(SR.BindingType, config.BindingType));
                        ToolConsole.WriteQueryLine("             " + SR.GetString(SR.BindingConfigurationName, config.BindingName));
                        ToolConsole.WriteQueryLine("             " + SR.GetString(SR.Address, addr));
                    }
                }
            }
 
        }
 
        static void DoList()
        {
            ValidateQueryParams();
 
            string application = null;
            Guid appid;
 
            if (options.Application != null)
            {
                // Make sure that the application exists, and get its Guid
 
 
                if (!ComAdminWrapper.ResolveApplicationId(options.Application, out appid))
                {
                    throw CreateArgumentException(Cmd.Application, options.Application, SR.GetString(SR.ApplicationNotFound, options.Application), null);
                }
 
                application = appid.ToString("B");
            }
 
            List<EndpointConfig> endpointConfigs = new List<EndpointConfig>();
 
            List<EndpointConfigContainer> containers = GetContainersForQueryOrRemove(options.Hosting, application, options.WebServer, options.WebDirectory);
 
            if (containers != null)
            {
                foreach (EndpointConfigContainer container in containers)
                {
                    try
                    {
                        List<EndpointConfig> configs = null;
                        if (!string.IsNullOrEmpty(application))
                        {
                            configs = container.GetEndpointConfigs(new Guid(application));
                        }
                        else
                        {
                            configs = container.GetEndpointConfigs();
                        }
 
                        endpointConfigs.AddRange(configs);
                    }
#pragma warning suppress 56500 // covered by FxCOP
                    catch (Exception)
                    {
                        if (container is WasEndpointConfigContainer)
                            ToolConsole.WriteWarning(SR.GetString(SR.InvalidConfigFile, ((WasEndpointConfigContainer)container).ConfigFile.OriginalFileName));
 
                        if (container is ComplusEndpointConfigContainer)
                            ToolConsole.WriteWarning(SR.GetString(SR.InvalidConfigFile, ((ComplusEndpointConfigContainer)container).ConfigFile.OriginalFileName));
                    }
                }
            }
 
 
            Dictionary<Guid, Dictionary<Guid, Dictionary<Guid, List<EndpointConfig>>>> applicationToComponents = new Dictionary<Guid, Dictionary<Guid, Dictionary<Guid, List<EndpointConfig>>>>();
            foreach (EndpointConfig config in endpointConfigs)
            {
                Dictionary<Guid, Dictionary<Guid, List<EndpointConfig>>> componentToInterfaces = null;
                Dictionary<Guid, List<EndpointConfig>> interfacesForComponents = null;
                List<EndpointConfig> endpointsForInterface = null;
 
                if (!applicationToComponents.TryGetValue(config.Appid, out componentToInterfaces))
                {
                    componentToInterfaces = new Dictionary<Guid, Dictionary<Guid, List<EndpointConfig>>>();
                    applicationToComponents[config.Appid] = componentToInterfaces;
                }
                if (!componentToInterfaces.TryGetValue(config.Clsid, out interfacesForComponents))
                {
                    interfacesForComponents = new Dictionary<Guid, List<EndpointConfig>>();
                    componentToInterfaces[config.Clsid] = interfacesForComponents;
                }
                if (!interfacesForComponents.TryGetValue(config.Iid, out endpointsForInterface))
                {
                    endpointsForInterface = new List<EndpointConfig>();
                    interfacesForComponents[config.Iid] = endpointsForInterface;
                }
                endpointsForInterface.Add(config);
            }
            IEnumerator<KeyValuePair<Guid, Dictionary<Guid, Dictionary<Guid, List<EndpointConfig>>>>> enumerateApps = applicationToComponents.GetEnumerator();
            while (enumerateApps.MoveNext())
            {
                IEnumerator<KeyValuePair<Guid, Dictionary<Guid, List<EndpointConfig>>>> enumerateComponents = enumerateApps.Current.Value.GetEnumerator();
                ComAdminAppInfo appInfo = ComAdminWrapper.GetAppInfo(enumerateApps.Current.Key.ToString("B"));
                if (appInfo == null)
                    continue;
                ToolConsole.WriteQueryLine(SR.GetString(SR.EnumeratingComponentsForApplication, options.ShowGuids ? appInfo.ID.ToString("B") : appInfo.Name));
 
                foreach (EndpointConfigContainer container in containers)
                {
                    if (container.HasEndpointsForApplication(enumerateApps.Current.Key))
                    {
                        if (container is WasEndpointConfigContainer)
                        {
                            ToolConsole.WriteQueryLine("     " + SR.GetString(SR.WasHosting));
                            ToolConsole.WriteQueryLine("     " + SR.GetString(SR.ConfigFileName, ((WasEndpointConfigContainer)container).ConfigFile.OriginalFileName));
                        }
                        else
                        {
                            ToolConsole.WriteQueryLine("     " + SR.GetString(SR.ComplusHosting));
                            ToolConsole.WriteQueryLine("     " + SR.GetString(SR.ConfigFileName, ((ComplusEndpointConfigContainer)container).ConfigFile.OriginalFileName));
                        }
                    }
                }
 
                while (enumerateComponents.MoveNext())
                {
                    IEnumerator<KeyValuePair<Guid, List<EndpointConfig>>> enumerateInterfaces = enumerateComponents.Current.Value.GetEnumerator();
                    ComAdminClassInfo classInfo = appInfo.FindClass(enumerateComponents.Current.Key.ToString("B"));
                    if (classInfo == null)
                        continue;
                    ToolConsole.WriteQueryLine("     " + SR.GetString(SR.EnumeratingInterfacesForComponent, options.ShowGuids ? classInfo.Clsid.ToString("B") : classInfo.Name));
 
                    while (enumerateInterfaces.MoveNext())
                    {
                        ComAdminInterfaceInfo interfaceInfo = classInfo.FindInterface(enumerateInterfaces.Current.Key.ToString("B"));
                        if (interfaceInfo == null)
                        {
                            foreach (EndpointConfig config in enumerateInterfaces.Current.Value)
                            {
                                if (config.IsMexEndpoint)
                                {
                                    DisplayEndpointConfig(config);
 
                                    continue;
                                }
                            }
                        }
                        else
                        {
                            ToolConsole.WriteQueryLine("          " + SR.GetString(SR.EnumeratingEndpointsForInterfaces, options.ShowGuids ? interfaceInfo.Iid.ToString("B") : interfaceInfo.Name));
 
                            foreach (EndpointConfig config in enumerateInterfaces.Current.Value)
                                DisplayEndpointConfig(config);
                        }
                    }
                }
            }
        }
 
        static void DoUninstall()
        {
            ValidateRemoveParams();
            ComAdminAppInfo appInfo = ComAdminWrapper.GetAppInfo(options.Application);
            if (appInfo == null)
            {
                throw CreateArgumentException(Cmd.Application, options.Application, SR.GetString(SR.ApplicationNotFound, options.Application), null);
            }
 
            //ValidateApplication(appInfo, options.Hosting);
            Guid sourceAppId = appInfo.ID;
            string application = sourceAppId.ToString("B");
            IList<ComponentDefinition<Guid>> guidComponents = null;
            if (options.AllComponents)
            {
                GetAllComponentsForRemove(appInfo, out guidComponents);
            }
            else
            {
                GetComponentsFromInputForRemove(appInfo, options.Components, out guidComponents);
            }
 
            List<EndpointConfigContainer> containers = GetContainersForQueryOrRemove(options.Hosting, application, options.WebServer, options.WebDirectory);
            if (guidComponents.Count == 0)
                ToolConsole.WriteWarning(SR.GetString(SR.NoneOfTheComponentsSatisfiedTheRemoveCriteria));
 
            try
            {
                bool update = false;
                foreach (EndpointConfigContainer container in containers)
                {
                    List<EndpointConfig> endpointsToDelete = new List<EndpointConfig>();
                    List<EndpointConfig> endpointConfigs = container.GetEndpointConfigs(sourceAppId);
                    foreach (EndpointConfig endpointConfig in endpointConfigs)
                    {
                        if (ShouldDelete(endpointConfig, guidComponents))
                        {
                            endpointsToDelete.Add(endpointConfig);
                        }
                    }
                    if (endpointsToDelete.Count != 0)
                    {
                        container.Remove(endpointsToDelete);
                        update = true;
                    }
 
                }
                if (!update)
                    ToolConsole.WriteWarning(SR.GetString(SR.NoneOfConfigsFoundMatchTheCriteriaSpecifiedNothingWillBeRemoved));
 
                foreach (EndpointConfigContainer container in containers)
                {
                    container.PrepareChanges();                    // containers are allowed to throw from Prepare
                }
            }
            catch (Exception e)
            {
                if (e is NullReferenceException || e is SEHException)
                {
                    throw;
                }
 
                foreach (EndpointConfigContainer container in containers)
                {
                    container.AbortChanges();     // containers shouldn't throw from here
                }
                throw CreateException(SR.GetString(SR.ErrorDuringRemove), e);
            }
 
            // Commit time!
            foreach (EndpointConfigContainer container in containers)
            {
                container.CommitChanges();      // containers shouldn't throw from here
            }
        }
 
        static bool ShouldDelete(EndpointConfig endpointConfig, IList<ComponentDefinition<Guid>> guidComponents)
        {
            foreach (ComponentDefinition<Guid> component in guidComponents)
            {
                if (component.Component == endpointConfig.Clsid)
                {
                    foreach (InterfaceDefination<Guid> interfaceDef in component.Interfaces)
                    {
                        if (interfaceDef.Interface == endpointConfig.Iid)
                        {
                            endpointConfig.Methods = interfaceDef.Methods;
                            return true;
                        }
                    }
                }
            }
            return false;
        }
 
        static void EnsureUserIsAdministrator()
        {
            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            if (!principal.IsInRole(WindowsBuiltInRole.Administrator))
            {
                throw CreateException(SR.GetString(SR.MustBeAnAdministrator), null);
            }
        }
 
        // returns strongly typed, verified components/interfaces in an application
        static void GetAllComponentsForAdd(ComAdminAppInfo appInfo, bool mex, out IList<ComponentDefinition<Guid>> outComps)
        {
            outComps = new List<ComponentDefinition<Guid>>();
 
            foreach (ComAdminClassInfo classInfo in appInfo.Classes)
            {
                ComponentDefinition<Guid> outComp;
 
                if (!ValidateClass(classInfo))
                {
                    continue;
 
                }
 
                outComp = new ComponentDefinition<Guid>(classInfo.Clsid);
 
                foreach (ComAdminInterfaceInfo interfaceInfo in classInfo.Interfaces)
                {
                    if (ComPlusTypeValidator.VerifyInterface(interfaceInfo, options.AllowReferences, classInfo.Clsid))
                        outComp.AddInterface(interfaceInfo.Iid, ComPlusTypeValidator.FetchAllMethodsForInterface(interfaceInfo));
                }
                if (mex && (outComp.Interfaces != null))
                    outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
                if (outComp.Interfaces != null)
                    outComps.Add(outComp);
                else
                    ToolConsole.WriteWarning(SR.GetString(SR.NoneOfTheSpecifiedInterfacesForComponentWereFoundSkipping, Tool.Options.ShowGuids ? classInfo.Clsid.ToString("B") : classInfo.Name));
 
            }
        }
 
        // returns strongly typed, verified components/interfaces in an application
        static void GetAllComponentsForRemove(ComAdminAppInfo appInfo, out IList<ComponentDefinition<Guid>> outComps)
        {
            outComps = new List<ComponentDefinition<Guid>>();
 
            foreach (ComAdminClassInfo classInfo in appInfo.Classes)
            {
                ComponentDefinition<Guid> outComp;
 
 
                outComp = new ComponentDefinition<Guid>(classInfo.Clsid);
 
                foreach (ComAdminInterfaceInfo interfaceInfo in classInfo.Interfaces)
                    outComp.AddInterface(interfaceInfo.Iid, null);
                outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
                outComps.Add(outComp);
            }
        }
 
 
        // returns strongly typed, verified components, from loosely-typed (string) user inputs
        static void GetComponentsFromInputForAdd(ComAdminAppInfo appInfo, IList<ComponentDefinition<string>> inComps, bool mex, bool priorEndpointsExist, out IList<ComponentDefinition<Guid>> outComps)
        {
            string missingInterface = String.Empty;
            outComps = new List<ComponentDefinition<Guid>>();
 
            foreach (ComponentDefinition<string> inComp in inComps)
            {
                ComponentDefinition<Guid> outComp = null;
 
                ComAdminClassInfo classInfo = appInfo.FindClass(inComp.Component);
 
                if (classInfo == null)
                {
                    ToolConsole.WriteWarning(SR.GetString(SR.CannotFindComponentInApplicationSkipping, inComp.Component, Tool.Options.ShowGuids ? appInfo.ID.ToString("B") : appInfo.Name));
                    continue;
                }
 
                if (!ValidateClass(classInfo))
                    continue;
 
                // Find existing componentDef if it was referenced in an earlier iteration
                foreach (ComponentDefinition<Guid> cd in outComps)
                {
                    if (cd.Component == classInfo.Clsid)
                    {
                        outComp = cd;
                    }
                }
 
                if (outComp == null)
                {
                    outComp = new ComponentDefinition<Guid>(classInfo.Clsid);
                }
 
                if (inComp.AllInterfaces)
                {
                    foreach (ComAdminInterfaceInfo interfaceInfo in classInfo.Interfaces)
                    {
                        if (ComPlusTypeValidator.VerifyInterface(interfaceInfo, options.AllowReferences, classInfo.Clsid))
                            outComp.AddInterface(interfaceInfo.Iid, ComPlusTypeValidator.FetchAllMethodsForInterface(interfaceInfo));
 
                    }
                    if ((outComp.Interfaces != null) && mex)
                        outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
 
 
                }
                else
                {
                    foreach (InterfaceDefination<string> comInterface in inComp.Interfaces)
                    {
                        string itfName = comInterface.Interface;
                        if (itfName == typeof(IMetadataExchange).GUID.ToString("B"))
                        {
                            if (!mex)
                                outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
                        }
                        else
                        {
                            ComAdminInterfaceInfo interfaceInfo = classInfo.FindInterface(itfName);
                            if (interfaceInfo == null)
                            {
                                ToolConsole.WriteWarning(SR.GetString(SR.CannotFindInterfaceInCatalogForComponentSkipping, itfName, inComp.Component));
                                missingInterface = itfName;
                                continue;
                            }
                            if (comInterface.AllMethods)
                            {
                                if (ComPlusTypeValidator.VerifyInterface(interfaceInfo, options.AllowReferences, classInfo.Clsid, true))
                                    outComp.AddInterface(interfaceInfo.Iid, ComPlusTypeValidator.FetchAllMethodsForInterface(interfaceInfo));
                                else
                                    throw CreateException(SR.GetString(SR.InvalidInterface), null);
                            }
                            else
                            {
                                if (ComPlusTypeValidator.VerifyInterfaceMethods(interfaceInfo, comInterface.Methods, options.AllowReferences, true))
                                    outComp.AddInterface(interfaceInfo.Iid, (List<string>)comInterface.Methods);
                                else
                                    throw CreateException(SR.GetString(SR.InvalidMethod), null);
                            }
 
                        }
                    }
 
                    if ((outComp.Interfaces != null) || priorEndpointsExist)
                    {
                        if (mex)
                            outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
                    }
 
                }
                if (outComp.Interfaces != null)
                    outComps.Add(outComp);
                else
                    ToolConsole.WriteWarning(SR.GetString(SR.NoneOfTheSpecifiedInterfacesForComponentWereFoundSkipping, inComp.Component));
            }
 
            if (outComps.Count == 0 && (!String.IsNullOrEmpty(missingInterface)))
                throw Tool.CreateException(SR.GetString(SR.NoComponentContainsInterface, missingInterface), null);
        }
 
        static void GetComponentsFromInputForRemove(ComAdminAppInfo appInfo, IList<ComponentDefinition<string>> inComps, out IList<ComponentDefinition<Guid>> outComps)
        {
            outComps = new List<ComponentDefinition<Guid>>();
 
            foreach (ComponentDefinition<string> inComp in inComps)
            {
                ComponentDefinition<Guid> outComp = null;
 
                ComAdminClassInfo classInfo = appInfo.FindClass(inComp.Component);
 
                if (classInfo == null)
                {
                    ToolConsole.WriteWarning(SR.GetString(SR.CannotFindComponentInApplicationSkipping, inComp.Component, Tool.Options.ShowGuids ? appInfo.ID.ToString("B") : appInfo.Name));
                    continue;
                }
 
 
                // Find existing componentDef if it was referenced in an earlier iteration
                foreach (ComponentDefinition<Guid> cd in outComps)
                {
                    if (cd.Component == classInfo.Clsid)
                    {
                        outComp = cd;
                    }
                }
 
                if (outComp == null)
                {
                    outComp = new ComponentDefinition<Guid>(classInfo.Clsid);
                }
 
                if (inComp.AllInterfaces)
                {
                    foreach (ComAdminInterfaceInfo interfaceInfo in classInfo.Interfaces)
                        outComp.AddInterface(interfaceInfo.Iid, ComPlusTypeValidator.FetchAllMethodsForInterface(interfaceInfo, false));
                    outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
 
 
                }
                else
                {
                    foreach (InterfaceDefination<string> comInterface in inComp.Interfaces)
                    {
                        string itfName = comInterface.Interface;
                        if (itfName == typeof(IMetadataExchange).GUID.ToString("B"))
                        {
                            outComp.AddInterface(typeof(IMetadataExchange).GUID, null);
                        }
                        else
                        {
                            ComAdminInterfaceInfo interfaceInfo = classInfo.FindInterface(itfName);
                            if (interfaceInfo == null)
                            {
                                ToolConsole.WriteWarning(SR.GetString(SR.CannotFindInterfaceInCatalogForComponentSkipping, itfName, inComp.Component));
                                continue;
                            }
                            if (comInterface.AllMethods)
                            {
                                outComp.AddInterface(interfaceInfo.Iid, ComPlusTypeValidator.FetchAllMethodsForInterface(interfaceInfo));
                            }
                            else
                            {
 
                                outComp.AddInterface(interfaceInfo.Iid, (List<string>)comInterface.Methods);
                            }
 
                        }
                    }
                }
                if (outComp.Interfaces != null)
                    outComps.Add(outComp);
                else
                {
                    ToolConsole.WriteWarning(SR.GetString(SR.NoneOfTheSpecifiedInterfacesForComponentWereFoundSkipping, inComp.Component));
                }
            }
        }
 
        public static bool CheckForCorrectOle32()
        {
            Guid clsid = new Guid("0000032E-0000-0000-C000-000000000046");
            IPSFactoryBuffer psFac = SafeNativeMethods.DllGetClassObject(clsid, typeof(IPSFactoryBuffer).GUID) as IPSFactoryBuffer;
            object o1;
            object o2;
            try
            {
                psFac.CreateProxy(IntPtr.Zero, clsid, out o1, out o2);
            }
            catch (ArgumentException)
            {
                return true;
            }
            catch (COMException)
            {
                return false;
            }
            return false;
        }
        public static int Main(string[] args)
        {
            // make sure the text output displays properly on various languages
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentUICulture.GetConsoleFallbackUICulture();
            if ((System.Console.OutputEncoding.CodePage != 65001) &&
                 (System.Console.OutputEncoding.CodePage !=
                  Thread.CurrentThread.CurrentUICulture.TextInfo.OEMCodePage))
            {
                Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
            }
 
            object serviceConfig = new CServiceConfig();
            IServiceSysTxnConfig sysTxnconfing = serviceConfig as IServiceSysTxnConfig;
            if (sysTxnconfing == null)
            {
                ToolConsole.WriteError(SR.GetString(SR.WindowsFunctionalityMissing), "");
                return 1;
            }
            if ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor == 1))
            {
                if (!CheckForCorrectOle32())
                {
                    ToolConsole.WriteError(SR.GetString(SR.WindowsFunctionalityMissing), "");
                    return 1;
                }
            }
            try
            {
                EnsureUserIsAdministrator();
                Tool.options = Options.ParseArguments(args);
                ToolConsole.Verbose = options.Verbose;
 
                Run();
            }
            catch (ArgumentException ae)
            {
                ToolConsole.WriteError(ae);
                Console.WriteLine(SR.GetString(SR.MoreHelp, Abbr.Help));
                return 1;
            }
            catch (ApplicationException appException)
            {
                ToolConsole.WriteError(appException);
                return 1;
            }
            catch (Exception e)
            {
                if (e is NullReferenceException || e is SEHException)
                {
                    throw;
                }
                ToolConsole.WriteDetailedException(e, SR.GetString(SR.UnExpectedError));
                return 1;
            }
            return 0;
        }
 
        static void Run()
        {
            if (!options.NoLogo)
            {
                DisplayLogo();
            }
 
            if (options.Help)
            {
                ToolConsole.Verbose = false;  // For Help-mode, ignore quiet flag
                DisplayHelp(options.Mode);
                return;
            }
 
            switch (options.Mode)
            {
                case Mode.NotSpecified:
                    {
                        throw CreateArgumentException(Cmd.Mode, "", SR.GetString(SR.ArgumentRequired, Cmd.Mode), null);
                    }
                case Mode.Install:
                    {
                        DoInstall();
                        break;
                    }
                case Mode.Uninstall:
                    {
                        DoUninstall();
                        break;
                    }
                case Mode.List:
                    {
                        DoList();
                        break;
                    }
                default:
                    {
                        Debug.Assert(false, "unknown mode");
                        break;
                    }
            }
        }
 
        static void ValidateAddParams()
        {
            if (options.Application == null)
            {
                throw CreateArgumentException(Cmd.Application, null, SR.GetString(SR.ArgumentRequired, Cmd.Application), null);
            }
 
            if (!options.AllComponents && ((options.Components == null) || options.Components.Count == 0))
            {
                throw CreateArgumentException(Cmd.Contract, null, SR.GetString(SR.ArgumentRequired, Cmd.Contract), null);
            }
 
            switch (options.Hosting)
            {
                case Hosting.NotSpecified:
                    {
                        throw CreateArgumentException(Cmd.Hosting, null, SR.GetString(SR.ArgumentRequired, Cmd.Hosting), null);
                    }
                case Hosting.Complus:
                    {
                        if (options.WebDirectory != null)
                        {
                            throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebDirectory), null);
                        }
                        if (options.WebServer != null)
                        {
                            throw CreateArgumentException(Cmd.WebServer, options.WebServer, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebServer), null);
                        }
                        break;
                    }
                case Hosting.Was:
                    {
                        if (options.WebDirectory == null)
                        {
                            throw CreateArgumentException(Cmd.WebDirectory, null, SR.GetString(SR.ArgumentRequired, Cmd.WebDirectory), null);
                        }
                        break;
                    }
            }
        }
 
        static void ValidateRemoveParams()
        {
            if (options.Application == null)
            {
                throw CreateArgumentException(Cmd.Application, null, SR.GetString(SR.ArgumentRequired, Cmd.Application), null);
            }
 
            if (!options.AllComponents && ((options.Components == null) || options.Components.Count == 0))
            {
                throw CreateArgumentException(Cmd.Contract, null, SR.GetString(SR.ArgumentRequired, Cmd.Contract), null);
            }
 
            switch (options.Hosting)
            {
                case Hosting.NotSpecified:
                    {
                        if (options.WebDirectory != null)
                        {
                            throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebDirectory), null);
                        }
                        break;
 
                    }
                case Hosting.Complus:
                    {
                        if (options.WebDirectory != null)
                        {
                            throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebDirectory), null);
                        }
                        if (options.WebServer != null)
                        {
                            throw CreateArgumentException(Cmd.WebServer, options.WebServer, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebServer), null);
                        }
                        break;
                    }
                case Hosting.Was:
                    {
                        break;
                    }
            }
        }
 
        static void ValidateQueryParams()
        {
 
            if (options.AllComponents || ((options.Components != null) && options.Components.Count > 0))
            {
                throw CreateArgumentException(Cmd.Contract, null, SR.GetString(SR.ExclusiveOptionsSpecified, Cmd.Contract, Cmd.Mode + ":query"), null);
            }
 
            switch (options.Hosting)
            {
                case Hosting.NotSpecified:
                    {
                        if (options.WebDirectory != null)
                        {
                            throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebDirectory), null);
                        }
                        break;
 
                    }
                case Hosting.Complus:
                    {
                        if (options.WebDirectory != null)
                        {
                            throw CreateArgumentException(Cmd.WebDirectory, options.WebDirectory, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebDirectory), null);
                        }
                        if (options.WebServer != null)
                        {
                            throw CreateArgumentException(Cmd.WebServer, options.WebServer, SR.GetString(SR.InvalidArgumentForHostingMode, Cmd.WebServer), null);
                        }
                        break;
                    }
                case Hosting.Was:
                    {
                        break;
                    }
            }
        }
 
        static void ValidateApplication(ComAdminAppInfo appInfo, Hosting hosting)
        {
            if (appInfo.IsSystemApplication)
            {
                throw CreateArgumentException(Cmd.Application, appInfo.Name, SR.GetString(SR.SystemApplicationsNotSupported), null);
            }
 
            if (hosting == Hosting.Complus)
            {
                if (!appInfo.IsServerActivated)
                {
                    throw CreateArgumentException(Cmd.Application, appInfo.Name, SR.GetString(SR.LibraryApplicationsNotSupported), null);
                }
 
                if (appInfo.IsAutomaticRecycling)
                {
                    throw CreateArgumentException(Cmd.Application, appInfo.Name, SR.GetString(SR.ProcessRecyclingNotSupported), null);
                }
 
                if (appInfo.IsProcessPooled)
                {
                    throw CreateArgumentException(Cmd.Application, appInfo.Name, SR.GetString(SR.ProcessPoolingNotSupported), null);
                }
            }
        }
 
        static bool ValidateClass(ComAdminClassInfo classInfo)
        {
            if (classInfo.IsPrivate)
            {
                ToolConsole.WriteWarning(SR.GetString(SR.CannotExposePrivateComponentsSkipping, Tool.Options.ShowGuids ? classInfo.Clsid.ToString("B") : classInfo.Name));
                return false;
            }
            return true;
        }
 
 
 
    }
}