Git Product home page Git Product logo

cppclimigrationsample's Introduction

Porting a C++/CLI Project to .NET Core

One of the new features of Visual Studio 2019 version 16.4 and .NET Core 3.1 is the ability to build C++/CLI projects targeting .NET Core. This can be done either directly with cl.exe and link.exe (using the new /clr:netcore option) or via MSBuild (using <CLRSupport>NetCore</CLRSupport>). In this post, I'll walk through the steps necessary to migrate a simple C++/CLI interop project to .NET Core. More details can be found in .NET Core documentation.

The sample project

First, I need to make a sample solution to migrate. I'm going to use an app with a native entry point that displays a Windows Forms form via C++/CLI. Migrating a solution with a managed entry point interoperating with native dependencies via C++/CLI would be just as easy, though. To get started, I've created a solution with three projects:

  1. NativeApp A C++ Windows app from Visual Studio's 'Windows Desktop Application' template.
    1. This will be the app's entry point.
    2. I've updated it to display the managed form (via the CppCliInterop project) and call a method on it when the IDM_ABOUT command is invoked.
  2. ManagedLibrary A C# Windows Forms library targeting .NET Core.
    1. This will provide a WinForms form for the native app to display.
    2. I've added a text box to the form and a method to set the text box's text. I've also multi-targeted this project for .NET Core and .NET Framework so that it can be used with either. This way we can focus on migrating just the C++/CLI portion of the sample.
  3. CppCliInterop A .NET Framework C++/CLI library.
    1. This will be used as the interop layer to connect the app to the managed WinForms library.
    2. It references ManagedLibrary and allows native projects to use it.
    3. This is the project that needs to be migrated to .NET Core.

The sample code is available on GitHub. When you start the app, if you click on the Help -> About menu, the WinForms form will be displayed with text in its text box supplied by the NativeApp project.

Migrating a vcxproj to .NET Core

Now for the interesting part - updating the sample app to run on .NET Core. The changes needed are actually quite minimal. If you've migrated C# projects to .NET Core before, migrating C++/CLI projects is even simpler because the project file format doesn't change. With managed projects, .NET Core and .NET Standard projects use the new SDK-style project file format. For C++/CLI projects, though, the same vcxproj format is used to target .NET Core as .NET Framework.

All that's needed is to make a few changes to the project file. Some of these can be done through the Visual Studio IDE, but others (such as adding WinForms references) can't be yet. So the easiest way to update the project file, currently, is to just unload the project in VS and edit the vcxproj directly or to use an editor like VS Code or Notepad.

  1. Replace <CLRSupport>true</CLRSupport> with <CLRSupport>NetCore</CLRSupport>. This tells the compiler to use /clr:netcore instead of /clr when building.

    1. This change can be done through Visual Studio's project configuration interface if you prefer.
    2. Note that <CLRSupport> is specified separately in each configuration/platform-specific property group in the sample project's project file, so the update needs to be made four different places.
  2. Replace <TargetFrameworkVersion>4.7</TargetFrameworkVersion> with <TargetFramework>netcoreapp3.1</TargetFramework>.

    1. These settings can be modified through Visual Studio's project configuration interface in the 'Advanced' tab. Note, however, that changing a project's CLR support setting as described in the previous step won't change <TargetFrameworkVersion> automatically, so be sure to clear the ".NET Target Framework Version" setting before selecting .NET Core Runtime Support.
  3. Replace .NET Framework references (to System, System.Data, System.Windows.Forms, and System.Xml) with the following reference to WinForms components from the Windows Desktop .NET Core SDK. This step doesn't have Visual Studio IDE support yet, so it must be done by editing the vcxproj directly. Notice that only a reference to the Windows Desktop SDK is needed because the .NET Core SDK (which includes libraries like System, System.Xml, etc.) is included automatically. There are different Framework references for WinForms, WPF, or both (as explained in the migration docs).

    <FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />

With those changes made, the C++/CLI project will build successfully targeting .NET Core. If you're using Visual Studio 2019 16.4, though, the app won't run yet. There's one more step to get it working.

When .NET Core's CoreCLR runtime loads, it uses a .runtimeconfig.json file to know which version of .NET Core to run against. Managed .NET Core apps generate this file automatically (so, if we were migrating an app with a managed entry point, the migrated app would already work). Up until Visual Studio 2019 16.5 preview 2, though, C++/CLI libraries didn't generate this file, so it had to be added manually if a managed assembly hadn't already initialized .NET Core before the C++/CLI library was used. This has been fixed in Visual Studio 2019 16.5 preview 2. So, if you're using the latest Visual Studio preview, the migration is done! If an older version of Visual Studio is being used, we'll need to create this CppCliInterop.runtimeconfig.json file manually and make sure it's copied to the output directory:

{
  "runtimeOptions": {
    "tfm": "netcoreapp3.1",
    "framework": {
      "name": "Microsoft.WindowsDesktop.App",
      "version": "3.1.0"
    }
  }
}

The app can now run on .NET Core! A migrated version of the source is available in the NetCore branch in the sample's GitHub repository. Here's the Windows form running in front of the loaded modules showing coreclr.dll loaded.

C++/CLI scenario on .NET Core

Building without MSBuild

Migrating this sample app to .NET Core was simply a matter of updating the project file to target .NET Core instead of .NET Framework. If you need to build C++/CLI assemblies directly with cl.exe and link.exe, that's supported, too. The necessary steps are:

  1. Use /clr:netcore in place of /clr when calling cl.exe.
  2. Reference necessary .NET Core reference assemblies using /FU (.NET Core reference assemblies are typically installed under %ProgramFiles%\dotnet\packs\<SDK>\<Version>\ref).
  3. When linking, include the .NET Core app host directory as a LibPath. The .NET Core app host files are typically installed under %ProgramFiles%\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\<Version>\runtime\win-x64\native).
  4. Make sure that ijwhost.dll (which is needed to start the .NET Core runtime) is copied locally from the .NET Core app host location. MSBuild does this automatically if building a vcxproj project.
  5. Create a .runtimeconfig.json file, as discussed previously.

