Поскольку .NET плагины AutoCAD (и не только они) имеют зависимость от версий обозначенной САПР, то нередко приходится один и тот же исходный код компилировать отдельно под разные версии AutoCAD. Результаты компиляции я, как правило, размещаю либо в одном и том же каталоге плагина, либо по специальным его подкаталогам, имена которых указывают на целевую версию ядра AutoCAD, а так же зависимость от разрядности приложения (если таковая присутствует). Какой из двух перечисленных вариантов использовать — зависит от конкретного случая.


Т.о. результат может выглядеть, к примеру, либо так:

либо так:

Имена файлов, зависящих от версии AutoCAD, так же содержат в виде суффикса версию ядра приложения, а так же, в случае необходимости, разрядность целевой платформы. Например, согласно обозначенному выше скрину, в подкаталоге .R17.2×64 будет находиться файл RegionTools.17.2×64.dll, а в подкаталоге .R20.0 — файл RegionTools.20.0.dll.

Я использую версию ядра AutoCAD, а не год (2009, 2010, 2011 и т.д.), обозначенный в имени САПР, т.к. программно нужную версию DLL файла удобней находить именно по версии ядра AutoCAD — это наиболее надёжная и точная информация.

Конечно, при такой системе наименований рядовому пользователю может быть сложно понять, какой именно DLL файл из набора имеющихся подкаталогов, ему следует загружать в установленную у него версию AutoCAD. Как вариант: можно в файле readme.txt разместить текстовую информацию о том, для какой версии AutoCAD какой DLL файл следует загружать.

Однако можно эту задачу решить иначе: непосредственно в подкаталоге .bin создавать единственный DLL файл, который предназначен для загрузки в любую версию AutoCAD. Предназначение этого файла заключается в том, чтобы загрузить в AutoCAD наиболее подходящую версию плагина, найдя её либо в текущем каталоге сборки, либо в соответствующих подкаталогах. На скрине показанном выше эта роль возложена на файл RegionTools.dll.

Т.о. Какую бы версию AutoCAD пользователь не имел на своей машине, ему всегда нужно загружать только файл RegionTools.dll
Аналогичная проблема актуальна так же для плагинов ARX и VBA (VBA «хромает» по части разрядности: x86x64). Поэтому было бы вполне логично расширить решение таким образом, чтобы оно работало не только для .NET, но так же и для C++, VBA. Для ARX и VBA плагинов систему наименований, а так же структуру подкаталогов использую такие же, как и для .NET (указана мною выше).

Поскольку данный подход удобно применять во всех плагинах,  то его можно оформить в виде шаблона проекта:

Далее приводится подробно комментированный код обозначенной выше логики. Проект компилирую с опцией AnyCPU под .NET 3.5,  хотя AutoCAD 2009 по умолчанию использует 3.0. Мой выбор обусловлен тем, что AutoCAD 2009 может вместо 3.0 использовать 3.5, в которой присутствует технология LINQ, активно мною используемая. Версии ниже чем AutoCAD 2009 мне не интересны. Однако тут возникает один нюанс: на исходном компьютере так же должен быть установлен .NET Framework 3.5 SP1.

/* EntryPoint.cs
 * © Andrey Bushman, 2014
 * Поиск и загрузка версии плагина .NET, ARX или VBA, наиболее пригодной для 
 * текущей версии AutoCAD.
 * http://bushman-andrey.blogspot.ru/2014/06/dll-autocad.html
 */
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

#if AUTOCAD
using cad = Autodesk.AutoCAD.ApplicationServices.Application;
using Rt = Autodesk.AutoCAD.Runtime;
#endif

[assembly: Rt.ExtensionApplication(typeof(Bushman.CAD.EntryPoint
  .EntryPoint))]

namespace Bushman.CAD.EntryPoint {
  /// <summary>
  /// Задачей данного класса является поиск и загрузка в AutoCAD наиболее 
  /// подходящей для него версии плагина.
  /// </summary>
  public sealed class EntryPoint : Rt.IExtensionApplication {
    const String netPluginExtension = ".dll";
    static readonly String[] extensions = new String[] { ".arx"".dvb" };
    static readonly String[] methodNames = new String[] { "LoadArx""LoadDVB" 
    };

