//--------------------------------------------------------------------- _dispBuildEvents_OnBuildProjConfigDoneEventHandler CreateBuildHandler( string solutionConfigurationName, string projectName, Action <bool> userCallBack) { var buildContext = new BuildContext(); _dispBuildEvents_OnBuildProjConfigDoneEventHandler onBuildDone = (string project, string projectConfig, string platform, string solutionConfig, bool success) => OnBuildProjConfigDone( project, projectConfig, platform, solutionConfig, success, buildContext); buildContext.OnBuildDone = onBuildDone; buildContext.UserCallBack = userCallBack; buildContext.ProjectName = projectName; buildContext.SolutionConfigurationName = solutionConfigurationName; return(onBuildDone); }
// 1: show assembly code for currently open source file // 2: show preprocessed source code private void showCppOutput(int mode = 1) { string functionOfInterest; string curCodeLine; inspectCurrentCppFile(out functionOfInterest, out curCodeLine); // get current configuration Document doc = dte.ActiveDocument; Project proj = doc.ProjectItem.ContainingProject; ConfigurationManager mgr = proj.ConfigurationManager; string platform = mgr.ActiveConfiguration.PlatformName; string conf = mgr.ActiveConfiguration.ConfigurationName; // find the currently active configuration for the current file // don't use SolutionBuild as there may be mixed platforms // use late binding for version independence dynamic file = doc.ProjectItem.Object; // as VCFile dynamic fileconfigs = file.FileConfigurations; // as IVCCollection dynamic fileconfig = fileconfigs.Item(conf + "|" + platform); // as VCFileConfiguration dynamic tool = fileconfig.Tool; // VCCLCompilerTool // brute-force way to prevent project file modifications // copy to TEMP and restore later proj.Save(); string tempCopyPath = Path.Combine(Path.GetTempPath(), proj.Name); File.Copy(proj.FullName, tempCopyPath, true); string generatedFile; if (mode == 1) { // asmListingAsmSrc => '.asm' generatedFile = Path.GetTempFileName() + ".asm"; tool.WholeProgramOptimization = false; tool.AssemblerOutput = Enum.Parse(tool.AssemblerOutput.GetType(), "asmListingAsmSrc"); tool.AssemblerListingLocation = generatedFile; tool.WarnAsError = false; } else /*if (mode == 2)*/ { generatedFile = Path.GetTempFileName() + ".cpp"; tool.GeneratePreprocessedFile = Enum.Parse(tool.GeneratePreprocessedFile.GetType(), "preprocessYes"); // there's no separate option for this, so misuse /Fo tool.ObjectFile = generatedFile; } // VCFileConfiguration.Compile often does not work anymore and blocks the GUI // so just use the Compile command by installing a one-time callback _dispBuildEvents_OnBuildProjConfigDoneEventHandler onProjBuildDone = null; onProjBuildDone = (project, projectConfig, platfrm, solutionConfig, success) => { // Unique name is project name including solution folders hierarchy if (project != proj.UniqueName) { return; } dte.Events.BuildEvents.OnBuildProjConfigDone -= onProjBuildDone; if (File.Exists(tempCopyPath)) // just to be safe { File.Delete(proj.FullName); File.Move(tempCopyPath, proj.FullName); } if (success) { postCompileCpp(generatedFile, mode, functionOfInterest, curCodeLine); } }; dte.Events.BuildEvents.OnBuildProjConfigDone += onProjBuildDone; dte.ExecuteCommand("Build.Compile"); }
// 1: show assembly code for currently open source file // 2: show preprocessed source code private void showCppOutput(int mode = 1) { // if in a header try to open the cpp file switchToCppFile(); // get the currently active document from the IDE Document doc = dte.ActiveDocument; TextDocument tdoc = doc.Object("TextDocument") as TextDocument; if (tdoc == null) { package.showMsgBox("Could not obtain the active TextDocument object"); return; } // get currently viewed function string functionOfInterest = ""; TextSelection selection = tdoc.Selection; CodeElement codeEl = selection.ActivePoint.CodeElement[vsCMElement.vsCMElementFunction]; if (codeEl == null) { dte.StatusBar.Text = "You should place the cursor inside a function."; dte.StatusBar.Highlight(true); } else { functionOfInterest = codeEl.FullName; } // TODO: in case of a template this gets something like funcName<T>, the assembly contains funcName<actualType> // it doesn't in the case of macros either, e.g. gets _tmain but in the asm it will be wmain // http://www.viva64.com/en/a/0082/#ID0ELOBK // EditPoint directly manipulates text buffer data instead of operating with the text through the editor UI. int line = selection.ActivePoint.Line; EditPoint editPoint = tdoc.CreateEditPoint(); string curCodeLine = editPoint.GetLines(line, line + 1); // TODO: comments are removed when preprocessing and thus can't find a line with comments // get current configuration Project proj = doc.ProjectItem.ContainingProject; ConfigurationManager mgr = proj.ConfigurationManager; string platform = mgr.ActiveConfiguration.PlatformName; string conf = mgr.ActiveConfiguration.ConfigurationName; // find the currently active configuration for the current file // don't use SolutionBuild as there may be mixed platforms // use late binding for version independence dynamic file = doc.ProjectItem.Object; // as VCFile dynamic fileconfigs = file.FileConfigurations; // as IVCCollection dynamic fileconfig = fileconfigs.Item(conf + "|" + platform); // as VCFileConfiguration dynamic tool = fileconfig.Tool; // VCCLCompilerTool // save original settings to restore them later // there seems to be no better way // DTE undo contexts doesn't cover these project settings // unload/reload the project may close all open files // manipulating proj.Saved or .IsDirty does not work bool lto = tool.WholeProgramOptimization; dynamic asmtype = tool.AssemblerOutput; dynamic genPreprocessed = tool.GeneratePreprocessedFile; string asmloc = tool.AssemblerListingLocation; string objFileLocation = tool.ObjectFile; string generatedFile; if (mode == 1) { // asmListingAsmSrc => '.asm' generatedFile = Path.GetTempFileName() + ".asm"; //System.IO.Path.GetTempPath tool.WholeProgramOptimization = false; tool.AssemblerOutput = (dynamic)Enum.Parse(tool.AssemblerOutput.GetType(), "asmListingAsmSrc"); tool.AssemblerListingLocation = generatedFile; } else /*if (mode == 2)*/ { // not generally applicable //generatedFile = prj.ProjectDirectory + prjconfig.IntermediateDirectory + Replace(file.Name, ".cpp", ".i"); generatedFile = Path.GetTempFileName() + ".cpp"; tool.GeneratePreprocessedFile = (dynamic)Enum.Parse(tool.GeneratePreprocessedFile.GetType(), "preprocessYes"); // there's no separate option for this, so misuse /Fo tool.ObjectFile = generatedFile; } try { // forceBuild (even if up-to-date) and waitOnBuild fileconfig.Compile(true, true); } catch (Exception e) { package.writeStatus($"VCFileConfiguration.Compile() failed: {e.Message}. Trying command Build.Compile now..."); _dispBuildEvents_OnBuildProjConfigDoneEventHandler onProjBuildDone = null; onProjBuildDone = (project, projectConfig, platfrm, solutionConfig, success) => { dte.Events.BuildEvents.OnBuildProjConfigDone -= onProjBuildDone; // naive cleanup if (mode == 1) { tool.WholeProgramOptimization = lto; tool.AssemblerOutput = asmtype; tool.AssemblerListingLocation = asmloc; } else if (mode == 2) { tool.GeneratePreprocessedFile = genPreprocessed; tool.ObjectFile = objFileLocation; } if (success) { postCompileCpp(generatedFile, mode, functionOfInterest, curCodeLine); } }; dte.Events.BuildEvents.OnBuildProjConfigDone += onProjBuildDone; dte.ExecuteCommand("Build.Compile"); return; } // naive cleanup if (mode == 1) { tool.WholeProgramOptimization = lto; tool.AssemblerOutput = asmtype; tool.AssemblerListingLocation = asmloc; } else if (mode == 2) { tool.GeneratePreprocessedFile = genPreprocessed; tool.ObjectFile = objFileLocation; } postCompileCpp(generatedFile, mode, functionOfInterest, curCodeLine); }