Поделиться через


TN041. Миграция MFC/OLE1 на MFC/OLE 2

Примечание

Следующее техническое примечание не было обновлено, поскольку сначала оно было включено в электронную документацию.В результате некоторые процедуры и разделы могут быть устаревшими или неверными.Для получения последних сведений рекомендуется выполнить поиск интересующей темы в алфавитном указателе документации в Интернете.

Общие проблемы, относящиеся к миграции

Одной из целей разработки за 2 OLE класса в MFC (2.5 и выше), сохранение многие из одной архитектуры положенной на месте в MFC 2.0 для поддержки OLE 1.0. В результате многие класс OLE в MFC 2.0 все еще существуют в данной версии MFC (COleDocument, COleServerDoc, COleClientItem, COleServerItem). Кроме того, многие API в этих классах одинаковым. Однако OLE отличается от 2 drastically OLE 1.0, поэтому следует ожидает, что некоторые сведения были изменены. Если вы знакомы с поддержкой OLE1 MFC 2.0, будет заполнение дома с поддержкой MFC 2.0.

При использовании существующего приложения MFC/OLE1 и добавить функцию OLE 2 на нее, прочтите эту заметку в первую очередь. Эта заметка рассматриваются некоторые общие проблемы, которые могут возникнуть при переносящ ваша функция OLE1 в MFC/OLE 2 и затем рассматриваются расчехленные проблемы при переносящ 2 приложения включенного в MFC 2.0: примеры MFC OLE OCLIENT и HIERSVR.

Архитектура документов и представлений MFC важны

Если приложение не используется архитектура документов и представлений MFC и необходимо добавить поддержку OLE 2 в приложение, теперь время перемещения в документ/представление. Многие преимущества OLE MFC 2 класса реализуются только после того, как приложение использует встроенные компоненты архитектуры и MFC.

Реализация сервера или контейнер без использования архитектуры MFC возможно, но не рекомендуется.

Используйте реализацию MFC вместо.

«Класс» законсервированной реализации» MFC, например CToolBar, CStatusBar и CScrollView предусмотрены встроенные код отдельного экземпляра для поддержки OLE 2. Таким образом, если можно использовать в приложении, необходимо извлечь переводится в свои усилия, чтобы сделать их поддержку OLE. Опять же, например в «крен-ваш- собственным класс» здесь же в этих целях, но не предложено. Если требуется предоставить аналогичную функциональность, исходный код MFC превосходная ссылку работы с некоторыми из более точные точек OLE (особенно когда возможности для в встроенной активацией).

См. пример кода MFC

