Why EnvDTE.ProjectItem.FileCodeModel is Null on Dynamics 365 in VS 2017 project - visual-studio-2017

I am writing code to get the CodeElements from .xpp file in D365 project, but FileCodeModel value is always null
foreach (Project project in applicationObject.Solution.Projects)
{
var projectItems = GetProjectItemsRecursively(project.ProjectItems);
foreach (ProjectItem item in projectItems)
{
if ((item.FileCodeModel != null))
{
foreach (CodeElement elem in item.FileCodeModel.CodeElements)
{
}
}
}
}

According to the documentation for ProjectItem.FileCodeModel, "A FileCodeModel object is returned only for project items that are code files and in projects that implement the Visual Studio code model."
Since x++ is a very distant cousin of the .NET family, my guess would be that its files (.xml files that combine code and metadata) are not recognized as code files and/or the D365FO projects do not implement the VS code model.

Related

Project.ProjectReferences shows no item instead of list of project dependencies

I am using the following code to open solution, load the project and create the compilation.
var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
Project valueObjectProject = solution.Projects.FirstOrDefault(proj => String.Equals(proj.Name,
"ValueObject", StringComparison.CurrentCultureIgnoreCase));
var bofCompilation = await valueObjectProject.GetCompilationAsync();
Issue: no of items in valueObjectProject.ProjectReferences and compilation.References is 0, which is not true. The property should show a list of projects on which the ValueObject project depends upon. But, I am getting list of all the microsoft assemblies which the project uses under valueObject.MetadataReferences and compilation.ExternalReferences
Currently, the Diagnostics shows multiple errors of type TypeNotFound because the referenced types are declared in different assemblies. I think this is because the compilation does not have project dependency information. Don't know what is going wrong.
any help would be highly appreciated.

VS 2017 Designer: Method not found

