Запустить Autocad 2015 через com если установлен Autocad 2016

Автор Тема: Запустить Autocad 2015 через com если установлен Autocad 2016  (Прочитано 8255 раз)

0 Пользователей и 2 Гостей просматривают эту тему.

Оффлайн drunkwolfsАвтор темы

  • ADN OPEN
  • Сообщений: 21
  • Карма: 1
  • Skype: drunkwolfs
Столкнулся с проблемой при запуске Autocad 2015 через COM если кроме него еще установлен Autocad 2016.
Вместо 2015-го запускается 2016-й.
Запускаю так:
Код - C# [Выбрать]
  1. var t = Type.GetTypeFromProgID("AutoCAD.Application.20", true);
  2. var obj = Activator.CreateInstance(t, true);
Вместо 2013-го запускается 2014-й.
Запускаю так:
Код - C# [Выбрать]
  1. var t = Type.GetTypeFromProgID("AutoCAD.Application.19", true);
  2. var obj = Activator.CreateInstance(t, true);
Вероятно эта проблема актуальна и для других младших версий автокада если установлена более старшая версия (второе значение ревизии после точки).
В реестре нашел вот такое для AutoCAD.Application.20:
Код - Microsoft Registry [Выбрать]
  1. Windows Registry Editor Version 5.00
  2.  
  3. [HKEY_CLASSES_ROOT\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}]
  4. @="AutoCAD Application"
  5.  
  6. [HKEY_CLASSES_ROOT\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\LocalServer32]
  7. @="C:\\Program Files\\Autodesk\\AutoCAD 2016\\acad.exe /Automation"
  8.  
  9. [HKEY_CLASSES_ROOT\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\ProgId]
  10. @="AutoCAD.Application.20"
  11.  
  12. [HKEY_CLASSES_ROOT\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\Programmable]
  13. @=""
  14.  
  15. [HKEY_CLASSES_ROOT\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\TypeLib]
  16. @="{4E3F492A-FB57-4439-9BF0-1567ED84A3A9}"
  17.  
  18. [HKEY_CLASSES_ROOT\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\VersionIndependentProgId]
  19. @="AutoCAD.Application"
  20.  
и для AutoCAD.Application.19
Код - Microsoft Registry [Выбрать]
  1. Windows Registry Editor Version 5.00
  2.  
  3. [HKEY_CLASSES_ROOT\CLSID\{BD0DEB94-63DB-4392-9420-6EEE05094B1F}]
  4. @="AutoCAD Application"
  5.  
  6. [HKEY_CLASSES_ROOT\CLSID\{BD0DEB94-63DB-4392-9420-6EEE05094B1F}\LocalServer32]
  7. @="C:\\Program Files\\Autodesk\\AutoCAD 2014\\acad.exe /Automation"
  8.  
  9. [HKEY_CLASSES_ROOT\CLSID\{BD0DEB94-63DB-4392-9420-6EEE05094B1F}\ProgId]
  10. @="AutoCAD.Application.19"
  11.  
  12. [HKEY_CLASSES_ROOT\CLSID\{BD0DEB94-63DB-4392-9420-6EEE05094B1F}\Programmable]
  13. @=""
  14.  
  15. [HKEY_CLASSES_ROOT\CLSID\{BD0DEB94-63DB-4392-9420-6EEE05094B1F}\TypeLib]
  16. @="{D5C3CB6F-AA0A-4D45-B02D-CF2974EFD4BE}"
  17.  
  18. [HKEY_CLASSES_ROOT\CLSID\{BD0DEB94-63DB-4392-9420-6EEE05094B1F}\VersionIndependentProgId]
  19. @="AutoCAD.Application"
  20.  
  21.  

Так как же через COM запускать автокады 2015, 2013 и другие если установлено несколько версий автокада из одной ревизии?

Отмечено как Решение drunkwolfs 08-12-2016, 17:40:17

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13894
  • Карма: 1789
  • Рыцарь ObjectARX
  • Skype: rivilis
Так как же через COM запускать автокады 2015, 2013 и другие если установлено несколько версий автокада из одной ревизии?
Через COM - никак. Можно (нужно) запустить через Process.Start и потом подключится к нему через COM. Впрочем возникнет проблема если есть уже запущенные AutoCAD'ы.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн drunkwolfsАвтор темы

  • ADN OPEN
  • Сообщений: 21
  • Карма: 1
  • Skype: drunkwolfs
Впрочем возникнет проблема если есть уже запущенные AutoCAD'ы.
то есть если запущено 2 экземпляра 2015-го автокада то я не смогу выбрать к какому из них я хочу подключиться? Есть решения этой проблемы? (кроме закрытия запущенного автокада)

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13894
  • Карма: 1789
  • Рыцарь ObjectARX
  • Skype: rivilis
то есть если запущено 2 экземпляра 2015-го автокада то я не смогу выбрать к какому из них я хочу подключиться? Есть решения этой проблемы? (кроме закрытия запущенного автокада)
Нет. Во всяком случае мне такое решение неизвестно. Теоретически все COM-объекты записываются в ROT (http://adn-cis.org/dostup-k-com-prilozheniyam-iz-tabliczyi-ispolnyayushhixsya-obektov-(rot).html), но если уже один AutoCAD 2015 туда записан, то второй записываться не будет.
Можешь Проверить такой код:
Код - C# [Выбрать]
  1. using System;
  2. using System.Reflection;
  3. using System.Collections;
  4. using System.Runtime.InteropServices;
  5. using System.Runtime.InteropServices.ComTypes;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10.  
  11. namespace ConsoleApplication1
  12. {
  13.   class Program
  14.   {
  15.     static void Main(string[] args)
  16.     {
  17.       TestROT();
  18.     }
  19.     [DllImport("ole32.dll")]
  20.     static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);
  21.  
  22.     [DllImport("ole32.dll")]
  23.     public static extern void GetRunningObjectTable(
  24.         int reserved,
  25.         out IRunningObjectTable prot);
  26.  
  27.     //Requires Using System.Runtime.InteropServices.ComTypes
  28.     //Get all running AutoCAD instance by querying ROT
  29.     private static List<object> GetAcadInstances(string[] progIds)
  30.     {
  31.       List<string> clsIds = new List<string>();
  32.  
  33.       //get the autocad clsid
  34.       foreach (string progId in progIds)
  35.       {
  36.         Type type = Type.GetTypeFromProgID(progId);
  37.  
  38.         if (type != null)
  39.           clsIds.Add(type.GUID.ToString().ToUpper());
  40.       }
  41.  
  42.       //Get Running Object Table ...
  43.       IRunningObjectTable Rot = null;
  44.       GetRunningObjectTable(0, out Rot);
  45.       if (Rot == null)
  46.         return null;
  47.  
  48.       //get enumerator for ROT entries
  49.       IEnumMoniker monikerEnumerator = null;
  50.       Rot.EnumRunning(out monikerEnumerator);
  51.       if (monikerEnumerator == null)
  52.         return null;
  53.  
  54.       monikerEnumerator.Reset();
  55.  
  56.       List<object> instances = new List<object>();
  57.  
  58.       IntPtr pNumFetched = new IntPtr();
  59.       IMoniker[] monikers = new IMoniker[1];
  60.  
  61.       //Go through all entries and identifies ACAD instances
  62.       while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0)
  63.       {
  64.         IBindCtx bindCtx;
  65.         CreateBindCtx(0, out bindCtx);
  66.         if (bindCtx == null)
  67.           continue;
  68.  
  69.         string displayName;
  70.         monikers[0].GetDisplayName(bindCtx, null, out displayName);
  71.  
  72.         foreach (string clsId in clsIds)
  73.         {
  74.           if (displayName.ToUpper().IndexOf(clsId) > 0)
  75.           {
  76.             object ComObject;
  77.             Rot.GetObject(monikers[0], out ComObject);
  78.  
  79.             if (ComObject == null)
  80.               continue;
  81.             if (instances.IndexOf(ComObject) == -1)
  82.               instances.Add(ComObject);
  83.             break;
  84.           }
  85.         }
  86.       }
  87.  
  88.       return instances;
  89.     }
  90.  
  91.     private static void TestROT()
  92.     {
  93.       string[] progIds =
  94.     {
  95.         "AutoCAD.Application.17",
  96.         "AutoCAD.Application.17.1",
  97.         "AutoCAD.Application.17.2",
  98.         "AutoCAD.Application.18",
  99.         "AutoCAD.Application.18.1",
  100.         "AutoCAD.Application.18.2",
  101.         "AutoCAD.Application.19",
  102.         "AutoCAD.Application.19.1",
  103.         "AutoCAD.Application.19.2",
  104.         "AutoCAD.Application.20",
  105.         "AutoCAD.Application.20.1",
  106.         "AutoCAD.Application.20.2",
  107.         "AutoCAD.Application.21",
  108.         "AutoCAD.Application.21.1",
  109.         "AutoCAD.Application.21.2"
  110.  
  111.     };
  112.  
  113.       List<object> instances = GetAcadInstances(progIds);
  114.  
  115.       foreach (object acadObj in instances)
  116.       {
  117.         try
  118.         {
  119.           //Late bind property "AcadApplication.Preferences.Profiles.ActiveProfile"
  120.  
  121.           object Preferences = acadObj.GetType().InvokeMember("Preferences",
  122.               System.Reflection.BindingFlags.GetProperty,
  123.               null, acadObj,
  124.               null, null, null, null);
  125.  
  126.           object Profiles = Preferences.GetType().InvokeMember("Profiles",
  127.               System.Reflection.BindingFlags.GetProperty,
  128.               null, Preferences,
  129.               null, null, null, null);
  130.  
  131.           string ActiveProfile = Profiles.GetType().InvokeMember("ActiveProfile",
  132.               System.Reflection.BindingFlags.GetProperty,
  133.               null, Profiles,
  134.               null, null, null, null) as string;
  135.           Console.WriteLine(ActiveProfile);
  136.           Console.ReadKey();
  137.  
  138.         }
  139.         catch
  140.         {
  141.           continue;
  142.         }
  143.       }
  144.     }
  145.   }
  146. }
