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


TN041: Миграция MFC/OLE1 к MFC/OLE 2

ПримечаниеПримечание

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

Общие вопросы, связанные с миграцией

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

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

Документ MFC и архитектура вид важными

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

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

Используйте реализацию MFC вместо собственных

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

Просмотрите образец кода MFC

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

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

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

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

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

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

Анализ проблем: OCLIENT из MFC 2.0

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

ПримечаниеПримечание

Ошибки компилятора и пошаговый процесс созданных с помощью Visual C++ 2.0.Отдельные сообщения об ошибках и расположения могут измениться с 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, который рисует на контроллер домена метафайла.Кроме того, параметр pFormatDC больше не требуется, поскольку границы построят одно из «контроллера домена атрибута» 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 '

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

Другая область, значительно отличаются обработка буфера обмена OLE 2.С OLE1 с помощью окна API буфера обмена с буфером обмена.С помощью 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.Кроме того, новые ЯВЛЯЕТСЯ элементы создаются с 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 использовались для запросов и управления область элементов (элементы left и 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);

Else в 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.

Добавьте сочетания клавиш для ЭКРАНИРОВАНИЯ с 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

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

ПримечаниеПримечание

Ошибки компилятора и пошаговый процесс созданных с помощью Visual C++ 2.0.Отдельные сообщения об ошибках и расположения могут измениться с 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-сервер и изменить код.Ниже приведены некоторые элементы, которые нужно учитывать:

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

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

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

Необходимо Идентификатор GUID для документа.Это уникальный идентификатор типа документа (128 бита).AppWizard создает для пользователя решение — если используется метод, описанный здесь скопировать новый код из нового серверного приложения, созданного AppWizard, можно просто «похитить» GUID из этого приложения.Если это не так, можно использовать программу GUIDGEN.EXE в каталоге BIN.

Требуется «подключения» объект 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 в OLE 2, хотя MFC обычно выполняется преобразование 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 образцы GlobalUnlock 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 checked - параметр сервера». «Это растровое изображение можно импортировать в 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 реализует перечислены ниже:

  • Увеличащ true, для расширения функциональности 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 собственных данных.

См. также

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

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

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