Beispiel #1
0
        /// <summary>
        /// Retrieves the FSharp project node from the IVsProject interface
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        public static Microsoft.VisualStudio.FSharp.ProjectSystem.ProjectNode getFSharpProjectNode(IVsProject root)
        {
            IOLEServiceProvider sp;

            ErrorHandler.ThrowOnFailure(root.GetItemContext(VSConstants.VSITEMID_ROOT, out sp));

            IntPtr objPtr = IntPtr.Zero;

            try
            {
                Guid hierGuid = typeof(VSLangProj.VSProject).GUID;
                Guid UNKguid  = NativeMethods.IID_IUnknown;
                ErrorHandler.ThrowOnFailure(sp.QueryService(ref hierGuid, ref UNKguid, out objPtr));

                var OAVSProject = (VSLangProj.VSProject)Marshal.GetObjectForIUnknown(objPtr);
                var OAProject   = (Microsoft.VisualStudio.FSharp.ProjectSystem.Automation.OAProject)OAVSProject.Project;
                return(OAProject.Project);
            }
            finally
            {
                if (objPtr != IntPtr.Zero)
                {
                    Marshal.Release(objPtr);
                }
            }
        }
Beispiel #2
0
 /// <summary>
 /// Runs the custom tool of a project item.
 /// </summary>
 /// <param name="project">IVsProject</param>
 /// <param name="itemId">item id</param>
 public static void RunCustomToolOfItem(this IVsProject project, uint itemId)
 {
     Microsoft.VisualStudio.OLE.Interop.IServiceProvider ppSP;
     project.GetItemContext(itemId, out ppSP);
     Microsoft.VisualStudio.Shell.ServiceProvider itemContextService = new Microsoft.VisualStudio.Shell.ServiceProvider(ppSP);
     EnvDTE.ProjectItem       templateItem  = (EnvDTE.ProjectItem)itemContextService.GetService(typeof(EnvDTE.ProjectItem));
     VSLangProj.VSProjectItem vsProjectItem = templateItem.Object as VSLangProj.VSProjectItem;
     vsProjectItem.RunCustomTool();
 }
Beispiel #3
0
        private static ProjectItem RetrieveProjectItem(string documentPath)
        {
            int  itemFound;
            uint itemId;

            VSDOCUMENTPRIORITY[] pdwPriority = new VSDOCUMENTPRIORITY[1];

            DTE dte = Package.GetGlobalService(typeof(DTE)) as DTE;

            if (dte == null)
            {
                throw new InvalidOperationException("Cannot get the global service from package. DTE is null. Document path is " + documentPath);
            }

            Array ary = dte.ActiveSolutionProjects as Array;

            if (ary == null)
            {
                throw new InvalidOperationException("Cannot get the active solution projects. Document path is " + documentPath);
            }

            Project project = ary.GetValue(0) as Project;

            if (project == null)
            {
                throw new InvalidOperationException("Cannot get the first project. Document path is " + documentPath);
            }

            IVsProject vsProject = VsHelper.ToVsProject(project);

            if (project == null)
            {
                throw new InvalidOperationException("Cannot convert project to VS project. Document path is " + documentPath);
            }

            vsProject.IsDocumentInProject(documentPath, out itemFound, pdwPriority, out itemId);

            if (itemFound == 0 || itemId == 0)
            {
                throw new InvalidOperationException("VsProject.IsDocumentInProject failed to find the document in the project. Document path is " + documentPath);
            }

            IServiceProvider oleSp;

            vsProject.GetItemContext(itemId, out oleSp);
            if (oleSp == null)
            {
                throw new InvalidOperationException("Cannot get item context. Document path is " + documentPath);
            }

            ServiceProvider sp   = new ServiceProvider(oleSp);
            ProjectItem     item = sp.GetService(typeof(ProjectItem)) as ProjectItem;

            return(item);
        }
        /// <summary>
        /// Looks through the <paramref name="project"/> and all subitems / subprojects to find the project hosting the active configuration section designer window.
        /// </summary>
        /// <param name="project">the parent project.</param>
        /// <param name="docPriority">Specifies the priority level of a document within a project.</param>
        /// <param name="configurationSectionModelFile">the project item represented by inputFilePath, if found (ex: MyProject\ConfigurationSection.csd).</param>
        /// <param name="inputFilePath">the file path of the project item.</param>
        /// <returns><c>true</c> if found; otherwise <c>false</c>.</returns>
        public static bool TryFindProjectItemWithFilePath(Project project, VSDOCUMENTPRIORITY[] docPriority, string inputFilePath, out ProjectItem configurationSectionModelFile)
        {
            Diagnostics.DebugWrite("VsHelper.TryFindProjectItemWithFilePath (VH.TFP).");
            bool projectFound = false;

            configurationSectionModelFile = null;

            // Nothing useful for this project. Process the next one.
            if (string.IsNullOrEmpty(project.FileName) || !File.Exists(project.FileName))
            {
                Diagnostics.DebugWrite("VH.TFP >> Nothing useful found in this current dte.Solution.Projects item. Continuing loop...");
                return(false);
            }

            // obtain a reference to the current project as an IVsProject type
            IVsProject vsProject = VsHelper.ToVsProject(project);

            Diagnostics.DebugWrite("VH.TFP >> IVsProject vsProject = VsHelper.ToVsProject( project='{0}' )", project.Name);

            int  iFound = 0;
            uint itemId = 0;

            // this locates, and returns a handle to our source file, as a ProjectItem
            vsProject.IsDocumentInProject(inputFilePath, out iFound, docPriority, out itemId);
            Diagnostics.DebugWrite("VH.TFP >> vsProject.IsDocumentInProject(inputFilePath, out iFound={0}, pdwPriority, out itemId={1}).", iFound, itemId);

            // TODO: [abm] Below here, project build failed! Error was "type is not of VsProject". This only occured on a brand new
            // project with brand new csd. After failed rebuild attempt of project, it all worked.
            // Find out why and fix (or create warning message) to guide future users! Not yet reproducible...

            // if this source file is found in this project
            if (iFound != 0 && itemId != 0)
            {
                Diagnostics.DebugWrite("VH.TFP >> (iFound != 0 && itemId != 0) == TRUE!!!");
                Microsoft.VisualStudio.OLE.Interop.IServiceProvider oleSp = null;
                vsProject.GetItemContext(itemId, out oleSp);
                if (oleSp != null)
                {
                    Diagnostics.DebugWrite("VH.TFP >> vsProject.GetItemContext( itemId, out oleSp ) >> oleSp != null! Getting ServiceProvider sp...");
                    ServiceProvider sp = new ServiceProvider(oleSp);
                    // convert our handle to a ProjectItem
                    configurationSectionModelFile = sp.GetService(typeof(ProjectItem)) as ProjectItem;

                    if (configurationSectionModelFile != null)
                    {
                        Diagnostics.DebugWrite("VH.TFP >>  configurationSectionModelFile = sp.GetService( typeof( ProjectItem ) ) as ProjectItem is NOT null! Setting this._project to the project we were working on...");
                        // We now have what we need. Stop looking.
                        projectFound = true;
                    }
                }
            }
            return(projectFound);
        }
 /// <summary>
 /// Pres the content of the generate.
 /// </summary>
 /// <param name="vsProject">The vs project.</param>
 /// <param name="inputFileName">The input file path.</param>
 /// <exception cref="System.ApplicationException">
 /// Unable to retrieve Visual Studio ProjectItem
 /// or
 /// Unable to retrieve Visual Studio ProjectItem
 /// </exception>
 protected void PreGenerateCode(IVsProject vsProject, string inputFileName)
 {
     _newFileNames.Clear();
     int iFound;
     uint itemId;
     vsProject.IsDocumentInProject(inputFileName, out iFound, new VSDOCUMENTPRIORITY[1], out itemId);
     if (iFound == 0 || itemId == 0)
         throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem");
     IServiceProvider sp;
     vsProject.GetItemContext(itemId, out sp);
     if (sp == null)
         throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem");
     var item = (new ServiceProvider(sp).GetService(typeof(ProjectItem)) as ProjectItem);
     foreach (string i in this)
     {
         try
         {
             var inputFileName2 = GetFileName(i);
             _newFileNames.Add(inputFileName2);
             var path = Path.Combine(inputFileName.Substring(0, inputFileName.LastIndexOf(Path.DirectorySeparatorChar)), inputFileName2);
             var inputFileContent2 = string.Empty;
             if (File.Exists(path))
                 try { inputFileContent2 = File.ReadAllText(path); }
                 catch (Exception) { inputFileContent2 = string.Empty; }
             var s = File.Create(path);
             try
             {
                 var data = GenerateChildCode(path, inputFileContent2);
                 s.Write(data, 0, data.Length);
                 s.Close();
                 item.ProjectItems.AddFromFile(path);
             }
             catch (Exception)
             {
                 s.Close();
                 if (File.Exists(path))
                     File.Delete(path);
             }
         }
         catch (Exception ex) { throw ex; }
     }
     foreach (ProjectItem childItem in item.ProjectItems)
         if (!(childItem.Name.EndsWith(GetDefaultExtension()) || _newFileNames.Contains(childItem.Name)))
             childItem.Delete();
 }
