예제 #1
0
        /// <summary>
        /// Ensure that the current project item has the required extensions loaded.
        /// This is only called after verifying that the current project item does
        /// not satisfy the requirements.
        /// </summary>
        /// <param name="projectItem">The <see cref="EnvDTE.ProjectItem"/> to modify</param>
        /// <param name="serviceProvider">The <see cref="IServiceProvider"/> for document tracking.</param>
        /// <param name="extensions">An <see cref="T:ICollection{System.String}"/> of additional required extensions</param>
        public static bool EnsureExtensions(EnvDTE.ProjectItem projectItem, IServiceProvider serviceProvider, ICollection <string> extensions)
        {
            ServiceProvider provider = new ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)projectItem.DTE);

            // UNDONE: Localize message strings in here
            if ((int)DialogResult.No == VsShellUtilities.ShowMessageBox(
                    provider,
                    "Additional extensions are required to support the chosen generators. Would you like to load the required extensions now?",
                    "ORM Generator Selection",
                    OLEMSGICON.OLEMSGICON_QUERY,
                    OLEMSGBUTTON.OLEMSGBUTTON_YESNO,
                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST))
            {
                return(false);
            }
            EnvDTE.Document document    = projectItem.Document;
            bool            secondPass  = false;
            bool            tryDocument = true;
            string          itemPath    = null;

            while (tryDocument)
            {
                object     documentExtensionManager;
                MethodInfo methodInfo;
                if (null != document &&
                    null != (documentExtensionManager = ORMCustomToolUtility.GetDocumentExtension <object>(document, "ORMExtensionManager", itemPath ?? (itemPath = projectItem.get_FileNames(0)), serviceProvider)) &&
                    null != (methodInfo = documentExtensionManager.GetType().GetMethod("EnsureExtensions", new Type[] { typeof(string[]) })))
                {
                    string[] extensionsArray = new string[extensions.Count];
                    extensions.CopyTo(extensionsArray, 0);
                    methodInfo.Invoke(documentExtensionManager, new object[] { extensionsArray });
                    return(true);
                }

                if (secondPass)
                {
                    return(false);
                }
                tryDocument = false;
                secondPass  = true;

                // UNDONE: Localize message strings in here
                if ((int)DialogResult.No == VsShellUtilities.ShowMessageBox(
                        provider,
                        "The .ORM file must be open in the default designer to add extensions. Would you like to open or reopen the document now?",
                        "ORM Generator Selection",
                        OLEMSGICON.OLEMSGICON_QUERY,
                        OLEMSGBUTTON.OLEMSGBUTTON_YESNO,
                        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST))
                {
                    return(false);
                }

                if (document != null)
                {
                    document.Close(EnvDTE.vsSaveChanges.vsSaveChangesPrompt);
                    document = projectItem.Document;
                }
                if (document == null)
                {
                    projectItem.Open(Guid.Empty.ToString("B")).Visible = true;
                    document    = projectItem.Document;
                    tryDocument = true;
                }
            }
            return(false);
        }
