Тема: Принудительное закрытие документа

Функция acDocManager->closeDocument(pActiveDoc); не закрывает документ сразу, а ждет пока будет произведен выход из контекста приложения. Подскажите как принудительно закрыть документ, чтобы знать то место в коде, где документ уже точно выгружен.

Re: Принудительное закрытие документа

S P пишет:

а ждет пока будет произведен выход из контекста приложения

Контекста приложения или контекста документа? Пытаешься закрыть активный документ? Попробуй через ActiveX

Re: Принудительное закрытие документа

Александр Ривилис пишет:
S P пишет:

а ждет пока будет произведен выход из контекста приложения

Контекста приложения или контекста документа? Пытаешься закрыть активный документ? Попробуй через ActiveX

Спасибо. А где поподробнее почитать про контексты - какой раздел документации?

Re: Принудительное закрытие документа

А где поподробнее почитать про контексты - какой раздел документации?

А это очень мутная тема. Автодеск не счел нужным в доступной для понимания форме рассказать о том, где и какие потоки (то ли потоки [thread], а то ли нити [fiber]) начинаются и заканчиваются и как между собой взаимодействуют. Так, чтоб наглядно (с картинками), раз и навсегда расставить точки в этом вопросе.

Re: Принудительное закрытие документа

Товарищи, что то я не могу все равно разобраться с контекстами AutoCAD. Решение из поста по ссылке Александра Ривилиса (выше) все таки не является панацеей.

Предположим, есть такая функция:

void closeActiveDocument(void)
{
   CComPtr<IDispatch> pDisp = acedGetIDispatch(TRUE);
   CComPtr<IAcadApplication> pComApp;
   HRESULT hr = pDisp->QueryInterface(__uuidof(IAcadApplication),(void**)&pComApp);
   CComPtr<IAcadDocument> pComDoc;
   hr = pComApp->get_ActiveDocument(&pComDoc);
   hr = pComDoc->Close();
}

Если функция вызывается из контекста приложения, то все Ok и документ закроется. Если же имеем контекст документа, то в последнем вызове
hr = pComDoc->Close();
получим hr = 0x8021006f, т.е. не S_OK. Типа "drawing is busy", судя по вот  ЭТОМУ посту. Надо во что бы то ни стало использовать 'Application Context'.

Тогда делаем функцию 'closeActiveDocument' вот так:

void closeInApplicationContext(void *pData)
{
   CComPtr<IDispatch> pDisp = acedGetIDispatch(TRUE);
   CComPtr<IAcadApplication> pComApp;
   HRESULT hr = pDisp->QueryInterface(__uuidof(IAcadApplication),(void**)&pComApp);
   CComPtr<IAcadDocument> pComDoc;
   hr = pComApp->get_ActiveDocument(&pComDoc);
   hr = pComDoc->Close();
}

void closeActiveDocument(void)
{
   void *pData;
   acDocManager->executeInApplicationContext(closeInApplicationContext, pData);
}

Но все равно получаем тот же код ошибки и документ не закрывается!!!

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

Re: Принудительное закрытие документа

S P пишет:

прям пляски с бубном и все ради обыкновенного закрытия документа.

Попытка закрыть активный документ из контекста этого же документа - это тоже самое, что рубить сук, на котром сидишь.

(изменено: S P, 25 августа 2011г. 04:48:13)

Re: Принудительное закрытие документа

Александр Ривилис пишет:
S P пишет:

прям пляски с бубном и все ради обыкновенного закрытия документа.

Попытка закрыть активный документ из контекста этого же документа - это тоже самое, что рубить сук, на котром сидишь.

Ну а если мне НЕОБХОДИМО закрыть этот активный документ. AutoCAD самостоятельно переключает эти контексты и как я понял "это мутная тема", КАК он это делает. Как я могу "покинуть" контекст документа, как "пересесть" на другой сук то? Почему я назвал все это "плясками с бубном" - просто я работал и с другими CAD-системами (Solid, Inventor) - там управление документами куда как прозрачнее, а ведь это системы твердотельного моделирования, там ведь сборки со структурой изделия и много еще чего. Не суть.

В общем, в том и вопрос, как "грамотно" переключаться в нужный контекст? Александр, так я правильно понимаю, что использование AcApDocManagerReactor::documentDestroyed( ) отсюда единственное адекватное решение?

Re: Принудительное закрытие документа

Почему ты не можешь работать из контекста приложения? И вообще опиши задачу подробнее. Наверняка есть другое решение.

Re: Принудительное закрытие документа

может пригодится:
внутри класса в acrxentrypoint.cpp добавляешь функцию

static void arxProjectmy_closedoc(void)
{
  acDocManager->curDocument()->database()->disableUndoRecording(Adesk::kTrue); // убираем запрос на сохранение документа
  acDocManager->curDocument()->pushDbmod();
  ads_queueexpr(_T("(COMMAND \"_CLOSE\")\n"));
}

перед классом не забудь:

extern "C" int ads_queueexpr(ACHAR *);

ну и в любой функции любого класса (да вообще где угодно :) ):

ads_queueexpr(_T("(COMMAND \"MY_CLOSEDOC\")\n"));// закрываем чертеж, т.к. он корявый