Beispiel #6
0
        private ProjectItem _getTemplateProjectItem()
        {
            Project dteProject = _getTemplateProject();

            IVsProject vsProject = _dteProjectToVsProject(dteProject);

            int  iFound = 0;
            uint itemId = 0;

            VSDOCUMENTPRIORITY[] pdwPriority = new VSDOCUMENTPRIORITY[1];
            int result = vsProject.IsDocumentInProject(_host.TemplateFile, out iFound, pdwPriority, out itemId);

            if (result != VSConstants.S_OK)
            {
                throw new Exception("Unexpected error calling IVsProject.IsDocumentInProject");
            }
            if (iFound == 0)
            {
                throw new Exception("Cannot retrieve ProjectItem for template file");
            }
            if (itemId == 0)
            {
                throw new Exception("Cannot retrieve ProjectItem for template file");
            }

            Microsoft.VisualStudio.OLE.Interop.IServiceProvider itemContext = null;
            result = vsProject.GetItemContext(itemId, out itemContext);
            if (result != VSConstants.S_OK)
            {
                throw new Exception("Unexpected error calling IVsProject.GetItemContext");
            }
            if (itemContext == null)
            {
                throw new Exception("IVsProject.GetItemContext returned null");
            }

            ServiceProvider itemContextService = new ServiceProvider(itemContext);
            ProjectItem     templateItem       = (ProjectItem)itemContextService.GetService(typeof(ProjectItem));

            Debug.Assert(templateItem != null, "itemContextService.GetService returned null");

            return(templateItem);
        }
        /// <summary>
        /// Retrieves the FSharp project node from the IVsProject interface
        /// </summary>
        /// <param name="root"></param>
        /// <returns></returns>
        public static Microsoft.VisualStudio.FSharp.ProjectSystem.ProjectNode getFSharpProjectNode(IVsProject root)
        {
            IOLEServiceProvider sp;
            ErrorHandler.ThrowOnFailure(root.GetItemContext(VSConstants.VSITEMID_ROOT, out sp));

            IntPtr objPtr = IntPtr.Zero;
            try
            {
                Guid hierGuid = typeof(VSLangProj.VSProject).GUID;
                Guid UNKguid = NativeMethods.IID_IUnknown;
                ErrorHandler.ThrowOnFailure(sp.QueryService(ref hierGuid, ref UNKguid, out objPtr));

                var OAVSProject = (VSLangProj.VSProject)Marshal.GetObjectForIUnknown(objPtr);
                var OAProject = (Microsoft.VisualStudio.FSharp.ProjectSystem.Automation.OAProject)OAVSProject.Project;
                return OAProject.Project;
            }
            finally
            {
                if (objPtr != IntPtr.Zero)
                    Marshal.Release(objPtr);
            }
        }