Несколько примеров MFC OLE, включающие функции. Каждое из этих приложений реализует OLE из другого угла.

  • HIERSVR   Значенный главным образом для использования в качестве серверное приложение. Он был включен в MFC 2.0 как приложение MFC/OLE1 и был перенесен на MFC/OLE 2 и затем расширил таким образом, чтобы она реализует множество OLE функции, доступные в OLE 2.

  • OCLIENT   Это изолированный контейнерное приложение, значенные, что продемонстрировало многие OLE функций с точки зрения контейнера. Оно слишком был перенесен на основе MFC 2.0, а затем был расширен для поддержки многие OLE более сложных функций (например, пользовательские форматы буфера обмена и ссылки на встроенным элементам.

  • DRAWCLI   Это приложение реализует поддержку OLE-контейнер подобно OCLIENT делает, но сделать в пределах структуры существующей объектно-ориентированной программы рисования. Он показывает, как можно реализовать поддержку OLE-контейнер и интегрировать ее в существующие приложения.

  • SUPERPAD   Это приложение, а также было явно отдельным приложением, также OLE-сервер. Поддержка сервера она реализует довольно минималиста. Особое интереса, он использует OLE службы буфера обмена, чтобы копировать данные в буфер обмена, но использует функцию построения в элемент управления «правки» Windows для реализации функциональности вставлять буфера обмена. Это указывает интересный набор традиционных потребления, так и интеграции API Windows с новыми API OLE.

Дополнительные сведения о примерах приложений см. в разделе «пример» раздела MFC.

Определенное исследование: OCLIENT на основе MFC 2.0

, Как описано выше, OCLIENT были включены в MFC OLE, начиная с 2.0 и MFC/OLE1. Действия, это приложение первоначальной преобразуется использовать классы MFC/OLE 2 описаны ниже. Несколько функций, добавленные после начального порт завершен, чтобы проиллюстрировать классы MFC/OLE. Эти функции не будут рассмотрены далее; см. пример сам дополнительные сведения об этих дополнительных функций.

Примечание

Ошибки компилятора и пошаговый процесс созданные с Visual C++ 2.0 C.Некоторые сообщения об ошибках и расположения могут изменять C с Visual C++ 4.0, но основные сведения остаются допустимыми.

Получение его работу стало

Принято подход к порту образца OCLIENT в MFC/OLE начать с ее построение и требует очевидные ошибки компилятора, которые приведут к. Если берете образец OCLIENT на основе MFC 2.0 и компилировать его под этой версией MFC, вы обнаружите, что нет, что множество ошибок для разрешения. Ошибки в том порядке, в котором они происходили описаны ниже.

Компилировать и устраните ошибки

\oclient\mainview.cpp(104) : error C2660: 'Draw' : function does not take 4 parameters

Первая ошибка относится COleClientItem::Draw. В MFC/OLE1 ее выполнения дополнительных параметров, чем версия MFC/OLE принимает. Дополнительные параметры не были часто являются обязательными и обычно NULL (как в этом примере). Эта версия MFC автоматически может указывать значения для lpWBounds при CDC, рисование в DC метафайлов. Кроме того, параметр pFormatDC больше не требуется, поскольку платформа построения одно из «DC атрибута» pDC переданного недопустимо. Чтобы решить эту проблему, просто удалите 2 дополнительных параметров NULL вызову рисования.

\oclient\mainview.cpp(273) : error C2065: 'OLE_MAXNAMESIZE' : undeclared identifier
\oclient\mainview.cpp(273) : error C2057: expected constant expression
\oclient\mainview.cpp(280) : error C2664: 'CreateLinkFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
\oclient\mainview.cpp(286) : error C2664: 'CreateFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '
\oclient\mainview.cpp(288) : error C2664: 'CreateStaticFromClipboard' : cannot convert parameter 1 from 'char [1]' to 'enum ::tagOLERENDER '

Ошибки над результатами из-за того, что все функции COleClientItem::CreateXXXX в MFC/OLE1 требуют, чтобы было передано уникальное имя для представления элемента. Это было требованием основного OLE API. Это не обязательно в MFC/OLE 2, поскольку 2 не использует OLE DDE как основной механизм взаимодействия (имя было использовано в сеансе DDE). Чтобы устранить эту проблему, можно удалить функцию CreateNewName, так и все ссылки на него. Легко определить, что каждая функция MFC/OLE ожидает в данной версии просто устанавливая курсор на вызове и клавишу F1.

Другая область, значительно другую обработку буфера обмена OLE 2. С OLE1, используется API буфера обмена Windows взаимодействие с буфером обмена. Это делается с OLE 2 с другим механизмом. API MFC/OLE1 высказывать буфер обмена были открыты перед копировать объект COleClientItem в буфер обмена. Это больше не требуется и приведет к все операции с буфером обмена MFC/OLE сбой. При редактировании кода, чтобы удалить зависимости от CreateNewName, также необходимо удалить код, который открывает и закрывает буфер обмена Windows.

\oclient\mainview.cpp(332) : error C2065: 'AfxOleInsertDialog' : undeclared identifier
\oclient\mainview.cpp(332) : error C2064: term does not evaluate to a function
\oclient\mainview.cpp(344) : error C2057: expected constant expression
\oclient\mainview.cpp(347) : error C2039: 'CreateNewObject' : is not a member of 'CRectItem'

Результат этих ошибок из обработчика CMainView::OnInsertObject. Обработка «команда вставки нового объекта» другая область действия, где были изменены, несколько. В этом случае проще всего просто слияние исходной реализация, то, AppWizard нового приложения OLE-контейнер. Фактически, это метод, который может применяется миграции другие приложения. В MFC/OLE1, указанной «диалогового окна» добавление объекта путем вызова функции AfxOleInsertDialog. В данной версии при создании объекта диалогового окна COleInsertObject и вызове DoModal. Кроме того, новый элемент OLE создаются с помощью CLSID вместо строки classname. Конечный результат должен выглядеть что-нибудь подобное

COleInsertDialog dlg;
if (dlg.DoModal() != IDOK)
    return;

BeginWaitCursor();

CRectItem* pItem = NULL;
TRY
{
    // First create the C++ object
    pItem = GetDocument()->CreateItem();
    ASSERT_VALID(pItem);

    // Initialize the item from the dialog data.
    if (!dlg.CreateItem(pItem))
        AfxThrowMemoryException();
           // any exception will do
    ASSERT_VALID(pItem);
        
    // run the object if appropriate
    if (dlg.GetSelectionType() == 
            COleInsertDialog::createNewItem)
        pItem->DoVerb(OLEIVERB_SHOW, this);
        
    // update right away
    pItem->UpdateLink();
    pItem->UpdateItemRectFromServer();
        
    // set selection to newly inserted item
    SetSelection(pItem);
    pItem->Invalidate();
}
CATCH (CException, e)
{  
    // clean up item
    if (pItem != NULL)
        GetDocument()->DeleteItem(pItem);
            
    AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
    
EndWaitCursor();

Примечание

Вставить новый объект может быть разным для приложения).

Также необходимо включить <afxodlgs.h>, содержащий объявление класса диалогового окна COleInsertObject, а также другими диалоговые окна, предоставляемые MFC.

\oclient\mainview.cpp(367) : error C2065: 'OLEVERB_PRIMARY' : undeclared identifier
\oclient\mainview.cpp(367) : error C2660: 'DoVerb' : function does not take 1 parameters

Эти ошибки, вызванные тем фактом константы некоторые изменения в OLE OLE1 2, даже если в сути они совпадают. В этом случае OLEVERB_PRIMARY меняется на OLEIVERB_PRIMARY. Как в OLE1, так и в OLE 2, основная обычно выполняется команда определяется, когда пользователь дважды щелкает на элементе.

Кроме того, DoVerb теперь принимает дополнительный параметр — указатель на представление (CView*). Этот параметр используется только для реализации «визуального редактирования» (или встроенной активации). Сейчас, задать параметр значение NULL, так как не реализации этой функции в настоящее время.

Чтобы убедиться, что платформа никогда не пытается на месте активировать, необходимо переопределить COleClientItem::CanActivate следующим образом:

BOOL CRectItem::CanActivate()
{
    return FALSE;
}

\oclient\rectitem.cpp(53) : error C2065: 'GetBounds' : undeclared identifier
\oclient\rectitem.cpp(53) : error C2064: term does not evaluate to a function
\oclient\rectitem.cpp(84) : error C2065: 'SetBounds' : undeclared identifier
\oclient\rectitem.cpp(84) : error C2064: term does not evaluate to a function

В MFC/OLE1, COleClientItem::GetBounds и SetBounds, используются для запроса и управляют область элемента (элементы левая и top были всегда равно нулю). В MFC/OLE 2 это более не поддерживается COleClientItem::GetExtent и SetExtent, которые работают с SIZE или CSize вместо.

Код для нового SetItemRectToServer и вызовы UpdateItemRectFromServer выглядит следующим образом:

BOOL CRectItem::UpdateItemRectFromServer()
{
   ASSERT(m_bTrackServerSize);
   CSize size;
   if (!GetExtent(&size))
      return FALSE;    // blank

   // map from HIMETRIC to screen coordinates
   {
      CClientDC screenDC(NULL);
      screenDC.SetMapMode(MM_HIMETRIC);
      screenDC.LPtoDP(&size);
   }
   // just set the item size
   if (m_rect.Size() != size)
   {
      // invalidate the old size/position
      Invalidate();
      m_rect.right = m_rect.left + size.cx;
      m_rect.bottom = m_rect.top + size.cy;
      // as well as the new size/position
      Invalidate();
   }
   return TRUE;
}

BOOL CRectItem::SetItemRectToServer()
{
   // set the official bounds for the embedded item
   CSize size = m_rect.Size();
   {
      CClientDC screenDC(NULL);
      screenDC.SetMapMode(MM_HIMETRIC);
      screenDC.DPtoLP(&size);
   }
   TRY
   {
      SetExtent(size);  // may do a wait
   }
   CATCH(CException, e)
   {
      return FALSE;  // links will not allow SetBounds
   }
   END_CATCH
   return TRUE;
}

\oclient\frame.cpp(50) : error C2039: 'InWaitForRelease' : is not a member of 'COleClientItem'
\oclient\frame.cpp(50) : error C2065: 'InWaitForRelease' : undeclared identifier
\oclient\frame.cpp(50) : error C2064: term does not evaluate to a function

В синхронных вызовов API MFC/OLE1 из контейнера на сервер сымитировал, поскольку OLE1 было асинхронно, по сути, во многих случаях. Было необходимо проверять выдающего асинхронного вызова выполняется перед их команды от пользователя. MFC/OLE1 стала функцию COleClientItem::InWaitForRelease для методика. В MFC/OLE 2 это не обязательно, поэтому можно удалить переопределение OnCommand в CMainFrame все вместе.

На этом этапе OCLIENT компилируется и ссылки.

Другие необходимые изменения

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

Во-первых, необходимо инициализировать OLE библиотеки. Это делается путем вызова AfxOleInit из InitInstance:

if (!AfxOleInit())
{
  AfxMessageBox("Failed to initialize OLE libraries");
  return FALSE;
}

Также рекомендуется, чтобы проверить наличие виртуальных функций для изменения списка параметров. Одна такая функция COleClientItem::OnChange, переопределенное в каждом контейнерном приложении MFC/OLE. С помощью просмотра справки, вы увидите, что было добавлено дополнительное «dwParam DWORD». Новое CRectItem::OnChange выглядит следующим образом:

void 
CRectItem::OnChange(OLE_NOTIFICATION wNotification, DWORD dwParam)
{
  if (m_bTrackServerSize &&
        !UpdateItemRectFromServer())
  {
    // Blank object
    if (wNotification == OLE_CLOSED)
    {
      // no data received for the object - destroy it
      ASSERT(!IsVisible());
      GetDocument()->DeleteItem(this);
      return;   // no update (item is gone now)
    }
  }
  if (wNotification != OLE_CLOSED)
      Dirty();
  Invalidate();  // any change will cause a redraw
}

В MFC/OLE1, приложение-контейнеры вывели класс документа из COleClientDoc. В MFC/OLE 2 этот класс был удален и был заменен COleDocument (эта новая организация упрощает построение контейнер и серверные приложения). #define, которое сопоставляет COleClientDoc в COleDocument для упрощения миграции приложений MFC/OLE1 в MFC/OLE 2, например OCLIENT. Одной из функций не предоставленных COleDocument, предоставленное COleClientDoc записи сопоставления сообщений стандартной команды. Это делается, чтобы серверные приложения, которые используют COleDocument (косвенно), не снесут с ними нагрузку этих обработчиков команд, если они не будут контейнер или серверное приложение. Необходимо добавить следующие записи в схеме CMainDoc сообщений:

ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdatePasteMenu)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_LINK, OnUpdatePasteLinkMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_LINKS, OnUpdateEditLinksMenu)
ON_COMMAND(ID_OLE_EDIT_LINKS, COleDocument::OnEditLinks)
ON_UPDATE_COMMAND_UI(ID_OLE_VERB_FIRST, OnUpdateObjectVerbMenu)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_CONVERT, OnUpdateObjectVerbMenu)
ON_COMMAND(ID_OLE_EDIT_CONVERT, OnEditConvert)