A few caveats

As you can see, with Visual Studio 2019 16.4 and .NET Core 3.1, targeting .NET Core with C++/CLI projects is easy. There are a few C++/CLI limitations to look out for, though.

  1. C++/CLI support is Windows only, even when running on .NET Core. If you need interoperability cross-platform, use platform invokes.
  2. C++/CLI projects cannot target .NET Standard - only .NET Core or .NET Framework - and multi-targeting isn't supported, so building a library that will be used by both .NET Framework and .NET Core callers will require two project files.
  3. If a project uses APIs that aren't available in .NET Core, those calls will need to be updated to .NET Core alternatives. The .NET Portability Analyzer can help to find any Framework dependencies that won't work on .NET Core.

Wrap-up and resources

Hopefully this sample shows how to take advantage of the new functionality in Visual Studio 2019 16.4 and .NET Core 3.1 to migrate C++/CLI projects to .NET Core. The following links may be useful for further reading.

cppclimigrationsample's People

Contributors

mjrousos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cppclimigrationsample's Issues

Documentation: Debugging Cpp/CLI

I spent significant time in finding the option to debug mixed mode for CPP/CLI, it would be nice if we update documentation with following debugging option.

NativeApp project properties > Configuration Properties > Debugging > Debugger Type = Mixed (.Net Core)
CppCliInterop project properties > Configuration Properties > Debugging > Debugger Type = Mixed (.Net Core)

C++/CLI Net Core 3.1 dll includes reference to every dll included in framework

Hi,

It wasn't clear on the best place to raise this so I'm hoping that you might be able to point me to the correct place. Apologies for opening in this repo.

When compiling a C++/CLI project using Net Core 3.1 and inspecting it's references in say dotPeek it lists every single dll that's part of the Microsoft.NETCore.App 3.1 framework (%ProgramFiles%\dotnet\packs\Microsoft.NETCore.App.Ref\3.1.0\ref\netcoreapp3.1). Building with .Net 4.x and the resulting dll only includes the required references.

This is rather undesirable as .Net 5.0 has removed support for some of these dlls (e.g. System.Runtime.InteropServices.WindowsRuntime) which I'm not using and yet show up in the references (everything shows up). I would like to also provide a .Net 5.0 targeted build however I'm getting a linker error which is possibly another bug.

I can also reproduce this with the netcore branch of this repo. My project is https://github.com/cefsharp/CefSharp

If you can point in the correct direction for where to discuss this that would be greatly appreciated.

Thanks,
Alex


clicppnetcorerferences

System:
Visual Studio: 16.8.3

dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.101
Commit: d05174dc5a

Runtime Environment:
OS Name: Windows
OS Version: 10.0.19041
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.101\

Host (useful for support):
Version: 5.0.1
Commit: b02e13abab

.NET SDKs installed:
5.0.100 [C:\Program Files\dotnet\sdk]
5.0.101 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
Microsoft.AspNetCore.All 2.1.23 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.23 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.23 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Microsoft.NuGet.Targets error

Using Visual Studio 2019 (16.10.3) I get this error:

  Using "ResolveNuGetPackageAssets" task from assembly "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.Build.Tasks.dll".
  Task "ResolveNuGetPackageAssets"
    C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\NuGet\16.0\Microsoft.NuGet.targets(198,5): error : Your project does not reference ".NETCoreApp,Version=v3.1" framework. Add a reference to ".NETCoreApp,Version=v3.1" in the "TargetFrameworks" property of your project file and then re-run NuGet restore.
  Done executing task "ResolveNuGetPackageAssets" -- FAILED.
Done building target "ResolveNuGetPackageAssets" in project "CppCliInterop.vcxproj" -- FAILED.```

Visual Studio 2019 crashes with mixed debugging (.Net Core)

The latest version of Visual Studio 2019 (16.5.2) crashes when in a mixed debugging (.Net Core) session.

As soon as you want to look at a managed variable the crash occurs. So if you want to look at the value of _managedState, Visual Studio 2019 crashes.

image
Event Viewer shows:

Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000
Exception code: 0xc0000005
Fault offset: 0x01548ca0
Faulting process id: 0x2914
Faulting application start time: 0x01d607a4b457b6d1
Faulting application path: E:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\devenv.exe
Faulting module path: unknown
Report Id: a0ae67a1-4bdf-4467-9c83-6c9549ac87a2
Faulting package full name: 
Faulting package-relative application ID:

And:

Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException
   at MCppEE.QueryAssemblyCompiler.GetIlasmNameInternal(MCppEE.Type, Boolean, Boolean)
   at MCppEE.QueryAssemblyCompiler.GetIlasmName(MCppEE.Type, Boolean)
   at MCppEE.QueryAssemblyCompiler.GetIlasmNameInternal(MCppEE.Type, Boolean, Boolean)
   at MCppEE.FunctionBuilder.GetFunctionDefinition()
   at MCppEE.CompilerEntryPoint.GetClrLocalVariableQuery(Microsoft.VisualStudio.Debugger.Evaluation.DkmInspectionContext, Microsoft.VisualStudio.Debugger.Clr.DkmClrInstructionAddress, Boolean)
   at Microsoft.VisualStudio.Debugger.EntryPoint.IDkmClrExpressionCompiler_GetClrLocalVariableQuery(IntPtr, IntPtr, IntPtr, Byte, IntPtr ByRef)

Apparently mixed .Net Core debugging is using .Net Framework!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.