Beispiel #8
0
 int IVsProject.GetItemContext(uint itemid, out VisualStudio.OLE.Interop.IServiceProvider ppSP)
 {
     return(_innerProject.GetItemContext(itemid, out ppSP));
 }
Beispiel #9
0
        /// <summary>
        /// Looks through the <paramref name="project"/> and all subitems / subprojects to find the project hosting the active configuration section designer window.
        /// </summary>
        /// <remarks>
        /// Checks if <paramref name="csdDocumentFilePath"/> is inside <paramref name="project"/>. If true, the id of
        /// <paramref name="csdDocumentFilePath"/> is located and used to return the CSD file as a ProjectItem object
        /// <paramref name="configurationSectionModelFile"/>.
        /// </remarks>
        /// <param name="project">the parent project.</param>
        /// <param name="docPriority">Specifies the priority level of a document within a project.</param>
        /// <param name="configurationSectionModelFile">(out) the project item represented by csdDocumentFilePath, if found (ex: MyProject\ConfigurationSection.csd).</param>
        /// <param name="csdDocumentFilePath">the file path of the CSD project item.</param>
        /// <returns><c>true</c> if found; otherwise <c>false</c>.</returns>
        public static bool TryFindProjectItemWithFilePath(Project project, VSDOCUMENTPRIORITY[] docPriority, string csdDocumentFilePath, out ProjectItem configurationSectionModelFile)
        {
            Diagnostics.DebugWrite("VsHelper.TryFindProjectItemWithFilePath (VH.TFP).");
            bool projectFound = false;

            configurationSectionModelFile = null;

            // Nothing useful for this project. Process the next one.
            if (string.IsNullOrEmpty(project.FileName) || !File.Exists(project.FileName))
            {
                Diagnostics.DebugWrite("VH.TFP >> Nothing useful found in this current dte.Solution.Projects item. Continuing loop...");
                return(false);
            }

            // obtain a reference to the current project as an IVsProject type
            IVsProject vsProject = VsHelper.ToVsProject(project); // ABM - Issue 10435: 2nd WindowsService project results in FAILURE here.

            Diagnostics.DebugWrite("VH.TFP >> IVsProject vsProject = VsHelper.ToVsProject( project='{0}' )", project.Name);

            int  iFound = 0;
            uint itemId = 0;

            // this locates, and returns a handle to our source file, as a ProjectItem
            int result = vsProject.IsDocumentInProject(csdDocumentFilePath, out iFound, docPriority, out itemId); // ABM - Issue 10435: WindowsService project results in iFound=0!!!

            // itemid: Pointer to the item identifier of the document within the project.
            // NOTE: itemId is either a specific id pointing to the file, or is one of VSITEMID enumeration.
            // VSITEMID represents Special items inside a VsHierarchy:

            /*
             * public enum VSITEMID
             * {
             * Selection = 4294967293, // all the currently selected items. // represents the currently selected item or items, which can include the root of the hierarchy.
             * Root = 4294967294,      // the hierarchy itself. // represents the root of a project hierarchy and is used to identify the entire hierarchy, as opposed to a single item.
             * Nil = 4294967295,       // no node.// represents the absence of a project item. This value is used when there is no current selection.
             * }
             * http://visual-studio.todaysummary.com/q_visual-studio_76086.html
             *
             * http://msdn.microsoft.com/en-us/subscriptions/downloads/microsoft.visualstudio.shell.interop.ivshierarchy(v=vs.100).aspx
             */


            if (result != VSConstants.S_OK)
            {
                throw new Exception("Unexpected error calling IVsProject.IsDocumentInProject.");
            }

            Diagnostics.DebugWrite("VH.TFP >> vsProject.IsDocumentInProject(inputFilePath, out iFound={0}, pdwPriority, out itemId={1}).", iFound, itemId);

            // TODO: [abm] Below here, project build failed! Error was "type is not of VsProject". This only occured on a brand new
            // project with brand new csd. After failed rebuild attempt of project, it all worked.
            // Find out why and fix (or create warning message) to guide future users! Not yet reproducible...

            // if this source file is found in this project
            if (iFound != 0 && itemId != 0)
            {
                Diagnostics.DebugWrite("VH.TFP >> (iFound != 0 && itemId != 0) == TRUE!!!");
                Microsoft.VisualStudio.OLE.Interop.IServiceProvider oleSp = null;
                vsProject.GetItemContext(itemId, out oleSp);
                if (oleSp != null)
                {
                    Diagnostics.DebugWrite("VH.TFP >> vsProject.GetItemContext( itemId, out oleSp ) >> oleSp != null! Getting ServiceProvider sp...");
                    ServiceProvider sp = new ServiceProvider(oleSp);
                    // convert our handle to a ProjectItem
                    configurationSectionModelFile = sp.GetService(typeof(ProjectItem)) as ProjectItem;

                    if (configurationSectionModelFile != null)
                    {
                        Diagnostics.DebugWrite("VH.TFP >>  configurationSectionModelFile = sp.GetService( typeof( ProjectItem ) ) as ProjectItem is NOT null! Setting this._project to the project we were working on...");
                        // We now have what we need. Stop looking.
                        projectFound = true;
                    }
                }
            }
            return(projectFound);
        }
