Сообщество программистов Autodesk в СНГ

ADN Club => ObjectARX => Тема начата: begiz от 16-07-2014, 17:19:00

Название: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 16-07-2014, 17:19:00
Добрый день,
Продолжаю мигрироватся на 2015.
Процедура должна выполнятся из модального окна синхронно.
acedCommand не осталось, заменили на acedCommandC и на acedCommandS.
acedCommandC - вызывается после завершения процедуры, так не подходит.
acedCommandS - возврасиает ошибку 22, ERR_BAD_COMMAND., по логике как раз acedCommandS подходит.
Есть подозрение что чего-то не так с названием фаила, но в консоли не видно как название передалось.
Пробовал и в кавычках (одинарных и двоиных и без них) и с двоиными '\'.

Может есть еще какие-то моменты?

Код - C++ [Выбрать]
  1. struct resbuf vl_old,vl_new;
  2.         vl_new.restype = RTSHORT;
  3.         vl_old.restype = RTSHORT;
  4.         acedGetVar(_T("SDI"),&vl_old);
  5.         int val = vl_old.resval.rint;
  6.         vl_new.resval.rint = 0;
  7.         acedSetVar(_T("SDI"),&vl_new);
  8.         acedSetVar(_T("backgroundplot"),&vl_new);
  9.         acedSetVar(_T("filedia"),&vl_new);
  10.         this->BeginEditorCommand();
  11.         acedCommand(RTSTR,_T("-publish"),RTSTR,file,RTNONE); //file - c:\\test.dsd
  12.         //acedCommandC(NULL,NULL,RTSTR,_T("-publish"),RTSTR,file,RTNONE);
  13.         //acedCommandS(RTSTR,_T("-publish"),RTSTR,file,RTNONE);
  14.         this->CompleteEditorCommand();
  15.         vl_new.resval.rint = 1;
  16.         acedSetVar(_T("filedia"),&vl_new);
  17.         acedSetVar(_T("SDI"),&vl_old);
  18.  
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 16-07-2014, 17:43:13
1) Версия AutoCAD английская? Если нет, то правильнее не _T("-publish"), а _T("_-publish")
2) Попробуй заменить в имени файла все _T('\\') на _T('/')
3) Включи на время теста системную переменную CMDECHO - она позволит посмотреть запросы командной строки.
4) Так как команде передаются все параметры за один раз, то похоже, что тебя устроит вариант acedCommandS
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 17-07-2014, 09:22:00
1.Версия англицкая
2.попробовал, ничего не поменялось
3.CMDECHO на 1, но в том то и дело что выводится только -publish, а какой параметр, т.е. какой фаил подаётся невидно. Создается впечатление что он вообще не подается
4.попробовал acedCmdS, тоже самое
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 17-07-2014, 10:05:35
Попробуй не из диалогового окна работает ли acedCommandS(RTSTR,_T("_-publish"),RTSTR,file,RTNONE);
Если работает, то подготовь проект, в котором диалоговое окно с кнопкой, которая вызывает этот код - отправлю в ADN DevHelp
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 17-07-2014, 11:16:25
В процессе создания проекта выяснилось.
errno - 22, где то раньше устанавливался и к етому участку кода отношения не имел.
Сейчас возврасяется 0, но это все равно никак не работает PUBLISH не запускается. Т.е. ни из окна, ни через команду.
Собрал проект с разными вариантами выполнения, ни 1 не работает.

p.s. Для проверки использовал DSD созданный ACAD.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 17-07-2014, 12:13:18
Я потестировал немного. Результат - acedCommandS с командой -PUBLISH не работает, а acedCommandC работает, но команда запускается только после закрытия диалогового окна. Отправлю сегодня запрос в ADN DevHelp.
Хотел уточнить - в предыдущих версиях AutoCAD у тебя этот код работал (с учетом acedCommand)?
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 17-07-2014, 13:13:04
Код в пригинале был такой, почему не помню:
acedCommand(RTSTR,_T("-publish"),RTNONE);
acedCommand(RTSTR,_T("c:\\test.dsd"),RTNONE);