    /// <summary>
    /// Код этого метода будет запущен на исполнение при загрузке сборки в 
    /// AutoCAD. В результате его работы происходит попытка найти и загрузить в
    /// AutoCAD наиболее подходящую версию плагина из имеющихся в наличии.
    /// </summary>
    public void Initialize() {
      // Для начала извлекаем информацию о текущей версии AutoCAD и ищем
      // соответствующую ей версию файла. Имя такого файла должно 
      // формироваться по правилу: 
      //    ИмяТекущейСборки.Major.Minor[x86|x64].(dll|arx|dvb).
      // Где <Major> и <Minor> - это значения одноимённых свойств объекта 
      // Version, полученного из Application.Version.
      Version version = cad.Version;

      String fileFullName = GetType().Assembly.Location;

      Version minVersion = new Version(17, 2);

      FileInfo targetDllFullName = FindFile(fileFullName, version, minVersion);

      if(targetDllFullName == null)
        return;

      // Если найден файл, соответствующий нашей версии AutoCAD, то 
      // загружаем его.
      Assembly asm = null;
      try {
        if(targetDllFullName.Extension.Equals(netPluginExtension,
          StringComparison.CurrentCultureIgnoreCase))
          asm = Assembly.LoadFrom(targetDllFullName.FullName);
        else {
          Int32 index = Array.IndexOf(extensions, targetDllFullName.Extension);

          if(index >= 0) {
            Object application = cad.AcadApplication;

            application.GetType().InvokeMember(methodNames[index], BindingFlags
              .InvokeMethod, null, application, new Object[] { 
                targetDllFullName.FullName });
          }
        }
      }
      catch {
      }
    }

    /// <summary>
    /// Получить имя наиболее подходящего файла, для его последующей загрузки в
    /// AutoCAD. Если такой файл не будет найден, то возвращается null.
    /// </summary>
    /// <param name="fileFullName">"Базовое" имя файла, т.е. полное имя 
    /// файла без указания в нём версий ядра и разрядности платформы.</param>
    /// <param name="expectedVersion">Версия AutoCAD, для которой следует 
    /// выполнить поиск соответствующей версии файла.</param>
    /// <param name="minVersion">Наименьшая версия AutoCAD, ниже которой не 
    /// следует выполнять поиск.</param>
    /// <returns>Возвращается FileInfo наиболее подходящего файла, для его 
    /// последующей загрузки в AutoCAD. Если такой файл не будет найден, то 
    /// возвращается null.</returns>
    private FileInfo FindFile(String fileFullName, Version expectedVersion,
      Version minVersion) {

      if(fileFullName == null)
        throw new ArgumentNullException("fileFullName");

      if(fileFullName.Trim() == String.Empty)
        throw new ArgumentException(
          "fileFullName.Trim() == String.Empty");

      if(expectedVersion < minVersion)
        throw new ArgumentException(
          "expectedVersion < minVersion");

      Int32 major = expectedVersion.Major;
      Int32 minor = expectedVersion.Minor;

      String directory = Path.GetDirectoryName(fileFullName);
      String fileName = Path.GetFileNameWithoutExtension(fileFullName);

      String coreString = String.Format("{0}.{1}", major.ToString(),
        minor.ToString());

      String subDirectoryName = "R" + coreString;
      String subDirectoryName_xPlatform = subDirectoryName + (IntPtr.Size == 4
        ? "x86" : "x64");

      String targetFileName = String.Empty;
      String targetFileName_xPlatform = String.Empty;
      String targetFileFullName = String.Empty;
      String targetFileFullName_xPlatform = String.Empty;

      List<String> items = new List<String>(extensions);
      items.Insert(0, netPluginExtension);

      String name = String.Empty;

      foreach(String extension in items) {

        targetFileName = String.Format("{0}.{1}{2}", fileName, coreString,
          extension);
        targetFileName_xPlatform = String.Format("{0}.{1}{2}{3}", fileName,
          coreString, (IntPtr.Size == 4 ? "x86" : "x64"), extension);

        // Сначала выполняем поиск в текущем каталоге
        targetFileFullName = Path.Combine(directory, targetFileName);
        if(File.Exists(targetFileFullName)) {
          name = targetFileFullName;
          break;
        }
        targetFileFullName_xPlatform = Path.Combine(directory,
          targetFileName_xPlatform);
        if(File.Exists(targetFileFullName_xPlatform)) {
          name = targetFileFullName_xPlatform;
          break;
        }

        // Если в текущем каталоге подходящий файл не найден, то продолжаем
        // поиск по соответствующим подкаталогам
        targetFileFullName = directory + "\" + subDirectoryName +
          "\" + targetFileName;
        if(File.Exists(targetFileFullName)) {
          name = targetFileFullName;
          break;
        }

        targetFileFullName_xPlatform = directory + "\" +
          subDirectoryName_xPlatform + "\" + targetFileName_xPlatform;
        if(File.Exists(targetFileFullName_xPlatform)) {
          name = targetFileFullName_xPlatform;
          break;
        }
      }

      // Если найден файл, соответствующий нашей версии AutoCAD, то возвращаем 
      // соответтствующий ему объект FileInfo.
      if(File.Exists(name)) {
        return new FileInfo(name);
      }
      // Если соответствия не найдено, то продолжаем поиск, последовательно 
      // проверяя наличие подходящего файла для более ранних версий AutoCAD
      else {
        if(minor == 0) {
          minor = 3;
          --major;
        }
        else {
          --minor;
        }

        Version version = new Version(major, minor);
        if(version < minVersion)
          return null;
        FileInfo file = FindFile(fileFullName, new Version(major, minor),
          minVersion);
        return file;
      }
    }

    /// <summary>
    /// Код данного метода выполняется при завершении работы AutoCAD.
    /// </summary>
    public void Terminate() {
    }
  }
}