Реализация всей из этих команд в COleDocument, которая является базовым классом для документа.

На этом этапе, OCLIENT функциональное приложение OLE-контейнер. Можно вставлять элементы любого типа OLE1 OLE (или 2). Поскольку не реализован необходимый код, чтобы включить встроенную активацию, элементы редактируются в отдельном окне подобно с OLE1. В следующем разделе обсуждаются необходимые для включения известный редактирование локально («визуальным редактирования»).

Добавление «визуального редактирования»

Одной из наиболее интересных особенностей OLE встроенная функция активация (или «визуального редактирования»). Эта функция позволяет серверное приложение принимало над части пользовательского интерфейса контейнера обеспечивается более бесшовный интерфейс редактирования для пользователя. Для реализации встроенную активацию OCLIENT к некоторым ресурсам специальным нужно добавлять, так и некоторый дополнительный код. Эти ресурсы и код обычно предоставляемых AppWizard — на самом деле, значительная часть кода ниже. занимано непосредственно из свежего AppWizard приложения с поддержкой контейнера «».

Прежде всего, необходимо добавить ресурс меню, используемый при изменении элемента, на месте активен. Можно создать этот дополнительный ресурс меню в Visual C++, скопировав ресурс IDR_OCLITYPE и удалить все, кроме поп- ИБП файла и окна. 2 Разделительной полосы вставляются между поп- ИБП файла и окна для отображения разделение групп (оно должно выглядеть следующим образом: Файл | | Окно). Дополнительные сведения о том, что середина этих разделителей и как меню сервера и контейнера объединяются в разделе «меню и ресурсы: Слияния меню» в OLE 2 класса.

