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

23/07/2015

Удаление меню из строки меню и из памяти

Вопрос:
Моё приложение создаёт меню и добавляет его используя IAcadPopupMenus.Add. Удаление его позднее при помощи RemoveMenuFromMenuBar или IAcadPopupMenu.RemoveFromMenuBar работает, но повторная попытка добавить тоже самое меню терпит неудачу. Почему и как это исправить?

Ответ:
Хотя пользовательское меню может быть удалено из строки меню после добавления, меню остаётся в памяти AutoCAD. Это можно проверить если сравнить значения IAcadPopupMenus.GetCount() до и после удаления меню – значение останется тем же, так как меню остаётся внутри коллекции меню. Пожалуйста проверьте демонстрационный код ниже: он добавляет 3 меню в первую группу меню. Запустите снова и код удалит одно меню, и сравните счетчик меню до и после удаления.

Если меню добавлено таким способом оно остаётся в памяти до конца сессии AutoCAD. Любые меню, которые были добавлены, остаются до конца сессии. Любое меню, которое уже было добавлено в течение сессии AutoCAD может быть повторно вставлено в строку меню. Метод Add не следует вызвать повторно, так как при этом программа может завершиться аварийно.

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

Хотя вы, возможно, сможете избежать этой проблемы путем перебора меню для проверки меню, которое имеет имя вашего меню. Если нашли, то не вызывайте  Add, а вместо этого, получив указатель на существующее меню используйте InsertMenuInMenuBar(). Но к сожалению, это тоже приводит к аварийному завершению, так как указатели на меню недоступны.

В этом случае создавайте свои меню в своей собственной группе меню, которая полностью выгружается при выгрузке приложения в UnLoad().

Код - C++: [Выделить]
  1. // Разрешаем меню загружаться/выгружаться в одной команде.
  2. static bool bIsMenuLoaded = false;
  3. void demo()
  4. {
  5.     AutoCAD::IAcadApplication *pAcad;
  6.     AutoCAD::IAcadMenuBar *pMenuBar;
  7.     AutoCAD::IAcadMenuGroups *pMenuGroups;
  8.     AutoCAD::IAcadMenuGroup *pMenuGroup;
  9.     AutoCAD::IAcadPopupMenus *pPopUpMenus;
  10.     AutoCAD::IAcadPopupMenu *pPopUpMenu;
  11.     AutoCAD::IAcadPopupMenuItem *pPopUpMenuItem;
  12.  
  13.     HRESULT hr = NOERROR;
  14.     LPUNKNOWN pUnk = NULL;
  15.     LPDISPATCH pAcadDisp = acedGetIDispatch(TRUE);
  16.     if(pAcadDisp==NULL)
  17.         return;
  18.  
  19.     hr = pAcadDisp->QueryInterface(AutoCAD::IID_IAcadApplication,(void**)&pAcad);
  20.     pAcadDisp->Release();
  21.     if (FAILED(hr))
  22.         return;
  23.  
  24.     pAcad->put_Visible(true);
  25.     pAcad->get_MenuBar(&pMenuBar);
  26.     pAcad->get_MenuGroups(&pMenuGroups);
  27.     pAcad->Release();
  28.     long numberOfMenus;
  29.     pMenuBar->get_Count(&numberOfMenus);
  30.     pMenuBar->Release();
  31.  
  32.     VARIANT index;
  33.     VariantInit(&index);
  34.     V_VT(&index) = VT_I4;
  35.     V_I4(&index) = 0;
  36.  
  37.     pMenuGroups->Item(index, &pMenuGroup);
  38.     pMenuGroups->Release();
  39.  
  40.     pMenuGroup->get_Menus(&pPopUpMenus);
  41.     pMenuGroup->Release();
  42.  
  43.  
  44.    if (!bIsMenuLoaded) {       
  45.         // Добавляем три меню
  46.         HRESULT hr = pPopUpMenus->Add(
  47.             _T("myDemoMenu1"), &pPopUpMenu);
  48.         hr = pPopUpMenus->Add(
  49.             _T("myDemoMenu2"), &pPopUpMenu);
  50.         hr = pPopUpMenus->Add(
  51.            _T("myDemoMenu3"), &pPopUpMenu);
  52.  
  53.         if (hr == S_OK) {
  54.             acutPrintf(_T("\nМеню создано."));
  55.  
  56.         } else {
  57.             acutPrintf(_T("\nМеню не создано."));
  58.         }
  59.          bIsMenuLoaded = true;
  60.     }
  61.     else // Удаляем меню
  62.     {       
  63.        long count = 0;
  64.         pPopUpMenus->get_Count(&count);
  65.         acutPrintf(_T("\n Счетчик до удаления: %d"),count) ;
  66.  
  67.         long indexOfMyMenu = -1;
  68.         AutoCAD::IAcadPopupMenu* eachMenu = NULL;
  69.         for (long i=0; i< count; i++)
  70.         {
  71.           BSTR np;
  72.           pPopUpMenus->Item(_variant_t(i),&eachMenu);
  73.           eachMenu->get_Name(&np);
  74.           // Удаляем первое меню в группе
  75.           if (_tcscmp(np, _T("myDemoMenu1"))==0)
  76.           {
  77.               indexOfMyMenu = i;
  78.               break;
  79.           }
  80.         }
  81.  
  82.         // Удаляем
  83.         if(indexOfMyMenu > -1)
  84.         {
  85.             HRESULT hr = pPopUpMenus->RemoveMenuFromMenuBar(_variant_t(indexOfMyMenu));
  86.             assert (hr == S_OK);
  87.         }
  88.          pPopUpMenus->get_Count(&count);
  89.          // Снова пересчитываем после удаления.
  90.         acutPrintf(_T("\n Счетчик после удаления: %d"),count) ;
  91.          bIsMenuLoaded = false;
  92.     }
  93.  
  94.     pPopUpMenus->Release();
  95. }

 

Источник: http://adndevblog.typepad.com/autocad/2013/02/remove-a-menu-from-the-menubar-_and_-memory.html

Автор перевода: Александр Ривилис

Обсуждение: http://adn-cis.org/forum/index.php?topic=2874

Опубликовано 23.07.2015
Отредактировано 24.07.2015 в 19:57:13