Тема: Программная загрузка *.mns
Как можно программно выполнять загрузку панели инструментов из *.mns файла при загрузке ARX?
И аналогично, убирать, при выгрузке?
Информационный портал для профессионалов в области САПР
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Форумы CADUser → Программирование → ObjectARX → Программная загрузка *.mns
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Как можно программно выполнять загрузку панели инструментов из *.mns файла при загрузке ARX?
И аналогично, убирать, при выгрузке?
t_errno MenuLoader::loadMenu()
{
if ( acDocManager->documentCount() >= 1 ) {
CString MenuFileName = "MNUNAME.MNU", GroupName = "GROUP_NAME_FROM_MNU_FILE_HERE";
//----------------------------------------------------------
// Other (throw cleary com) implementation
AutoCAD::IAcadApplication * pAcad;
AutoCAD::IAcadMenuBar * pMenuBar;
AutoCAD::IAcadMenuGroups * pMenuGroups;
AutoCAD::IAcadMenuGroup * pMenuGroup;
AutoCAD::IAcadPopupMenus * pPopUpMenus;
AutoCAD::IAcadPopupMenu * pPopUpMenu;
HRESULT hr = NOERROR;
LPUNKNOWN pUnk = NULL;
LPDISPATCH pAcadDisp = NULL;
pAcadDisp = acedGetAcadWinApp()->GetIDispatch(TRUE);
// Use IUnknown to get the AutoCAD application object.
hr = pAcadDisp->QueryInterface(AutoCAD::IID_IAcadApplication,(void**)&pAcad);
pAcadDisp->Release();
if (FAILED(hr)) return ErCode::eFAIL;
// Make sure AutoCAD is visible.
pAcad->put_Visible(true);
// Get the menu bar and menu groups collections
pAcad->get_MenuBar(&pMenuBar);
pAcad->get_MenuGroups(&pMenuGroups);
pAcad->Release();
// Determine how many menus are current on the menu bar.
long numberOfMenus;
pMenuBar->get_Count(&numberOfMenus);
pMenuBar->Release();
// Determine is menu already loaded
bool bIsMenuLoaded = false;
CString mnuPath = pGlobVars->getMenuPath();
for(long i = 0; i < numberOfMenus; i++)
{
_variant_t index = i;
pMenuGroups->Item(index, &pMenuGroup);
BSTR menu_name;
pMenuGroup->get_Name(&menu_name);
if(menu_name == GroupName)
{
bIsMenuLoaded = true;
break;
}
pMenuGroup->Release();
}
// If menu is not loaded then load it.
if(!bIsMenuLoaded)
{
_bstr_t path = mnuPath + MenuFileName;
pMenuGroups->Load(path, _variant_t(false), &pMenuGroup);
pMenuGroup->get_Menus(&pPopUpMenus);
pMenuGroup->Release();
long numOfPops = 0;
pPopUpMenus->get_Count(&numOfPops);
for ( int i = 0; i < numOfPops; i++ )
{
_variant_t popUpNum;
popUpNum = (long)i;
pPopUpMenus->Item(popUpNum, &pPopUpMenu);
pPopUpMenu->InsertInMenuBar(_variant_t(numberOfMenus+(long)i-2L));
pPopUpMenu->Release();
}
pPopUpMenus->Release();
}
pMenuGroups->Release();
//----------------------------------------------------------
}
return ErCode::sOK;
}
t_errno MenuLoader::unloadMenu()
{
CString GroupName = "GROUP_NAME_FROM_MNU_FILE_HERE";
AutoCAD::IAcadApplication * pAcad;
AutoCAD::IAcadMenuBar * pMenuBar;
AutoCAD::IAcadMenuGroups * pMenuGroups;
AutoCAD::IAcadMenuGroup * pMenuGroup;
HRESULT hr = NOERROR;
LPUNKNOWN pUnk = NULL;
LPDISPATCH pAcadDisp = NULL;
pAcadDisp = acedGetAcadWinApp()->GetIDispatch(TRUE);
// Use IUnknown to get the AutoCAD application object.
hr = pAcadDisp->QueryInterface(AutoCAD::IID_IAcadApplication,(void**)&pAcad);
pAcadDisp->Release();
if (FAILED(hr)) return ErCode::eFAIL;
// Get the menu bar and menu groups collections
hr = pAcad->get_MenuBar(&pMenuBar);
if (FAILED(hr)) return ErCode::eFAIL;
hr = pAcad->get_MenuGroups(&pMenuGroups);
if (FAILED(hr)) return ErCode::eFAIL;
pAcad->Release();
// Determine how many menus are current on the menu bar.
long numberOfMenus;
pMenuBar->get_Count(&numberOfMenus);
pMenuBar->Release();
for(long i = 0; i < numberOfMenus; i++)
{
_variant_t index = i;
pMenuGroups->Item(index, &pMenuGroup);
BSTR menu_name;
pMenuGroup->get_Name(&menu_name);
if(GroupName == menu_name)
{
pMenuGroup->Unload();
break;
}
pMenuGroup->Release();
}
pMenuGroups->Release();
return ErCode::sOK;
}
Выгружаю меню по событию beginQuit или отслеживаю когда закрывается последний документ. т.е. если приходит событие в реакторе, что документ закрывается и кол-во документов равно 1, то зову unloadMenu.
Еще тонкий момент - в 2002-м событие beginQuit приходит до закрытия всех документов, а в 2004(5) после. (Про что я сильно ругался где-то ранее). Поэтому и приходится отслеживать либо закрытие последнего документа, либо сообытие о выходе - что раньше произойдет.
Но после закрытия последнего документа может наступить открытие еще нескольких. А менюшки уже не будет :( И что делать бедным пользователям?
> ROMA
Загрузить его (программно) в реакторе AcApDocManagerReactor::documentActivated(), если меню еще не было загружено. Так что пользователям ничего делать будет не нужно! :)
Кстати, начиная с AutoCAD 2000 есть недокументированная функция, экспортируемая из acad.exe и присутствующая в acad.lib:
bool __cdecl AcadIsQuitting(void);
С ее помощью в момент закрытия последнего документа можно определить закрывается ли при этом и сам AutoCAD.
При использовании этой функции в 2002 CAD все работает как и ожидалось, но в 2005 эта функция всегда возвращает false.
В чем может быть дела?
Вызов функции помещен в методы documentToBeDestroyed
documentDestroyed
> ROMA
На то она и недокументированная...
Есть еще один вариант:
static bool isMenuUnloaded = false; // Здесь свое имя меню static char sMenuName[]="MyMenuName"; // ----------------------------------------------------------------------------- void QuitingReactor::documentLockModeChanged( AcApDocument * param2, AcAp::DocLockMode myPreviousMode, AcAp::DocLockMode myCurrentMode, AcAp::DocLockMode currentMode, const char * pGlobalCmdName) { char sRealGlobalName[256]; if (*pGlobalCmdName == '#') strcpy(sRealGlobalName,pGlobalCmdName+1); else strcpy(sRealGlobalName,pGlobalCmdName); if (!isMenuUnloaded) { if (!stricmp(sRealGlobalName,"QUIT") || !stricmp(sRealGlobalName,"EXIT")) { veto(); // Запрещаем выполнение команды char cmd[1024]; sprintf(cmd,"(command \"_.menuunload\" \"%s\") ",sMenuName); isMenuUnloaded = true; acDocManagerPtr()->sendStringToExecute(curDoc(),cmd,true,false,false); sprintf(cmd,"_.%s ",sRealGlobalName); acDocManagerPtr()->sendStringToExecute(curDoc(),cmd,true,false,false); } } AcApDocManagerReactor::documentLockModeChanged (param2, myPreviousMode, myCurrentMode, currentMode, pGlobalCmdName) ; }
Увы, но это тоже не идеальный вариант... Если был хотя бы один несохраненный чертеж, то пользователь может отказаться от завершения работы AutoCAD, а меню уже выгружено. Так что или нужно принудительно сохранять все чертежи или наоборот сбрасывать у них DBMOD и они не будут сохранены...
А есть еще решения?
Как все таки убирать за собой? меню и toolbar?
Помогите разобраться
Нужно подключить меню при загрузке AutoCAD
Попробовал подключить меню, как советовал KonstantinM в начале темы.
Не получается получить интерфейсы COM
Выводится сообщение “'AutoCAD' : is not a class or namespace name” или “IID_IAcadApplication' : is not a member of 'AutoCAD”
Подскажите, что делаю неправильно
Делаю как указано в справочной системе по разделу “COM, importing ActiveX interfaces”, (правда с некоторыми отклонениями - там не говорится, что нужно создавать проект с поддержкой COM. И поскольку Wizard сам генерирует часть кода, некоторые части я пропускал, поскольку код уже присутствует).
1. Создаю новый проект с поддержкой MFC и COM
2.Добавляю в проект библиотеки
acad.lib
acdb16.lib
rxapi.lib
acedapi.lib
3. Создаю новый CPP файл, в котором создаю функцию
void AddMenu(void) { AutoCAD::IAcadApplication *pAcad; AutoCAD::IAcadMenuBar *pMenuBar; AutoCAD::IAcadMenuGroups *pMenuGroups; AutoCAD::IAcadMenuGroup *pMenuGroup; AutoCAD::IAcadPopupMenus *pPopUpMenus; AutoCAD::IAcadPopupMenu *pPopUpMenu; AutoCAD::IAcadPopupMenuItem *pPopUpMenuItem; HRESULT hr = NOERROR; CLSID clsid; LPUNKNOWN pUnk = NULL; LPDISPATCH pAcadDisp = NULL; hr = ::CLSIDFromProgID(L"AutoCAD.Application", &clsid); if (FAILED(hr)) return; if(::GetActiveObject(clsid, NULL, &pUnk) != S_OK) return; hr = pUnk->QueryInterface(IID_IDispatch, (LPVOID*) &pAcadDisp); pUnk->Release(); if (FAILED(hr)) return; hr = pAcadDisp->QueryInterface([b]AutoCAD::IID_IAcadApplication [/b], (void**)&pAcad); pAcadDisp->Release(); if (FAILED(hr)) return; pAcad->put_Visible(true); };
Компилятор выводит ошибку
error C2653: 'AutoCAD' : is not a class or namespace name
Если в файле StdAfx.h, в строке, созданной генератором
#import "acax16enu.tlb" raw_interfaces_only no_namespace
удалить часть строки - “no_namespace” – выводится сообщение
error C2039: 'IID_IAcadApplication' : is not a member of 'AutoCAD'
Что нужно сделать, чтобы видеть идентификатор 'IID_IAcadApplication' ?
> Ura
Или вместо:
#import "acax16enu.tlb" raw_interfaces_only no_namespace
использовать:
#import "acax16enu.tlb"
Или убрать пространство имен (namespace) AutoCAD у всех переменных (т.е. вместо AutoCAD::IID_IAcadApplication писать IID_IAcadApplication и т.д.)
Спасибо Александр, за помощь. Получилось.
Компилируется нормально.
Правда не все понятно.
Попробовал оставить только
#import "acax16enu.tlb"
Выводится сообщение об ошибке
error C2039: 'IID_IAcadApplication' : is not a member of 'AutoCAD'
Если оставить
#import "acax16enu.tlb" raw_interfaces_only no_namespace
и убрать пространство имен AutoCAD
Выводится сообщение об ошибке
error C2371: 'AcadSecurityParamsType' : redefinition; different basic types’
и так по всем функциям “acax16enu.tlb”
Попробовал заменить на строку из примера samples\com\AsdkPlainComSamp_dg\ AsdkPlainComDocSamp.cpp (из которого и был взят фрагмент функции)
#import "acax16enu.tlb" no_implementation raw_interfaces_only named_guids
Все заработало. Компилируется без ошибок
Если изменить “named_guids” на любое другое значение, например на “named”, начинается все по новой.
‘warning C4185: ignoring unknown #import attribute 'named'
Возможно потому и сработало, что весь код взят из одного примера, в котором забито конкретное пространство имен? Возможно этим можно объяснить, почему Твои рекомендации не подошли на 100%. Но ссылки на named_guids нигде нет, по крайней мере я не нашел. Странно все это.
И тут еще вопрос, на что влияет “named_guids”? Если я создам еще одну программу с тем же именем, не будут ли они конфликтовать? Или это действует только в пределах одной программы на этапе компиляции?
Хотелось бы узнать, что эти ключи означают, и где можно определить пространство имен. Нигде в справке описания не нашел.
> Ura
Прочитай в описание директивы #import в по MS VS Help. Там описано что такое named_guids.
> Александр Ривилис
Спасибо.
Теперь все понятно.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Форумы CADUser → Программирование → ObjectARX → Программная загрузка *.mns
Форум работает на PunBB, при поддержке Informer Technologies, Inc