Как только получен эти меню не созданные необходимо включить платформе знать о них. Это делается путем вызова CDocTemplate::SetContainerInfo для шаблона документа перед добавлением его в список шаблонов документов в вашем InitInstance. Новый код, чтобы зарегистрировать шаблон документов выглядит следующим образом:

CDocTemplate* pTemplate = new CMultiDocTemplate(
    IDR_OLECLITYPE,
    RUNTIME_CLASS(CMainDoc),
    RUNTIME_CLASS(CMDIChildWnd),    // standard MDI child frame
    RUNTIME_CLASS(CMainView));
pTemplate->SetContainerInfo(IDR_OLECLITYPE_INPLACE);
AddDocTemplate(pTemplate);

Ресурс IDR_OLECLITYPE_INPLACE ресурс специальных на месте, созданный в Visual C++.

Чтобы включить встроенную активацию, существуют некоторые действия, которые необходимо изменить способ в производном классе CView (CMainView), так и в производном классе COleClientItem (CRectItem). Все эти переопределений предоставляются AppWizard и большинство реализации нужно непосредственно из приложения AppWizard по умолчанию.

В первом шаге этого порта, встроенной активация была запрещена полностью путем переопределения COleClientItem::CanActivate. Это переопределение должно быть удалено, чтобы разрешить встроенная функция активации. Кроме того, NULL был передан на все вызовы функции DoVerb (2 из них), поскольку защита представление был только для встроенной активации. Для полной реализации встроенную активацию необходимо передать правильное представление в вызове DoVerb. Один из этих вызовов в CMainView::OnInsertObject:

pItem->DoVerb(OLEIVERB_SHOW, this);

Другого в CMainView::OnLButtonDblClk:

m_pSelection->DoVerb(OLEIVERB_PRIMARY, this);

Необходимо переопределить COleClientItem::OnGetItemPosition. Это сообщает серверу, где поместить его окно относительно окно контейнера, когда элемент на месте активирован. Для OCLIENT реализация реализуется тривиальным образом:

void CRectItem::OnGetItemPosition(CRect& rPosition)
{
    rPosition = m_rect;
}

Большинство серверы также реализуют, называется «на месте» изменить. Это позволяет перемещенное окно сервера, который необходимо изменить, и пока пользователь изменяет элемент. Контейнер должен участвовать в этом действии, поскольку перемещение или размера окна обычно влияет на саму размер и положение в документе контейнера. Реализацию OCLIENT синхронизировать внутренний прямоугольник, поддерживаемый m_rect с новыми позицией размерами.

