Создать чертеж в текущем проекте AutoCAD Electrical

Автор Тема: Создать чертеж в текущем проекте AutoCAD Electrical  (Прочитано 12167 раз)

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

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

  • ADN OPEN
  • Сообщений: 27
  • Карма: 2
Господа, пытаюсь на C# создать в электрикале новый чертеж в текущем проекте.
Чертеж-то создаю, но не могу найти как привязать его к проекту - имя проекта текущего документа и системная переменная с именем текущего проекта пусты.
Полная ж задача сводится к тому, что надо создавать сразу несколько чертежей по заданным шаблонам - аналогично действию, когда в диспетчере проектов, при нажатии правой кнопкой мыши, выбирается пункт "создать чертеж" и открывается окно для заполнения его свойств (имя, шаблон, описание, значения для листа).

Код - C# [Выбрать]
  1. public class CreateNewDrawInProj: IExtensionApplication
  2. {
  3.         [CommandMethod("qwe")]
  4.         public void Qwe()
  5.         {
  6.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  7.             Editor ed = doc.Editor;
  8.             Database db = doc.Database;
  9.  
  10.             String CurrFileName = doc.Name;
  11.  
  12.             String TemplateFileName = @"C:\Template\A3-1.dwt"; // Директория с шаблонами
  13.             NewFileName = System.IO.Path.GetDirectoryName(CurrFileName) + System.IO.Path.DirectorySeparatorChar + "NewFileName.dwg";
  14.  
  15.             if (System.IO.File.Exists(NewFileName))
  16.                 System.IO.File.Delete(NewFileName);
  17.  
  18.             Database NewDB = new Database(false, true);
  19.            
  20.             NewDB.ReadDwgFile(TemplateFileName, FileOpenMode.OpenForReadAndWriteNoShare, true, "");
  21.               NewDB.ProjectName = db.ProjectName; // Empty
  22.               Object ProlName = Application.GetSystemVariable("PROJECTNAME"); // Empty
  23.             NewDB.CloseInput(true);
  24.             NewDB.SaveAs(NewFileName, DwgVersion.Newest);
  25.            
  26.             Application.DocumentManager.ExecuteInApplicationContext(CreateNewDoc, null);
  27.         }
  28.  
  29.         private String NewFileName = string.Empty;
  30.         private void CreateNewDoc(object userdata)
  31.         {
  32.             Document NewDoc = Application.DocumentManager.Open(NewFileName, false);
  33.             Application.DocumentManager.MdiActiveDocument = NewDoc;
  34.         }
  35.  
  36.         public void Initialize()
  37.         {
  38.         }
  39.         public void Terminate()
  40.         {
  41.         }
  42. }
  43.  

Я знаю, что список включенных в проект чертежей хранится в специальном XML-файле имя_проекта.aepx.
Неужели надо вручную туда дописывать добавляемые чертежи. И опять же как все же узнать имя текущего проекта?
Бензопила пилит тело, а виолончель душу.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Насколько я в курсе в AutoCAD Electrical всё API на AutoLISP. Например, функция (ace_getactiveproject) возвращает активный проект.
А (c:ace_add_dwg_to_project  dwg2add  paramlst) добавляет чертежи в текущий проект.


 
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 27
  • Карма: 2
Александр Ривилис, ясно, спасибо. Придется копать в сторону AutoLisp.
Бензопила пилит тело, а виолончель душу.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Александр Ривилис, ясно, спасибо. Придется копать в сторону AutoLisp.

Можно попытаться вызвать lisp-функции из .NET: P/Invoke для acedEvaluateLisp
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 27
  • Карма: 2
Можно попытаться вызвать lisp-функции из .NET
Спасибо за идею, а то совсем тоска.
Бензопила пилит тело, а виолончель душу.

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

  • ADN OPEN
  • Сообщений: 27
  • Карма: 2