예제 #2
0
        /// <summary>
        /// Return a sorted array of loaded extensions
        /// </summary>
        public string[] GetLoadedExtensions(IServiceProvider serviceProvider)
        {
            string[] retVal = myLoadedExtensions;
            if (retVal == null)
            {
                if (myDocument == null && myProjectItem != null)
                {
                    myDocument = myProjectItem.Document;
                }

                object     documentExtensionManager;
                MethodInfo methodInfo;
                string     itemPath = null;
                if (null != myDocument &&
                    null != (documentExtensionManager = ORMCustomToolUtility.GetDocumentExtension <object>(myDocument, "ORMExtensionManager", itemPath = myProjectItem.get_FileNames(0), serviceProvider)) &&
                    null != (methodInfo = documentExtensionManager.GetType().GetMethod("GetLoadedExtensions", Type.EmptyTypes)))
                {
                    retVal     = methodInfo.Invoke(documentExtensionManager, null) as string[];
                    myDocument = null;                     // No longer needed
                }
                Stream stream = null;
                if (null == retVal)
                {
                    // First used the passed in stream
                    stream = myStream;

                    // Next use an open text document. Note that this will already have provided
                    // an extension manager if this is an open ORM designer
                    if (stream == null && myDocument != null)
                    {
                        EnvDTE.TextDocument textDoc = ORMCustomToolUtility.GetDocumentExtension <EnvDTE.TextDocument>(myDocument, "TextDocument", itemPath ?? (itemPath = myProjectItem.get_FileNames(0)), serviceProvider);
                        if (textDoc != null)
                        {
                            // Note that the stream will be closed with the default reader settings of the XmlReader below
                            stream = new MemoryStream(Encoding.UTF8.GetBytes(textDoc.StartPoint.CreateEditPoint().GetText(textDoc.EndPoint)), false);
                        }
                    }

                    // Try the file directly from the project item
                    if (stream == null && myProjectItem != null)
                    {
                        // Note that the stream will be closed with the default reader settings of the XmlReader below
                        stream = new FileStream(myProjectItem.get_FileNames(0), FileMode.Open);
                    }
                }
                if (stream != null)
                {
                    // Attempt to open the stream as an Xml file to
                    // get the required extensions from the Xml
                    string[] namespaces     = null;
                    int      namespaceCount = 0;
                    try
                    {
                        XmlReaderSettings readerSettings = new XmlReaderSettings();
                        readerSettings.CloseInput = true;
                        using (XmlReader reader = XmlReader.Create(stream, readerSettings))
                        {
                            reader.MoveToContent();
                            if (reader.NodeType == XmlNodeType.Element)
                            {
                                int attributeCount = reader.AttributeCount;
                                if (attributeCount != 0)
                                {
                                    namespaces = new string[attributeCount];
                                    if (reader.MoveToFirstAttribute())
                                    {
                                        do
                                        {
                                            if (reader.Prefix == "xmlns" || reader.Name == "xmlns")
                                            {
                                                // Note that some of these are standard, not extensions, but it
                                                // isn't worth the trouble to add extra ORM knowledge here to figure it out
                                                string value = reader.Value;
                                                if (!string.IsNullOrEmpty(value))
                                                {
                                                    namespaces[namespaceCount] = reader.Value;
                                                    ++namespaceCount;
                                                }
                                            }
                                        } while (reader.MoveToNextAttribute());
                                    }
                                }
                            }
                        }
                    }
                    catch (XmlException)
                    {
                        // Nothing to do
                    }
                    finally
                    {
                        if (myStream != null)
                        {
                            myStream.Seek(0, SeekOrigin.Begin);
                            myStream = null;
                        }
                    }
                    if (namespaceCount != 0)
                    {
                        if (namespaceCount != namespaces.Length)
                        {
                            Array.Resize(ref namespaces, namespaceCount);
                        }
                        retVal = namespaces;
                    }
                }
                if (retVal == null)
                {
                    retVal = new string[0];
                }
                else
                {
                    Array.Sort <string>(retVal);
                }
                myLoadedExtensions = retVal;
            }
            return(retVal);
        }
        protected override void OnClosed(EventArgs e)
        {
            if (_savedChanges)
            {
                // Make sure the current document has the necessary
                // extensions loaded.
                // UNDONE: We should be able to do this with the document
                // closed or open as text as well via a registered service
                // on the ORMDesignerPackage, but this is sufficient for now.
                Dictionary <string, string> requiredExtensions = null;
                string[] loadedExtensions = null;
                foreach (IORMGenerator selectedGenerator in _mainBranch.SelectedGenerators)
                {
                    foreach (string requiredExtension in selectedGenerator.GetRequiredExtensionsForInputFormat("ORM"))
                    {
                        if (loadedExtensions == null)
                        {
                            loadedExtensions = (new ORMExtensionManager(_projectItem)).GetLoadedExtensions(_serviceProvider);
                        }
                        if (Array.BinarySearch <string>(loadedExtensions, requiredExtension) < 0)
                        {
                            if (requiredExtensions == null)
                            {
                                requiredExtensions = new Dictionary <string, string>();
                            }
                            else if (requiredExtensions.ContainsKey(requiredExtension))
                            {
                                continue;
                            }
                            requiredExtensions.Add(requiredExtension, requiredExtension);
                        }
                    }
                }
                if (requiredExtensions != null)
                {
                    _savedChanges = ORMExtensionManager.EnsureExtensions(_projectItem, _serviceProvider, requiredExtensions.Values);
                }
            }
            if (_savedChanges)
            {
#if VISUALSTUDIO_10_0
                ProjectItemGroupElement itemGroup = _originalItemGroup;
                ProjectRootElement      project   = _project;
#else // VISUALSTUDIO_10_0
                BuildItemGroup itemGroup = _originalItemGroup;
                Microsoft.Build.BuildEngine.Project project = _project;
#endif // VISUALSTUDIO_10_0
                EnvDTE.ProjectItem projectItem    = _projectItem;
                string             sourceFileName = _sourceFileName;
                Dictionary <string, PseudoBuildItem> pseudoItems = _pseudoItemsByOutputFormat;
                IDictionary <string, IORMGenerator>  generators  =
#if VISUALSTUDIO_15_0
                    ORMCustomTool.GetORMGenerators(_serviceProvider);
#else
                    ORMCustomTool.ORMGenerators;
#endif
                PseudoBuildItem pseudoItem;
                string          generatorNameData;        // The first string is the primary generator, others are the format modifiers, space delimited
                IVsShell        shell;

                Dictionary <string, IORMGenerator> generatorsWithTargetsByOutputFormat = null;
                IDictionary <string, ORMCustomToolUtility.GeneratorTargetSet> targetSetsByFormatName = null;
                foreach (PseudoBuildItem testPseudoItem in pseudoItems.Values)
                {
                    string         primaryGeneratorName;
                    IList <string> generatorTargets;
                    IORMGenerator  generator;
                    if (!string.IsNullOrEmpty(generatorNameData = testPseudoItem.CurrentGeneratorNames) &&
                        null != (primaryGeneratorName = ORMCustomToolUtility.GetPrimaryGeneratorName(generatorNameData)) &&
                        generators.TryGetValue(primaryGeneratorName, out generator) &&
                        null != (generatorTargets = generator.GeneratorTargetTypes) &&
                        0 != generatorTargets.Count)
                    {
                        (generatorsWithTargetsByOutputFormat ?? (generatorsWithTargetsByOutputFormat = new Dictionary <string, IORMGenerator>(StringComparer.OrdinalIgnoreCase)))[generator.ProvidesOutputFormat] = generator;
                    }
                }
                if (generatorsWithTargetsByOutputFormat != null)
                {
                    IDictionary <string, GeneratorTarget[]> docTargets = null;
                    EnvDTE.Document projectItemDocument = projectItem.Document;
                    string          itemPath;
                    if (projectItemDocument != null)
                    {
                        using (Stream targetsStream = ORMCustomToolUtility.GetDocumentExtension <Stream>(projectItemDocument, "ORMGeneratorTargets", itemPath = projectItem.get_FileNames(0), _serviceProvider))
                        {
                            if (targetsStream != null)
                            {
                                targetsStream.Seek(0, SeekOrigin.Begin);
                                docTargets = new BinaryFormatter().Deserialize(targetsStream) as IDictionary <string, GeneratorTarget[]>;
                            }
                        }
                    }
                    else if (null != (shell = _serviceProvider.GetService(typeof(SVsShell)) as IVsShell))
                    {
                        Guid       pkgId = typeof(ORMDesignerPackage).GUID;
                        IVsPackage package;
                        if (0 != shell.IsPackageLoaded(ref pkgId, out package) || package == null)
                        {
                            shell.LoadPackage(ref pkgId, out package);
                        }

                        // Temporarily load the document so that the generator targets can be resolved.
                        using (Store store = new ModelLoader(ORMDesignerPackage.ExtensionLoader, true).Load(projectItem.get_FileNames(0)))
                        {
                            docTargets = GeneratorTarget.ConsolidateGeneratorTargets(store as IFrameworkServices);
                        }
                    }

                    // We have generators that care about targets, which means that ExpandGeneratorTargets will
                    // product placeholder targets for these generators even if docTargets is currently null.
                    // This allows the dialog to turn on a generator before the data (or even extension) to feed
                    // it is available in the model and provides a smooth transition in and out of this placeholder
                    // state. It is up to the individual generators to proceed without explicit target data or
                    // to produce a message for the user with instructions on how to add the data to the model.
                    Dictionary <string, string> generatorNamesByOutputFormat = new Dictionary <string, string>();
                    foreach (KeyValuePair <string, PseudoBuildItem> pair in pseudoItems)
                    {
                        generatorNameData = pair.Value.CurrentGeneratorNames;
                        if (!string.IsNullOrEmpty(generatorNameData))
                        {
                            generatorNamesByOutputFormat[pair.Key] = ORMCustomToolUtility.GetPrimaryGeneratorName(generatorNameData);
                        }
                    }
                    targetSetsByFormatName = ORMCustomToolUtility.ExpandGeneratorTargets(generatorNamesByOutputFormat, docTargets
#if VISUALSTUDIO_15_0
                                                                                         , _serviceProvider
#endif // VISUALSTUDIO_15_0
                                                                                         );
                }

                Dictionary <string, BitTracker> processedGeneratorTargets = null;
                if (targetSetsByFormatName != null)
                {
                    processedGeneratorTargets = new Dictionary <string, BitTracker>();
                    foreach (KeyValuePair <string, ORMCustomToolUtility.GeneratorTargetSet> kvp in targetSetsByFormatName)
                    {
                        processedGeneratorTargets[kvp.Key] = new BitTracker(kvp.Value.Instances.Length);
                    }
                }

                if (null != itemGroup)
                {
#if VISUALSTUDIO_10_0
                    Dictionary <string, ProjectItemElement> removedItems = null;
                    foreach (ProjectItemElement item in itemGroup.Items)
#else // VISUALSTUDIO_10_0
                    Dictionary <string, BuildItem> removedItems = null;
                    foreach (BuildItem item in itemGroup)
#endif // VISUALSTUDIO_10_0
                    {
                        string        primaryGeneratorName;
                        string        outputFormat;
                        IORMGenerator generator;
                        if (null != (primaryGeneratorName = ORMCustomToolUtility.GetPrimaryGeneratorName(item.GetEvaluatedMetadata(ITEMMETADATA_ORMGENERATOR))) &&
                            string.Equals(item.GetEvaluatedMetadata(ITEMMETADATA_DEPENDENTUPON), sourceFileName, StringComparison.OrdinalIgnoreCase) &&
                            generators.TryGetValue(primaryGeneratorName, out generator) &&
                            pseudoItems.TryGetValue(outputFormat = generator.ProvidesOutputFormat, out pseudoItem))
                        {
                            generatorNameData = pseudoItem.CurrentGeneratorNames;
                            ORMCustomToolUtility.GeneratorTargetSet targetSet = null;
                            BitTracker processedForFormat = default(BitTracker);
                            if (targetSetsByFormatName != null)
                            {
                                if (targetSetsByFormatName.TryGetValue(outputFormat, out targetSet))
                                {
                                    processedForFormat = processedGeneratorTargets[outputFormat];
                                }
                            }

                            List <PseudoBuildInstance> originalInstances;
                            bool removeInstance = false;
                            if (string.IsNullOrEmpty(generatorNameData))
                            {
                                // The item is deleted, mark for removal
                                removeInstance = true;
                            }
                            else if (null != (originalInstances = pseudoItem.OriginalInstances))
                            {
                                for (int i = 0, count = originalInstances.Count; i < count && !removeInstance; ++i)
                                {
                                    PseudoBuildInstance instance = originalInstances[i];
                                    if (instance.IsRemoved)
                                    {
                                        continue;
                                    }

                                    GeneratorTarget[] targets = instance.OriginalGeneratorTargets;
                                    if (targetSet != null)
                                    {
                                        if (targets == null)
                                        {
                                            // Remove, if a target set is available then it must be used
                                            removeInstance = true;
                                        }
                                        else
                                        {
                                            int instanceIndex = targetSet.IndexOfInstance(targets, delegate(int ignoreInstance) { return(processedForFormat[ignoreInstance]); });
                                            if (instanceIndex == -1)
                                            {
                                                removeInstance = true;
                                            }
                                            else if (!processedForFormat[instanceIndex])
                                            {
                                                if (instance.OriginalGeneratorNames != generatorNameData)
                                                {
                                                    // This is a preexisting item, update its meta information
                                                    ORMCustomToolUtility.SetItemMetaData(item, ITEMMETADATA_ORMGENERATOR, generatorNameData);
                                                }
                                                processedForFormat[instanceIndex]       = true;
                                                processedGeneratorTargets[outputFormat] = processedForFormat;
                                                break;
                                            }
                                        }
                                    }
                                    else if (targets != null)
                                    {
                                        // Remove, formatter changed to one that does not use a generator target
                                        removeInstance = true;
                                    }
                                    else if (instance.OriginalGeneratorNames != generatorNameData)
                                    {
                                        // This is a preexisting item, update its meta information
                                        ORMCustomToolUtility.SetItemMetaData(item, ITEMMETADATA_ORMGENERATOR, generatorNameData);
                                    }

                                    if (removeInstance)
                                    {
                                        instance.IsRemoved = true;
                                    }
                                }
                            }

                            if (removeInstance)
                            {
                                if (removedItems == null)
                                {
#if VISUALSTUDIO_10_0
                                    removedItems = new Dictionary <string, ProjectItemElement>();
#else // VISUALSTUDIO_10_0
                                    removedItems = new Dictionary <string, BuildItem>();
#endif // VISUALSTUDIO_10_0
                                }
                                removedItems[ORMCustomToolUtility.GetItemInclude(item)] = item;
                            }
                        }
                    }
                    if (removedItems != null)
                    {
                        EnvDTE.ProjectItems subItems = projectItem.ProjectItems;
#if VISUALSTUDIO_10_0
                        foreach (KeyValuePair <string, ProjectItemElement> removePair in removedItems)
                        {
                            ProjectItemElement      removeItem = removePair.Value;
                            ProjectElementContainer removeFrom;
                            if (null != (removeFrom = removeItem.Parent))
                            {
                                removeFrom.RemoveChild(removeItem);
                            }
#else // VISUALSTUDIO_10_0
                        foreach (KeyValuePair <string, BuildItem> removePair in removedItems)
                        {
                            project.RemoveItem(removePair.Value);
#endif // VISUALSTUDIO_10_0
                            try
                            {
                                EnvDTE.ProjectItem subItem = subItems.Item(removePair.Key);
                                if (subItem != null)
                                {
                                    subItem.Delete();
                                }
                            }
                            catch (ArgumentException)
                            {
                                // Swallow
                            }
                        }
                    }

#if !VISUALSTUDIO_10_0
                    // Empty item groups remove themselves from the project, we'll need
                    // to recreate below if the group is empty after the remove phase.
                    if (itemGroup.Count == 0)
                    {
                        itemGroup = null;
                    }
#endif
                }

                // Removes and changes are complete, proceed with adds for any new items
                string newItemDirectory          = null;
                string projectPath               = null;
                EnvDTE.ProjectItems projectItems = null;
                string tmpFile = null;
                // Adding a file to our special item group adds it to the build system. However,
                // it does not add it to the parallel project system, which is what displays in
                // the solution explorer. Therefore, we also explicitly add the item to the
                // project system as well. Unfortunately, this extra add automatically creates
                // a redundant item (usually in a new item group) for our adding item. Track anything
                // we add through the project system so that we can remove these redundant items from the
                // build system when we're done.
                Dictionary <string, string> sideEffectItemNames = null;
                try
                {
                    Action <IORMGenerator, string, ORMCustomToolUtility.GeneratorTargetSet, GeneratorTarget[]> addProjectItem = delegate(IORMGenerator generator, string allGenerators, ORMCustomToolUtility.GeneratorTargetSet targetSet, GeneratorTarget[] targetInstance)
                    {
                        if (itemGroup == null)
                        {
#if VISUALSTUDIO_10_0
                            itemGroup = project.AddItemGroup();
#else
                            itemGroup = project.AddNewItemGroup();
#endif
                            itemGroup.Condition = string.Concat(ITEMGROUP_CONDITIONSTART, _projectItemRelativePath, ITEMGROUP_CONDITIONEND);
                        }
                        if (newItemDirectory == null)
                        {
                            // Initialize general information
#if VISUALSTUDIO_10_0
                            projectPath = project.FullPath;
#else
                            projectPath = project.FullFileName;
#endif
                            newItemDirectory = Path.GetDirectoryName(new Uri(projectPath).MakeRelativeUri(new Uri((string)projectItem.Properties.Item("LocalPath").Value)).ToString());
                            projectItems     = projectItem.ProjectItems;
                        }

                        string defaultFileName  = generator.GetOutputFileDefaultName(sourceFileName);
                        string fileName         = targetInstance == null ? defaultFileName : ORMCustomToolUtility.GeneratorTargetSet.DecorateFileName(defaultFileName, targetInstance);
                        string fileRelativePath = Path.Combine(newItemDirectory, fileName);
                        string fileAbsolutePath = string.Concat(new FileInfo(projectPath).DirectoryName, Path.DirectorySeparatorChar, fileRelativePath);
#if VISUALSTUDIO_10_0
                        ProjectItemElement newBuildItem;
#else
                        BuildItem newBuildItem;
#endif
                        newBuildItem = generator.AddGeneratedFileItem(itemGroup, sourceFileName, fileRelativePath);

                        if (allGenerators != null)
                        {
                            ORMCustomToolUtility.SetItemMetaData(newBuildItem, ITEMMETADATA_ORMGENERATOR, allGenerators);
                        }

                        if (targetInstance != null)
                        {
                            ORMCustomToolUtility.SetGeneratorTargetMetadata(newBuildItem, targetInstance);
                        }

                        (sideEffectItemNames ?? (sideEffectItemNames = new Dictionary <string, string>()))[fileRelativePath] = null;
                        if (File.Exists(fileAbsolutePath))
                        {
                            try
                            {
                                projectItems.AddFromFile(fileAbsolutePath);
                            }
                            catch (ArgumentException)
                            {
                                // Swallow
                            }
                        }
                        else
                        {
                            if (tmpFile == null)
                            {
                                tmpFile = Path.GetTempFileName();
                            }
                            EnvDTE.ProjectItem newProjectItem = projectItems.AddFromTemplate(tmpFile, fileName);
                            string             customTool;
                            if (!string.IsNullOrEmpty(customTool = newBuildItem.GetMetadata(ITEMMETADATA_GENERATOR)))
                            {
                                newProjectItem.Properties.Item("CustomTool").Value = customTool;
                            }
                        }
                    };

                    foreach (KeyValuePair <string, PseudoBuildItem> keyedPseudoItem in pseudoItems)
                    {
                        pseudoItem = keyedPseudoItem.Value;
                        string allGenerators    = pseudoItem.CurrentGeneratorNames;
                        string primaryGenerator = ORMCustomToolUtility.GetPrimaryGeneratorName(allGenerators);
                        if (allGenerators == primaryGenerator)
                        {
                            allGenerators = null;
                        }
                        IORMGenerator generator    = generators[primaryGenerator];
                        string        outputFormat = generator.ProvidesOutputFormat;
                        ORMCustomToolUtility.GeneratorTargetSet targetSet = null;
                        if (targetSetsByFormatName != null)
                        {
                            targetSetsByFormatName.TryGetValue(outputFormat, out targetSet);
                        }

                        if (targetSet != null)
                        {
                            // OriginalInstances were already updated in the remove loop and processed
                            // instances were flagged. Find additional instances from the target set (created
                            // just now from the current model), not from the pseudoItem (created from the project
                            // files that possibly reflect a previous version of the model).
                            GeneratorTarget[][] instances = targetSet.Instances;
                            BitTracker          processed = processedGeneratorTargets[outputFormat];

                            for (int i = 0, count = instances.Length; i < count; ++i)
                            {
                                if (!processed[i])
                                {
                                    addProjectItem(generator, allGenerators, targetSet, instances[i]);
                                }
                            }
                        }
                        else if (pseudoItem.OriginalInstances == null)
                        {
                            addProjectItem(generator, allGenerators, null, null);
                        }
                        else
                        {
                            // Make sure there was an original instance that did not have a target set.
                            List <PseudoBuildInstance> originals = pseudoItem.OriginalInstances;
                            int i = 0, count = originals.Count;
                            for (; i < count; ++i)
                            {
                                if (originals[i].OriginalGeneratorTargets == null)
                                {
                                    break;
                                }
                            }

                            if (i == count)
                            {
                                addProjectItem(generator, allGenerators, null, null);
                            }
                        }
                    }
                }
                finally
                {
                    if (tmpFile != null)
                    {
                        File.Delete(tmpFile);
                    }
                }

                if (sideEffectItemNames != null)
                {
                    ORMCustomToolUtility.RemoveSideEffectItems(sideEffectItemNames, project, itemGroup);
                }

#if VISUALSTUDIO_10_0
                // Old group remove themselves when empty, but this is
                // not true in the new build system. Clean up as needed.
                if (itemGroup != null &&
                    itemGroup.Items.Count == 0)
                {
                    project.RemoveChild(itemGroup);
                }
#endif
                VSLangProj.VSProjectItem vsProjectItem = projectItem.Object as VSLangProj.VSProjectItem;
                if (vsProjectItem != null)
                {
                    vsProjectItem.RunCustomTool();
                }
            }
            base.OnClosed(e);
        }