예제 #1
0
        /// <summary>
        /// Initializes the package right after it's been "sited" into the fully-initialized Visual Studio IDE.
        /// </summary>
        protected override void Initialize()
        {
            Logging.WriteLine("Initializing UnrealVS extension...");

            // Grab the MenuCommandService
            MenuCommandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;

            // Get access to Visual Studio's DTE object.  This object has various hooks into the Visual Studio
            // shell that are useful for writing extensions.
            DTE = (DTE)GetGlobalService(typeof(DTE));
            Logging.WriteLine("DTE version " + DTE.Version);

            // Get selection manager and register to receive events
            SelectionManager =
                ServiceProvider.GlobalProvider.GetService(typeof(SVsShellMonitorSelection)) as IVsMonitorSelection;
            SelectionManager.AdviseSelectionEvents(this, out SelectionEventsHandle);

            // Get solution and register to receive events
            SolutionManager = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution2;
            UpdateUnrealLoadedStatus();
            SolutionManager.AdviseSolutionEvents(this, out SolutionEventsHandle);

            // Grab the solution build manager.  We need this in order to change certain things about the Visual
            // Studio environment, like what the active startup project is
            // Get solution build manager
            SolutionBuildManager =
                ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2;
            SolutionBuildManager.AdviseUpdateSolutionEvents(this, out UpdateSolutionEventsHandle);

            // Create our command-line editor
            CommandLineEditor = new CommandLineEditor();

            // Create our startup project selector
            StartupProjectSelector = new StartupProjectSelector();

            // Create 'BuildStartupProject' instance
            BuildStartupProject = new BuildStartupProject();

            // Create 'CompileSingleFile' instance
            CompileSingleFile = new CompileSingleFile();

            // Create 'GenerateProjectFiles' tools
            GenerateProjectFiles = new GenerateProjectFiles();

            // Create Batch Builder tools
            BatchBuilder = new BatchBuilder();

            // Create the project menu quick builder
            QuickBuilder = new QuickBuild();

            // Call parent implementation
            base.Initialize();

            if (DTE.Solution.IsOpen)
            {
                StartTicker();
            }
        }
        private void BuildJobSetsCollectionOnCollectionChanged(object sender, EventArgs eventArgs)
        {
            Logging.WriteLine("BuildJobSet Collection changed");

            if (SetCombo.SelectedItem == null)
            {
                SetCombo.SelectedItem = _state._BuildJobSetsCollection[0];
            }
        }
예제 #3
0
        /// Called by combo control to query the text to display or to apply newly-entered text
        private void ComboHandler(object Sender, EventArgs Args)
        {
            try
            {
                var OleArgs = (OleMenuCmdEventArgs)Args;

                string InString = OleArgs.InValue as string;
                if (InString != null)
                {
                    // New text set on the combo - set the command line property
                    DesiredCommandLine = null;
                    CommitCommandLineText(InString);
                }
                else if (OleArgs.OutValue != IntPtr.Zero)
                {
                    string EditingString = null;
                    if (OleArgs.InValue != null)
                    {
                        object[] InArray = OleArgs.InValue as object[];
                        if (InArray != null && 0 < InArray.Length)
                        {
                            EditingString = InArray.Last() as string;
                        }
                    }

                    string TextToDisplay = string.Empty;
                    if (EditingString != null)
                    {
                        // The control wants to put EditingString in the box
                        TextToDisplay = DesiredCommandLine = EditingString;
                    }
                    else
                    {
                        // This is always hit at the end of interaction with the combo
                        if (DesiredCommandLine != null)
                        {
                            TextToDisplay      = DesiredCommandLine;
                            DesiredCommandLine = null;
                            CommitCommandLineText(TextToDisplay);
                        }
                        else
                        {
                            TextToDisplay = MakeCommandLineComboText();
                        }
                    }

                    Marshal.GetNativeVariantForObject(TextToDisplay, OleArgs.OutValue);
                }
            }
            catch (Exception ex)
            {
                Exception AppEx = new ApplicationException("CommandLineEditor threw an exception in ComboHandler()", ex);
                Logging.WriteLine(AppEx.ToString());
                throw AppEx;
            }
        }
예제 #4
0
        /// <summary>
        /// Returns all the .uprojects found under the solution root folder.
        /// </summary>
        public static IDictionary <string, string> GetUProjects()
        {
            var Folder = GetSolutionFolder();

            if (string.IsNullOrEmpty(Folder))
            {
                return(new Dictionary <string, string>());
            }

            if (Folder != CachedUProjectRootFolder)
            {
                Logging.WriteLine("GetUProjects: recaching uproject paths...");
                DateTime Start = DateTime.Now;

                CachedUProjectRootFolder = Folder;
                CachedUProjectPaths      = EnumerateProjects(new DirectoryInfo(Folder)).Select(x => x.FullName);
                CachedUProjects          = null;

                TimeSpan TimeTaken = DateTime.Now - Start;
                Logging.WriteLine(string.Format("GetUProjects: EnumerateProjects took {0} sec", TimeTaken.TotalSeconds));

                foreach (string CachedUProjectPath in CachedUProjectPaths)
                {
                    Logging.WriteLine(String.Format("GetUProjects: found {0}", CachedUProjectPath));
                }

                Logging.WriteLine("    DONE");
            }

            if (CachedUProjects == null)
            {
                Logging.WriteLine("GetUProjects: recaching uproject names...");

                var ProjectPaths = UnrealVSPackage.Instance.GetLoadedProjectPaths();
                var ProjectNames = (from path in ProjectPaths select Path.GetFileNameWithoutExtension(path)).ToArray();

                var CodeUProjects = from UProjectPath in CachedUProjectPaths
                                    let ProjectName = Path.GetFileNameWithoutExtension(UProjectPath)
                                                      where ProjectNames.Any(name => string.Compare(name, ProjectName, StringComparison.OrdinalIgnoreCase) == 0)
                                                      select new { Name = ProjectName, FilePath = UProjectPath };

                CachedUProjects = new Dictionary <string, string>();

                foreach (var UProject in CodeUProjects)
                {
                    if (!CachedUProjects.ContainsKey(UProject.Name))
                    {
                        CachedUProjects.Add(UProject.Name, UProject.FilePath);
                    }
                }

                Logging.WriteLine("    DONE");
            }

            return(CachedUProjects);
        }
예제 #5
0
        /// IDispose pattern lets us clean up our stuff!
        protected override void Dispose(bool disposing)
        {
            if (Ticker != null && Ticker.IsAlive)
            {
                Thread.Sleep(TickPeriod + TickPeriod);
                if (Ticker.IsAlive)
                {
                    Logging.WriteLine("WARNING: Force aborting Ticker thread");
                    Ticker.Abort();
                }
            }

            base.Dispose(disposing);

            // Clean up singleton instance
            PrivateInstance = null;

            CommandLineEditor      = null;
            StartupProjectSelector = null;
            BatchBuilder           = null;
            QuickBuilder           = null;

            if (CompileSingleFile != null)
            {
                CompileSingleFile.Dispose();
                CompileSingleFile = null;
            }

            // No longer want solution events
            if (SolutionEventsHandle != 0)
            {
                SolutionManager.UnadviseSolutionEvents(SolutionEventsHandle);
                SolutionEventsHandle = 0;
            }
            SolutionManager = null;

            // No longer want selection events
            if (SelectionEventsHandle != 0)
            {
                SelectionManager.UnadviseSelectionEvents(SelectionEventsHandle);
                SelectionEventsHandle = 0;
            }
            SelectionManager = null;

            // No longer want update solution events
            if (UpdateSolutionEventsHandle != 0)
            {
                SolutionBuildManager.UnadviseUpdateSolutionEvents(UpdateSolutionEventsHandle);
                UpdateSolutionEventsHandle = 0;
            }
            SolutionBuildManager = null;

            Logging.WriteLine("Closing UnrealVS extension");
            Logging.Close();
        }
