Межпроцессорное взаимодействие
При разработке нового приложения (на поддерживаемых языках программирования) оно может выполняться как в основном процессе AutoCAD, так и вне процесса. Настоящее .NET API предназначено только для работы в одном процессе с AutoCAD; вместе с тем использование ActiveX Automation позволяет работать как в данном процессе, так и вне его.
Для создания нового процесса AutoCAD необходимо создать новый экземпляр приложения AutoCAD или обратиться к уже запущенному приложению помимо данного. После получения ссылки на запущенный экземпляр AutoCAD, при помощи ActiveX Automation производим загрузку в него целевой .NET-библиотеки с помощью метода SendCommand, который является членом документа AutoCAD, возвращаемым через свойство ActiveDocument приложения AcadApplication.
Пример ниже иллюстрирует такой подход - к примеру, библиотека загружена в AutoCAD 2022 и вызывает новое окно (либо пытается подключиться к уже имеющемуся) для AutoCAD 2023. После загрузки, в новый документ загружается через консоль некая .NET-библиотека, которой подается команда с целевыми параметрами обработки.
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Interop;
public class Loader
{
[CommandMethod("ConnectToNcad")]
public static void ConnectToNcad()
{
AcadApplication acAppComObj = null;
const string strProgId = "AutoCAD.Application.24.2";
// Get a running instance of nanoCAD
try
{
acAppComObj = (AcadApplication)Marshal.GetActiveObject(strProgId);
}
catch // An error occurs if no instance is running
{
try
{
// Create a new instance of AutoCAD
acAppComObj = (AcadApplication)Activator.CreateInstance(Type.GetTypeFromProgID(strProgId), true);
}
catch
{
// If an instance of AutoCAD is not created then message and exit
System.Windows.Forms.MessageBox.Show("Instance of 'AutoCAD.Application' could not be created.");
return;
}
}
// Display the application and return the name and version
acAppComObj.Visible = true;
System.Windows.Forms.MessageBox.Show("Now running " + acAppComObj.Name + "version " + acAppComObj.Version);
// Get the active document
AcadDocument acDocComObj;
acDocComObj = acAppComObj.ActiveDocument;
// Optionally, load your assembly and start your command or if your assembly
// is demandloaded, simply start the command of your in-process assembly.
acDocComObj.SendCommand("(command " + (char)34 + "NETLOAD" + (char)34 + " " +
(char)34 + "c:/myapps/mycommands.dll" + (char)34 + ") ");
acDocComObj.SendCommand("MyCommand ");
}
}
Примечание: при использовании .NET 8+ метода System.Runtime.InteropServices.Marshal.GetActiveObject в системной библиотеке нет. Вместо него можно использовать различные реализации, например, код ниже:
//From https://stackoverflow.com/a/65496277
public static class Marshal2
{
\internal const String OLEAUT32 = "oleaut32.dll";
\internal const String OLE32 = "ole32.dll";
[System.Security.SecurityCritical] // auto-generated_required
public static Object GetActiveObject(String progID)
{
Object obj = null;
Guid clsid;
// Call CLSIDFromProgIDEx first then fall back on CLSIDFromProgID if
// CLSIDFromProgIDEx doesn't exist.
try
{
CLSIDFromProgIDEx(progID, out clsid);
}
// catch
catch (System.Exception)
{
CLSIDFromProgID(progID, out clsid);
}
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
return obj;
}
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
[DllImport(OLE32, PreserveSig = false)]
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
[System.Security.SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
[DllImport(OLE32, PreserveSig = false)]
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
[System.Security.SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
//[DllImport(Microsoft.Win32.Win32Native.OLEAUT32, PreserveSig = false)]
[DllImport(OLEAUT32, PreserveSig = false)]
[System.Runtime.Versioning.ResourceExposure(System.Runtime.Versioning.ResourceScope.None)]
[System.Security.SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
}