Beispiel #10
0
        public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace,
                            IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            // SwitchDomainForRazorEngine();
            byte[] resultBytes;
            try
            {
                var model = new RazorModel();
                //set file name and namespace for model using
                model.DefaultNameSpace = wszDefaultNamespace;
                var info = new FileInfo(wszInputFilePath);
                if (info.Exists)
                {
                    model.FileName = info.Name;
                }
                int                  iFound;
                uint                 itemId;
                ProjectItem          item;
                VSDOCUMENTPRIORITY[] pdwPriority = new VSDOCUMENTPRIORITY[1];

                // obtain a reference to the current project as an IVsProject type
                IVsProject vsProject = VsHelper.ToVsProject(project);
                // this locates, and returns a handle to our source file, as a ProjectItem
                vsProject.IsDocumentInProject(wszInputFilePath, out iFound, pdwPriority, out itemId);

                // if our source file was found in the project (which it should have been)
                if (iFound != 0 && itemId != 0)
                {
                    IServiceProvider oleSp;
                    vsProject.GetItemContext(itemId, out oleSp);
                    if (oleSp != null)
                    {
                        ServiceProvider sp = new ServiceProvider(oleSp);
                        // convert our handle to a ProjectItem
                        item = sp.GetService(typeof(ProjectItem)) as ProjectItem;
                    }
                    else
                    {
                        throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem");
                    }
                }
                else
                {
                    throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem");
                }

                var generator = new RazorGenerator(wszInputFilePath, bstrInputFileContents, model);
                generator.Init();
                //get extension from header file
                if (!string.IsNullOrEmpty(generator.RazorTemplate.OutPutExtension))
                {
                    _extenstion = generator.RazorTemplate.OutPutExtension;
                }
                //generate code
                var result = generator.Render();
                resultBytes = Encoding.UTF8.GetBytes(result);
                int outputLength = resultBytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
                Marshal.Copy(resultBytes, 0, rgbOutputFileContents[0], outputLength);
                pcbOutput = (uint)outputLength;
                return(VSConstants.S_OK);
            }
            catch (TemplateCompilationException tex)
            {
                //Display error in result template
                foreach (var compilerError in tex.CompilerErrors)
                {
                    pGenerateProgress.GeneratorError(0, 1, compilerError.ErrorText, (uint)compilerError.Line,
                                                     (uint)compilerError.Column);
                }
                var message = MRazorUtil.GetError(tex);
                resultBytes = Encoding.UTF8.GetBytes(message);
                int outputLength = resultBytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
                Marshal.Copy(resultBytes, 0, rgbOutputFileContents[0], outputLength);
                pcbOutput = (uint)outputLength;
                return(VSConstants.S_FALSE);// Change to E_Fail will display error in error list
            }
            catch (Exception ex)
            {
                var messageBuilder = new StringBuilder(ex.Message);
                messageBuilder.AppendLine();
                if (ex.Source != null)
                {
                    messageBuilder.Append(ex.Source);
                }
                messageBuilder.Append(ex.StackTrace);
                if (ex.InnerException != null)
                {
                    messageBuilder.AppendLine();
                    messageBuilder.Append(ex.InnerException.Message + ex.InnerException.StackTrace);
                }
                resultBytes = Encoding.UTF8.GetBytes(messageBuilder.ToString());
                int outputLength = resultBytes.Length;
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(outputLength);
                Marshal.Copy(resultBytes, 0, rgbOutputFileContents[0], outputLength);
                pcbOutput = (uint)outputLength;
                return(VSConstants.S_FALSE);// Change to E_Fail will display error in error list
            }
            //finally
            //{
            //    //unload domain for unload dll loaded from InputDllFolder
            //    if (_domain != null) AppDomain.Unload(_domain);
            //}
        }