Значит
0) Путем упорного гугления собрал воедино советы уважаемого Александра Ривилиса, касательно данного вопроса, разбросанные в веках.
1) Загрузил и распаковал ObjectARX2018.
2) Подключил из него к проекту три библиотеки (AcCoreMgd.dll, AcDbMgd.dll, AcMgd.dll).
3) С помощью утилиты dumpbin (dumpbin.exe /exports accore.dll >accore.txt), поставляемой вместе с вижуал студией, обнаружил в этих библиотеках точку входа в функцию acedEvaluateLisp (?acedEvaluateLisp@@YAHPEB_WAEAPEAUresbuf@@@Z)
4) Используя технологию P/Invoke, подключил к своей библиотеке функцию acedEvaluateLisp.
5) Используя AcadEvalLisp попытался выполнить в контексте автокада ace_getactiveproject, но на этом застопорился.
Не могу обработать возвращаемый результат - (5014,-1). То ли 5014 это код ошибки, то ли нет, но в любом случае -1 это не имя текущего проекта.
Если передать в AcadEvalLisp строковый параметр "(+ 100 50 30 20 10)", то результат (5003,210), где 210 и есть сумма всех слагаемых. При этом 5003 это не 5014.
Прошу подсказать что можно предпринять.

Код - C# [Выбрать]
  1. public class DrawDraw
  2. {
  3.     [System.Security.SuppressUnmanagedCodeSecurity]
  4.     [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl,
  5.     EntryPoint = "?acedEvaluateLisp@@YAHPEB_WAEAPEAUresbuf@@@Z")] // dumpbin.exe /exports accore.dll >accore.txt
  6.     extern private static int acedEvaluateLisp(string lispLine, out IntPtr result);
  7.  
  8.     static public ResultBuffer AcadEvalLisp(string arg)
  9.     {
  10.         IntPtr rb = IntPtr.Zero;
  11.         acedEvaluateLisp(arg, out rb);
  12.  
  13.         if (rb != IntPtr.Zero)
  14.         {
  15.             try
  16.             {
  17.                 ResultBuffer rbb = DisposableWrapper.Create(typeof(ResultBuffer), rb, true) as ResultBuffer;
  18.                 return rbb;
  19.             }
  20.             catch
  21.             {
  22.                 return null;
  23.             }
  24.         }
  25.         return null;
  26.     }
  27.  
  28.     [CommandMethod("qqqtest")]
  29.     static public void test()
  30.     {
  31.         ResultBuffer rb = AcadEvalLisp("ace_getactiveproject"); // Без проверки на существование функции
  32.         if (rb != null)
  33.         {
  34.             Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(rb.ToString()); // Результат выполнения: (5014,-1)
  35.         }
  36.         else
  37.         {
  38.             Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nError in evaluation");
  39.         }
  40.     }
  41. }
Бензопила пилит тело, а виолончель душу.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
        ResultBuffer rb = AcadEvalLisp("ace_getactiveproject"); // Без проверки на существование функции
А скобки где? Это же функция. Должно быть так:
Код - C# [Выбрать]
  1.        ResultBuffer rb = AcadEvalLisp("(ace_getactiveproject)");
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Заодно проверь что будет если ты в командной строке AutoCAD Electrical введёшь:
Код - Auto/Visual Lisp [Выбрать]
  1. (ace_getactiveproject)
(т.е. просто вызовешь эту lisp-функцию).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не могу обработать возвращаемый результат - (5014,-1). То ли 5014 это код ошибки, то ли нет, но в любом случае -1 это не имя текущего проекта.
Код - C++ [Выбрать]
  1. #define RTVOID    5014 /* Blank symbol */
Т.е. 5014 - это "ничего".
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Не поленился и скачал AutoCAD Electrical 2019. В его составе есть файл с документацией ACE_API.chm. В нём описание методов работы с API Electrical. В частности указано как можно работать через .NET. Вместо P/Invoke acedEvaluateLisp используется acedInvoke:





Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 27
  • Карма: 2
А скобки где? Это же функция. Должно быть так
Буду знать, спасибо.
Со скобками все завелось.
Вместо P/Invoke acedEvaluateLisp используется acedInvoke
Пробовал применить acedInvoke, но при вызове получал access violation. Не стал разбираться, вернулся к acedEvaluateLisp. Если сейчас дожму вызов лисповских функций, то вернусь к Invoke.
О результатах отпишусь. Еще раз спасибо, что не ленитесь.  :)
Бензопила пилит тело, а виолончель душу.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Пробовал применить acedInvoke, но при вызове получал access violation. Не стал разбираться, вернулся к acedEvaluateLisp.
И правильно сделал.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN OPEN
  • Сообщений: 27
  • Карма: 2