BOOL CRectItem::OnChangeItemPosition(const CRect& rectPos)
{
    ASSERT_VALID(this);

    if (!COleClientItem::OnChangeItemPosition(rectPos))
        return FALSE;

    Invalidate();
    m_rect = rectPos;
    Invalidate();
    GetDocument()->SetModifiedFlag();

    return TRUE;
}

На этом этапе, достаточно ли код, чтобы разрешить элемент на месте, чтобы активировать и работать с размером и переместить элемент, если он активен, но код не позволяет пользователю, чтобы выйти из сеанса редактирования. Хотя некоторые серверы, содержатся сами эти функции путем обработки ключ escape-последовательности, предложено, контейнеры предоставляют 2 способа отключить элемент: (1), щелкнув вне элемента, а (2), нажав клавишу ESCAPE ключ.

Для ключа ESCAPE добавьте сочетание клавиш с Visual C++ сопоставляет ключ VK_ESCAPE команду, ID_CANCEL_EDIT добавляет к ресурсам. Обработчик для этой команды следует:

// The following command handler provides the standard
// keyboard user interface to cancel an in-place
// editing session.void CMainView::OnCancelEdit()
{
    // Close any in-place active item on this view.
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL)
        pActiveItem->Close();
    ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
}

Для обработки случай, когда пользователь щелкает мышью за пределами элемента, добавьте следующий код в начало CMainView::SetSelection:

if (pNewSel != m_pSelection || pNewSel == NULL)
{
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL && pActiveItem != pNewSel)
        pActiveItem->Close();
}
    

Если элемент на месте активен, он должен иметь фокус. Убедиться в этом случае следует обработать OnSetFocus, чтобы фокус будет всегда передаются к активному элементу при представления получит фокус.

// Special handling of OnSetFocus and OnSize are required 
// when an object is being edited in-place.
void CMainView::OnSetFocus(CWnd* pOldWnd)
{
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL &&
    pActiveItem->GetItemState() == COleClientItem::activeUIState)
    {
        // need to set focus to this item if it is same view
        CWnd* pWnd = pActiveItem->GetInPlaceWindow();
        if (pWnd != NULL)
        {
            pWnd->SetFocus();  // don't call the base class
            return;
        }
    }

    CView::OnSetFocus(pOldWnd);
}

При изменении размера представления, необходимо убедиться, что активный элемент прямоугольник обрезки был изменен. Для этого необходимо проводилась обработчик для OnSize:

void CMainView::OnSize(UINT nType, int cx, int cy)
{
    CView::OnSize(nType, cx, cy);
    COleClientItem* pActiveItem = 
        GetDocument()->GetInPlaceActiveItem(this);
    if (pActiveItem != NULL)
        pActiveItem->SetItemRects();
}

Определенное исследование: HIERSVR на основе MFC 2.0

HIERSVR также содержится в MFC 2.0 и ввод с OLE MFC/OLE1. Эта заметка кратко описаны шаги, это приложение первоначальной преобразуется использовать классы MFC/OLE 2. Несколько функций, добавленные после начального порт завершен, чтобы проиллюстрировать классы MFC/OLE 2. Эти функции не будут рассмотрены далее; см. пример сам дополнительные сведения об этих дополнительных функций.

Примечание

Ошибки компилятора и пошаговый процесс созданные с Visual C++ 2.0 C.Некоторые сообщения об ошибках и расположения могут изменять C с Visual C++ 4.0, но основные сведения остаются допустимыми.

Получение его работу стало

Принято подход к порту образца HIERSVR в MFC/OLE начать с ее построение и требует очевидные ошибки компилятора, которые приведут к. Если берете образец HIERSVR на основе MFC 2.0 и компилировать его под этой версией MFC, вы обнаружите, что не очень много ошибок для разрешения (хотя более чем с примером OCLIENT). Ошибки в том порядке, в котором они обычно появляются описаны ниже.

Компилировать и устраните ошибки

\hiersvr\hiersvr.cpp(83) : error C2039: 'RunEmbedded' : is not a member of 'COleTemplateServer'

Эта ошибка указывает, первая намного больше проблему с функцией InitInstance для сервера. Инициализация, необходимых для OLE-сервера всего один из самых больших изменений можно внести в приложение MFC/OLE1 доступ к его работы. Чтобы обойти эту задачу выполняет действия, AppWizard создает для OLE-сервера и изменить код соответственно. Ниже приведены некоторые точки, которых следует придерживаться:

Необходимо инициализировать OLE библиотеки путем вызова AfxOleInit

Вызов SetServerInfo объекта шаблона документа для задания данных дескрипторов и класса среды выполнения ресурсов сервера, которые не могут быть установлены с помощью конструктора CDocTemplate.

Не отображать главное окно приложения, если /Embedding указан в командной строке.

Потребуется Идентификатор GUID для документа. Это уникального идентификатора для типа документа (- 128). AppWizard создан автоматически, а при использовании метода описанный здесь копирование новый код из нового серверного приложения, созданного AppWizard, можно просто «украдите» идентификатор GUID из этого приложения. Если не можно использовать программу GUIDGEN.EXE в каталоге ЯЩИКА.