I have a windows form that contains a user control (each defined in separate assemblies). Both the form and the user control call an extension method on BindingList<>. The extension method is defined in a 3rd assembly. Everything compiles & runs fine.
However, if I try to open the form in Visual Studio 2017 designer, I get an error:
To prevent possible data loss before loading the designer, the following errors must be resolved:
Method not found: 'System.ComponentModel.BindingList1 KamaTrenda.Utilities.Lists.ListUtilities.AddReset(System.ComponentModel.BindingList1,
System.Collections.Generic.IEnumerable`1)'.
Call stack:
at System.ComponentModel.ReflectPropertyDescriptor.SetValue(Object
component, Object value) at
Microsoft.VisualStudio.Shell.Design.VsTargetFrameworkPropertyDescriptor.SetValue(Object
component, Object value) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializePropertyAssignStatement(IDesignerSerializationManager
manager, CodeAssignStatement statement,
CodePropertyReferenceExpression propertyReferenceEx, Boolean
reportError) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeAssignStatement(IDesignerSerializationManager
manager, CodeAssignStatement statement) at
System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeStatement(IDesignerSerializationManager
manager, CodeStatement statement)
Commenting out the content of the setter of this property allows for opening the form in the designer:
public IList<IPosition> PositionsToDisplay
{
get { return myPositionsToDisplay.Select(x => x.Position).ToList(); }
set { myPositionsToDisplay.AddReset(value.Select(x => new PositionAdapter(x))); }
}
myPositionsToDisplay:
private readonly BindingList<PositionAdapter> myPositionsToDisplay = new SortableBindingList<PositionAdapter>();
And AddReset:
public static class ListUtilities
{
public static BindingList<T> AddReset<T>(this BindingList<T> list, IEnumerable<T> toAdd)
{
list.RaiseListChangedEvents = false;
foreach (T item in toAdd)
list.Add(item);
list.RaiseListChangedEvents = true;
list.ResetBindings();
return list; // for chaining
}
}
I have tried adding
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
to the definition of PositionsToDisplay, and it made no difference.
I tried rebuilding, manually deleting the contents obj & bin directories for all 3 projects, as well as the contents of AppData\Local\Microsoft\VisualStudio\15.0_6d397e1a\ProjectAssemblies, closing all open documents in VS 2017, closing the solution, and restarting Visual Studio, and it made no difference.
The .resx file of neither the form, nor the control, refer to the property.
The Designer.cs for the form had some code that seemed to be causing the issue:
this.control.PositionsToDisplay = ((System.Collections.Generic.IList<IPosition>)(resources.GetObject("control.PositionsToDisplay")));
Deleting this (presumably after adding DesignerSerializationVisibility.Hidden, so that it does not get re-generated) seemed to solve the issue.

Roslyn Workspace API : Emiting Wpf and Silverlight Projects

I try Emit each project in this solution.
I wonder why there is a problem with Emiting "Wpf" and "Silverlight" projects. I can understand that I can't Emit Console Project that I am currently executing.
How I can add missing references?
Here is my code.:
public static async Task EmitProject(Project proj)
{
var c = await proj.GetCompilationAsync();
var r = c.Emit("my" + proj.Name );
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(r.Success + " " + proj.Name);
if (!r.Success)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(r.Diagnostics.First(k => k.WarningLevel == 0));
}
}
Silverlight and WPF projects have a somewhat complicated build process, where some of the code is generated at build time by things like the XAML Markup Compiler. Calling Emit doesn't trigger that code to run - it just represents a single call to the CSC task in MSBuild.
Most of the time OpenSolutionAsync actually causes the build to progress far enough that the invocation of CSC will work, but apparently not for these project types.
For the ConsoleApplication, the issue is that it references a PCL, and the facade references are not being added correctly.
Can you file an issue at http://github.com/dotnet/roslyn for us to investigate?

Can I programmatically collapse/expand all preprocessor blocks of a certain name in Visual Studio 2012?

My current project has a lot of debug preprocessor blocks scattered throughout the code. These are intentionally named differently to the system _DEBUG and NDEBUG macros, so I have a lot of this:
// Some code here
#ifdef PROJNAME_DEBUG
//unit tests, assumption testing, etc.
#endif
// code continues
These blocks sometimes get rather large, and their presence can sometimes inhibit code readability. In Visual Studio 2012 I can easily collapse these, but it would be nice to automatically have all of them collapsed, allowing me to expand them if I want to see what's in there. However, as I also have a bunch of header guards I don't want to collapse all preprocessor blocks, only the #ifdef PROJNAME_DEBUG ones.
Can I do this?
This is the most easiest scenario you can achive it, I think.
You should create an Add-In first in C#. (in VS 2013 they become deprecated :( )
In the OnConnection method you should add your command:
public void OnConnection( object application, ext_ConnectMode connectMode, object addInInst, ref Array custom )
{
_applicationObject = (DTE2)application;
if (connectMode == ext_ConnectMode.ext_cm_AfterStartup || connectMode == ext_ConnectMode.ext_cm_Startup)
{
Commands2 commands = (Commands2)_applicationObject.Commands;
try
{
//Add a command to the Commands collection:
Command command = commands.AddNamedCommand2(_addInInstance, "MyAddinMenuBar", "MyAddinMenuBar", "Executes the command for MyAddinMenuBar", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
}
catch (System.ArgumentException)
{
//If we are here, bla, bla... (Auto generated)
}
}
}
Note: you can find how parameters are act at the reference of AddNamedCommand2
The template created version would be also fine, but naturaly it worth to name your command properly.
After that you need to add your logic to Exec method:
public void Exec( string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled )
{
handled = false;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if (commandName == "MyAddinMenuBar.Connect.MyAddinMenuBar")
{
List<string> args = (varIn as string).Split(' ').ToList();
TextSelection ts;
ts = (TextSelection)_applicationObject.ActiveDocument.Selection;
EditPoint ep = (ts.ActivePoint).CreateEditPoint();
ep.StartOfDocument();
do
{
string actualLine = ep.GetLines(ep.Line, ep.Line + 1);
if (args.TrueForAll(filter => actualLine.Contains(filter)))
{
_applicationObject.ExecuteCommand("Edit.GoTo", ep.Line.ToString());
_applicationObject.ExecuteCommand("Edit.ToggleOutliningExpansion");
}
ep.LineDown();
} while (!ep.AtEndOfDocument);
handled = true;
return;
}
}
}
Note: Name you given to the command is checked in exec.
Than you can build.
Deployment of Add-In can happen through an [ProjectName].AddIn file in ..\Documents\Visaul Studio 20[XY]\AddIns\. (Created by the template, you should copy if you move the Add-In elsewhere)
You should place your Add-In assembly where the Assembly element of the mentioned file you set to point. To change version you should modify the text in Version element.
After you deployed and started Studio, you should activate the Add-In in the manager in Toolsmenu.
You need to expand all collapsable section in your code file (CTRL+M+L with C# IDE settigs).
This is required because I found only a way to invert the state of collapsion. If you find better command, you can change it.
Next you should activate Command Window to use the the created command.
Now only you need to type your commands name, like this:
MyAddinMenuBar.Connect.MyAddinMenuBar #ifdef PROJNAME_DEBUG
Hopefully magic will happen.
This solution is independent of language of code you edit so pretty multifunctional.

Visual Studio Addin - Get Name\Path of binary of a c++ project?

I want to get the binary name of a C++ Project with a Visual Studio C# Addin.
I googled and found, that the the EnvDTE.Configuration.properties should have a element called "AssemblyName" but C++ projects do not seem to have this element.
Did somebody know where could I get this information inside a visual studio addin?
For VC++ projects you need to get access to the VCConfiguration object which you should be able to get at from the EnvDTE.Project's Object property like:
EnvDTE.Project project = ...
VCProject vcProj = (VCProject)project.Object;
IVCCollection configs = (IVCCollection)vcProj.Configurations;
VCConfiguration config = (VCConfiguration)configs.Item(configName); // like "Debug"
At that point with the VCConfiguration how exactly to get at the correct properties depends on your set up. You can access the the VCLinkerTool from the Tools property and get at the OutputFile and other properties. Or, if you use the newer inherited property sheets you may access those through the Rules property.
IVCCollection tools = (IVCCollection)config.Tools;
VCLinkerTool linkTool = (VCLinkerTool)tools.Item("Linker Tool");
string outputFile = linkTool.OutputFile;
// -------
IVCRulePropertyStorage ruleStorage = config.Rules.Item(ruleName);
string outputFile = ruleStorage.GetEvaluatedPropertyValue("TargetName");
In order to get the complete path of the binary, follow the steps as #Chadwick said to get the VCConfiguration object. And then, just use the following line of code:
//returns the complete binary name including path as a string
var primaryOutput = config.PrimaryOutput;