Create a Visual Studio project programmatically - c#

As my question say I want to create a new project based in a template which already created an tested and works fine, but i have two problems when i tried to do it in C# code (in a mvc3 project).
Which are the differences between EnvDTE80, EnvDTE90 and EnvDTE100 because i tried to do this example with EnvDTE100 but it doesn't work because the object handle it's Solution4 not Solution2 and Solution4 doesn't have the same behavior.
How can I create the project without use the default path, but an specific folder that i need
UPDATE
here's the code that works if I used the dll called EnvDTE80
System.Type type = System.Type.GetTypeFromProgID("VisualStudio.DTE.8.0");
Object obj = System.Activator.CreateInstance(type, true);
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)obj;
Solution2 _solution = (Solution2)dte.Solution;
string projectTemplatePath = #"C:\Documents and Settings\jmachado\Escritorio";
projectTemplatePath =_solution.GetProjectTemplate("",""); <-- looking for some overload to create project based in a specific folder an not from '<drive>:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ProjectTemplates\Language.'
But if i used the EnvDTE100
System.Type type = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
Object obj = System.Activator.CreateInstance(type, true);
EnvDTE100.DTE2 dte = (EnvDTE100.DTE2)obj;
Solution4 _solution = (Solution4)dte.Solution;
string projectTemplatePath = #"C:\Documents and Settings\jmachado\Escritorio";
projectTemplatePath =_solution.GetProjectTemplate("",""); <-- looking for some overload to create project based in a specific folder an not from '<drive>:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ProjectTemplates\Language.'
and Say's that DTE2 doesn't exit's in the namespace of EnvDTE100

EnvDTE80, EnvDTE90 and EnvDTE100 are DTE type libraries for VS 8.0 (2005), 9.0 (2008) and 10.0 (2010), correspondingly.
There are only two DTE root object interfaces, as of VS2010 - DTE2 being the latest. So, to get the DTE object for VS 2010, you do:
System.Type type = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0");
Object obj = System.Activator.CreateInstance(type, true);
EnvDTE80.DTE2 dte = (EnvDTE100.DTE2)obj;
Note that ProgID is for "10.0", but variable type is still EnvDTE80.DTE2.
The rest should work from there. Note also that you can always cast Solution4 to Solution2 if you need it (but GetProjectTemplate should be available directly on Solution4).

Related

How to get "Include Paths" property of Microsoft Macro Assembler in Visual Studio by a plugin?

I'm workng to get include path resolved by some VS plugin (asm-dude in fact). Include path in microsoft macro assembler looks like this:
includepath
Include file resolve part in asm-dude lies in: https://github.com/HJLebbink/asm-dude/blob/vxix2022-B/VS/CSHARP/asm-dude-vsix/Tools/LabelGraph.cs#L602
Anyway, at the beginning I think I just need to get the value of IncludePath property, and then other things can be done in a minute. But after reading some docs I realized I'm in a mess. It seems that VS prevents me to get names of all properties, but I can only get the value by the name.
Codes I write are like:
DTE dte = Package.GetGlobalService(typeof(SDTE)) as DTE;
Projects projects = dte.Solution.Projects;
if (projects.Count != 0)
{
VCProject project = (VCProject)projects.Item(1).Object;
VCConfiguration cfg = project.ActiveConfiguration;
if (cfg != null)
{
string includePathStr = cfg.GetEvaluatedPropertyValue("IncludePaths");
}
}
but in vein, it gets include path of msvc, not MASM
I cast Project to VCProject because it's a VC project. Although I can iterate properties of a non-VCProject's configuration, but it doesn't seem to work on VCProject, because it doesn't have a (at least not public) member named properties. All these docs tell me that I can only get its value by name, but the problem is I don't know its name. Or I'm completely wrong? I must admit that I'm new to VS plugins.
refs I used so far:
https://learn.microsoft.com/en-us/previous-versions/dn655034(v=vs.140)?redirectedfrom=MSDN
https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.vcprojectengine.vcconfiguration?view=visualstudiosdk-2022

Visual Studio SDK get type modifier information - is type abstract or internal?

