ActivistInvestor \ Tony T
Distributed under the terms of the MIT License
- Prerequisites
- Multi-targeting Basics
- Multi-targeting Example Project
- Debug Profiles
- Converting Existing Projects to use Multi-targeting
- Diagnostic Console Output
Table of contents generated with markdown-toc
This file and the materials it is included with contain Autodesk-confidential information relating to AutoCAD 2027 that is restricted by NDA. It is not intended for public distribution or disclosure to anyone that is not bound by the terms of the NDA for AutoCAD 2027 prior to FCS.
A minimal example project that uses Multi-targeting to target 3 different versions of the .NET framework (.NET Framework 4.71, .NET 8.0, and .NET 10.0), and 8 AutoCAD product releases that use those frameworks (AutoCAD 2020 through AutoCAD 2027)
See the topic below describing required environment variables that define the locations of reference assemblies for AutoCAD
releases targeting .NET 4.x, .NET 8.0, and .NET 10.0.
These environment variables are required in order for the build
logic in the included Directory.Build.props file to work correctly.
Without defining these environment variables, nothing will work.
Multi-targeting provides a means for a single .NET SDK-style project to target multiple .NET framework versions. When you build a multi-target project, the project is built multiple times, once for each targeted framework version, with the build output for each placed in a different sub-folder below the \Release and \Debug folders.
To use multi-targeting in a C# project, you must use the <TargetFrameworks>
element (plural) in your .csproj file, rather than the <TargetFramework>
element (singular) (see this article for an overview).
That page also shows how to use the <TargetFrameworks> element.
For example, in the .csproj file of a project that uses the Directory.Build.props and
Directory.Build.targets files included in this project, you can target
all AutoCAD releases from AutoCAD 2020 thru AutoCAD 2027 (spanning 3 different
framework versions), thusly:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net471;net8.0-windows;net10.0-windows</TargetFrameworks>
</PropertyGroup>
</Project>You don't have to target all three frameworks or AutoCAD releases. For example, you can target only .NET 4.x- and .NET 8.0-based releases of AutoCAD. Or, you can target only .NET 8.0- and .NET 10.0-based releases. For example, to target only AutoCAD 2025 or later, you would use:
<PropertyGroup>
<TargetFrameworks>net10.0-windows;net8.0-windows</TargetFrameworks>
</PropertyGroup>Or, to target AutoCAD 2020 through AutoCAD 2026, you would use:
<PropertyGroup>
<TargetFrameworks>net8.0-windows;net471</TargetFrameworks>
</PropertyGroup>In the <TargetFrameworks> element, The first item in
the list of target framework monikers (TFMs) determines
the project context, or which framework Visual Studio
uses for the display of item states in Solution Explorer.
You can easily change the project context framework by
editing the <TargetFrameworks> element and rearranging
the order of the TFMs, so that the first item is the TFM
of the framework used for the project context, however
you should first ensure that the project buiilds without
error, and there are no unsaved changes in open files.
In a multi-target project, whenever you directly edit the project's .csproj file, you should you first unload the project, then open and edit the .csproj file, save your edits, and then reload the project.
Visual Studio 2022 provides no way to create a multi-target project via the
'create a new project' UI. To create a new project that uses multi-targeting,
You first create a standard classlibrary project that targets a single framework
version, and then manually edit the .csproj file and change the <TargetFramework>
element to <TargetFrameworks> and specify the desired framework versions, and
also add the Directory.Build.props and Directory.Build.targets files to the
project. It is strongly recommended that you first Unload the project before
editing its .csproj file, and then after saving changes, reload the project.
Within the <TargetFrameworks> element, each target framework's Target
Framework Moniker (TFM) must be specified, delimited by semicolons. You
can find a list of valid TFMs here,
although for AutoCAD development, the set of usable TFMs is limited to the
following:
| Target Framework Moniker | Framework Version | Targeted AutoCAD products |
|---|---|---|
net471 |
.NET 4.71 | AutoCAD 2020-2024 |
net8.0 or net8.0-windows |
.NET 8.0 | AutoCAD 2025 & 2026 |
net10.0 or net10.0-windows |
.NET 10.0 | AutoCAD 2027 or later |
The included build logic in the Directory.Build.* files is designed
to require the developer to specify the locations of AutoCAD assemblies
for each .NET framework version they wish to target. Environment variables
are used to allow the Directory.Build.* files to be fully-portable
across development environments without requiring changes.
At least two of these environment variables must be defined in order for
the multi-target build logic to work as-designed. Each of these environment
variables is required only if you are targeting the corresponding framework.
For example, if you don't intend to target .NET 4.x in any project, then you
don't have to define the AC_NET_4_REF_PATH environment variable, as it will
never be used.
You can use the setx command to define these environment variables,
or the Environment Variables dialog in Windows.
| Environment Variable | Description |
|---|---|
AC_NET_4_REF_PATH |
Path to reference assemblies for AutoCAD 2020-2024 |
AC_NET_8_REF_PATH |
Path to reference assemblies for AutoCAD 2025-2026 |
AC_NET_10_REF_PATH |
Path to reference assemblies for AutoCAD 2027 |
Note: The above environment variable values must not include a trailing slash (\).
Requiring paths to AutoCAD reference assemblies for each target framework to be specified using environment variables allows the Directory.Build.* files to be fully-portable across machines where the locations of the reference assemblies may differ, thereby supporting widespread distribution and team development scenarios.
When multi-targeting is used, different assembly references must be used for each targeted framework version. In the included example project, under the Dependencies node in Solution Explorer, you will see child nodes whose names are the TFM of each targeted framework, and each of those child nodes will contain assembly references that are specific to that target framework.
The following clip shows the example project open in Solution Explorer, with the Properties palette to its right. Notice that as references from different target frameworks are selected, the properties palette displays the effective path to the reference, confirming that it is the correct reference path for the target framework.
Using different, framework-specific AutoCAD references is required when multi-targeting different AutoCAD product releases that use different framework versions. This poses a problem and is the most-complicated aspect of building multi-target AutoCAD extensions.
Unfortunately, Visual Studio and its project architecture provides
no way to reference multiple, framework-specific versions of the same
assembly in a multi-target project. That can't be done via the UI,
and further, a Visual Studio project has no formal representation of
multiple, framework-specific assemblies. Hence, getting Visual Studio
to use multiple versions of framework-specific assemblies requires
custom build logic like that provided by the Directory.Build.props
and Directory.Build.targets files included in this distribution.
When multi-targeting is used with the included Directory.Build.props
and Directory.Build.targets files, you do not have to manually add
different versions of the same AutoCAD assembly reference to each target
framework's references. In fact, you can't do that using the Visual
Studio UI - when you right-click on the Dependencies node (or any
framework-specific child node) in a multi-target project and choose
Add Project Reference, You must select an assembly having a specific
path, and Visual Studio adds the assembly reference to the .csproj file,
that includes a <HintPath/> element that specifies the absolute path
to the selected assembly. By default, and without the use of the custom
build logic provided in this distribution, builds will fail, because Visual
Studio is incorrectly using the same version of the referenced assembly
for all targeted frameworks, when different versions of that assembly
must be used with each target framework.
The custom build logic in the included Directory.Build.* files transparently
solves that problem. When that custom build logic is used in a multi-target project,
You can use Visual Studio's UI to add a reference to an AutoCAD assembly to your
project, in the same way you do in a single-target project, and Visual Studio will
ignore the path specified in the <HintPath/> element, and will instead use the
path specified in one of the environment variables you've
set for each target framework (described below). After you've added references to
AutoCAD assemblies to a multi-target project using the Visual Studio UI, you can open
the .csproj file and remove the <HintPath/> elements that Visual Studio generated,
as they will not be used in any case.
The solution takes advantage of a subtle aspect of Visual Studio's assembly resolution
algorithm, which is that it searches for an assembly in other locations before it
searches the path specified in the <HintPath/> element. Visual Studio provides a way
to add one or more paths to the list of paths that it searches before it uses the path
specified in the <HintPath/> element. This solution simply adds the location of the
AutoCAD reference assemblies for the target framework currently being built to that list
of paths that Visual Studio searches before falling-back to the <HintPath> element, and
the correct version of the assembly (corresponding to the target framework that's being
built) is found. Note that this path-injection process happens for each target framework
in a multi-target project, which means that each target framework uses AutoCAD assemblies
from a different location, that correspond to that framework.
You can also add references to AutoCAD assemblies manually by editing the .csproj file.
If you do that, you can safely omit <HintPath/> elements as they will not be used,
provided that the required environment variables described below
have been set, and the included Directory.Build.props and Directory.Build.targets files
are being used by the project.
You will note that this example project does not use Autodesk-provided Nuget packages for AutoCAD. There are several reasons for this:
-
There is no package for AutoCAD releases targeting .NET 4.x.
-
Autodesk's NuGet packages do not support nuget package versioning, that allows a single package to provide multiple versions of its assemblies, one for each target framework supported by the library, or one version for each AutoCAD product release. Instead, Autodesk released separate packages for different AutoCAD releases based on the version of .NET which they target, and while they can generally be used across product releases that target the same version of .NET, there can be subtle API revisions across those releases that could result in issues.
-
AutoCAD releases and the versions of .NET which they target are not fully-aligned, and without nuget semantic package versioning support, there is no mechanism that allows a package reference to specify assemblies for a specific AutoCAD product release among several that target the same version of .NET. For example, neither of the following will work:
<PackageReference Include="AutoCAD.NET" Version="25.0.0" /> <!-- 2025 DLLs -->
<PackageReference Include="AutoCAD.NET" Version="25.1.0" /> <!-- 2026 DLLs -->To support all AutoCAD product releases that target the same version of .NET, a rule of thumb is to always target the oldest product release for a given .NET framework version. So, for AutoCAD releases that target .NET 4.x, that would mean compiling against the assemblies for AutoCAD 2020, and for releases that target .NET 8.0, compiling against the assemblies for AutoCAD 2025.
This example project and the included build logic is designed to support only one AutoCAD product release for each targeted .NET version, and it is your decision on what specific AutoCAD product release's assemblies should be used. You can specify that by setting the environment variables that are used to specify the locations of the AutoCAD assemblies for each targeted framework to the appropriate locations holding the assemblies for the AutoCAD product release you want to compile against, although it is strongly recommended to follow the above rule-of-thumb.
For other third-party nuget packages that support package versioning and multiple target frameworks, there is no difference in how you include them in multi-target projects verses single-target projects. In other words, It just works. However, you should keep in mind that if you are going to target all of the AutoCAD releases from 2020-2027 and later, you should ensure that any third-party nuget packages you need to use supports all of the framework versions your project targets.
Project references in multi-target projects work the same way they do in single-target projects with several special requirements.
First, you don't have to specify separate project references for each target framework, but any project references must be to projects that multi-target at least the same frameworks that are targeted by the referencing project. In other words, if your project targets .NET 4.x, .NET 8.0, and .NET 10.0, any project references must be to projects that also multi-target those same framework versions.
The included Directory.Build.props and Directory.Build.targets files implement the
multi-target build logic that is used by all projects in a solution, and all projects
that use those files. These files serve to vastly simplify building AutoCAD extensions
that use multi-targeting to target multiple AutoCAD/NET framework versions.
Directory.Build.props and Directory.Build.targets are designed to be fully-reusable
and are not coupled to a specific project or solution. You can copy and use them in other
multi-target AutoCAD projects as needed, with no changes required.
It is recommended that you add Directory.Build.props and Directory.Build.targets to your
Solution folder, above any project folders, so that they will be used by all projects in the
solution. You can also add them as Solution Items, but that's optional and not required. If
you add these files to your solution's folder, you don't have to add them to individual projects
in the solution that are contained within the solution's folder, as they are automatically
used by all projects within the folder where the files are located.
Before you can use the included Directory.Build.props and
Directory.Build.targets in a project, you must
assign values to at least two of the three AC_NET_X_REF_PATH environment variables described above. The values of these environment variables must point to the locations of AutoCAD reference assemblies for each targeted framework version.
The included Directory.Build.targets file also adds references to the 3 basic AutoCAD assemblies that are used in most managed extensions:
AcMgd.dllAcCoreMgd.dllAcDbMgd.dll
Hence, you do not (and should not) add references to those assemblies to any project that uses the included Directory.Build.targets file. You can add additional AutoCAD references to Directory.Build.targets that will be used by all projects that use that file, that eliminates the need to add those same references to each project.
The custom build logic in the included Directory.Build.* files recognize the <RealDwgExtension> property, which can be set to true in a .csproj file to prevent AcMgd.dll from being referenced, which is required in projects where the extension is to be loaded into a RealDwg host application such as AutoCAD Core Console:
<PropertyGroup>
<RealDwgExtension>true</RealDwgExtension>
</PropertyGroup>If you target .NET 4.x, you can set <LangVersion> to at least 8.0 to support compilation of Nullable Reference Types and implicit usings. Or, you can disable both of those features (as is done in this example
project) if you are primarily compiling migrated legacy code that doesn't use those features. If you don't set <LangVersion> in a multi-target project, Visual Studio uses the language version officially-supported for each target framework. If you target .NET 4.x and your code uses Nullable Reference Types, Implicit Usings, or other features not supported by the language version for .NET 4.x, you will get compiler errors for the .NET 4.x build.
While you can set <LangVersion> to a value that's greater than the officially-supported value for .NET 4.x, you cannot use framework-dependent features (such as Span<T>, ranges, etc.) that were introduced in more-recent framework and C# versions, because the language features have a dependence on a more recent framework version. In some cases, packages can be added to projects targeting legacy
framework versions that add various features introduced in later framework versions to them. Examples
include the System.Memory NuGet package, which enables the use of Span<T> in older framework versions, including .NET 4.x.
Targeting releases of AutoCAD that use .NET 4.x with the same code base that targets .NET 8.0 or later, can be problematic depending on what features/functionality the code uses from newer frameworks and language versions. With Windows Forms components, the issues increase exponentially.
If you can, avoid targeting older AutoCAD product releases that use .NET
4.x and you will be free from the restrictions and limitations on code that
goes with targeting that framework version. The Directory.Build.targets
and Directory.Build.props files included in this example are designed to
support targeting AutoCAD 2020 or later, but you don't have to target all
releases in multi-target projects that use these files. If you do not
specify .NET 4.x in your project's <TargetFrameworks> element, there will
be no build output generated for .NET 4.x, and no references for .net 4.x
needed, and that works without having to modify the Directory.Build.props or
Directory.Build.targets files. So, you can leave the Directory.Build.* files
as-is, and target only a subset of the frameworks those files support.
Targeting multiple framework/AutoCAD versions from a single code base can introduce another layer of complexity that you may need to deal with, which is that you may have situations where you want to leverage a feature that exists in some, but not all of the targeted framework versions.
In those cases, you can use conditional compilation with compiler-defined preprocessor symbols,
that allow you to conditionally include/exclude code depending on the
targeted framework version/AutoCAD release. The following example shows
the use of one of those preprocessor symbols with #if/#else/#endif, to
define two different implementations of a method, one for .NET 4.x, and
the other for .NET 8.0 or later. Note that this example can be expressed
more succinctly, but is not done that way in this case, mainly for illustration
purposes.
public static partial class Check
{
#if NET8_0_OR_GREATER
public static void IsNotNull(object arg, [CallerArgumentExpression("arg")] string msg = "null argument")
{
if(arg is null)
throw new ArgumentNullException(msg).Log(msg);
}
#else // .NET 4.x doesn't support [CallerArgumentExpression] attribute :(
public static void IsNotNull(object arg, string msg = "null argument")
{
if(arg == null)
throw new ArgumentNullException(msg).Log(msg);
}
#endif
}The Directory.Build.props file included in this project define several
constants that are useful for conditional code compilation. The compiler
constants shown below can be used just like the standard compiler-defined
preprocessor symbols (e.g., NET_8_OR_GREATER), and in fact, they are
merely synonyms for same, but help to make the intent clearer.
| Symbol | Condition |
|---|---|
AUTOCAD_2020_OR_GREATER |
Defined when targeting AutoCAD 2020 or later |
AUTOCAD_2025_OR_GREATER |
Defined when targeting AutoCAD 2025 or later |
AUTOCAD_2027_OR_GREATER |
Defined when targeting AutoCAD 2027 or later |
Example usage (C#):
#if AUTOCAD_2025_OR_GREATER
// code here will be included only when
// targeting AutoCAD 2025/NET 8.0 or later.
#endifIn a multi-target project, the Visual Studio editor must use one and only one target framework for the editor context. The editor context controls how intellisense, code completion, error checking, display of code based on conditional compilation, and various other code-related functions work, based on the current target framework.
For example, the above snippet shows two versions of a method, one used when targeting .NET 4.x and the other when targeting .NET 8.0 or later. In the editor, one of these two methods will appear in gray, which indicates it is not included in the compilation for the current target framework. The current target framework used for the editor context can be selected from the left-most drop-down control on the navigation bar located just above the editor window. From this control you can select any targeted framework to use as the editor context.
In the clip below, the above example is shown in the editor window, with
conditional compilation using the NET_8_OR_GREATER compiler constant, to
control which version of the method is included for .NET 8 or later, and
which is included for .NET 4.X. The clip shows what happens when the current
target framework is changed from the target framework selector dropdown.
Notice that as the current target framework is changed, the display of each
of the two versions of the method are toggled between included and excluded.
The included example project (AcadMultiTargetExample) targets the following framework versions and AutoCAD product releases:
| Target Framework | Target Framework Moniker (TFM) | AutoCAD Product Release(s) |
|---|---|---|
| .NET Framework 4.71 | net471 |
AutoCAD 2020 through 2024 |
| .NET 8.0 | net8.0-windows |
AutoCAD 2025, 2026 |
| .NET 10.0 | net10.0-windows |
AutoCAD 2027 |
This example project includes a launchSettings.json file (in the
Properties folder) that configures the project for debugging in Visual
Studio. The launchSettings.json file defines 3 debugging profiles, one
for each targeted framework/AutoCAD release.
You must edit this file and change the paths assigned to the
workingDirectory property to point to the locations of the AutoCAD
executable (e.g., acad.exe) to launch, for each launch profile. You
can leave the executablePath property as-is, since Visual Studio
will look for acad.exe in the working directory and find it. You
should also remove profiles for framework versions that your project
does not target.
You can also add command line arguments to be passed to the executable
as well in the commandLineArgs property. The commandLineArgs property
in the example project is defined to pass the /nologo switch to start
AutoCAD without showing the splash screen.
When you run the project in the debugger, you can select which launch profile to use from the dropdown list on the Visual Studio toolbar:
While it's possible to convert an existing project to use multi-targeting, it may ultimately be better to start from scratch with a new project and copy the code files from the existing project to the new one, to ensure that the project is correctly-configured for multi-targeting.
If you prefer to convert an existing project, follow the steps below. These steps should also be followed to create a new project that uses multi-targeting, after first creating a new classlibrary project that targets a single framework, and then following these same steps to configure the new project to use multi-targeting.
When converting an existing project, you should backup the existing project
first. These steps assume that you've already defined the (AC_NET_x_REF_PATH)
environment variables that are described above, to point to the AutoCAD
reference assembly locations for each targeted framework.
These steps outline the process of converting an existing (or new project) that targets a single framework version to one that targets multiple framework versions:
-
If the project is open in Visual Studio, right-click on the project node in Solution Explorer, and choose Unload Project from the context menu.
-
Open the project's .csproj file and change the
<TargetFramework>element to<TargetFrameworks>, and specify the desired framework versions, separated by semicolons. For example, to target AutoCAD 2020 through AutoCAD 2027 you would use:
<PropertyGroup>
<TargetFrameworks>net10.0;net8.0;net471</TargetFrameworks>
</PropertyGroup>-
Add copies of the
Directory.Build.propsandDirectory.Build.targetsfiles from this project to the project you are converting to multi-targeting. You should copy these files to the solution folder that contains the project being converted. You don't have to explicitly add these files to the project, as it will automatically use them if the project is located in the same folder or in any subfolder of the solution folder. -
Add a copy of the
launchSettings.jsonfile from this sample project to the Properties folder of the project being converted, and edit it to have the correct path(s) to the AutoCAD executable(s) and working directories for each targeted framework/AutoCAD release. Note that this step is optional and not required for multi-targeting to work. -
Remove any references to
acmgd.dll,acdbmgd.dll, andaccoremgd.dllfrom the .csproj file for the project being converted, as these three references are included by theDirectory.Build.targetsfile. If the project being converted is designed to not have a dependence on AutoCAD, and is intended to be loaded into AutoCAD Core Console or another RealDwg host application, add the following to the .csproj file to suppress referencing ofAcMgd.dll:
<PropertyGroup>
<RealDwgExtension>true</RealDwgExtension>
</PropertyGroup>-
If an existing project includes references to AutoCAD assemblies other than
AcMgd.dll,AcDbMgd.dll, andAcCoreMgd.dll, remove the<HintPath/>child elements from those<Reference>elements, as they will not be used. Note that this step is optional. -
Finally, save all open files, and right-click on the project in Solution Explorer and choose Reload Project, and then build the solution.
After completing the above steps, if Visual Studio displays error messages, it is most-likely a result of it not being able to fully-reconcile changes made to the project. In that case, you should save all open files, close and restart Visual Studio, and reload the solution containing the project.
When a multi-target project is built, for each targeted framework version, a diagnostic message is displayed on the output console indicating the target build and the path to the set of AutoCAD reference assemblies used to build that target. You can view the Output pane to see these messages and use them to verify that build targets are using the correct set of AutoCAD reference assemblies:
1>Built target for AutoCAD 2020 / .NET v4.7.1 using references from C:\Program Files\Autodesk\AutoCAD 2023
1>Built target for AutoCAD 2025 / .NET v8.0 using references from C:\Program Files\Autodesk\AutoCAD 2025
1>Built target for AutoCAD 2027 / .NET v10.0 using references from C:\Program Files\Autodesk\AutoCAD 2027
For issues, questions, and general discussion you can visit the repository where this project is hosted.




