File: src\VisualStudio\IntegrationTest\Harness\IntegrationTestServiceShared\IntegrationTestServiceCommands.cs
Web Access
Project: src\src\VisualStudio\IntegrationTest\Harness\IntegrationTestServiceDev18\Microsoft.VisualStudio.IntegrationTestService.Dev18.csproj (Microsoft.VisualStudio.IntegrationTestService)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
namespace Microsoft.VisualStudio.IntegrationTestService
{
    using System;
    using System.Collections;
    using System.ComponentModel.Design;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Channels;
    using System.Runtime.Remoting.Channels.Ipc;
    using System.Runtime.Serialization.Formatters;
    using Microsoft.VisualStudio.Shell;
 
    internal sealed class IntegrationTestServiceCommands : IDisposable
    {
        public const int CmdIdStartIntegrationTestService = 0x5201;
        public const int CmdIdStopIntegrationTestService = 0x5204;
 
        public static readonly Guid GuidIntegrationTestCmdSet = new Guid("F3505B05-AF1E-493A-A5A5-ECEB69C42714");
 
        private static readonly BinaryServerFormatterSinkProvider DefaultSinkProvider = new BinaryServerFormatterSinkProvider()
        {
            TypeFilterLevel = TypeFilterLevel.Full,
        };
 
        private readonly Package _package;
 
        private readonly MenuCommand _startMenuCmd;
        private readonly MenuCommand _stopMenuCmd;
 
        private IntegrationService? _service;
        private IpcChannel? _serviceChannel;
        private ObjRef? _marshalledService;
 
        private IntegrationTestServiceCommands(Package package)
        {
            _package = package ?? throw new ArgumentNullException(nameof(package));
 
            var startMenuCmdId = new CommandID(GuidIntegrationTestCmdSet, CmdIdStartIntegrationTestService);
            _startMenuCmd = new MenuCommand(StartServiceCallback, startMenuCmdId)
            {
                Enabled = true,
                Visible = true,
            };
 
            var stopMenuCmdId = new CommandID(GuidIntegrationTestCmdSet, CmdIdStopIntegrationTestService);
            _stopMenuCmd = new MenuCommand(StopServiceCallback, stopMenuCmdId)
            {
                Enabled = false,
                Visible = false,
            };
 
            if (ServiceProvider.GetService(typeof(IMenuCommandService)) is OleMenuCommandService menuCommandService)
            {
                menuCommandService.AddCommand(_startMenuCmd);
                menuCommandService.AddCommand(_stopMenuCmd);
            }
        }
 
        public static IntegrationTestServiceCommands? Instance
        {
            get;
            private set;
        }
 
        private IServiceProvider ServiceProvider => _package;
 
        public static void Initialize(Package package)
        {
            Instance = new IntegrationTestServiceCommands(package);
        }
 
        public void Dispose()
            => StopServiceCallback(this, EventArgs.Empty);
 
        /// <summary>
        /// Starts the IPC server for the Integration Test service.
        /// </summary>
        private void StartServiceCallback(object sender, EventArgs e)
        {
            if (_startMenuCmd.Enabled)
            {
                _service = new IntegrationService();
 
                _serviceChannel = new IpcChannel(
                    new Hashtable
                    {
                        { "name", $"Microsoft.VisualStudio.IntegrationTest.ServiceChannel_{Process.GetCurrentProcess().Id}" },
                        { "portName", _service.PortName },
                    },
                    clientSinkProvider: new BinaryClientFormatterSinkProvider(),
                    serverSinkProvider: DefaultSinkProvider);
 
                var serviceType = typeof(IntegrationService);
                _marshalledService = RemotingServices.Marshal(_service, serviceType.FullName, serviceType);
 
                _serviceChannel.StartListening(null);
                ChannelServices.RegisterChannel(_serviceChannel, ensureSecurity: false);
 
                SwapAvailableCommands(_startMenuCmd, _stopMenuCmd);
            }
        }
 
        /// <summary>Stops the IPC server for the Integration Test service.</summary>
        private void StopServiceCallback(object sender, EventArgs e)
        {
            if (_stopMenuCmd.Enabled)
            {
                if (_serviceChannel != null)
                {
                    if (ChannelServices.RegisteredChannels.Contains(_serviceChannel))
                    {
                        ChannelServices.UnregisterChannel(_serviceChannel);
                    }
 
                    _serviceChannel.StopListening(null);
                    _serviceChannel = null;
                }
 
                GC.KeepAlive(_marshalledService);
                _marshalledService = null;
                _service = null;
 
                SwapAvailableCommands(_stopMenuCmd, _startMenuCmd);
            }
        }
 
        private static void SwapAvailableCommands(MenuCommand commandToDisable, MenuCommand commandToEnable)
        {
            commandToDisable.Enabled = false;
            commandToDisable.Visible = false;
 
            commandToEnable.Enabled = true;
            commandToEnable.Visible = true;
        }
    }
}