PS: по поводу ограничений, ads_queueexpr работает из контекста приложения. если по-простому, то команда my_closedoc вызовется только после того, как отработает вся arx-функция, следовательно, чтоб не отрабатывал код, если это не нужно, выходи из функции, например, так

void arx-команда()
{
  // проверка на необходимость закрытия документа
  ...
  if (закрыть текущий документ)
  {
    ads_queueexpr(_T("(COMMAND \"MY_CLOSEDOC\")\n"));
    return;
  }
  // продолжается команда
  ...
}

Re: Принудительное закрытие документа

Задача в общих чертах следующая:
    1. Есть AutoCAD с ARX-приложением внутри
    2. Есть сторонняя система, которая может обрабатывать документы AutoCAD(сохранять внутрь себя, выгружать из себя и т.д.). Система имеет набор интерфейсных функций(через IDispatch) для осуществления этих операций.

Предположим, что я хочу выгрузить документ из сторонней системы с помощью соответствующей интерфейсной функции. Но эта функция не сможет выгрузить документ, если он, например, был выгружен ранее и открыт в данный момент в AutoCAD.
Поэтому предпринимается такой порядок действий:
    1. Проверяется наличие документа в каталоге выгрузки
    2. Если да, то проверяется, открыт ли данный документ в AutoCAD
    3. Если да, то его необходимо закрыть
    4. Документ(если он есть) удаляется
    5. Вызывается функция выгрузки
    6. Открывается только что выгруженный документ

Аналогично может быть описано помещение документа из AutoCAD в стороннюю систему - тоже документ сначала надо закрыть, потом поместить, потом заново открыть.   

Таким образом в ARX-приложении я имею несколько функций типа OpenFromExternal, SaveToExternal, которые привязаны, например, к элементам интерфейса через зарегестрированные пользовательские команды. Ну это не так важно.

Так вот я бы и рад работать из контекста приложения. Меня он устраивает smile Но AutoCAD против sad Он за меня решает в каком контексте мне работать. В одной функции, скажем SaveToExternal проверка
acDocManager->isApplicationContext() дает true, а скажем в  OpenFromExternal - false. Почему так - я не понимаю.

Что влияет на переключения контекста - какие действия с моей стороны?

Re: Принудительное закрытие документа

Таким образом в ARX-приложении я имею несколько функций типа OpenFromExternal, SaveToExternal, которые привязаны, например, к элементам интерфейса через зарегестрированные пользовательские команды. Ну это не так важно.

вот как раз это и важно. я так понимаю, есть окно с кучей кнопочек. и окно это модальное. в данном случае ничего у тебя не выйдет (сам на это натыкался)!!! окно должно быть немодальным (желательно глобальная переменная этого окна, которая определяется в классе (например, в момент загрузки arx), и по командам это окно меняет видимость. ну и не забываем убивать его при выгрузке arx, а то автокад начнет бунтовать, тогда можно смело работать через контекст приложения.)
Кстати, что по поводу моего кода? Это как раз второй вариант. ток это самое модальное окно должно убиваться, т.к. код дальше не пойдет из-за фокуса окна

(изменено: Александр Ривилис, 25 августа 2011г. 11:57:08)

Re: Принудительное закрытие документа

S P пишет:

2. Если да, то проверяется, открыт ли данный документ в AutoCAD
3. Если да, то его необходимо закрыть

А если в этот момент с ним работает пользователь и ты его принудительно закрываешь? Может корректнее сообщить об этой проблеме пользователю и попросить его закрыть?

S P пишет:

В одной функции, скажем SaveToExternal проверка acDocManager->isApplicationContext() дает true, а скажем в OpenFromExternal - false. Почему так - я не понимаю.


Тут не понятно откуда ты вызываешь эти функции. Вообще-то контекст документа должен быть только если ты определил команду без флага ACRX_CMD_SESSION и вызываешь свою функцию из неё. Во всех других случаях - контекст приложения.

(изменено: S P, 25 августа 2011г. 13:44:46)

Re: Принудительное закрытие документа

Николай пишет:

вот как раз это и важно. я так понимаю, есть окно с кучей кнопочек. и окно это модальное

Нет не так. Эти кнопки размещены на обычной панели инструментов, созданной через AutoCAD COM API.

Александр Ривилис пишет:
S P пишет:

2. Если да, то проверяется, открыт ли данный документ в AutoCAD

3. Если да, то его необходимо закрыть

А если в этот момент с ним работает пользователь и ты его принудительно закрываешь? Может корректнее сообщить об этой проблеме пользователю и попросить его закрыть?

Ну так это ведь сам пользователь инициирует выгрузку по новой - т.е. у меня конечно выводится предупреждение о том, что документ уже открыт и есть возможность либо отказаться, либо продолжить выгрузку по новой, если пользователь считает, что серьезно напортачил а изменения необратимы.


Александр Ривилис пишет:
S P пишет:

В одной функции, скажем SaveToExternal проверка acDocManager->isApplicationContext() дает true, а скажем в OpenFromExternal - false. Почему так - я не понимаю.

Тут не понятно откуда ты вызываешь эти функции. Вообще-то контекст документа должен быть только если ты определил команду без флага ACRX_CMD_SESSION и вызываешь свою функцию из неё. Во всех других случаях - контекст приложения.

Александр,большое спасибо! У меня флаг ACRX_CMD_SESSION не был установлен при регистрации команд. Теперь все заработало нормально.

Николай, спасибо также!