Он работает в 2004,2006,2007,2012;

Поменял на этот, потому что исходя из документации синхронный вызов долзен быть сразу со всеми параметрами.
acedCommand(RTSTR,_T("-publish"),RTSTR,_T("c:\\test.dsd"),RTNONE);

Для проверки сделал также и в 2012, всё работает как и в первом случае.
А с acedCommandS ни 1 из вариантов не работает.

Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 17-07-2014, 13:55:15
Понятно. Отправил запрос в ADN DevHelp. Когда появится информация - сообщу. Могу предположить что это баг и возможно понадобится выполнять PUBLISH другим способом.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 17-07-2014, 15:13:41
Пока будем ждать ответа из ADN DevHelp попробуй такой код вместо -PUBLISH:
Код - C++ [Выбрать]
  1.         AcPlDSDData dsdDataObj;                        
  2.         dsdDataObj.readDSD(_T("C:\\test.dsd")); // Читаем dsd-файл
  3.         AcPlPlotConfig* pConfig = NULL;        
  4.         // Устанавливаем текущую конфигурацию печати
  5.         // Возможно потребуются дополнительные настройки
  6.         acplPlotConfigManager->getCurrentConfig(pConfig);
  7.         bool bShowPlotProgress = true;
  8.         // Запускаем публикацию
  9.         acplPublishExecute( dsdDataObj, pConfig, bShowPlotProgress );
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 17-07-2014, 15:37:10
"acplmisc.h" добавил.
не нахожу какой .lib добавить, без него линкер ругается,  что acplPublishExecute не определен
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 17-07-2014, 16:11:29
AcPublish_crx.lib для AutoCAD 2013...2015 и AcPublish.lib для версий до AutoCAD 2012 включительно

Проще всего в stdafx.h добавить строки:
Код - C++ [Выбрать]
  1. #include "acplmisc.h"
  2. #pragma comment(lib,"AcPublish_crx.lib")
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 17-07-2014, 16:59:15
Ну уже явно лучше!!! :D
ACAD пытается печатать, правда заставляет выбрать место и название DWF, хотя ето в DSD указано.
Пробовал установить setPlotToFile, но получаю eNotApplicable.

Это если вызываю из модального окна.
А если просто так, то на acplPlotConfigManager->getCurrentConfig(pConfig) вылетает, перед етим возвращая eNullPtr = 506  :-\
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 17-07-2014, 17:23:47
Это если вызываю из модального окна.
А если просто так, то на acplPlotConfigManager->getCurrentConfig(pConfig) вылетает, перед етим возвращая eNullPtr = 506
Можно эту строку вообще убрать.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 18-07-2014, 01:52:51
ACAD пытается печатать, правда заставляет выбрать место и название DWF, хотя ето в DSD указано.
Есть как минимум один вариант - использовать Win32 Hook для автоматического нажатия кнопки Да (OK) в момент появления диалога запроса имени файла. Я попросил ADN DevHelp уточнить есть ли еще варианты.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 18-07-2014, 12:14:26
А это метод с использованием Win32 Hook:

Код - C++ [Выбрать]
  1. //////////////////////////////////////////////////////////////////////////
  2. //            Класс для автоматического нажатия кнопки Да (OK)
  3. //////////////////////////////////////////////////////////////////////////
  4. class HelpHook {
  5. public:
  6.   HelpHook ()
  7.   {
  8.     hMsgBoxHook = SetWindowsHookEx(WH_CBT,&HelpHook::CBTProc,_hdllInstance,0); 
  9.   }
  10.   ~HelpHook()  
  11.   {
  12.     UnhookWindowsHookEx(hMsgBoxHook); hMsgBoxHook = 0;
  13.   }
  14. private:
  15.   static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
  16.   {
  17.     HWND hwnd, hwndButton;
  18.     if (nCode == HCBT_ACTIVATE) {
  19.       hwnd = (HWND)wParam; hwndButton = GetDlgItem(hwnd, IDOK);
  20.       if (hwndButton) {
  21.         SendMessage(hwndButton,BM_CLICK,0,0);
  22.       }
  23.     }
  24.     return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
  25.   }
  26.   static HHOOK hMsgBoxHook;
  27. };
  28.  
  29. HHOOK HelpHook::hMsgBoxHook = 0;
  30.  
  31. void DLGTestCommand::OnBnClickedPublishe()
  32. {
  33.   AcPlDSDData dsdDataObj;                      
  34.   dsdDataObj.readDSD(_T("C:\\test.dsd")); // Читаем dsd-файл
  35.   DeleteFile(dsdDataObj.destinationName()); // Удаляем файл предыдущей печати
  36.   AcPlPlotConfig* pConfig = NULL;      
  37.   bool bShowPlotProgress = true;
  38.   // Запускаем публикацию
  39.   {
  40.     HelpHook hlp;
  41.     acplPublishExecute( dsdDataObj, pConfig, bShowPlotProgress );
  42.   }
  43. }
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 18-07-2014, 14:05:45
Спасибо,
попробую как работает пока ADN не ответчает.
Тут момент такой еще получается, ОК будет назат, но название и место сохранения фаила будут не ясны.
Попробую с Hook'ом поработать, может окно ввода названия вытащу.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 21-07-2014, 15:19:42
Получил от ADN DevHelp подтверждение о баге при запуске -PUBLISH при помощи acedCommandS. Передано разработчикам для исправления.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 21-07-2014, 15:24:07
О грусть и печаль!!
А они случаем не предложили альтернативного метода, дабы не колдовать с Hook'ми и всплывающими окнами?
Чтобы это можно было сделать без вмешательства узера?
Через тот же PlotAPI, но полностю автоматизировать?
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 21-07-2014, 15:37:03
А они случаем не предложили альтернативного метода, дабы не колдовать с Hook'ми и всплывающими окнами?
Чтобы это можно было сделать без вмешательства узера?
Я попросил их указать workaround для этого случая. Ну и как отдельный запрос висит возможность для acplPublishExecute указать имя выходного файла. Но на этот запрос пока реакции нет. Будем ждать.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 01:38:40
Обратил внимание на интересную закономерность. При первом запуске в сеансе работы AutoCAD при выполнении функции acplPublishExecute имя dwf-файла соотвествует значению имени файла (без имени каталога) DWF из секции Target dsd-файла. При этом каталог не всегда соотвествует тому, на который ссылается DWF. Скорее он соотвествует каталогу, в котором находится dsd-файл. При последующих вызовах полный путь к dwf-фалу в точности соотвествует тому, который указан в DWF. Похоже на небольшой, но неприятный баг.
Если необходимо изменить путь к записываемому dwf-файлу, то удобно пользоваться функцией WritePrivateProfileString:
Код - C++ [Выбрать]
  1. WritePrivateProfileString(_T("Target"), _T("DWF"), pathDWF, pathDSD);
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 07:59:54
Нашел вот такую запись по поводу функции acplPublishExecute.

http://forums.autodesk.com/t5/ObjectARX/AcPublish-arx-needs-to-be-loaded-before-acplPublishExecute/td-p/3641762 (http://forums.autodesk.com/t5/ObjectARX/AcPublish-arx-needs-to-be-loaded-before-acplPublishExecute/td-p/3641762)

Попробую, отпишусь что получилось.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 08:54:57
Хм. А ведь похоже это именно тот случай. Теперь правильный путь у меня берется с первого раза. Если нужен код - выложу.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 11:14:13
Спасибо. Разобрался, всё как бы работает.
На данный момент оставляю так, но буду ждать ответа от ADN.
Я только "ЗА" избавится от всех acedCommand которые у меня используются, но Hook это временное решение.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 11:33:33
но Hook это временное решение
Ну вообще-то он не нужен. Достаточно изменить в dsd-файле:
Код - INI [Выбрать]
  1. PromptForDwfName=TRUE
на
Код - INI [Выбрать]
  1. PromptForDwfName=FALSE