Если запущено два экземпляра одной версии AutoCAD и у них разные активные профили, то всё равно выводится будет одно и тоже имя профиля, что говорит о том, что мы каждый раз цепляемся к одному и тому AutoCAD (который первый запущен).
Поэтому в очередной раз не рекомендую работать с AutoCAD "снаружи".
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн drunkwolfsАвтор темы

  • ADN OPEN
  • Сообщений: 21
  • Карма: 1
  • Skype: drunkwolfs
но если уже один AutoCAD 2015 туда записан, то второй записываться не будет
Похоже запись в таблице дублируется, запустил 2 автокада, обе записи относятся к одному экземпляру автокада.

Спасибо за код, попробую что нибудь с этим сделать.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13894
  • Карма: 1789
  • Рыцарь ObjectARX
  • Skype: rivilis
Спасибо за код, попробую что нибудь с этим сделать.
Попробуй. Но думаю, что это бесполезно. Нужно предупреждать пользователя и оставлять только один открытый AutoCAD.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн drunkwolfsАвтор темы

  • ADN OPEN
  • Сообщений: 21
  • Карма: 1
  • Skype: drunkwolfs
Решил проблему правкой реестра в ветки пользователя. (Она имеет приоритет перед HKLM)
Для 2015-го автокада:
Код - Microsoft Registry [Выбрать]
  1. [HKEY_CURRENT_USER\Software\Classes\AutoCAD.Application.20.0]
  2. @="AutoCAD.Application.20.0"
  3.  
  4. [HKEY_CURRENT_USER\Software\Classes\AutoCAD.Application.20.0\Clsid]
  5. @="{0B628DE4-07AD-4284-81CA-5B439F67C5E6}"
  6.  
  7. [HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}]
  8. @="AutoCAD Application"
  9.  
  10. [HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\LocalServer32]
  11. @="C:\\Program Files\\Autodesk\\AutoCAD 2015\\acad.exe /Automation"
  12.  
  13. [HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\ProgId]
  14. @="AutoCAD.Application.20.0"
  15.  
  16. [HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\Programmable]
  17. @=""
  18.  
  19. [HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\TypeLib]
  20. @="{4E3F492A-FB57-4439-9BF0-1567ED84A3A9}"
  21.  
  22. [HKEY_CURRENT_USER\Software\Classes\Wow6432Node\CLSID\{0B628DE4-07AD-4284-81CA-5B439F67C5E6}\VersionIndependentProgId]
  23. @="AutoCAD.Application"
  24.  

С ROT ничего не получилось.Так и не нашел ответа как получить оба объекта из таблицы. Похоже это баг библиотеки OLE. Она возвращает из таблицы первое найденное совпадение по имени.