Beispiel #11
0
        /// <summary>
        /// Implements the IVsSingleFileGenerator.Generate method.
        /// Executes the transformation and returns the newly generated output file, whenever a custom tool is loaded, or the input file is saved
        /// </summary>
        /// <remarks>
        /// When this is called, the current generator enumerator consists of a list of file extentions that we are going to generate.
        /// </remarks>
        /// <param name="wszInputFilePath">The full path of the input file. May be a null reference (Nothing in Visual Basic) in future releases of Visual Studio, so generators should not rely on this value</param>
        /// <param name="bstrInputFileContents">The contents of the input file. This is either a UNICODE BSTR (if the input file is text) or a binary BSTR (if the input file is binary). If the input file is a text file, the project system automatically converts the BSTR to UNICODE</param>
        /// <param name="wszDefaultNamespace">This parameter is meaningful only for custom tools that generate code. It represents the namespace into which the generated code will be placed. If the parameter is not a null reference (Nothing in Visual Basic) and not empty, the custom tool can use the following syntax to enclose the generated code</param>
        /// <param name="rgbOutputFileContents">[out] Returns an array of bytes to be written to the generated file. You must include UNICODE or UTF-8 signature bytes in the returned byte array, as this is a raw stream. The memory for rgbOutputFileContents must be allocated using the .NET Framework call, System.Runtime.InteropServices.AllocCoTaskMem, or the equivalent Win32 system call, CoTaskMemAlloc. The project system is responsible for freeing this memory</param>
        /// <param name="pcbOutput">[out] Returns the count of bytes in the rgbOutputFileContent array</param>
        /// <param name="pGenerateProgress">A reference to the IVsGeneratorProgress interface through which the generator can report its progress to the project system</param>
        /// <returns>If the method succeeds, it returns S_OK. If it fails, it returns E_FAIL</returns>
        public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput,
                            IVsGeneratorProgress pGenerateProgress)
        {
            // TODO: There are a number of nested try catch blocks that should be cleaned up.
            // Make sure exception handling is properly laid out. This function has high
            // complexity (probably too high with cycl over 30), which makes error handling important. What
            // exceptions escape (ie. not handled)? What halts file generation? etc...
            try
            {
                // EnsureActiveProjectSet();

                VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "");
                VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, string.Format("------ CSD file generation started: Configuration document: {0} ------", InputFilePath));

                Diagnostics.DebugWrite("VsMultipleFileGenerator => VSMFG.");

                ProjectItem configurationSectionModelFile = null;

                _bstrInputFileContents = bstrInputFileContents;
                _wszInputFilePath      = wszInputFilePath;
                _generatorProgress     = pGenerateProgress;
                _oldFileNames.Clear();
                _newFileNames.Clear();

                // Look through all the projects in the solution
                // The _project holds DTE reference, so not needed here.
                //DTE dte = (DTE)Package.GetGlobalService(typeof(DTE));
                //Diagnostics.DebugWrite("VSMFG.Generate >> dte.Solution.Projects.Count = {0}.", dte.Solution.Projects.Count);

                VsOutputWindowPaneManager.OutputWindowWrite(vsOutputWindowPaneName, "* Searching for configuration project handle... ");

                Project     project     = null;
                ProjectItem projectItem = null;
                if (!VsHelper.FindProjectContainingFile(InputFilePath, out projectItem, out project))
                {
                    // TODO: Will this fail if NEW diagram is created but not saved? Confirm. I THINK empty diagram is always saved to disk upon creation.
                    throw new ApplicationException("Could not retrieve Visual Studio ProjectItem and/or parent project containing this CSD diagram. Has this diagram been saved yet after being created?");
                }
                _project = project;

                // obtain a reference to the current project as an IVsProject type
                IVsProject vsProject = VsHelper.ToVsProject(_project); // ABM - Issue 10435: 2nd WindowsService project results in FAILURE here.
                Diagnostics.DebugWrite("VH.TFP >> IVsProject vsProject = VsHelper.ToVsProject( project='{0}' )", _project.Name);

                int  iFound = 0;
                uint itemId = 0;

                // this locates, and returns a handle to our source file, as a ProjectItem
                // TODO: 20140908: Might not be needed due to the new way I locate projectitem and project.
                VSDOCUMENTPRIORITY[] prio = new VSDOCUMENTPRIORITY[(int)VSDOCUMENTPRIORITY.DP_Standard];
                int result = vsProject.IsDocumentInProject(InputFilePath, out iFound, prio, out itemId); // ABM - Issue 10435: WindowsService project results in iFound=0!!!

                #region VSITEMID Documentation
                // itemid: Pointer to the item identifier of the document within the project.
                // NOTE: itemId is either a specific id pointing to the file, or is one of VSITEMID enumeration.
                // VSITEMID represents Special items inside a VsHierarchy:

                /*
                 * public enum VSITEMID
                 * {
                 * Selection = 4294967293, // all the currently selected items. // represents the currently selected item or items, which can include the root of the hierarchy.
                 * Root = 4294967294,      // the hierarchy itself. // represents the root of a project hierarchy and is used to identify the entire hierarchy, as opposed to a single item.
                 * Nil = 4294967295,       // no node.// represents the absence of a project item. This value is used when there is no current selection.
                 * }
                 */
                /*
                 * http://visual-studio.todaysummary.com/q_visual-studio_76086.html
                 *
                 * http://msdn.microsoft.com/en-us/subscriptions/downloads/microsoft.visualstudio.shell.interop.ivshierarchy(v=vs.100).aspx
                 * The IVsHierarchy interface is a generic interface to a hierarchy of nodes. Each node, including the root node, can have arbitrary
                 * properties associated with it. Each node on the hierarchy object is identified using a cookie (VSITEMID), which indicates a particular
                 * node. This cookie is invisible to the consumer of IVsHierarchy, and is typically a pointer to some private data maintained by the
                 * hierarchy's implementation.
                 *
                 * A VSITEMID is a DWORD uniquely identifying a node within a hierarchy. Itemids from one IVsHierarchy may not be passed to another hierarchy. Also, note that itemids have a limited lifetime, as indicated by events fired by the hierarchy, so holding on to itemids for long durations will require either the sinking of these events, or the conversion of the itemid into a canonical, persistable form.
                 *
                 * An item in a hierarchy can be a leaf node, a container of other items, or a link into some other hierarchy using GetNestedHierarchy.
                 *
                 * The IVsHierarchy interface is not used only for project hierarchies. For example, the Server Explorer window implements the IVsHierarchy interface to display its hierarchy, which is not a project hierarchy.
                 *
                 * There are times when it is useful to query a hierarchy about various virtual nodes, such as the hierarchy itself or the selected nodes within the hierarchy. Where such virtual nodes are potentially of interest, one of the predefined VSITEMID values may be passed.
                 *
                 * The environment views a project as a hierarchy, that is, a tree of nodes in which the nodes are project items. Each node also has a set of associated properties, and provides hierarchy management for VSPackages that implement project hierarchies.
                 *
                 * Notes to Implementers
                 * Implemented by VSPackages that create their own project hierarchy.
                 *
                 * Notes to Callers
                 * Called by the environment to get and set hierarchy properties.*/

                #endregion

                if (result != VSConstants.S_OK)
                {
                    throw new Exception("Unexpected error calling IVsProject.IsDocumentInProject.");
                }

                Diagnostics.DebugWrite("VH.TFP >> vsProject.IsDocumentInProject(inputFilePath, out iFound={0}, pdwPriority, out itemId={1}).", iFound, itemId);

                // if this source file is found in this project
                if (iFound != 0 && itemId != 0)
                {
                    Diagnostics.DebugWrite("VH.TFP >> (iFound != 0 && itemId != 0) == TRUE!!!");
                    Microsoft.VisualStudio.OLE.Interop.IServiceProvider oleSp = null;
                    vsProject.GetItemContext(itemId, out oleSp);
                    if (oleSp != null)
                    {
                        Diagnostics.DebugWrite("VH.TFP >> vsProject.GetItemContext( itemId, out oleSp ) >> oleSp != null! Getting ServiceProvider sp...");
                        ServiceProvider sp = new ServiceProvider(oleSp);
                        // convert our handle to a ProjectItem
                        configurationSectionModelFile = sp.GetService(typeof(ProjectItem)) as ProjectItem;

                        if (configurationSectionModelFile != null)
                        {
                            Diagnostics.DebugWrite("VH.TFP >>  configurationSectionModelFile = sp.GetService( typeof( ProjectItem ) ) as ProjectItem is NOT null! Setting this._project to the project we were working on...");
                            // We now have what we need. Stop looking.
                        }
                    }
                    else
                    {
                        throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem");
                    }
                }
                else
                {
                    VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "error: Unable to retrieve Visual Studio ProjectItem. File generation halted.");
                    throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem. Try running the tool again.");
                }

                // ABM: Code below was the complex and error prone way to find project/items. Interface exists to easily
                // locate these items. This interface is used to set current project as local variable instead of here.
                /**/
                // [7296] FILE = ~\ConfigurationSectionDesigner\Debugging\Sample.csd.
                if (!VsHelper.TryFindProjectItemAndParentProject(InputFilePath, out _project, out configurationSectionModelFile) || _project == null)
                {
                    VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "error: Unable to retrieve Visual Studio ProjectItem. File generation halted.");
                    throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem. Try running the tool again.");
                }
                /**/
                VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "found!");

                // Check out this CSD file. DISABLED: Too much can go wrong the way this generator is currently structured.

                /*if (_project.DTE.SourceControl.IsItemUnderSCC(InputFilePath) && !_project.DTE.SourceControl.IsItemCheckedOut(InputFilePath))
                 * { _project.DTE.SourceControl.CheckOutItem(InputFilePath); } */

                // Check for source control integration for the CSD item and check it out of needed.
                //if (VsHelper.IsItemUnderSourceControl(dte, configurationSectionModelFile))
                if (_project.DTE.SourceControl.IsItemUnderSCC(InputFilePath) &&
                    !_project.DTE.SourceControl.IsItemCheckedOut(InputFilePath))
                {
                    // ABM: For simplicity, we checkout the CSD file and all subitems. All file operations later down the chain will not have a SC issue.
                    // REASON: This generator has a unique design where null generated content means "don't write to file at this step". For cs files,
                    //         the write to file occurs outside of the iteration later on. For diagram, it never happens. All of these conditions
                    //         make selective SC checkout more complicated than the possible performance improvement is worth. Opinions?

                    VsHelper.CheckoutItem(_project.DTE, configurationSectionModelFile);
                }

                #region new

                // Get names of all of the existing files under CSD.
                foreach (ProjectItem childItem in configurationSectionModelFile.ProjectItems)
                {
                    _oldFileNames.Add(childItem.Name);
                }
                #endregion

                // now we can start our work, iterate across all the 'elements' in our source file.
                // Each of these items is a file extension.
                foreach (TIterativeElement item in this)
                {
                    // This try catch only exists for debugging purposes.
                    try
                    {
                        // obtain a name for this target file
                        string fileName = GetFileName(item);
                        Diagnostics.DebugWrite("VSMFG.Generate >> Filename for current element in loop is '{0}'", fileName);

                        // add it to the tracking cache
                        _newFileNames.Add(fileName);

                        // fully qualify the file on the filesystem
                        //string strFile = Path.Combine(wszInputFilePath.Substring(0, wszInputFilePath.LastIndexOf(Path.DirectorySeparatorChar)), fileName);
                        string strFile = Path.Combine(Path.GetDirectoryName(wszInputFilePath), fileName);

                        bool isNewAdded = !_oldFileNames.Contains(fileName);

                        /*
                         * if (!isNewAdded)
                         * {
                         *  if (_project.DTE.SourceControl.IsItemUnderSCC(strFile) && !_project.DTE.SourceControl.IsItemCheckedOut(strFile))
                         *  {
                         *      Diagnostics.DebugWrite("VSMFG.Generate >> Checking file out from source control '{0}'", fileName);
                         *      _project.DTE.SourceControl.CheckOutItem(strFile);
                         *  }
                         * }*/

                        // create the file
                        FileStream fs = null;

                        try
                        {
                            // generate our target file content
                            byte[] data = GenerateContent(item); // NOTE: For .diagram and .cs, this will be null, so those will not be written.

                            // if data is null, it means to ignore the contents of the generated file (no write to file).
                            if (data == null)
                            {
                                continue;
                            }

                            fs = File.Create(strFile);

                            #region Replaced code: Remove later.

                            /*if (!isNewAdded)
                             * {
                             *  // If the (xsd or config) file already exists, only save the data if the generated file is different than the existing file.
                             *  if (!Util.IsDataEqual(File.ReadAllBytes(strFile), data))
                             *  {
                             *      // Check out this file.
                             *      if (_project.DTE.SourceControl.IsItemUnderSCC(strFile) &&
                             *          !_project.DTE.SourceControl.IsItemCheckedOut(strFile))
                             *      {
                             *          Diagnostics.DebugWrite("VSMFG.Generate >> Checking file out from source control '{0}'", fileName);
                             *          _project.DTE.SourceControl.CheckOutItem(strFile);
                             *      }
                             *
                             *      Diagnostics.DebugWrite("VSMFG.Generate >> File data has changed for file '{0}'. Re-using existing file...", strFile);
                             *      fs = File.Open(strFile, FileMode.Truncate);
                             *  }
                             * }
                             * else
                             * {
                             *  // create the file
                             *  fs = File.Create(strFile);
                             * }*/

                            //if (fs != null) // We only write if file is modified or new.
                            //{

                            #endregion

                            VsOutputWindowPaneManager.OutputWindowWrite(vsOutputWindowPaneName, "* Generating the " + item + " file...");

                            // write it out to the stream
                            fs.Write(data, 0, data.Length);
                            fs.Close();
                            OnFileGenerated(strFile, isNewAdded);

                            // add the newly generated file to the solution, as a child of the source file
                            //if (!configurationSectionModelFile.ProjectItems.Cast<ProjectItem>().Any(pi => pi.Name == fileName))
                            if (isNewAdded)
                            {
                                ProjectItem itm = configurationSectionModelFile.ProjectItems.AddFromFile(strFile);

                                /*
                                 * Here you may wish to perform some addition logic such as, setting a custom tool for the target file if it
                                 * is intented to perform its own generation process.
                                 * Or, set the target file as an 'Embedded Resource' so that it is embedded into the final Assembly.
                                 *
                                 * EnvDTE.Property prop = itm.Properties.Item("CustomTool");
                                 * //// set to embedded resource
                                 * itm.Properties.Item("BuildAction").Value = 3;
                                 * if (String.IsNullOrEmpty((string)prop.Value) || !String.Equals((string)prop.Value, typeof(AnotherCustomTool).Name))
                                 * {
                                 *  prop.Value = typeof(AnotherCustomTool).Name;
                                 * }
                                 */
                            }
                            //}
                        }
                        catch (Exception e)
                        {
                            //GeneratorProgress.GeneratorError( false, 0, string.Format( "{0}\n{1}", e.Message, e.StackTrace ), -1, -1 );
                            //GeneratorProgress.GeneratorError(0, 0, string.Format("{0}\n{1}", e.Message, e.StackTrace), 0, 0);

                            if (File.Exists(strFile))
                            {
                                // TODO: ABM - Should we write this error to the file (breaking the build), or just show error and keep old file?
                                File.WriteAllText(strFile, "An exception occured while running the CsdFileGenerator on this file. See the Error List for details. E=" + e);
                            }
                            throw;
                        }
                        finally
                        {
                            if (fs != null)
                            {
                                fs.Close();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // This is here for debugging purposes, as setting a breakpoint here can be very helpful
                        Diagnostics.DebugWrite("VSMFG.Generate >> EXCEPTION: {0}", ex);
                        throw;
                    }
                }

                // perform some clean-up, making sure we delete any old (stale) target-files
                VsOutputWindowPaneManager.OutputWindowWrite(vsOutputWindowPaneName, "* Cleaning up existing files... ");
                foreach (ProjectItem childItem in configurationSectionModelFile.ProjectItems)
                {
                    string next;
                    DefaultExtension(out next);

                    if (!(childItem.Name.EndsWith(next) || _newFileNames.Contains(childItem.Name)))
                    {
                        // then delete it
                        childItem.Delete();
                    }
                }
                VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "complete!");

                VsOutputWindowPaneManager.OutputWindowWrite(vsOutputWindowPaneName, "* Generating the class file... ");

                // generate our default content for our 'single' file
                byte[] defaultData = null;
                try
                {
                    // This will call GenerateAllContent(string.Format("{0}-gen", [cs or vb]));
                    defaultData = GenerateDefaultContent();
                }
                catch (Exception ex)
                {
                    Diagnostics.DebugWrite("VSMFG.Generate >> EXCEPTION: {0}", ex);
                    throw;
                    //GeneratorProgress.GeneratorError( false, 0, string.Format( "{0}\n{1}", ex.Message, ex.StackTrace ), -1, -1 );
                    //GeneratorProgress.GeneratorError(0, 0, string.Format("{0}\n{1}", ex.Message, ex.StackTrace), 0, 0);
                }
                VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "complete!");

                if (defaultData == null)
                {
                    defaultData = new byte[0];
                }
                // return our default data (code behind file), so that Visual Studio may write it to disk.

                /*
                 * You need to write the bytes of the generated file into this variable. However, you cannot
                 * do it directly (hence the IntPtr[] type) ?instead, you must use the System.Runtime.InteropServices.AllocCoTaskMem
                 * allocator to create the memory and write type bytes in there.
                 */
                rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(defaultData.Length);

                Marshal.Copy(defaultData, 0, rgbOutputFileContents[0], defaultData.Length);

                // must be set to the number of bytes that we wrote to rgbOutputFileContents.
                pcbOutput = (uint)defaultData.Length;

                //string codefileName = GetFileName(CodeFileExtension);
                //OnFileGenerated(codefileName, isNewAdded);

                VsOutputWindowPaneManager.OutputWindowWriteLine(vsOutputWindowPaneName, "========== CSD file generation: complete! ==========");
            }
            catch (Exception ex)
            {
                // Currently, all exceptions are rethrown to be caught here.
                OnError(ex);

                LogException(ex);

                rgbOutputFileContents[0] = IntPtr.Zero;
                pcbOutput = 0;
            }

            return(0);
        }