I use the IVsObjectList2.GetCategoryField2 method to retrieve different information of a type.
Now I wonder how I can retrieve C# specific information like abstract or internal modifier of a type?
The Object Browser can displays this informations.
Update 1:
I have made another attempt to get this information. Via the DynamicTypeService and the IVsHierarchy (of the project) I can get the TypeResolutionService. This can then return the Type I'm are looking for, and form the Type I get the infomrations (internal, abstract, etc.)
Unfortunately, this only works with .NET Framework projects. .NET Core projects don't work. The assumption is that .NET core projects cause problems when resolving, because the VS add-in (or Visual Studio SDK) run under .NET Framework.
var dte = Package.GetGlobalService(typeof(DTE)) as DTE2;
var serviceProvider = new ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte);
IVsSimpleObjectList2 objectList;
....
objectList.CountSourceItems(index, out var vsHierarchy, out var itemid, out var pcItems);
DynamicTypeService dynamicTypeService = (DynamicTypeService)serviceProvider.GetService(typeof(DynamicTypeService));
var typeResolutionService = dynamicTypeService.GetTypeResolutionService(hier);
var type = typeResolutionService.GetType("ObjectBuilder.ObjectBrowserTestTypes.AbstractTestClass");
More Infos here: Visual Studio Extension get all classes and interfaces metadata
I'm still looking for a solution. Does anyone have another idea?
At the end, I decided not to retrieve the information about the types via the Object-Browser or IVsObjectManager2. The reason is that I didn't get all the information I needed.
For types in the currently loaded visual studio projects I'm using the ElementClass or CodeClass class.
var service = Package.GetGlobalService(typeof(DTE)) as DTE2;
Project project = service?.Solution?.Projects.Item(0);
CodeType codeType = project.CodeModel.CodeTypeFromFullName("Full name of Type");
if (codeType.Kind == vsCMElement.vsCMElementClass && codeType is CodeClass2 codeClass)
{
// get all the information form the code class
var typeDescription = new TypeDescription();
typeDescription.FullName = codeClass.FullName;
typeDescription.ContainsGenericParameters = codeClass.IsGeneric;
typeDescription.IsAbstract = codeClass.IsAbstract;
}
For types that are in a referenced assembly I'm using Mono.Cecil. The advantage of Mono.Cecil is, that it works with .NET Framework DLLs and .NET Core DLLs. The path of the referenced assembly can be gotten via the VS-SDK.
var vsProject = project.Object as VSLangProj.VSProject;
var assemblyPath = vsProject.References.Item(0).Path;
ModuleDefinition module = Mono.Cecil.ModuleDefinition.ReadModule(assemblyPath);
foreach (TypeDefinition type in module.Types)
{
var isAbstract = type.IsAbstract;
}

Visual Studio 2017: Incompatible VCProjectEngine and EnvDTE

I am currently working on a legacy project that supports multiple VS versions (VS 2008 to VS 2015) and now supporting VS2017, for C++ Applications.
The project itself is in C# (in VS 2015).
In it, I am required to convert an EnvDTE.project into a VCProjectEngine.VCProject.
This conversion is working for other versions, but for VS2017 NULL is returned.
The following is a minimized working code for VS 2015:
//Here, EnvDTE and VCProjectEngine provided for VS2015 are used.
using EnvDTE;
using Microsoft.VisualStudio.VCProjectEngine;
..
..
//Path for a small VS2015 solution file.
String slnPath = #"<**>\Project_2015\Project_2015.sln";
Type EnvDteType = Type.GetTypeFromProgID("VisualStudio.DTE.14.0");
object obj = System.Activator.CreateInstance(EnvDteType, true);
EnvDTE.DTE DteObject = (EnvDTE.DTE)obj;
EnvDTE.Solution SolutionObject = (EnvDTE.Solution)DteObject.Solution;
SolutionObject.Open(slnPath);
Projects ProjectObjects = SolutionObject.Projects;
foreach (Project project in ProjectObjects)
{
//vcpro generated successfully.
VCProject vcpro = project.Object as VCProject;
}
However, the same code for VS2017 gets NULL in vcpro.
//Here, EnvDTE and VCProjectEngine provided for VS2017 are used
using EnvDTE;
using Microsoft.VisualStudio.VCProjectEngine;
..
..
//Path for a small VS2017 solution file.
String slnPath = #"<**>\Project_2017\Project_2017.sln";
Type EnvDteType = Type.GetTypeFromProgID("VisualStudio.DTE.15.0");
object obj = System.Activator.CreateInstance(EnvDteType, true);
EnvDTE.DTE DteObject = (EnvDTE.DTE)obj;
EnvDTE.Solution SolutionObject = (EnvDTE.Solution)DteObject.Solution;
SolutionObject.Open(slnPath);
Projects ProjectObjects = SolutionObject.Projects;
foreach (Project project in ProjectObjects)
{
//vcpro is NULL.
VCProject vcpro = project.Object as VCProject;
}
Am I missing something here, or is it a genuine problem of VS2017?
In any case, How can we resolve this or any workaround for this?
Any help is most welcomed.
Thanks.

Add ClassLibrary Project programmatically

I have a VS 2017 extension and have tried using my own custom Project Template, by adding it programmatically, but things aren't going so well.
In my endeavour to find the mistake, I would like to see whether it is my custom Project Template causing the problem or not. Therefore I want to programmatically add any other existing built-in VS project such as a ClassLibrary type project template.
It seems to be located here:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\ProjectTemplates\CSharp\Windows\1033\
But there isn't a zip folder and I can't create one in that directory according to Windows.
I will be using something similar to the following code:
Solution2 soln = (Solution2)visualStudioInstance.Solution;
string templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, projPath, "MyProjectName", false);
Am I on the right track?
I've tried it and I got an exception, but perhaps it was just because the zip folder doesn't exist.
UPDATE
The exception I get is:
"Object reference not set to an instance of an object."
I get it in the last line of the following code, when I try to add a reference to calcEngineProject. calcEngineProject is null even though it enters the if-statement and should be assigned the value of projCS.Object as VSProject2.
The code is as follows:
templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, prjPath, "ClassLibrary1", false);
foreach (Project p in soln.Projects)
{
if (String.Compare(p.Name, "ClassLibrary1") == 0)
{
projCS = p;
break;
}
}
if (projCS != null)
{
calcEngineProject = projCS.Object as VSProject2;
}
calcEngineProject.References.Add(Path.Combine(Config.Engine.EngineBinPath, "Engines.Calculation.dll"));
Also, I saw that templatePath is this:
"C:\PROGRAM FILES (X86)\MICROSOFT VISUAL
STUDIO\2017\PROFESSIONAL\COMMON7\IDE\EXTENSIONS\EYXTAMKA.FB4\ProjectTemplates\CSharp\.NET
Standard\1033\ClassLibrary\ClassLibrary.vstemplate"
and not
\%USERPROFILE%\Documents\My Exported Templates\
as mentioned in Upgrading custom project template

How do you get the current solution directory from a VSPackage?

Following is how you would get the current solution directory from an add-in:
_applicationObject = (DTE2)application; // retrieved from OnConnection method
string solutionDir = System.IO.Path.GetDirectoryName(_applicationObject.Solution.FullName);
How would you do this via a VSPackage?
I'm migrating a visual studio add-in to a VSPackage as I'm intending to add some user controls that require a deeper integration with the IDE.
I found some good references on the relative merits of add-ins vs integration packages such as:
http://nayyeri.net/visual-studio-addin-vs-integration-package-part-1
And some good tutorials on msdn on VSPackages such as:
http://msdn.microsoft.com/en-us/library/cc138589.aspx
I haven't found a good reference yet (on msdn or otherwise) on how the higher level interfaces in add-ins (such as DTE) map to lower level interfaces in VSPackages.
Any good references out there to help with general mapping from add-in interfaces to VSPackage interfaces?
I found the answer to the specific question. The VisualStudio.DTE object can be retrieved via the GetService() method as follows:
// Get an instance of the currently running Visual Studio IDE
DTE dte = (DTE)GetService(typeof(DTE));
string solutionDir = System.IO.Path.GetDirectoryName(dte.Solution.FullName);
You can get a DTE object from one of these functions:
public static DTE GetCurrentDTE(IServiceProvider provider)
{
/*ENVDTE. */DTE vs = (DTE)provider.GetService(typeof(DTE));
if (vs == null) throw new InvalidOperationException("DTE not found.");
return vs;
}
public static DTE GetCurrentDTE()
{
return GetCurrentDTE(/* Microsoft.VisualStudio.Shell. */ServiceProvider.GlobalProvider);
}
After that, you can get active Solution from DTE.Solution and Solution path from DTE.Solution.Path property.
If using the IVsSolution interface, you can use GetSolutionInfo to obtain the path of the solution, the solution filename, and the solution user options (SUO) filename:
this.solution.GetSolutionInfo(
out string solutionDirectory,
out string solutionFile,
out string userOptsFile);

Categories