/// <summary> /// Runs the generator on the current project item. /// </summary> /// <param name="document"></param> /// <returns></returns> public virtual void RunGeneratorEx(string document, bool runEvenIfNotDirty) { // Go run the generator on that node, but only if the file is dirty // in the running document table. Otherwise there is no need to rerun // the generator because if the original document is not dirty then // the generated output should be already up to date. // the original implementation is crappy. This method is called zillions of times by the environment, // so the first thing we should do is to see if there's any generator defined for this node. Why see if the file // is dirty if there's no generator even defined??? uint itemid = VSConstants.VSITEMID_NIL; ThreadHelper.ThrowIfNotOnUIThread(); IVsHierarchy hier = (IVsHierarchy)this.ProjectMgr; if (document != null && hier != null && ErrorHandler.Succeeded(hier.ParseCanonicalName((string)document, out itemid))) { FileNode node = (FileNode)this.ProjectMgr.NodeFromItemId(itemid); SingleFileGeneratorNodeProperties nodeproperties = node.NodeProperties as SingleFileGeneratorNodeProperties; // not every node is necessarily going to have a properties object derived from SFGNodeProperties if (nodeproperties != null && !string.IsNullOrEmpty(nodeproperties.CustomTool)) { try { this.InvokeGeneratorEx(node, document, runEvenIfNotDirty); } catch (Exception e) { if (System.Diagnostics.Debugger.IsAttached) { Debug.WriteLine(e.Message); } } } } }
/// <summary> /// Invokes the specified generator /// </summary> /// <param name="fileNode">The node on which to invoke the generator.</param> public /*protected internal, but public for FSharp.Project.dll*/ virtual void InvokeGenerator(FileNode fileNode) { if (fileNode == null) { throw new ArgumentNullException("node"); } SingleFileGeneratorNodeProperties nodeproperties = fileNode.NodeProperties as SingleFileGeneratorNodeProperties; if (nodeproperties == null) { throw new InvalidOperationException(); } string customToolProgID = nodeproperties.CustomTool; if (string.IsNullOrEmpty(customToolProgID)) { return; } string customToolNamespace = nodeproperties.CustomToolNamespace; try { if (!this.runningGenerator) { //Get the buffer contents for the current node string moniker = fileNode.GetMkDocument(); this.runningGenerator = true; //Get the generator IVsSingleFileGenerator generator; int generateDesignTimeSource; int generateSharedDesignTimeSource; int generateTempPE; SingleFileGeneratorFactory factory = new SingleFileGeneratorFactory(this.projectMgr.ProjectGuid, this.projectMgr.Site); ErrorHandler.ThrowOnFailure(factory.CreateGeneratorInstance(customToolProgID, out generateDesignTimeSource, out generateSharedDesignTimeSource, out generateTempPE, out generator)); //Check to see if the generator supports siting IObjectWithSite objWithSite = generator as IObjectWithSite; if (objWithSite != null) { objWithSite.SetSite(fileNode.OleServiceProvider); } //Determine the namespace if (string.IsNullOrEmpty(customToolNamespace)) { customToolNamespace = this.ComputeNamespace(moniker); } //Run the generator IntPtr[] output = new IntPtr[1]; output[0] = IntPtr.Zero; uint outPutSize; string extension; ErrorHandler.ThrowOnFailure(generator.DefaultExtension(out extension)); //Find if any dependent node exists string dependentNodeName = Path.GetFileNameWithoutExtension(fileNode.FileName) + extension; HierarchyNode dependentNode = fileNode.FirstChild; while (dependentNode != null) { if (string.Compare(dependentNode.ItemNode.GetMetadata(ProjectFileConstants.DependentUpon), fileNode.FileName, StringComparison.OrdinalIgnoreCase) == 0) { dependentNodeName = ((FileNode)dependentNode).FileName; break; } dependentNode = dependentNode.NextSibling; } //If you found a dependent node. if (dependentNode != null) { //Then check out the node and dependent node from SCC if (!this.CanEditFile(dependentNode.GetMkDocument())) { throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); } } else //It is a new node to be added to the project { // Check out the project file if necessary. if (!this.projectMgr.QueryEditProjectFile(false)) { throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); } } IVsTextStream stream; string inputFileContents = this.GetBufferContents(moniker, out stream); ErrorHandler.ThrowOnFailure(generator.Generate(moniker, inputFileContents, customToolNamespace, output, out outPutSize, this)); byte[] data = new byte[outPutSize]; if (output[0] != IntPtr.Zero) { Marshal.Copy(output[0], data, 0, (int)outPutSize); Marshal.FreeCoTaskMem(output[0]); } //Todo - Create a file and add it to the Project string fileToAdd = this.UpdateGeneratedCodeFile(fileNode, data, (int)outPutSize, dependentNodeName); } } finally { this.runningGenerator = false; } }
protected internal virtual void InvokeGeneratorEx(FileNode fileNode, String document, bool runEvenIfNotDirty) { base.InvokeGenerator(fileNode); Utilities.ArgumentNotNull("fileNode", fileNode); SingleFileGeneratorNodeProperties nodeproperties = fileNode.NodeProperties as SingleFileGeneratorNodeProperties; if (nodeproperties == null) { throw new InvalidOperationException(); } string customToolProgID = nodeproperties.CustomTool; if (string.IsNullOrEmpty(customToolProgID)) { return; } // not sure what to do if BuildAction is set to "MSBuild:Compile". IronPython doesn't handle this correctly either. // This build action is set for .xaml files but doing nothing doesn't seem to cause problems, so for now we ignore this // generator type and do nothing too. If we don't do this, we get lots of message boxes when the clsid of this non-existent // single file generator isn't found. // We should try to find out what the proper action is here. There is no "MSBuild:Compile" entry in the registry // for the C# or VB project system single file generators, so there must be some special handling for this build type // otherwise it would just be blank. Naturally, the IronPython sample isn't any help here. if (customToolProgID.StartsWith("MSBuild:Compile", StringComparison.OrdinalIgnoreCase)) { var project = fileNode.ProjectMgr as XSharpProjectNode; if (project.IsXamlFile(document)) { // need to generate the .g.prg file. project.Build(project.CurrentConfig.ConfigCanonicalName, "BuildGenerateSources"); // BuildGenerateSources } // The C# project system then calls a InvokeMsBuild method with the following contents /* * HRESULT CVsProjBaseFileNode::InvokeMSBuildTarget(_In_z_ LPCWSTR wszMSBuildTarget) * { * HRESULT hr = NOERROR; * * if (wszMSBuildTarget != NULL) * { * CLangBuildMgr *pBuildMgr = GetProject()->GetBuildMgr(); * CComPtr<MSBuildEngine::IProject> srpMSBuildProject = pBuildMgr->GetMSBuildProject(); * * if (CXMakeHelper::DoesTargetExist(srpMSBuildProject, wszMSBuildTarget) && pBuildMgr->HasPassedSecurityChecks()) * { * // Initialize the build engine for this project and configuration. * CSmartMSBuildInitializer smsbi; * CLangProjectConfig *pProjConfig = pBuildMgr->GetConfigs()->GetActiveConfig(); * hr = smsbi.Initialize(pBuildMgr, pProjConfig); * * if (SUCCEEDED(hr)) * { * // Build the specified target in the MSBuild project. * hr = pBuildMgr->BuildTarget(wszMSBuildTarget); * } * * // Don't bother keeping the return value here--we want to * // return failure from Initialize or BuildTarget instead. * smsbi.Restore(pBuildMgr); * } * } * * return hr; * } */ return; } string customToolNamespace = nodeproperties.CustomToolNamespace; try { if (!this.runningGenerator) { //Find if any dependent node exists string dependentNodeName = null; HierarchyNode dependentNode = fileNode.FirstChild; while (dependentNode != null) { string dependentUpon = dependentNode.ItemNode.GetMetadata(ProjectFileConstants.DependentUpon); if (!String.IsNullOrEmpty(dependentUpon)) { if (!Path.IsPathRooted(dependentUpon)) { dependentUpon = Path.Combine(Path.GetDirectoryName(fileNode.Url), dependentUpon); } if (string.Compare(dependentUpon, fileNode.Url, StringComparison.OrdinalIgnoreCase) == 0) { dependentNodeName = ((FileNode)dependentNode).FileName; break; } } dependentNode = dependentNode.NextSibling; } bool outputOutOfDate = dependentNodeName == null; if ((!runEvenIfNotDirty) && !outputOutOfDate) { string generatedFile = Path.Combine(Path.GetDirectoryName(fileNode.GetMkDocument()), dependentNodeName); outputOutOfDate = !File.Exists(generatedFile); if (!outputOutOfDate) { outputOutOfDate = File.GetLastWriteTime(fileNode.GetMkDocument()) > File.GetLastWriteTime(generatedFile); if (!outputOutOfDate) { IVsHierarchy rdtHier; IVsPersistDocData perDocData; uint cookie; outputOutOfDate = this.VerifyFileDirtyInRdt(document, out rdtHier, out perDocData, out cookie); } } } //if (runEvenIfNotDirty || outputOutOfDate) { //Get the buffer contents for the current node string moniker = fileNode.GetMkDocument(); this.runningGenerator = true; anyGeneratorsRunning++; //Get the generator IVsSingleFileGenerator generator; int generateDesignTimeSource; int generateSharedDesignTimeSource; int generateTempPE; SingleFileGeneratorFactory factory = new SingleFileGeneratorFactory(this.ProjectMgr.ProjectGuid, this.ProjectMgr.Site); ErrorHandler.ThrowOnFailure(factory.CreateGeneratorInstance(customToolProgID, out generateDesignTimeSource, out generateSharedDesignTimeSource, out generateTempPE, out generator)); //Check to see if the generator supports siting IObjectWithSite objWithSite = generator as IObjectWithSite; if (objWithSite != null) { objWithSite.SetSite(fileNode.OleServiceProvider); } //Determine the namespace if (string.IsNullOrEmpty(customToolNamespace)) { customToolNamespace = this.ComputeNamespace(moniker); } //Run the generator IntPtr[] output = new IntPtr[1]; output[0] = IntPtr.Zero; uint outPutSize; if (dependentNodeName == null) { string extension = null; try { generator.DefaultExtension(out extension); } catch (Exception e) { if (System.Diagnostics.Debugger.IsAttached) { Debug.WriteLine(e); } } if (!String.IsNullOrEmpty(extension)) { dependentNodeName = Path.GetFileNameWithoutExtension(fileNode.FileName) + extension; } else { dependentNodeName = fileNode.FileName; } } //If you found a dependent node. if (dependentNode != null) { //Then check out the node and dependent node from SCC if (!this.CanEditFile(dependentNode.GetMkDocument())) { throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); } } else //It is a new node to be added to the project { // Check out the project file if necessary. if (!this.ProjectMgr.QueryEditProjectFile(false)) { throw Marshal.GetExceptionForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED); } } IVsTextStream stream; string inputFileContents = this.GetBufferContents(moniker, out stream); var res = generator.Generate(moniker, inputFileContents, customToolNamespace, output, out outPutSize, this); byte[] data = new byte[outPutSize]; if (output[0] != IntPtr.Zero) { Marshal.Copy(output[0], data, 0, (int)outPutSize); Marshal.FreeCoTaskMem(output[0]); } //Todo - Create a file and add it to the Project string fileToAdd = this.UpdateGeneratedCodeFile(fileNode, data, (int)outPutSize, dependentNodeName, dependentNode); } } } finally { this.runningGenerator = false; anyGeneratorsRunning--; } }