Beispiel #12
0
        public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, Microsoft.VisualStudio.Shell.Interop.IVsGeneratorProgress pGenerateProgress)
        {
            this.bstrInputFileContents = bstrInputFileContents;
            this.wszInputFilePath      = wszInputFilePath;
            this._generatorProgress    = pGenerateProgress;
            this.newFileNames.Clear();

            // Look through all the projects in the solution
            EnvDTE.DTE           dte         = (EnvDTE.DTE)Package.GetGlobalService(typeof(EnvDTE.DTE));
            VSDOCUMENTPRIORITY[] pdwPriority = new VSDOCUMENTPRIORITY[1];
            EnvDTE.ProjectItem   item        = null;
            foreach (EnvDTE.Project project in dte.Solution.Projects)
            {
                try
                {
                    int  iFound = 0;
                    uint itemId = 0;

                    if (string.IsNullOrEmpty(project.FileName) || !File.Exists(project.FileName))
                    {
                        continue;
                    }

                    // obtain a reference to the current project as an IVsProject type
                    IVsProject vsProject = VsHelper.ToVsProject(project);

                    // this locates, and returns a handle to our source file, as a ProjectItem
                    vsProject.IsDocumentInProject(InputFilePath, out iFound, pdwPriority, out itemId);

                    // if this source file is found in this project
                    if (iFound != 0 && itemId != 0)
                    {
                        Microsoft.VisualStudio.OLE.Interop.IServiceProvider oleSp = null;
                        vsProject.GetItemContext(itemId, out oleSp);
                        if (oleSp != null)
                        {
                            ServiceProvider sp = new ServiceProvider(oleSp);
                            // convert our handle to a ProjectItem
                            item = sp.GetService(typeof(EnvDTE.ProjectItem)) as EnvDTE.ProjectItem;

                            if (item != null)
                            {
                                // We now have what we need. Break out of loop.
                                _project = project;
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    // This is here for debugging purposes, as setting a breakpoint here can be very helpful
                    throw ex;
                }
            }

            // Do sanity check
            if (_project == null || item == null)
            {
                throw new ApplicationException("Unable to retrieve Visual Studio ProjectItem. Try running the tool again.");
            }

            // now we can start our work, iterate across all the 'elements' in our source file
            foreach (IterativeElementType element in this)
            {
                try
                {
                    // obtain a name for this target file
                    string fileName = GetFileName(element);
                    // add it to the tracking cache
                    newFileNames.Add(fileName);
                    // fully qualify the file on the filesystem
                    string strFile = Path.Combine(wszInputFilePath.Substring(0, wszInputFilePath.LastIndexOf(Path.DirectorySeparatorChar)), fileName);

                    FileStream fs = null;
                    try
                    {
                        // generate our target file content
                        byte[] data = GenerateContent(element);

                        // if data is null, it means to ignore the contents of the generated file
                        if (data == null)
                        {
                            continue;
                        }

                        if (File.Exists(strFile))
                        {
                            // If the file already exists, only save the data
                            // if the generated file is different than the
                            // existing file.
                            byte[] oldData = File.ReadAllBytes(strFile);

                            bool equal = true;
                            if (oldData.Length == data.Length)
                            {
                                for (int i = 0; i < oldData.Length; i++)
                                {
                                    if (oldData[i] != data[i])
                                    {
                                        equal = false;
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                equal = false;
                            }

                            if (!equal)
                            {
                                fs = File.Open(strFile, FileMode.Truncate);
                            }
                        }
                        else
                        {
                            // create the file
                            fs = File.Create(strFile);
                        }

                        if (fs != null)
                        {
                            // write it out to the stream
                            fs.Write(data, 0, data.Length);
                        }

                        // add the newly generated file to the solution, as a child of the source file
                        if (item.ProjectItems.Cast <EnvDTE.ProjectItem>()
                            .Where(pi => pi.Name == fileName).Count() == 0)
                        {
                            EnvDTE.ProjectItem itm = item.ProjectItems.AddFromFile(strFile);

                            /*
                             * Here you may wish to perform some addition logic
                             * such as, setting a custom tool for the target file if it
                             * is intented to perform its own generation process.
                             * Or, set the target file as an 'Embedded Resource' so that
                             * it is embedded into the final Assembly.
                             *
                             * EnvDTE.Property prop = itm.Properties.Item("CustomTool");
                             * //// set to embedded resource
                             * itm.Properties.Item("BuildAction").Value = 3;
                             * if (String.IsNullOrEmpty((string)prop.Value) || !String.Equals((string)prop.Value, typeof(AnotherCustomTool).Name))
                             * {
                             *  prop.Value = typeof(AnotherCustomTool).Name;
                             * }
                             */
                        }
                    }
                    catch (Exception e)
                    {
                        //GeneratorProgress.GeneratorError( false, 0,
                        //    string.Format( "{0}\n{1}", e.Message, e.StackTrace ), -1, -1 );
                        GeneratorProgress.GeneratorError(0, 0, string.Format("{0}\n{1}", e.Message, e.StackTrace), 0, 0);
                        if (File.Exists(strFile))
                        {
                            File.WriteAllText(strFile,
                                              string.Format(
                                                  "An exception occured while running the {0} on this file. See the Error List for details.",
                                                  Const.FILEGENERATOR_IDENT));
                        }
                    }
                    finally
                    {
                        if (fs != null)
                        {
                            fs.Close();
                        }
                    }
                }
                catch (Exception ex)
                {
                    // This is here for debugging purposes, as setting a breakpoint here can be very helpful
                    throw ex;
                }
            }

            // perform some clean-up, making sure we delete any old (stale) target-files
            foreach (EnvDTE.ProjectItem childItem in item.ProjectItems)
            {
                string next = string.Empty;
                DefaultExtension(out next);

                if (!(childItem.Name.EndsWith(next) || newFileNames.Contains(childItem.Name)))
                {
                    // then delete it
                    childItem.Delete();
                }
            }

            // generate our default content for our 'single' file
            byte[] defaultData = null;
            try
            {
                defaultData = GenerateDefaultContent();
            }
            catch (Exception ex)
            {
                //GeneratorProgress.GeneratorError( false, 0,
                //    string.Format( "{0}\n{1}", ex.Message, ex.StackTrace ), -1, -1 );
                GeneratorProgress.GeneratorError(0, 0,
                                                 string.Format("{0}\n{1}", ex.Message, ex.StackTrace), 0, 0);
            }

            if (defaultData == null)
            {
                defaultData = new byte[0];
            }

            // return our default data, so that Visual Studio may write it to disk.
            rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(defaultData.Length);
            Marshal.Copy(defaultData, 0, rgbOutputFileContents[0], defaultData.Length);
            pcbOutput = (uint)defaultData.Length;

            return(0);
        }