Helper class that handle the scope of an automation function. It should be used inside a "using" directive to define the scope of the automation function and make sure that the ExitAutomation method is called.
상속: IDisposable
예제 #1
0
        /// <summary>
        ///     Creates a new project item from an existing item template file and adds it to the project.
        /// </summary>
        /// <param name="fileName">The full path and file name of the template project file.</param>
        /// <param name="name">The file name to use for the new project item.</param>
        /// <returns>A ProjectItem object. </returns>
        public override ProjectItem AddFromTemplate(string fileName, string name)
        {
            if (Project == null || Project.Project == null || Project.Project.Site == null || Project.Project.IsClosed)
            {
                throw new InvalidOperationException();
            }

            return UIThread.DoOnUIThread(delegate
            {
                var proj = Project.Project;
                ProjectItem itemAdded = null;

                using (var scope = new AutomationScope(Project.Project.Site))
                {
                    var fixedFileName = fileName;

                    if (!File.Exists(fileName))
                    {
                        var tempFileName = GetTemplateNoZip(fileName);
                        if (File.Exists(tempFileName))
                        {
                            fixedFileName = tempFileName;
                        }
                    }

                    // Determine the operation based on the extension of the filename.
                    // We should run the wizard only if the extension is vstemplate
                    // otherwise it's a clone operation
                    VSADDITEMOPERATION op;

                    if (Utilities.IsTemplateFile(fixedFileName))
                    {
                        op = VSADDITEMOPERATION.VSADDITEMOP_RUNWIZARD;
                    }
                    else
                    {
                        op = VSADDITEMOPERATION.VSADDITEMOP_CLONEFILE;
                    }

                    var result = new VSADDRESULT[1];

                    // It is not a very good idea to throw since the AddItem might return Cancel or Abort.
                    // The problem is that up in the call stack the wizard code does not check whether it has received a ProjectItem or not and will crash.
                    // The other problem is that we cannot get add wizard dialog back if a cancel or abort was returned because we throw and that code will never be executed. Typical catch 22.
                    ErrorHandler.ThrowOnFailure(proj.AddItem(NodeWithItems.ID, op, name, 0,
                        new string[1] {fixedFileName}, IntPtr.Zero, result));

                    var fileDirectory = proj.GetBaseDirectoryForAddingFiles(NodeWithItems);
                    var templateFilePath = Path.Combine(fileDirectory, name);
                    itemAdded = EvaluateAddResult(result[0], templateFilePath);
                }

                return itemAdded;
            });
        }
예제 #2
0
        /// <summary>
        ///     Adds an item to the project.
        /// </summary>
        /// <param name="path">The full path of the item to add.</param>
        /// <param name="op">The <paramref name="VSADDITEMOPERATION" /> to use when adding the item.</param>
        /// <returns>A ProjectItem object. </returns>
        protected virtual ProjectItem AddItem(string path, VSADDITEMOPERATION op)
        {
            if (Project == null || Project.Project == null || Project.Project.Site == null || Project.Project.IsClosed)
            {
                throw new InvalidOperationException();
            }

            return UIThread.DoOnUIThread(delegate
            {
                var proj = Project.Project;

                ProjectItem itemAdded = null;
                using (var scope = new AutomationScope(Project.Project.Site))
                {
                    var result = new VSADDRESULT[1];
                    ErrorHandler.ThrowOnFailure(proj.AddItem(NodeWithItems.ID, op, path, 0, new string[1] {path},
                        IntPtr.Zero, result));

                    var fileName = Path.GetFileName(path);
                    var fileDirectory = proj.GetBaseDirectoryForAddingFiles(NodeWithItems);
                    var filePathInProject = Path.Combine(fileDirectory, fileName);

                    itemAdded = EvaluateAddResult(result[0], filePathInProject);
                }

                return itemAdded;
            });
        }
예제 #3
0
        /// <summary>
        ///     Adds a folder to the collection of ProjectItems with the given name.
        ///     The kind must be null, empty string, or the string value of vsProjectItemKindPhysicalFolder.
        ///     Virtual folders are not supported by this implementation.
        /// </summary>
        /// <param name="name">The name of the new folder to add</param>
        /// <param name="kind">A string representing a Guid of the folder kind.</param>
        /// <returns>A ProjectItem representing the newly added folder.</returns>
        public override ProjectItem AddFolder(string name, string kind)
        {
            if (Project == null || Project.Project == null || Project.Project.Site == null || Project.Project.IsClosed)
            {
                throw new InvalidOperationException();
            }

            return UIThread.DoOnUIThread(delegate
            {
                //Verify name is not null or empty
                Utilities.ValidateFileName(Project.Project.Site, name);

                //Verify that kind is null, empty, or a physical folder
                if (!(string.IsNullOrEmpty(kind) || kind.Equals(Constants.vsProjectItemKindPhysicalFolder)))
                {
                    throw new ArgumentException("Parameter specification for AddFolder was not meet", "kind");
                }

                for (var child = NodeWithItems.FirstChild; child != null; child = child.NextSibling)
                {
                    if (child.Caption.Equals(name, StringComparison.OrdinalIgnoreCase))
                    {
                        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                            "Folder already exists with the name '{0}'", name));
                    }
                }

                var proj = Project.Project;

                HierarchyNode newFolder = null;
                using (var scope = new AutomationScope(Project.Project.Site))
                {
                    //In the case that we are adding a folder to a folder, we need to build up
                    //the path to the project node.
                    name = Path.Combine(NodeWithItems.VirtualNodeName, name);

                    newFolder = proj.CreateFolderNodes(name);
                }

                return newFolder.GetAutomationObject() as ProjectItem;
            });
        }