예제 #6
0
        /** Methods */

        /// <summary>
        /// Package constructor.  The package is being created but Visual Studio isn't fully initialized yet, so
        /// it's NOT SAFE to call into Visual Studio services from here.  Do that in Initialize() instead.
        /// </summary>
        public UnrealVSPackage()
        {
            // Register this key string so the package can save command line data to solution options files.
            // See OnLoadOptions() & OnSaveOptions()
            AddOptionKey(CommandLineOptionKey);
            AddOptionKey(BatchBuildSetsOptionKey);

            // Setup singleton instance
            PrivateInstance = this;

            Logging.Initialize(ExtensionName, VersionString);
            Logging.WriteLine("Loading UnrealVS extension package...");
        }
            /// <summary>
            /// Called from the package class when there are options to be read out of the solution file.
            /// </summary>
            /// <param name="Stream">The stream to load the option data from.</param>
            public void LoadOptions(Stream Stream)
            {
                try
                {
                    _BuildJobSetsCollection.Clear();

                    using (BinaryReader Reader = new BinaryReader(Stream))
                    {
                        int SetCount = Reader.ReadInt32();

                        for (int SetIdx = 0; SetIdx < SetCount; SetIdx++)
                        {
                            BuildJobSet LoadedSet = new BuildJobSet();
                            LoadedSet.Name = Reader.ReadString();
                            int JobCount = Reader.ReadInt32();
                            for (int JobIdx = 0; JobIdx < JobCount; JobIdx++)
                            {
                                Utils.SafeProjectReference ProjectRef = new Utils.SafeProjectReference {
                                    FullName = Reader.ReadString(), Name = Reader.ReadString()
                                };

                                string Config   = Reader.ReadString();
                                string Platform = Reader.ReadString();
                                BuildJob.BuildJobType JobType;

                                if (Enum.TryParse(Reader.ReadString(), out JobType))
                                {
                                    LoadedSet.BuildJobs.Add(new BuildJob(ProjectRef, Config, Platform, JobType));
                                }
                            }
                            _BuildJobSetsCollection.Add(LoadedSet);
                        }
                    }

                    if (_BuildJobSetsCollection.Count == 0)
                    {
                        BuildJobSet DefaultItem = new BuildJobSet {
                            Name = "UntitledSet"
                        };
                        _BuildJobSetsCollection.Add(DefaultItem);
                    }

                    StateLoaded?.Invoke(this, null);
                }
                catch (Exception ex)
                {
                    Exception AppEx = new ApplicationException("BatchBuilder failed to load options from .suo", ex);
                    Logging.WriteLine(AppEx.ToString());
                    throw AppEx;
                }
            }
        /// <summary>
        /// Called when a solution loads. Caches the solution build configs and sets the platform menus' visibility.
        /// Only platforms found in the laoded solution's list are shown.
        /// </summary>
        private void OnSolutionChanged()
        {
            CacheBuildConfigs();

            ActivePlaformMenus.Clear();
            Logging.WriteLine("Updating solution menu state, currently active config platforms are: " + string.Join(", ", SolutionConfigPlatforms));
            foreach (var SubMenu in SubMenus)
            {
                if (SolutionConfigPlatforms.Any(Platform => string.Compare(Platform, SubMenu.Name, StringComparison.InvariantCultureIgnoreCase) == 0))
                {
                    ActivePlaformMenus.Add(SubMenu.Name, AllPlaformMenus[SubMenu.Name]);
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Returns all the .uprojects found under the solution root folder.
        /// </summary>
        public static IDictionary <string, string> GetUProjects()
        {
            var Folder = GetSolutionFolder();

            if (string.IsNullOrEmpty(Folder))
            {
                return(new Dictionary <string, string>());
            }

            if (Folder != CachedUProjectRootFolder)
            {
                Logging.WriteLine("GetUProjects: recaching uproject paths...");

                CachedUProjectRootFolder = Folder;
                CachedUProjectPaths      = Directory.GetFiles(Folder, "*." + UProjectExtension, SearchOption.AllDirectories);
                CachedUProjects          = null;

                Logging.WriteLine("    DONE");
            }

            if (CachedUProjects == null)
            {
                Logging.WriteLine("GetUProjects: recaching uproject names...");

                var ProjectPaths = UnrealVSPackage.Instance.GetLoadedProjectPaths();
                var ProjectNames = (from path in ProjectPaths select Path.GetFileNameWithoutExtension(path)).ToArray();

                var CodeUProjects = from UProjectPath in CachedUProjectPaths
                                    let ProjectName = Path.GetFileNameWithoutExtension(UProjectPath)
                                                      where ProjectNames.Any(name => string.Compare(name, ProjectName, StringComparison.OrdinalIgnoreCase) == 0)
                                                      select new { Name = ProjectName, FilePath = UProjectPath };

                CachedUProjects = new Dictionary <string, string>();

                foreach (var UProject in CodeUProjects)
                {
                    if (!CachedUProjects.ContainsKey(UProject.Name))
                    {
                        CachedUProjects.Add(UProject.Name, UProject.FilePath);
                    }
                }

                Logging.WriteLine("    DONE");
            }

            return(CachedUProjects);
        }
예제 #10
0
        /// <summary>
        /// Enumerate projects under the given directory
        /// </summary>
        /// <param name="SolutionDir">Base directory to enumerate</param>
        /// <returns>List of project files</returns>
        static List <FileInfo> EnumerateProjects(DirectoryInfo SolutionDir)
        {
            // Enumerate all the projects in the same directory as the solution. If there's one here, we don't need to consider any other.
            List <FileInfo> ProjectFiles = new List <FileInfo>(SolutionDir.EnumerateFiles("*.uproject"));

            if (ProjectFiles.Count == 0)
            {
                // Build a list of all the parent directories for projects. This includes the UE4 root, plus any directories referenced via .uprojectdirs files.
                List <DirectoryInfo> ParentProjectDirs = new List <DirectoryInfo>();
                ParentProjectDirs.Add(SolutionDir);

                // Read all the .uprojectdirs files
                foreach (FileInfo ProjectDirsFile in SolutionDir.EnumerateFiles("*.uprojectdirs"))
                {
                    foreach (string Line in File.ReadAllLines(ProjectDirsFile.FullName))
                    {
                        string TrimLine = Line.Trim().Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar).Trim(Path.DirectorySeparatorChar);
                        if (TrimLine.Length > 0 && !TrimLine.StartsWith(";"))
                        {
                            try
                            {
                                ParentProjectDirs.Add(new DirectoryInfo(Path.Combine(SolutionDir.FullName, TrimLine)));
                            }
                            catch (Exception Ex)
                            {
                                Logging.WriteLine(String.Format("EnumerateProjects: Exception trying to resolve project directory '{0}': {1}", TrimLine, Ex.Message));
                            }
                        }
                    }
                }

                // Add projects in any subfolders of the parent directories
                HashSet <string> CheckedParentDirs = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase);
                foreach (DirectoryInfo ParentProjectDir in ParentProjectDirs)
                {
                    if (CheckedParentDirs.Add(ParentProjectDir.FullName) && ParentProjectDir.Exists)
                    {
                        foreach (DirectoryInfo ProjectDir in ParentProjectDir.EnumerateDirectories())
                        {
                            ProjectFiles.AddRange(ProjectDir.EnumerateFiles("*.uproject"));
                        }
                    }
                }
            }
            return(ProjectFiles);
        }
예제 #11
0
 /// <summary>
 /// Overrides Package.OnSaveOptions()
 /// Invoked by the Package class when there are options to be saved to the solution file.
 /// </summary>
 /// <param name="key">The name of the option key to save.</param>
 /// <param name="stream">The stream to save the option data to.</param>
 protected override void OnSaveOptions(string key, Stream stream)
 {
     try
     {
         if (0 == string.Compare(key, CommandLineOptionKey))
         {
             Logging.WriteLine("Saving CommandLineEditor options");
             CommandLineEditor.SaveOptions(stream);
         }
         else if (0 == string.Compare(key, BatchBuildSetsOptionKey))
         {
             Logging.WriteLine("Saving BatchBuilder options");
             BatchBuilder.SaveOptions(stream);
         }
     }
     catch (Exception Ex)
     {
         // Couldn't save options
         Exception AppEx = new ApplicationException("OnSaveOptions() failed with key " + key, Ex);
         Logging.WriteLine(AppEx.ToString());
         throw AppEx;
     }
 }
예제 #12
0
        /// <summary>
        /// Launches a program
        /// </summary>
        /// <param name="ProgramFile">Path to the program to run</param>
        /// <param name="Arguments">Command-line arguments</param>
        /// <param name="OnExit">Optional callback whent he program exits</param>
        /// <param name="OutputHandler">If supplied, std-out and std-error will be redirected to this function and no shell window will be created</param>
        /// <returns>The newly-created process, or null if it wasn't able to start.  Exceptions are swallowed, but a debug output string is emitted on errors</returns>
        public System.Diagnostics.Process LaunchProgram(string ProgramFile, string Arguments, EventHandler OnExit = null, DataReceivedEventHandler OutputHandler = null, bool bWaitForCompletion = false)
        {
            // Create the action's process.
            ProcessStartInfo ActionStartInfo = new ProcessStartInfo();

            ActionStartInfo.FileName  = ProgramFile;
            ActionStartInfo.Arguments = Arguments;

            if (OutputHandler != null)
            {
                ActionStartInfo.RedirectStandardInput  = true;
                ActionStartInfo.RedirectStandardOutput = true;
                ActionStartInfo.RedirectStandardError  = true;

                // True to use a DOS box to run the program in, otherwise false to run directly.  In order to redirect
                // output, UseShellExecute must be disabled
                ActionStartInfo.UseShellExecute = false;

                // Don't show the DOS box, since we're redirecting everything
                ActionStartInfo.CreateNoWindow = true;
            }


            Logging.WriteLine(String.Format("Executing: {0} {1}", ActionStartInfo.FileName, ActionStartInfo.Arguments));

            System.Diagnostics.Process ActionProcess;

            try
            {
                ActionProcess           = new System.Diagnostics.Process();
                ActionProcess.StartInfo = ActionStartInfo;

                if (OnExit != null)
                {
                    ActionProcess.EnableRaisingEvents = true;
                    ActionProcess.Exited += OnExit;
                }

                if (ActionStartInfo.RedirectStandardOutput)
                {
                    ActionProcess.EnableRaisingEvents = true;
                    ActionProcess.OutputDataReceived += OutputHandler;
                    ActionProcess.ErrorDataReceived  += OutputHandler;
                }

                // Launch the program
                ActionProcess.Start();

                if (ActionStartInfo.RedirectStandardOutput)
                {
                    ActionProcess.BeginOutputReadLine();
                    ActionProcess.BeginErrorReadLine();
                }

                if (bWaitForCompletion)
                {
                    while ((ActionProcess != null) && (!ActionProcess.HasExited))
                    {
                        ActionProcess.WaitForExit(50);
                    }
                }
            }
            catch (Exception Ex)
            {
                // Couldn't launch program
                Logging.WriteLine("Couldn't launch program: " + ActionStartInfo.FileName);
                Logging.WriteLine("Exception: " + Ex.Message);
                ActionProcess = null;
            }

            return(ActionProcess);
        }
예제 #13
0
        public StartupProjectSelector()
        {
            _bIsSolutionOpened = UnrealVSPackage.Instance.DTE.Solution.IsOpen;

            // Create the handlers for our commands
            {
                // StartupProjectCombo
                var StartupProjectComboCommandId = new CommandID(GuidList.UnrealVSCmdSet, StartupProjectComboId);
                var StartupProjectComboCommand   = new OleMenuCommand(StartupProjectComboHandler, StartupProjectComboCommandId);
                StartupProjectComboCommand.BeforeQueryStatus += (sender, args) => StartupProjectComboCommand.Enabled = _bIsSolutionOpened;
                UnrealVSPackage.Instance.MenuCommandService.AddCommand(StartupProjectComboCommand);

                // StartupProjectComboList
                var StartupProjectComboListCommandId = new CommandID(GuidList.UnrealVSCmdSet, StartupProjectComboListId);
                var StartupProjectComboListCommand   = new OleMenuCommand(StartupProjectComboListHandler, StartupProjectComboListCommandId);
                StartupProjectComboListCommand.BeforeQueryStatus += (sender, args) => StartupProjectComboListCommand.Enabled = _bIsSolutionOpened;
                UnrealVSPackage.Instance.MenuCommandService.AddCommand(StartupProjectComboListCommand);

                StartupProjectComboCommands = new[] { StartupProjectComboCommand, StartupProjectComboListCommand };
            }

            // Register for events that we care about
            UnrealVSPackage.Instance.OnStartupProjectChanged += OnStartupProjectChanged;
            UnrealVSPackage.Instance.OnSolutionOpened        +=
                delegate
            {
                Logging.WriteLine("Opened solution " + UnrealVSPackage.Instance.DTE.Solution.FullName);
                _bIsSolutionOpened = true;
                UpdateStartupProjectCombo();
                UpdateStartupProjectList(Utils.GetAllProjectsFromDTE());
            };
            UnrealVSPackage.Instance.OnSolutionClosing +=
                delegate
            {
                Logging.WriteLine("Closing solution");
                _bIsSolutionOpened = false;
                UpdateStartupProjectCombo();
                _CachedStartupProjects.Clear();
            };
            UnrealVSPackage.Instance.OnProjectOpened +=
                delegate(Project OpenedProject)
            {
                if (_bIsSolutionOpened)
                {
                    Logging.WriteLine("Opened project node " + OpenedProject.Name);
                    UpdateStartupProjectList(OpenedProject);
                }
                else
                {
                    Logging.WriteLine("Opened project node " + OpenedProject.Name + " with the solution CLOSED");
                }
            };
            UnrealVSPackage.Instance.OnProjectClosed +=
                delegate(Project ClosedProject)
            {
                Logging.WriteLine("Closed project node " + ClosedProject.Name);
                RemoveFromStartupProjectList(ClosedProject);
            };
            UnrealVSPackage.Instance.OptionsPage.OnOptionsChanged += OnOptionsChanged;

            UpdateStartupProjectList(Utils.GetAllProjectsFromDTE());
            UpdateStartupProjectCombo();
        }
예제 #14
0
        /// <summary>
        /// Helper to check the properties of a project and determine whether it can be run in VS.
        /// Projects that return true can be run in the debugger by pressing the usual Start Debugging (F5) command.
        /// </summary>
        public static bool IsProjectSuitable(Project Project)
        {
            try
            {
                Logging.WriteLine("IsProjectExecutable: Attempting to determine if project " + Project.Name + " is executable");

                var ConfigManager = Project.ConfigurationManager;
                if (ConfigManager == null)
                {
                    return(false);
                }

                var ActiveProjectConfig = Project.ConfigurationManager.ActiveConfiguration;
                if (ActiveProjectConfig != null)
                {
                    Logging.WriteLine(
                        "IsProjectExecutable: ActiveProjectConfig=\"" + ActiveProjectConfig.ConfigurationName + "|" + ActiveProjectConfig.PlatformName + "\"");
                }
                else
                {
                    Logging.WriteLine("IsProjectExecutable: Warning - ActiveProjectConfig is null!");
                }

                bool IsSuitable = false;

                if (Project.Kind.Equals(GuidList.VCSharpProjectKindGuidString, StringComparison.OrdinalIgnoreCase))
                {
                    // C# project

                    // Chris.Wood
                    //Property StartActionProp = GetProjectConfigProperty(Project, null, "StartAction");
                    //if (StartActionProp != null)
                    //{
                    //	prjStartAction StartAction = (prjStartAction)StartActionProp.Value;
                    //	if (StartAction == prjStartAction.prjStartActionProject)
                    //	{
                    //		// Project starts the project's output file when run
                    //		Property OutputTypeProp = GetProjectProperty(Project, "OutputType");
                    //		if (OutputTypeProp != null)
                    //		{
                    //			prjOutputType OutputType = (prjOutputType)OutputTypeProp.Value;
                    //			if (OutputType == prjOutputType.prjOutputTypeWinExe ||
                    //				OutputType == prjOutputType.prjOutputTypeExe)
                    //			{
                    //				IsSuitable = true;
                    //			}
                    //		}
                    //	}
                    //	else if (StartAction == prjStartAction.prjStartActionProgram ||
                    //			 StartAction == prjStartAction.prjStartActionURL)
                    //	{
                    //		// Project starts an external program or a URL when run - assume it has been set deliberately to something executable
                    //		IsSuitable = true;
                    //	}
                    //}

                    IsSuitable = true;
                }
                else if (Project.Kind.Equals(GuidList.VCProjectKindGuidString, StringComparison.OrdinalIgnoreCase))
                {
                    // C++ project

                    SolutionConfiguration SolutionConfig      = UnrealVSPackage.Instance.DTE.Solution.SolutionBuild.ActiveConfiguration;
                    SolutionContext       ProjectSolutionCtxt = SolutionConfig.SolutionContexts.Item(Project.UniqueName);

                    // Get the correct config object from the VCProject
                    string ActiveConfigName = string.Format(
                        "{0}|{1}",
                        ProjectSolutionCtxt.ConfigurationName,
                        ProjectSolutionCtxt.PlatformName);

                    // Get the VS version-specific VC project object.
                    VCProject VCProject = new VCProject(Project, ActiveConfigName);

                    if (VCProject != null)
                    {
                        // Sometimes the configurations is null.
                        if (VCProject.Configurations != null)
                        {
                            var VCConfigMatch = VCProject.Configurations.FirstOrDefault(VCConfig => VCConfig.Name == ActiveConfigName);

                            if (VCConfigMatch != null)
                            {
                                if (VCConfigMatch.DebugAttach)
                                {
                                    // Project attaches to a running process
                                    IsSuitable = true;
                                }
                                else
                                {
                                    // Project runs its own process

                                    if (VCConfigMatch.DebugFlavor == DebuggerFlavor.Remote)
                                    {
                                        // Project debugs remotely
                                        if (VCConfigMatch.DebugRemoteCommand.Length != 0)
                                        {
                                            // An remote program is specified to run
                                            IsSuitable = true;
                                        }
                                    }
                                    else
                                    {
                                        // Local debugger

                                        if (VCConfigMatch.DebugCommand.Length != 0 && VCConfigMatch.DebugCommand != "$(TargetPath)")
                                        {
                                            // An external program is specified to run
                                            IsSuitable = true;
                                        }
                                        else
                                        {
                                            // No command so the project runs the target file

                                            if (VCConfigMatch.ConfigType == ConfigType.Application)
                                            {
                                                IsSuitable = true;
                                            }
                                            else if (VCConfigMatch.ConfigType == ConfigType.Generic)
                                            {
                                                // Makefile

                                                if (VCConfigMatch.NMakeToolOutput.Length != 0)
                                                {
                                                    string Ext = Path.GetExtension(VCConfigMatch.NMakeToolOutput);
                                                    if (!IsLibraryFileExtension(Ext))
                                                    {
                                                        IsSuitable = true;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    // @todo: support other project types
                    Logging.WriteLine("IsProjectExecutable: Unrecognised 'Kind' in project " + Project.Name + " guid=" + Project.Kind);
                }

                return(IsSuitable);
            }
            catch (Exception ex)
            {
                Exception AppEx = new ApplicationException("IsProjectExecutable() failed", ex);
                Logging.WriteLine(AppEx.ToString());
                throw AppEx;
            }
        }