Требуется «подключения» находится объект COleTemplateServer в шаблон документов путем вызова COleTemplateServer::ConnectTemplate.

Обновление в системный реестр, когда приложение, выполняемое изолированное. В этом случае, если пользователь перемещает .EXE для приложения при запуске его на основе нового расположения обновляет базу данных регистрации системы Windows для указания на новое место.

После применения всех этих изменений на основе того, что AppWizard создает для InitInstance, и соответствующих InitInstance (GUID) для HIERSVR должно прочитать следующим образом:

// this is the GUID for HIERSVR documents
static const GUID BASED_CODE clsid =
    { 0xA0A16360L, 0xC19B, 0x101A, { 0x8C, 0xE5, 0x00, 0xDD, 0x01, 0x11, 0x3F, 0x12 } };
    
/////////////////////////////////////////////////////////////////////////////
// COLEServerApp initialization

BOOL COLEServerApp::InitInstance()
{
    // OLE 2 initialization
    if (!AfxOleInit())
    {
        AfxMessageBox("Initialization of the OLE failed!");
        return FALSE;
    }

    // Standard initialization
    LoadStdProfileSettings(); // Load standard INI file options 

    // Register document templates
    CDocTemplate* pDocTemplate;
    pDocTemplate = new CMultiDocTemplate(IDR_HIERSVRTYPE,
        RUNTIME_CLASS(CServerDoc),   
        RUNTIME_CLASS(CMDIChildWnd),
        RUNTIME_CLASS(CServerView));
    pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB);
    AddDocTemplate(pDocTemplate);

    // create main MDI Frame window
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
        return FALSE;
    m_pMainWnd = pMainFrame;

    SetDialogBkColor();   // gray look

    // enable file manager drag/drop and DDE Execute open
    m_pMainWnd->DragAcceptFiles();
    EnableShellOpen();
    
    m_server.ConnectTemplate(clsid, pDocTemplate, FALSE);
    COleTemplateServer::RegisterAll();

    // try to launch as an OLE server
    if (RunEmbedded())
    {
        // "short-circuit" initialization -- run as server!
        return TRUE;
    }
    m_server.UpdateRegistry();
    RegisterShellFileTypes();

    // not run as OLE server, so show the main window
    if (m_lpCmdLine[0] == '\0')
    {
        // create a new (empty) document
        OnFileNew();
    }
    else
    {
        // open an existing document
        OpenDocumentFile(m_lpCmdLine);
    }

    pMainFrame->ShowWindow(m_nCmdShow);
    pMainFrame->UpdateWindow();
    
    return TRUE;
}

Можно заметить, что приведенный выше код ссылается на новый идентификатор ресурса, IDR_HIERSVRTYPE_SRVR_EMB. Это ресурс меню, используемый, когда документ, внедренного в другом контейнере вообще. В MFC/OLE1 пункты меню, специфические для редактирования вложенный элемент были изменены на лету. Использование полностью другую структуру меню при редактировании вложенный элемент вместо изменения на основе документа значительно упростит предоставить интерфейсы другого пользователя для этих 2 разных режимов. Как будет впоследствии используется полностью отдельный ресурс меню редактирования внедренный объект на месте.

Чтобы создать этот ресурс, загрузите скрипт ресурса на Visual C++ и скопируйте существующий ресурс меню IDR_HIERSVRTYPE. Переименуйте новый ресурс. IDR_HIERSVRTYPE_SRVR_EMB (это же соглашения об именах, AppWizard используется). Следующее изменение «сохранение файла» в «обновлению файла»; присвойте ей идентификатор команды ID_FILE_UPDATE. Изменить файл «сохранить как» в «сохранить как» копии файла; присвойте ей идентификатор команды ID_FILE_SAVE_COPY_AS. Платформа предоставляет реализацию всех этих команд.

\hiersvr\svritem.h(60) : error C2433: 'OLESTATUS' : 'virtual' not permitted on data declarations
\hiersvr\svritem.h(60) : error C2501: 'OLESTATUS' : missing decl-specifiers
\hiersvr\svritem.h(60) : error C2146: syntax error : missing ';' before identifier 'OnSetData'
\hiersvr\svritem.h(60) : error C2061: syntax error : identifier 'OLECLIPFORMAT'
\hiersvr\svritem.h(60) : error C2501: 'OnSetData' : missing decl-specifiers

Несколько ошибок и в результате переопределения OnSetData, поскольку оно относится к типу OLESTATUS. OLESTATUS был ошибками способа возвращенными OLE1. Это меняется на HRESULT в 2 MFC OLE, хотя обычно преобразования HRESULT в COleException с ошибкой. В данном конкретном случае переопределение OnSetData больше не требуется, поэтому удобнее разместить для действия удалить его.

\hiersvr\svritem.cpp(30) : error C2660: 'COleServerItem::COleServerItem' : function does not take 1 parameters

Конструктор COleServerItem принимает дополнительный параметр «BOOL». Этот флажок указывает, как управление памятью осуществляется для объектов COleServerItem. Устанавливая его TRUE платформа обрабатывает управление памятью этих объектов — удаление, когда они больше не требуются. HIERSVR использует объекты CServerItem (производного от COleServerItem) в составе своих собственных данных, следовательно, установите этот флажок в FALSE. Это позволяет определить, когда HIERSVR каждый элемент сервера удаляется.

\hiersvr\svritem.cpp(44) : error C2259: 'CServerItem' : illegal attempt to instantiate abstract class
\hiersvr\svritem.cpp(44) : error C2259: 'CServerItem' : illegal attempt to instantiate abstract class

Так как эти ошибки, определяют некоторые функции «чисто- виртуального», которые не были переопределены в CServerItem. Как правило, это вызвано тем фактом, что список параметров OnDraw был изменен. Чтобы устранить эту ошибку, измените CServerItem::OnDraw следующим образом (так же как и объявление в svritem.h).

BOOL CServerItem::OnDraw(CDC* pDC, CSize& rSize)
{
    // request from OLE to draw node
    pDC->SetMapMode(MM_TEXT); // always in pixels
    return DoDraw(pDC, CPoint(0,0), FALSE);
}

Новый параметр «rSize». Это позволяет заполнения размер рисования, если удобный. Этот размер должен находиться в HIMETRIC. В этом случае не просто заполнить это значение в, поэтому платформа вызывает OnGetExtent для извлечения экстент. Для того, чтобы работать, необходимо реализовать OnGetExtent:

BOOL CServerItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
{
    if (dwDrawAspect != DVASPECT_CONTENT)
        return COleServerItem::OnGetExtent(dwDrawAspect, rSize);
        
    rSize = CalcNodeSize();
    return TRUE;
}

\hiersvr\svritem.cpp(104) : error C2065: 'm_rectBounds' : undeclared identifier
\hiersvr\svritem.cpp(104) : error C2228: left of '.SetRect' must have class/struct/union type
\hiersvr\svritem.cpp(106) : error C2664: 'void __pascal __far DPtoLP(struct ::tagPOINT __far *,int )__far const ' : cannot convert parameter 1 from 'int __far *' to 'struct ::tagPOINT __far *'

В функции CServerItem::CalcNodeSize размер элемента выполняется в HIMETRIC и сохраняется в m_rectBounds. Незадокументированный элемент 'm_rectBounds' COleServerItem не существует (он частично заменяется m_sizeExtent, но в OLE 2 этот член имеет потребление немного отличается от m_rectBounds и в OLE1). Вместо параметра HIMETRIC в этот размер переменной-члена, возврат его. Это возвращенное значение используется в OnGetExtent, — ранее.

CSize CServerItem::CalcNodeSize()
{
    CClientDC dcScreen(NULL);

    m_sizeNode = dcScreen.GetTextExtent(m_strDescription,
      m_strDescription.GetLength());
    m_sizeNode += CSize(CX_INSET * 2, CY_INSET * 2);

    // set suggested HIMETRIC size
    CSize size(m_sizeNode.cx, m_sizeNode.cy);
    dcScreen.SetMapMode(MM_HIMETRIC);
    dcScreen.DPtoLP(&size);
    return size;
}

CServerItem также переопределяет COleServerItem::OnGetTextData. Эта функция является устаревшим в MFC/OLE и заменяется другим механизмом. Версии MFC 3.0 образца HIERSVR MFC OLE реализует данную функцию можно переопределить COleServerItem::OnRenderFileData. Эта функция не важны для этого базового порта, поэтому можно удалить переопределение OnGetTextData.

Многие ошибки в svritem.cpp, которые не были адресованы. Они не " реальных" ошибок — только ошибок, вызванных предыдущими ошибками.

\hiersvr\svrview.cpp(325) : error C2660: 'CopyToClipboard' : function does not take 2 parameters

COleServerItem::CopyToClipboard больше не поддерживает «bIncludeNative» флажок. Собственный данные (данные, записываемые в элементе сервера обратно сериализации функцию) всегда копируется, поэтому удаляется первый параметр. Кроме того, CopyToClipboard создает исключение, когда произойдет ошибка вместо возвращения FALSE. Изменить код для CServerView::OnEditCopy следующим образом:

void CServerView::OnEditCopy()
{
    if (m_pSelectedNode == NULL)
        AfxThrowNotSupportedException();
        
    TRY
    {
        m_pSelectedNode->CopyToClipboard(TRUE);
    }
    CATCH_ALL(e)
    {
        AfxMessageBox("Copy to clipboard failed");
    }
    END_CATCH_ALL   
}

Хотя было несколько ошибок и в результате компиляции версии MFC 2.0 HIERSVR не существует, для той же версии OCLIENT, были фактически меньше изменений.

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

Добавление «визуального редактирования»

Чтобы добавить «визуального редактирования» (или встроенная функция активация) к этому серверному приложению, существуют только перечислено несколько действий необходимо соблюдать осторожность предотвращает:

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

  • Это приложение содержит панель инструментов, поэтому необходимо на панели инструментов отображается только подмножеством — инструмента соответствовать командам меню доступность сервера (совпадений ресурс меню упомянутый выше).

  • Необходим новый класс, производный от COleIPFrameWnd, который предоставляет интерфейс пользователя на месте (подобно CMainFrame, производное от CMDIFrameWnd, предоставляет пользовательский интерфейс MDI).

  • Необходимо указать платформу о специальных ресурсах и классов.