И что интересно, если AcPublish.arx не загружен предварительно, то эта установка не работает и нужен хук, а если загружен, то не нужен. Вот так то.  :) Уточню что я проверял только в AutoCAD 2015.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 11:45:39
Даже еще лучше,
можно использовать :
Код - C++ [Выбрать]
  1.     AcPlDSDData dsdDataObj;                        
  2.     dsdDataObj.readDSD(dsd); // Читаем dsd-файл
  3.     dsdDataObj.setPromptForDwfName(FALSE);
  4.  

Подтверждаю всё работает, спасибо! :)
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 11:50:13
А путь к dwf-файлу можно указать так:
Код - C++ [Выбрать]
  1. dsdDataObj.setDestinationName(pathDWF);
Что интересно, я проверял и dsdDataObj.setPromptForDwfName(FALSE); и dsdDataObj.setDestinationName(pathDWF); при не загруженном AcPublish.arx и они не работали.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 11:57:02
Так может можно вообше без DSD обойтись?
Т.Е. как то указать что нужен MultiSheet DWF и чтобы весь чертеж в DWF ушел или перечислить листы которые нужны?
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 12:02:10
Кстати, только что пришел ответ от ADN DevHelp по поводу использования acplPublishExecute. И в первой же строке кода они загружают AcPublish.arx
Так что совместными усилиями этот вопрос мы решили.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 12:08:03
Так может можно вообше без DSD обойтись?
Т.Е. как то указать что нужен MultiSheet DWF и чтобы весь чертеж в DWF ушел или перечислить листы которые нужны?
В принципе это возможно, т.е. ты можешь на лету сформировать AcPlDSDData. На C# есть пример для этого и думаю что перевести его на чистый ObjectARX не должно составить большого труда:
http://adndevblog.typepad.com/autocad/2012/05/how-to-use-autodeskautocadpublishingpublisherpublishexecute.html
P.S.: Хочу уточнить, что Autodesk.AutoCAD.Publishing.Publisher.PublishExecute в AutoCAD .NET API соответствует acplPublishExecute в ObjectARX.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 13:09:19
В указаном примере процедура схожая с той что у меня, только DSD заполняется не на прямую а через DsdData.
Так как вообсе от DSD отказатся не получиается, измемений не вносил.
Предоставляю код, надеюсь будет кому то полезен :)

Код - C++ [Выбрать]
  1.         CString full_file_path_name =  curDoc()->database()->fileName();
  2.        
  3.         CString dsd = full_file_path_name;
  4.         dsd.Replace(_T("dwg"),_T("dsd"));
  5.  
  6.         WORD wBOM = 0xFEFF;
  7.         DWORD NumberOfBytesWritten;
  8.  
  9.         HANDLE hFile = ::CreateFile(dsd, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); //for UTF16 little endian
  10.        ::WriteFile(hFile, &wBOM, sizeof(WORD), &NumberOfBytesWritten, NULL);
  11.        ::CloseHandle(hFile);
  12.  
  13.         AcDbObjectId objDictId = acdbHostApplicationServices()->workingDatabase()->layoutDictionaryId();
  14.         AcDbDictionary *pDict;
  15.         acdbOpenObject(pDict, objDictId, AcDb::kForRead);
  16.         AcDbDictionaryIterator *pI = pDict->newIterator();
  17.         pDict->close();
  18.  
  19.         while(!pI->done())
  20.         {
  21.                 WritePrivateProfileString(_T("DWF6Sheet:")+file_name+_T("-")+pI->name(),_T("DWG"),full_file_path_name,dsd);
  22.                 WritePrivateProfileString(_T("DWF6Sheet:")+file_name+_T("-")+pI->name(),_T("Layout"),pI->name(),dsd);
  23.                 pI->next();
  24.         }
  25.         delete pI;
  26.                
  27.         full_file_path_name.Replace(_T("dsd"),_T("dwf"));
  28.         WritePrivateProfileString(_T("Target"),_T("type"),_T("1"),dsd);
  29.         WritePrivateProfileString(_T("Target"),_T("DWF"),full_file_path_name,dsd);
  30.         WritePrivateProfileString(_T("Target"),_T("OUT"),full_file_path_name.Mid(0,ph.ReverseFind(_T('\\'))),dsd);
  31.  
  32.         struct resbuf vl_new;
  33.         vl_new.restype = RTSHORT;
  34.         int chk = 0;
  35.         vl_new.resval.rint = 0;
  36.         chk = acedSetVar(_T("backgroundplot"),&vl_new);
  37.         AcPlDSDData dsdDataObj;                        
  38.         dsdDataObj.readDSD(dsd);
  39.         dsdDataObj.setPromptForDwfName(FALSE);
  40.         DeleteFile(dsdDataObj.destinationName());
  41.        AcPlPlotConfig* pConfig = NULL;        
  42.        bool bShowPlotProgress = true;
  43.  
  44.        acedArxLoad(_T("AcPublish.arx")); //У меня вынесен в On_kInitAppMsg
  45.        acplPublishExecute( dsdDataObj, pConfig, bShowPlotProgress );
  46.  
  47.  
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 13:13:54
Так как вообсе от DSD отказатся не получиается, измемений не вносил.
Это в .NET не получается, т.к. в нём приходится менять "PromptForDwfName=TRUE" на "PromptForDwfName=FALSE", но ты можешь использовать dsdDataObj.setPromptForDwfName(FALSE); и тогда файл не нужен.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 13:27:19
Точно,
пробежал глазами до dsdData.ReadDsd(dsdFile);
и подумал что все равно в фаил записывается.
Сейчас попробую поправить.
Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: Александр Ривилис от 22-07-2014, 13:31:16
Кстати, пользуйся пожалуйста таким форматированием кода на форуме, а то я уже устал править:

(https://adn-cis.org/forum/proxy.php?request=http%3A%2F%2Fimg-fotki.yandex.ru%2Fget%2F6835%2F7842324.1%2F0_dfd09_10e1e1de_orig.png&hash=8fea8bc006f46b72bd503a43ea42be7c)

Название: Re: -PUBLISH через acedCommandC или acedCommandS в 2015
Отправлено: begiz от 22-07-2014, 14:54:15
А я то думаю чего это у меня фортамирование прыгает :)
Виноват, исправляюсь.
Обновленный рабочий код, без DSD.

Код - C++ [Выбрать]
  1.         AcDbObjectId objDictId = acdbHostApplicationServices()->workingDatabase()->layoutDictionaryId();
  2.         AcDbDictionary *pDict;
  3.         acdbOpenObject(pDict, objDictId, AcDb::kForRead);
  4.         AcDbDictionaryIterator *pI = pDict->newIterator();
  5.         pDict->close();
  6.  
  7.         AcPlDSDEntries entries;
  8.  
  9.         while(!pI->done())
  10.         {
  11.                 AcPlDSDEntry dsd_entry;
  12.                 dsd_entry.setDwgName(filename_2);
  13.                 dsd_entry.setLayout(pI->name());
  14.                 entries.append(dsd_entry);
  15.                 pI->next();
  16.         }
  17.         delete pI;
  18.  
  19.         AcPlDSDData dsdDataObj;
  20.         dsdDataObj.setSheetType(AcPlDSDEntry::SheetType::kMultiDWF);
  21.         dsdDataObj.setProjectPath(filename_2);
  22.         dsdDataObj.setDestinationName(ph);
  23.         dsdDataObj.setDSDEntries(entries);
  24.         dsdDataObj.setPromptForDwfName(FALSE);
  25.         DeleteFile(dsdDataObj.destinationName());
  26.                
  27.         struct resbuf vl_new;
  28.         vl_new.restype = RTSHORT;
  29.         vl_new.resval.rint = 0;
  30.         acedSetVar(_T("backgroundplot"),&vl_new);
  31.                                
  32.     AcPlPlotConfig* pConfig = NULL;        
  33.     bool bShowPlotProgress = true;
  34.         acplPublishExecute( dsdDataObj, pConfig, bShowPlotProgress );
  35.