Visual Studio 2017: Incompatible VCProjectEngine and EnvDTE - c#

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.

Related

GetTargetFrameworkIdentifier Static method invocation should be of the form: $([FullTypeName]::Method())

I am trying to get some net core 2.1 projects to build on a new build server that we have. We have installed Visual studio tools for 2017 and 2019.
I am getting this error when it tried to build it via our TFS build process. We use cake scripts to build the code.
C:\Program Files\dotnet\sdk\6.0.102\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.TargetFrameworkInference.targets(54,5): error MSB4186: Invalid static method invocation syntax: "[MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')". [MSBuild]::GetTargetFrameworkIdentifier Static method invocation should be of the form: $([FullTypeName]::Method()), e.g. $([System.IO.Path]::Combine(`a`, `b`)). [D:\Agents\EROS-006\_work\2\s\src\Cases.CommandHandlers\Cases.CommandHandlers.csproj]
Is it something to do with the csproj contents? We have this declared at the top as this bit of the message stands out
GetTargetFrameworkIdentifier Static method invocation should be of the form: $([FullTypeName]::Method())
The csproj version details:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeFrameworkVersion>2.1.4</RuntimeFrameworkVersion>
<TargetLatestAspNetCoreRuntimePatch>True</TargetLatestAspNetCoreRuntimePatch>
</PropertyGroup>
...
I have searched for an answer but seem to point to mono related things, which we don't use at all, its a windows machine with the visual studio tools installed as mentioned above.
The cake build part looks like this
Task("Build")
.IsDependentOn("Version")
.Does(() =>
{
var settings = new DotNetCoreRestoreSettings()
{
Sources = packageSources
};
DotNetCoreRestore(settings);
if(useLatestMsBuild){
MSBuild(solution, new MSBuildSettings {
Configuration = configuration,
MaxCpuCount = maxcpucount,
ArgumentCustomization = args => args
.Append("/p:Version=" + versionInfo.InformationalVersion.Replace("/", "-"))
.Append("/p:AssemblyVersion=" + versionInfo.AssemblySemVer)
.Append("/p:FileVersion=" + versionInfo.AssemblySemVer)
});
}else{
MSBuild(solution, new MSBuildSettings {
Configuration = configuration,
MaxCpuCount = maxcpucount,
ToolVersion = MSBuildToolVersion.VS2017,
Restore = true,
ArgumentCustomization = args => args
.Append("/p:Version=" + versionInfo.InformationalVersion.Replace("/", "-"))
.Append("/p:AssemblyVersion=" + versionInfo.AssemblySemVer)
.Append("/p:FileVersion=" + versionInfo.AssemblySemVer)
});
}
});
Looking at further build steps in cake and powershell there was mention of it compiling with mono instead of the default. Updating cake to version 2.0 and rewiting it from the ground up seems to resolve the issue.
Installing Visual Studio Build Tools 2022 and latest nuget.exe added to the environmental variable PATH seemed to help. Ideally installing everything that the build server has on it and running the same scripts locally helped a lot.

How to resolve BC30560: 'ExtensionAttribute' is ambiguous in the namespace 'System.Runtime.CompilerServices'?

I want to use MediaToolkit from Nuget Package Manager and in my test projects, the tool worked fine in VB.NET and C#.NET project. However, when I use it in my real project (which has been upgraded many times to higher version in VB.NET), I am always receiving an error attached screenshot. In my test project and real project, both are in .NET 4.6.
string videoPath = Server.MapPath("~/Video/" + fileUpload.FileName);
var inputVideoFile = new MediaFile { Filename = videoPath };
using (var engine = new Engine())
{
engine.GetMetadata(inputVideoFile);
}
duration = inputVideoFile.Metadata.Duration;
Could you please help me to resolve the issue?

C# Get Configuration from DTE

I'm trying to build some kind of custom Configuration Manager for Visual Studio 2013. I've created a VSPackage MenuCommand and currently run it in an visual studio experimental instance. To get the projects of the current solution i use this:
public static EnvDTE80.DTE2 GetActiveIDE()
{
// Get an instance of currently running Visual Studio IDE.
var dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.12.0");
return dte2;
}
public static IList<Project> Projects()
{
Projects projects = GetActiveIDE().Solution.Projects;
List<Project> list = new List<Project>();
var item = projects.GetEnumerator();
while (item.MoveNext())
{
var project = item.Current as Project;
if (project == null)
{
continue;
}
list.Add(project);
}
return list;
}
When I try to access the ConfigurationManager of a project, I get a NullRefernceException:
var projects = Projects().OrderBy(p => p.Name).ToList();
foreach (var project in projects)
{
DataRow row = solutionConfigurationData.NewRow();
row[0] = project.Name;
row[1] = project.ConfigurationManager.ActiveConfiguration.ConfigurationName;
row[2] = project.ConfigurationManager.ActiveConfiguration.PlatformName;
}
The COM-Object itself (project) works fine, because if comment out row[1] and row[2] I get a list of all project names.
Don't know how else to get the project configuration, because all the posts i found use the configuration manager.
1) Do not use Marshal.GetActiveObject to get the EnvDTE instance where your extension is loaded, it could return another running instance. Use GetService(typeof(EnvDTE.DTE))
2) Navigate the projects of the solution recursively, not linearly. See HOWTO: Navigate the files of a solution from a Visual Studio .NET macro or add-in.
3) EnvDTE.Project.ConfigurationManager can return null if the project doesn't support configuration. For C# and VB.NET project it should work, though. C++ projects use a different project model (VCConfiguration). For other projects maybe don't even support configuration programmatically.

Equivalent to VCPostBuildEventTool for C# project in visual studio 2010

I am writing an add-in for visual studio, which creates a test project for a production code project.
It should support C, C++ and C# projects.
for C/C++ projects I can progarmatically set the post and pre-build events using VCPostBuildEventTool.
this how I get it from the Project object:
VCProject vcTestProj = (VCProject)testProj.Object;
IVCCollection testProjCfgs = (IVCCollection)vcTestProj.Configurations;
VCConfiguration testProjDebugCfg = (VCConfiguration)testProjCfgs.Item("Debug");
VCLinkerTool testProjLinkerTool = (VCLinkerTool)((IVCCollection)testProjDebugCfg.Tools).Item("VCLinkerTool");
VCCLCompilerTool testProjectCompileTool = (VCCLCompilerTool)((IVCCollection)testProjDebugCfg.Tools).Item("C/C++ Compiler Tool");
VCPreBuildEventTool testProjPreBuildTool = (VCPreBuildEventTool)((IVCCollection)testProjDebugCfg.Tools).Item("Pre-Build Event Tool");
VCPostBuildEventTool testProjPostBuildTool = (VCPostBuildEventTool)((IVCCollection)testProjDebugCfg.Tools).Item("Post-Build Event Tool");
But a C# project can not be used as a VCProject, and I can't find a way to access it's pre and post build events progarmatically.
Anyway to do that?
C#/VB.NET projects are treated as the same, so they are part of ProjectProperties3 (or ProjectProperties2) interface,
http://msdn.microsoft.com/en-us/library/vslangproj2.projectproperties2.postbuildevent.aspx
How to get to that level is mentioned in
http://msdn.microsoft.com/en-us/library/ms228958.aspx

Create a Visual Studio project programmatically

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).

Categories