Ресурс меню является простым для создания. Запустите Visual C++, скопируйте ресурс меню в IDR_HIERSVRTYPE, вызываемому ресурс меню IDR_HIERSVRTYPE_SRVR_IP. Измените меню, чтобы будут выведены всплывающих окон только правки и меню " Справка ". Добавить 2 к разделителя меню между правкой и меню " Справка " (он должен выглядеть следующим образом: Изменить | | Справка). Дополнительные сведения о том, что середина этих разделителей и как меню сервера и контейнера объединяются, см. в разделе «меню и ресурсы: Слияния меню» в OLE 2 класса.

Растровое изображение для панели инструментов подмножества может быть создано легко скопировать одно из свежего приложения, созданного с AppWizard установлен параметр «сервера». Это растровое изображение затем можно импортировать в Visual C++. Убедитесь, что для растрового изображения идентификатор IDR_HIERSVRTYPE_SRVR_IP.

Класс, производный от COleIPFrameWnd можно скопировать из приложения, AppWizard с поддержкой сервера также. Скопируйте оба файлы, IPFRAME.CPP и IPFRAME.H и добавить их в проект. Убедитесь, что вызов LoadBitmap ссылается на IDR_HIERSVRTYPE_SRVR_IP растровое изображение, созданный на предыдущем шаге.

После этого новые ресурсы и классы создаются добавьте необходимый код, чтобы платформа знает об этих (и известно, что в приложении теперь поддерживает редактирование локально). Для этого необходимо добавить еще несколько параметров при вызове SetServerInfo в функции InitInstance:

pDocTemplate->SetServerInfo(IDR_HIERSVRTYPE_SRVR_EMB,
    IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame));

Теперь он готов к выполнению в любом месте в контейнере, также поддерживает встроенную активацию. Но, одна серьезные ошибки по-прежнему скрываясь в коде. HIERSVR поддерживает контекстное меню отображается, когда пользователь нажимает кнопку правой кнопки мыши. Это меню работает при HIERSVR полностью открыто, но не работает внедрение редактирования на месте. Причиной может быть зафиксирован вниз до этой одной строке кода в CServerView::OnRButtonDown:

pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
    point.x, point.y, AfxGetApp()->m_pMainWnd);

Обратите внимание на ссылку на AfxGetApp()->m_pMainWnd. Если сервер на месте активирован, он имеет главного окна и m_pMainWnd установлено, но обычно незаметного. Кроме того, это поле указывает на главное окно приложения, фреймовому окно с интерфейсом MDI, которое возникает, когда сервер полностью открыт или выполнять отдельный. Это не относится к активному окну фреймовому —, когда на месте активированы фреймовое окно, производное от COleIPFrameWnd. Получение правильного активное окно даже при изменении локально, в этой версии MFC добавляет новую функцию, AfxGetMainWnd. Как правило, следует использовать эту функцию вместо AfxGetApp()->m_pMainWnd. Этот код следует изменить следующим образом:

pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
    point.x, point.y, AfxGetMainWnd());

Теперь у OLE-сервер минимально допустимый для функциональной встроенной активации. Однако они по-прежнему множество функций, с MFC/OLE 2, которые не были доступны в MFC/OLE1. См. образец HIERSVR дополнительные идей для функций, может потребоваться реализовать. Некоторые из функций, HIERSVR реализует перечислены ниже:

  • По горизонтали, истинного расширения функциональности WYSISYG по отношению к контейнеру.

  • Перетаскивания и пользовательский формат буфера обмена.

  • Перемещение контейнера окна в качестве выделения изменен.

Образец HIERSVR в MFC 3.0 также использует немного другую структуру для ее элементов сервера. Это позволяет сохранить память и делает ссылается на более гибким. В версии 2.0 HIERSVR каждый узел в дереве , -COleServerItem. COleServerItem передает немного большего нагрузки строго, чем требуется для каждого из этих узлов, но COleServerItem необходимый для каждой активной ссылки. Однако в большинстве случаев очень мало активные ссылки на данный момент. Чтобы сделать это, эффективную HIERSVR в данной версии MFC отделяет узел из COleServerItem. Он содержит и CServerNode и CServerItem. CServerItem (Производное от COleServerItem) создается только по мере необходимости. После удаления остановить контейнера (или контейнеров) с помощью, указанную ссылку на определенный узел, CServerItem объект, связанный с CServerNode. Такой подход более эффективными и обеспечивают большую гибкость. Реализуется в его гибкость при работе со ссылками выбора нескольких элементов. Ни один из этих версий 2 выбора нескольких элементов поддержки HIERSVR, но являются гораздо проще для добавления (и к указателям поддержки к тем выделения) версии MFC 3.0 HIERSVR, поскольку COleServerItem отделяется от собственных данных.

См. также

Другие ресурсы

Технические примечания по номеру

Технические примечания по категории