예제 #4
0
        /// <summary>
        ///     Sets the value of the property at the specified index.
        /// </summary>
        /// <param name="index1">The index of the item to set.</param>
        /// <param name="index2">Reserved for future use.</param>
        /// <param name="index3">Reserved for future use.</param>
        /// <param name="index4">Reserved for future use.</param>
        /// <param name="value">The value to set.</param>
        public void set_IndexedValue(object index1, object index2, object index3, object index4, object value)
        {
            var par = pi.GetIndexParameters();
            var len = Math.Min(par.Length, 4);
            if (len == 0)
            {
                Value = value;
            }
            else
            {
                var index = new object[len];
                Array.Copy(new object[4] {index1, index2, index3, index4}, index, len);

                using (var scope = new AutomationScope(parent.Target.Node.ProjectMgr.Site))
                {
                    pi.SetValue(parent.Target, value, index);
                }
            }
        }
예제 #5
0
        /// <summary>
        ///     Saves or Save Asthe project.
        /// </summary>
        /// <param name="isCalledFromSaveAs">Flag determining which Save method called , the SaveAs or the Save.</param>
        /// <param name="fileName">The name of the project file.</param>
        private void DoSave(bool isCalledFromSaveAs, string fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }

            if (Project == null || Project.Site == null || Project.IsClosed)
            {
                throw new InvalidOperationException();
            }

            UIThread.DoOnUIThread(delegate
            {
                using (var scope = new AutomationScope(Project.Site))
                {
                    // If an empty file name is passed in for Save then make the file name the project name.
                    if (!isCalledFromSaveAs && string.IsNullOrEmpty(fileName))
                    {
                        // Use the solution service to save the project file. Note that we have to use the service
                        // so that all the shell's elements are aware that we are inside a save operation and
                        // all the file change listenters registered by the shell are suspended.

                        // Get the cookie of the project file from the RTD.
                        var rdt = Project.Site.GetService(typeof (SVsRunningDocumentTable)) as IVsRunningDocumentTable;
                        if (null == rdt)
                        {
                            throw new InvalidOperationException();
                        }

                        IVsHierarchy hier;
                        uint itemid;
                        IntPtr unkData;
                        uint cookie;
                        ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uint) _VSRDTFLAGS.RDT_NoLock, Project.Url,
                            out hier,
                            out itemid, out unkData, out cookie));
                        if (IntPtr.Zero != unkData)
                        {
                            Marshal.Release(unkData);
                        }

                        // Verify that we have a cookie.
                        if (0 == cookie)
                        {
                            // This should never happen because if the project is open, then it must be in the RDT.
                            throw new InvalidOperationException();
                        }

                        // Get the IVsHierarchy for the project.
                        var prjHierarchy = Project.InteropSafeIVsHierarchy;

                        // Now get the solution.
                        var solution = Project.Site.GetService(typeof (SVsSolution)) as IVsSolution;
                        // Verify that we have both solution and hierarchy.
                        if ((null == prjHierarchy) || (null == solution))
                        {
                            throw new InvalidOperationException();
                        }

                        ErrorHandler.ThrowOnFailure(
                            solution.SaveSolutionElement((uint) __VSSLNSAVEOPTIONS.SLNSAVEOPT_SaveIfDirty, prjHierarchy,
                                cookie));
                    }
                    else
                    {
                        // We need to make some checks before we can call the save method on the project node.
                        // This is mainly because it is now us and not the caller like in  case of SaveAs or Save that should validate the file name.
                        // The IPersistFileFormat.Save method only does a validation that is necesseray to be performed. Example: in case of Save As the  
                        // file name itself is not validated only the whole path. (thus a file name like file\file is accepted, since as a path is valid)

                        // 1. The file name has to be valid. 
                        var fullPath = fileName;
                        try
                        {
                            if (!Path.IsPathRooted(fileName))
                            {
                                fullPath = Path.Combine(Project.ProjectFolder, fileName);
                            }
                        }
                            // We want to be consistent in the error message and exception we throw. fileName could be for example #�&%"�&"%  and that would trigger an ArgumentException on Path.IsRooted.
                        catch (ArgumentException)
                        {
                            throw new InvalidOperationException(SR.GetString(SR.ErrorInvalidFileName,
                                CultureInfo.CurrentUICulture));
                        }

                        // It might be redundant but we validate the file and the full path of the file being valid. The SaveAs would also validate the path.
                        // If we decide that this is performance critical then this should be refactored.
                        Utilities.ValidateFileName(Project.Site, fullPath);

                        if (!isCalledFromSaveAs)
                        {
                            // 2. The file name has to be the same 
                            if (!NativeMethods.IsSamePath(fullPath, Project.Url))
                            {
                                throw new InvalidOperationException();
                            }

                            ErrorHandler.ThrowOnFailure(Project.Save(fullPath, 1, 0));
                        }
                        else
                        {
                            ErrorHandler.ThrowOnFailure(Project.Save(fullPath, 0, 0));
                        }
                    }
                }
            });
        }
예제 #6
0
        /// <summary>
        ///     Removes the project from the current solution.
        /// </summary>
        public virtual void Delete()
        {
            if (Project == null || Project.Site == null || Project.IsClosed)
            {
                throw new InvalidOperationException();
            }

            UIThread.DoOnUIThread(delegate
            {
                using (var scope = new AutomationScope(Project.Site))
                {
                    Project.Remove(false);
                }
            });
        }