О результатах отпишусь.
Код - C# [Выбрать]
  1. public class test : IExtensionApplication
  2. {
  3.     [System.Security.SuppressUnmanagedCodeSecurity]
  4.     [System.Runtime.InteropServices.DllImport("accore.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode, CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl, EntryPoint = "?acedEvaluateLisp@@YAHPEB_WAEAPEAUresbuf@@@Z")]
  5.     extern public static int acedEvaluateLisp(string lispLine, out IntPtr result);
  6.  
  7.     [CommandMethod("qwe", CommandFlags.Session)]
  8.     public void Qwe()
  9.     {
  10.         Document CurrDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  11.  
  12.         ResultBuffer rb = DrawDraw.AcadEvalLisp("(ace_getactiveproject)");
  13.         TypedValue tv = rb.AsArray().FirstOrDefault();
  14.         String CurrFileName = tv.Value.ToString();
  15.  
  16.         String TemplateFileName = @"C:\Template\А3 С4 л2.dwt";
  17.         String FileName = "NewFileName.dwg";
  18.         String FullFileName = Path.Combine(Path.GetDirectoryName(CurrFileName), FileName);
  19.  
  20.            
  21.  
  22.         Database NewDB = new Database(false, true);
  23.         NewDB.ReadDwgFile(TemplateFileName, FileOpenMode.OpenForReadAndWriteNoShare, true, "");
  24.         NewDB.CloseInput(true);
  25.            
  26.                    
  27.         if (File.Exists(FullFileName)) // Если есть файл с таким именем, то удалить
  28.         {
  29.             var AllOpenDocs = Application.DocumentManager.Cast<Document>(); // Если открыт, то закрыть
  30.             foreach (Document d in AllOpenDocs)
  31.                 if (d.Name.ToLower().Equals(FullFileName.ToLower()))
  32.                     d.CloseAndDiscard(); // Должен быть установлен флаг CommandFlags.Session
  33.  
  34.             File.Delete(FullFileName);
  35.         }
  36.         NewDB.SaveAs(FullFileName, DwgVersion.Newest);
  37.  
  38.         Application.DocumentManager.ExecuteInApplicationContext(OpenNewTemplateDoc, FullFileName);
  39.         rb = DrawDraw.AcadEvalLisp("(c:ace_add_dwg_to_project nil (list nil nil (list Discr1 Discr2 Discr3) nil nil))"); // Здесь первый nil имеется в виду текущий документ MdiActiveDocument, созданный в OpenNewTemplateDoc
  40.     }
  41.  
  42.     private void OpenNewTemplateDoc(object FileName)
  43.     {
  44.         Document NewDoc = Application.DocumentManager.Open(FileName.ToString(), false);
  45.         Application.DocumentManager.MdiActiveDocument = NewDoc;
  46.     }
  47. }

И опять спотыкаюсь об ровное место. Вроде все верно, но не добавляется созданный чертеж к проекту.
В тридцать девятой строке вызов ace_add_dwg_to_project возвращает единицу - то есть все успешно выполнилось, но в проекте ничего не меняется.
Если руками ввести команду из тридцать девятой строки в консоль автокада, то чертеж добавляется. А вот программно не хочет.
« Последнее редактирование: 29-10-2018, 13:30:36 от Александр Ривилис »
Бензопила пилит тело, а виолончель душу.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
1. Сомневаюсь, что acedEvaluateLisp работает в контексте приложения, как и lisp воообще. Когда ты запускаешь этот lisp-код из командной строки, то ты работаешь в контексте открытого документа.
2. В lisp-выражении есть Discr1, Discr2, Discr3. Это что-такое? Ты не передаёшь это значение в код.
3. После NewDB.SaveAs(FullFileName, DwgVersion.Newest); должно быть NewDB.Dispose()
4. Если у команды есть флаг CommandFlags.Session, то не нужен вызов ExecuteInApplicationContext
5. Не нужно засовывать код в спойлер, если в нём меньше 300 строк.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Попробуй для начала вместо первого nil в AcadEvalLisp указать полный путь к добавляемому файлу. Только не забудь про экранирование символов. Например,
Код - C# [Выбрать]
  1. rb = DrawDraw.AcadEvalLisp("(c:ace_add_dwg_to_project \"c:/temp/test.dwg\" nil (list nil nil (list Discr1 Discr2 Discr3) nil nil))");
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение