Загальні питання, що пов'язані з міграції
Одна з цілей дизайн OLE 2 класи у MFC 2.5 (і вище) було зберегти багато чого з тією ж архітектурою, покласти на місце у MFC 2.0 для підтримки OLE 1.0. Як наслідок, багато хто ж OLE класів у MFC 2.0 все ще існують в цій версії MFC (COleDocument, COleServerDoc, COleClientItem, COleServerItem). Крім того, багато хто з цих інтерфейсів в цих класах однакові. Однак, OLE 2 є суттєво відрізняється від OLE 1.0, так що ви можете очікувати, що деякі деталі були змінені. Якщо ви знайомі з Ole1, які потребують підтримки MFC 2.0, ви будете почувати себе вдома MFC, 2.0 підтримки.
Якщо ви знайшли існуючий додаток MFC/Ole1, які потребують і додавання функціональності OLE 2 до нього, ви повинні прочитати цю примітку. Ця Примітка охоплює деякі загальні питання, що можуть виникнути під час портування ваш Ole1, які потребують функціональність MFC/OLE 2 і потім обговорює проблеми, виявлені при портування двох додатків, що входять у MFC 2.0: MFC OLE зразки OCLIENT і HIERSVR.
Важливо MFC перегляду документа/архітектура
Якщо ваша заявка не використовувати MFC, перегляду документа/архітектура, і ви хочете, щоб додати підтримку OLE 2 для вашого застосування, зараз настав час, щоб перейти до перегляду документа /. Переваги MFC, OLE 2 класи тільки зрозумів, як тільки ваша заявка використовує вбудований архітектури та компоненти MFC.
Впровадження сервера або контейнер без використання MFC архітектури є можливим, але не рекомендується.
Використання MFC реалізації замість свій власний
Впровадження MFC "готові" класи, такі як CToolBar, CStatusBarта CScrollView мають вбудовані спеціальний корпус код для підтримки OLE 2. Отже, якщо ви можете використовувати ці класи у вашому додатку ви будете користуватися зусиль, покласти на них, щоб зробити їх OLE відомо. Знову ж таки це можна "roll свого власного" класи тут для цих цілей, але не передбачається. Якщо вам потрібно для здійснення схожу функціональність, вихідний код MFC є довідковий для вирішення деякі тонкощі OLE (особливо, коли мова заходить про активацію на місці).
Вивчити MFC приклад коду
Є ряд MFC зразки, які включають в себе функціональність OLE. Кожна з цих програм реалізує OLE з іншої точки зору:
HIERSVR - в основному для використання як сервер додатків. Це була включена у MFC 2.0 як додаток MFC/Ole1, які потребують і було перенесено до 2 MFC/OLE і потім розширена настільки, що він реалізує багато OLE функцій, доступних в OLE 2.
OCLIENT - це контейнер автономний додаток, означало продемонструвати багато функцій OLE з точки зору контейнера. Це теж була перенесена з MFC 2.0 а потім продовжено на підтримку багатьох з більш просунутих функцій OLE, наприклад, формати власні буфера обміну та посилання на вбудовані елементи.
DRAWCLI - це додаток реалізує підтримку контейнер OLE набагато як OCLIENT робить, за винятком, що він робить це в рамках існуючих об'єктно орієнтованого графічного програми. Він показує, як ви можете реалізувати підтримку контейнер OLE і включити його в ваш існуючий додаток.
SUPERPAD - цього додатка, а також як штраф окрему програму, також є сервером OLE. Підтримка сервера, він реалізує це досить мінімалістський. Особливий інтерес представляє використання служби OLE буфера обміну для копіювання даних до буфера обміну, але використовує функціональності вбудованого в Windows "Змінити" керування реалізувати функціональність буфера обміну вставити. Це показує, що цікаве поєднання традиційних використання Windows API, а також інтеграція з нового API OLE для.
Більш докладну інформацію про приклади додатків довідці в "MFC зразків".
Приклад: OCLIENT від MFC 2.0
Як зазначено вище, OCLIENT був включений у 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): помилка C2660: 'Малювати': функцію не займає 4 параметрів
Перша помилка стосується COleClientItem::Draw. У MFC/Ole1, які потребують знадобилося більше параметрів, ніж версія MFC/OLE приймає. Додаткові параметри часто не були необхідні і зазвичай NULL (як у цьому прикладі). Ця версія MFC автоматично визначає значення у lpWBounds, коли CDC, яка відображена на метафайли DC. Крім того, pFormatDC параметр немає необхідності оскільки рамках будуть будувати одну з "атрибут DC" pDC, прийнятий в. Щоб виправити цю проблему, ви просто видалити двох додаткові значення NULL для параметрів на заклик нічия.
\oclient\mainview.cpp(273): помилка C2065: 'OLE_MAXNAMESIZE': неоголошену ідентифікатор
\oclient\mainview.cpp(273): помилка C2057: очікується константних виразів
\oclient\mainview.cpp(280): помилка C2664: 'CreateLinkFromClipboard': не вдалося перетворити параметр 1 з 'char [1]' ' enum:: tagOLERENDER '
\oclient\mainview.cpp(286): помилка C2664: 'CreateFromClipboard': не вдалося перетворити параметр 1 з 'char [1]' ' enum:: tagOLERENDER '
\oclient\mainview.cpp(288): помилка C2664: 'CreateStaticFromClipboard': не вдалося перетворити параметр 1 з 'char [1]' ' enum:: tagOLERENDER '
Помилки вище в результаті той факт, що всі COleClientItem::CreateXXXX функцій у MFC/Ole1, які потребують необхідні, що представляє елемент передаються унікальне ім'я. Це була вимога базової OLE API. Це не є необхідним у MFC/OLE-2 оскільки OLE 2 не використовувати DDE як основний механізм зв'язку (назва була використана в розмовах DDE). Щоб вирішити цю проблему, можна видалити CreateNewName функції, як і всі посилання на нього. Легко знайти те, що кожна функція MFC/OLE очікує в цій версії просто шляхом розміщення курсору на дзвінок і натисніть клавішу F1.
Ще одна сфера, суттєво відрізняється – OLE 2 Оброблення буфера обміну. З Ole1, які потребують ви використовували буферу обміну Windows API для взаємодії з буфера обміну. З OLE 2 це робиться на інший механізм. API для MFC/Ole1, які потребують припустити, що буфера обміну було відкрито перед копіюванням COleClientItem об'єкт до буфера обміну. Це вже не необхідні і призведе до всіх операцій MFC/OLE буфера обміну на провал. Під час редагування код для видалення залежностей на CreateNewName, ви повинні також видалити код, який відкриває і закриває буфера обміну Windows.
\oclient\mainview.cpp(332): помилка C2065: 'AfxOleInsertDialog': неоголошену ідентифікатор
\oclient\mainview.cpp(332): помилка C2064: термін не отримує значення функції
\oclient\mainview.cpp(344): помилка C2057: очікується константних виразів
\oclient\mainview.cpp(347): помилка C2039: 'CreateNewObject': не є членом 'CRectItem'
Ці помилки в результаті CMainView::OnInsertObject обробника. Обробка команди "Вставити новий об'єкт" є ще одна сфера, де все змінилося зовсім небагато. У цьому випадку, це найпростіший просто об'єднати спочатку реалізація, що надаються AppWizard новий контейнер OLE-додаток. По суті, це метод, який можна застосувати до інших застосунки. У MFC/Ole1, які потребують відображається діалогове вікно "Вставити об'єкт" на виклик функції AfxOleInsertDialog . У цій версії ви побудувати на об'єкт діалогове вікно COleInsertObject і називаємо DoModal. Крім того, створення нових елементів OLE з CLSID замість того, щоб classname рядок. Кінцевий результат повинен виглядати наступним чином
COleInsertDialog dlg;
Якщо (dlg.DoModal()! = IDOK)
nbsp; повернення;
BeginWaitCursor();
CRectItem * pItem = NULL;
СПРОБУЙТЕ
{
/ / Перший створити об'єкт C++
pItem = GetDocument() - > CreateItem();
ASSERT_VALID(pItem);
/ / Ініціалізувати об'єкт діалогове вікно даних.
Якщо (! dlg.CreateItem(pItem))
AfxThrowMemoryException();
/ / буде робити будь-винятку
ASSERT_VALID(pItem);
/ / Запуск об'єкта, якщо відповідні
Якщо (dlg.GetSelectionType() == COleInsertDialog::createNewItem)
pItem - > DoVerb(OLEIVERB_SHOW, this);
/ / оновлення відразу
pItem - > UpdateLink();
pItem - > UpdateItemRectFromServer();
/ / встановити виділення до нового вставленого елемента
SetSelection(pItem);
pItem - > Invalidate();
}
УЛОВ ("CException", "e")
{/ / видалити елемент
Якщо (pItem! = NULL)
GetDocument() - > DeleteItem(pItem);
AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
EndWaitCursor()
Примітка Вставка нового об'єкта може бути різним для вашого застосування):
Це також необхідно включити lt;afxodlgs.h > яка містить декларації класі діалогове вікно " COleInsertObject ", як і інші стандартні діалоги надаються MFC.
\oclient\mainview.cpp(367): помилка C2065: 'OLEVERB_PRIMARY': неоголошену ідентифікатор
\oclient\mainview.cpp(367): помилка C2660: 'DoVerb': функцію не займає 1 параметрів
Ці помилки викликані той факт, що деякі константи Ole1, які потребують зміни до OLE 2, хоча в концепції вони те ж саме. У цьому випадку OLEVERB_PRIMARY було змінено на OLEIVERB_PRIMARY. У Ole1, які потребують і OLE 2 первинного дієслова зазвичай виконується на контейнер, коли користувач double-clicks з елемент.
Крім того, DoVerb тепер займає додатковий параметр — вказівник на подання (CView*). Цей параметр використовується тільки для здійснення "Візуального редагування" (або активації на місці). Зараз встановити цей параметр NULL, оскільки ви не є реалізацією цієї функції на цей час.
Щоб переконатися, що в рамках ніколи не спроб на місці активувати, ви повинні змінити COleClientItem::CanActivate наступним чином
BOOL CRectItem::Ca&nActivate()
{
nbsp; Повертає FALSE;
}
\oclient\rectitem.cpp(53): помилка C2065: 'GetBounds': неоголошену ідентифікатор
\oclient\rectitem.cpp(53): помилка C2064: термін не отримує значення функції
\oclient\rectitem.cpp(84): помилка C2065: 'SetBounds': неоголошену ідентифікатор
\oclient\rectitem.cpp(84): помилка C2064: термін не отримує значення функції
У MFC/Ole1, які потребують COleClientItem::GetBounds і SetBounds були використані для запиту та маніпулювати мірою елемент ( лівий та верхній члени завжди були нуля). У MFC/OLE 2 це безпосередньо підтримується COleClientItem::GetExtent та SetExtent, які мають справу з Розмір або CSize замість.
Код для вашого новий SetItemRectToServer, і такий вигляд UpdateItemRectFromServer дзвінки:
BOOL CRectItem::UpdateItemRectFromServer()
{
nbsp; ASSERT(m_bTrackServerSize);
Розмір CSize;
Якщо (!.GetExtent(&size))
Повертає FALSE; / / порожній
/ / карта з HIMETRIC на екран координати
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.LPtoDP(&size);
}
/ / тільки встановити розмір елемента
Якщо (m_rect.Size()! = розмір)
{
/ / допомого розмір старі позиції
Invalidate();
m_rect.Right = m_rect.left + size.cx;
m_rect.Bottom = m_rect.top + size.cy;
/ /, а також новий розмір/позиції
Invalidate();
}
повертає TRUE;
}
BOOL CRectItem::SetItemRectToServer()
{
/ / встановити межі офіційних впровадженого об'єкта
Розмір CSize = m_rect.Size();
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.DPtoLP(&size);
}
СПРОБУЙТЕ
{
SetExtent(size); / / може зробити чекати
}
УЛОВ ("CException", "e")
{
Повертає FALSE; / / посилання не дозволить SetBounds
}
END_CATCH
повертає TRUE;
}
\oclient\frame.cpp(50): помилка C2039: 'InWaitForRelease': не є членом 'COleClientItem'
\oclient\frame.cpp(50): помилка C2065: 'InWaitForRelease': неоголошену ідентифікатор
\oclient\frame.cpp(50): помилка C2064: термін не отримує значення функції
У MFC/Ole1, які потребують синхронних API викликів з контейнера на сервері, були імітації, оскільки Ole1, які потребують була по суті асинхронних, у багатьох випадках. Це було необхідно, щоб перевірити за видатні асинхронний виклик виконується перед обробкою команд користувача. MFC/Ole1, які потребують умови COleClientItem::InWaitForRelease функції, для цього. У MFC/OLE 2 це не є необхідним, так що ви можете видалити перевизначити OnCommand в CMainFrame усіх разом.
На даний момент OCLIENT компіляції та компонування.
Інші необхідні зміни
Є кілька речей, які не зробили, що буде тримати OCLIENT, запуск, однак. Це краще для вирішення цих проблем зараз, а не пізніше.
По-перше, це необхідно для ініціалізації бібліотек OLE. Це робиться шляхом виклику AfxOleInit із InitInstance:
якщо (!.AfxOleInit())
{
AfxMessageBox ("не вдалося ініціалізувати OLE бібліотек");
Повертає FALSE;
}
Це також гарна ідея, щоб перевірити наявність віртуальних функцій для параметра вносити зміни. Одна така функція є COleClientItem::OnChange, змінені в кожному контейнер MFC/OLE. Дивлячись на онлайн-довідка, ви побачите, був доданий в додаткові 'dwParam DWORD. Нові CRectItem::OnChange виглядає наступним чином
порожнечі CRectItem::OnChange (OLE_NOTIFICATION wNotification, DWORD dwParam)
{
Якщо (m_bTrackServerSize підсилювача; &
!UpdateItemRectFromServer())
{
/ / Порожні об'єкта
Якщо (wNotification = = OLE_CLOSED)
{
/ / дані не отримані для об'єкта - знищити його
СТВЕРДЖУВАТИ (!.IsVisible());
GetDocument() - > DeleteItem(this);
повернення; / / оновлення відсутні (елемент вже немає)
}
}
Якщо (wNotification! = OLE_CLOSED)
Dirty();
Invalidate(); / / будь-яких змін призведе до перемальовування
}
У MFC/Ole1, які потребують контейнер заявок отриманих клас документа з COleClientDoc. У MFC/OLE 2 цього класу були вилучені і замінені на COleDocument (Ця нова організація полегшує створення контейнер/сервер додатків). Існує на # визначити, що 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 ресурс і видалення все, крім файлу та вікно спливаючі вікна. Два бари розділювачі вставляються між спливаючі вікна файлів і вікно для позначення розділення груп (це повинно виглядати: файл | | Вікна). Більш докладну інформацію про те, що ці роздільники означає та як об'єднання меню сервер "і" контейнер побачити "Меню та ресурси: меню об'єднання" в OLE 2 класи.
Як тільки у вас ці меню створено, ви повинні дозволити рамках знати про них. Робиться це за номером CDocTemplate::SetContainerInfo шаблоні документа, перш ніж додавати його до списку шаблон документа у вашому InitInstance. Новий код для реєстрації шаблону документа виглядає наступним чином
CDocTemplate * pTemplate = новий CMultiDocTemplate (
nbsp; IDR_OLECLITYPE,
RUNTIME_CLASS(CMainDoc),
RUNTIME_CLASS(CMDIChildWnd) / / стандартний MDI дитини кадру
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 (є два з них), тому що надання подання був тільки необхідні для активації на місці. Повною мірою реалізувати активації на місці, це необхідно пройти правильний вигляд у виклику DoVerb . Один з цих викликів є у CMainView::OnInsertObject
pItem-> DoVerb(OLEIVERB_SHOW, this)
Інший спосіб полягає в CMainView::OnLButtonDblClk
m_pSelection-> DoVerb(OLEIVERB_PRIMARY, this)
Це необхідно, щоб перевизначити COleClientItem::OnGetItemPosition. Це вказує серверу де поставити його вікно по відношенню до вікна у Тара, коли елемент знаходиться на місці активовано. Для OCLIENT здійснення є тривіальним
недійсним CRectItem::OnGetItemPosition (CRect&, rPosition)
{
rPosition = m_rect;
}
Більшість серверів також реалізувати те, що називається "на місці зміна розміру." Це дозволяє бути розміром і переїхав в той час як користувач редагує елемент вікні сервер. Контейнер повинна брати участь у цій акції, оскільки переміщення або змінення розміру вікна зазвичай впливає на положення і розмір в документі-контейнері, сама по собі. Впровадження OCLIENT синхронізує внутрішній прямокутник, підтримується m_rect з нового положення і розмір.
BOOL CRectItem::OnChangeItemPosition(const CRectamp; rectPos)
{
ASSERT_VALID(This);
Якщо (!.COleClientItem::OnChangeItemPosition(rectPos))
Повертає FALSE;
Invalidate();
m_rect = rectPos;
Invalidate();
GetDocument() - > SetModifiedFlag();
повертає TRUE;
}
На даний момент є достатньо код, щоб елемент бути на місці активована і боротися з зміни розміру та переміщення об'єкта, коли активний, але немає не коду, який дозволить користувачеві для виходу з сеансу редагування. Хоча деякі сервери будуть мати таку змогу себе з обробки клавішу escape, він запропонував, що контейнери мають два способи вимкнути елемент: (1), натиснувши поза межами елементу і (2) натиснувши клавішу escape.
Для Втеча ключ додавати корисну можливість з Visual c + +, що карти VK_ESCAPE ключ до команди, ID_CANCEL_EDIT додається до ресурсів. Обробник для цієї команди випливає:
/ / Наступні команди обробника надає стандартний
/ / клавіатура інтерфейс користувача скасувати на місці
/ / редагування session.void CMainView::OnCancelEdit()
{
nbsp; / / Закрити будь-яку на місці активний об'єкт на це подання.
COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Якщо (pActiveItem! = NULL)
pActiveItem - > Close();
ASSERT(GetDocument()-> GetInPlaceActiveItem(this) = = NULL);
}
Для випадку, коли користувач натискає поза межами елементу, ви додати наступний код до початку CMainView::SetSelection
якщо (pNewSel! = m_pSelection | | pNewSel = = NULL)
{
nbsp; COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Якщо (pActiveItem! = NULL & & pActiveItem! = pNewSel)
pActiveItem - > Close();
}
& nbsp
Коли елемент є активним на місці, він повинен мати фокус. Щоб переконатися, що у цьому випадку ви впоратися OnSetFocus так, що фокус завжди передаються до активного елемента під час перегляду отримує фокус:
/ / Спеціальної обробки OnSetFocus і OnSize, необхідних / / коли об'єкт редагується на місці.
недійсним CMainView::OnSetFocus (CWnd * pOldWnd)
{
nbsp; COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Якщо (pActiveItem! = NULL & &
pActiveItem - > GetItemState() = = COleClientItem::activeUIState)
{
/ / необхідно перевести фокус на цей елемент, якщо він же вигляд
CWnd * pWnd = pActiveItem - > GetInPlaceWindow();
Якщо (pWnd! = NULL)
{
pWnd - > SetFocus(); / / не називайте базового класу
повернення;
}
}
CView::OnSetFocus(pOldWnd);
}
Під час перегляду розмірів, ви повинні повідомити про активний об'єкт, що змінилося прямокутника обрізання. Для цього ви надати обробник для OnSize:
втрати CMainView::OnSize (UINT nType, int cx, int cy)
{
nbsp; CView::OnSize (nType, cx, cy);
COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Якщо (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. Певні повідомлення про помилки та розташування може бути змінене з Visual c + +-4.0, але концептуальних інформація залишається дійсним.
Отримувати це і працює
Підхід до порту HIERSVR зразка, щоб MFC/OLE, є почати його побудову і виправлення помилок очевидні компілятор, що приведе. Якщо ви взяти зразок HIERSVR від MFC 2.0 і скомпілювати його під Ця версія MFC, ви знайдете, що не є багато помилок, щоб вирішити (хоча є більш ніж з OCLIENT зразків). Помилки в тому порядку, в якому вони зазвичай трапляються описані нижче.
Компіляції і виправити помилки
\hiersvr\hiersvr.cpp(83): помилка C2039: 'RunEmbedded': не є членом 'COleTemplateServer'
Перша помилка вказує на багато великі проблеми з InitInstance функції для серверів. Ініціалізації, необхідні для сервера OLE, ймовірно, однією з найбільших змін, вам доведеться зробити заявку MFC/Ole1, які потребують, щоб отримати це працює. Краще за все зробити, це подивитися на те, що створює для сервера OLE AppWizard та змінювати код відповідно. Ось деякі моменти, щоб мати на увазі:
Потрібно ініціалізувати бібліотек 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;
}
Ви помітите, що код вище відноситься до нових ресурсів ID, IDR_HIERSVRTYPE_SRVR_EMB. Це меню ресурс для використання під час редагування документа, вбудовані в інший контейнер. У MFC/Ole1, які потребують пунктів меню, специфічні для редагування впровадженого об'єкта змінено на льоту. Використовуючи структуру зовсім різні меню під час редагування впровадженого об'єкта замість того, щоб редагування документа на основі файлу робить її набагато легше, для забезпечення різних користувацьких інтерфейсів для ці два режими. Як ви побачите пізніше, зовсім окреме меню-ресурс використовується під час редагування в впроваджений об'єкт на місці.
Щоб створити цей ресурс, завантаження сценарію ресурс в Visual C++ і копіювання наявних ресурсів меню IDR_HIERSVRTYPE. Перейменувати новий ресурс IDR_HIERSVRTYPE_SRVR_EMB (це ж іменування, що використовує AppWizard). Наступна зміна "Збереження файлу" до "Оновлення"; Дайте йому команди ID ID_FILE_UPDATE. Також змінити "Зберегти як", щоб "Зберегти копію як"; Дайте йому команди ID ID_FILE_SAVE_COPY_AS. Рамках забезпечує виконання обох цих команд.
\hiersvr\svritem.h(60): помилка C2433: 'OLESTATUS': 'віртуального' не дозволено даних декларації
\hiersvr\svritem.h(60): помилка C2501: 'OLESTATUS': відсутній decl визначники
\hiersvr\svritem.h(60): C2146 помилка: синтаксис помилка: відсутні ';' перед ідентифікатор 'OnSetData'
\hiersvr\svritem.h(60): C2061 помилка: синтаксис помилка: ідентифікатор 'OLECLIPFORMAT'
\hiersvr\svritem.h(60): помилка C2501: 'OnSetData': відсутній decl визначники
Є ряд помилок в результаті перевизначити OnSetData, оскільки вона має на увазі OLESTATUS типу. OLESTATUS було так, як Ole1, які потребують повертаються помилки. Це було змінено на HRESULT в OLE 2, хоча MFC зазвичай перетворюється в HRESULT COleException яка містить помилку. В даному випадку перевизначити OnSetData більше не є необхідним, так простіше за все зробити, це видалити його.
\hiersvr\svritem.cpp(30): помилка C2660: 'COleServerItem::COleServerItem': функцію не займає 1 параметрів
Конструктор COleServerItem приймає додатковий параметр 'BOOL'. Цей прапор визначає, як управління пам'яттю робиться на COleServerItem об'єктів. Встановивши його до ІСТИНИ, в рамках ручками цих об'єктів, керування пам'яттю — видаляти їх, коли вони вже не потрібні. HIERSVR використовує CServerItem (походить від COleServerItem) об'єкти як частину своєї рідної даних, так що ви будете встановити цей прапор FALSE. Це дозволяє HIERSVR визначити, коли видаляється кожний елемент, сервер.
\hiersvr\svritem.cpp(44): помилка C2259: 'CServerItem': незаконно спроба примірник абстрактний клас
\hiersvr\svritem.cpp(44): помилка C2259: 'CServerItem': незаконно спроба примірник абстрактний клас
Як припускають, ці помилки, є деякі 'чистий віртуальних' функцій, які не були змінені в CServerItem. Швидше за все це викликано тим, що змінилося OnDraw в список параметрів. Щоб виправити цю помилку, змінити CServerItem::OnDraw наступним чином (а також декларації в svritem.h)
BOOL CServerItem::OnDraw(CDC* pDC, CSizeamp; rSize)
{
/ / запит з OLE для малювання вузол
pDC - > SetMapMode(MM_TEXT); / / завжди у пікселях
повернення DoDraw (pDC, CPoint(0,0), FALSE);
}
Новий параметр є 'rSize'. Це дозволяє заповнювати розмір полотна, якщо зручно. Цей розмір має бути в HIMETRIC. У цьому випадку, це не зручно, щоб заповнити це значення, так що рамках закликає OnGetExtent для отримання ступеня. Для цього на роботу ви будете мати для здійснення OnGetExtent:
BOOL CServerItem::OnGetExtent(DV&ASPECT dwDrawAspect, CSizeamp; rSize)
{
Якщо (dwDrawAspect! = DVASPECT_CONTENT)
повернення COleServerItem::OnGetExtent (dwDrawAspect, rSize);
rSize = CalcNodeSize();
повертає TRUE;
}
\hiersvr\svritem.cpp(104): помилка C2065: 'm_rectBounds': неоголошену ідентифікатор
\hiersvr\svritem.cpp(104): помилка C2228: ліворуч від '.SetRect' необхідно мати типу класу, структури, Союз
\hiersvr\svritem.cpp(106): помилка C2664: ' порожнеча __pascal __far DPtoLP (типу struct:: tagPOINT __far *, int) __far константа ': не вдалося перетворити параметр 1 з ' int __far *' до ' типу struct:: tagPOINT __far *'
На CServerItem::CalcNodeSize, у функції розмір елементів перетворюються на HIMETRIC і зберігаються в m_rectBounds. Незадокументовані 'm_rectBounds' член COleServerItem не існує (це було частково замінено на m_sizeExtent, але в OLE 2 цей компонент має дещо інший використання, ніж m_rectBounds зробив у Ole1, які потребують). Замість того, щоб встановлення розміру HIMETRIC до цієї змінної-члена, ви будете повернути її. Це значення використовується в OnGetExtent, реалізована раніше.
CSize CServerItem::CalcNodeSize()
{
nbsp; CClientDC dcScreen(NULL);
m_sizeNode = dcScreen.GetTextExtent (m_strDescription,
m_strDescription.GetLength());
m_sizeNode + = CSize (CX_INSET * 2, CY_INSET * 2);
/ / встановити запропонований розмір HIMETRIC
Розмір CSize (m_sizeNode.cx, m_sizeNode.cy);
dcScreen.SetMapMode(MM_HIMETRIC);
dcScreen.DPtoLP(&size);
повернення розмір;
}
CServerItem також має перевагу над COleServerItem::OnGetTextData. Ця функція є застарілою MFC/OLE і замінена інший механізм. Версія MFC 3.0 MFC OLE зразка HIERSVR здійснює цю функцію на заміщення COleServerItem::OnRenderFileData. Ця функція не важливо для цього основні порту, так що ви можете видалити перевизначити OnGetTextData.
Є багато більше помилок svritem.cpp, які ще не були розглянуті. Вони не є "реальний" помилки — просто помилки, викликані попередньої помилки.
\hiersvr\svrview.cpp(325): помилка C2660: 'CopyToClipboard': функцію не займе 2 параметри
COleServerItem::CopyToClipboard більше не підтримує прапор 'bIncludeNative'. Рідний даних (дані, записані сервера елемент Serialize функції) завжди копіюється, так що вам видалити перший параметр. Крім того, CopyToClipboard буде кидати виняток, коли помилка відбувається, замість того щоб повернутися FALSE. Наступним чином змінити код для CServerView::OnEditCopy
недійсним CServerView::OnEditCopy()
{
nbsp; Якщо (m_pSelectedNode = = NULL)
AfxThrowNotSupportedException();
СПРОБУЙТЕ
{
m_pSelectedNode - > CopyToClipboard(TRUE);
}
CATCH_ALL(e)
{
AfxMessageBox ("Копіювати до буфера обміну, помилка");
}
END_CATCH_ALL}
Хоча було більше помилок в результаті компіляції Версія MFC 2.0 HIERSVR, ніж було за таку саму версію OCLIENT, були насправді менше зміни.
На даний момент HIERSVR зібрати і посилання і функціонувати як OLE-сервер, але без редагування функції на місці, який буде реалізований Наступна.
Додавання "Візуального редагування"
Щоб додати цей додаток-сервер "Візуального редагування" (або активації на місці), є тільки кілька речей, які ви повинні дбати про:
Ресурс меню можна легко створити. Запустити Visual C++, копіювати ресурс меню IDR_HIERSVRTYPE меню ресурсу під назвою IDR_HIERSVRTYPE_SRVR_IP. Змінити меню, так що залишається спливаючі лише редагувати і допомогти меню вікна. Додати два роздільники меню між меню Правка і допомогти (він повинен виглядати: редагування | | Допомогти). Більш докладну інформацію про те, що ці роздільники означає та як об'єднання меню сервер "і" контейнер див "Меню та ресурси: меню об'єднання" в OLE 2 класи.
Малюнок для набір інструментів, можуть бути легко створені шляхом копіювання одного з свіжих програми AppWizard, що генеруються з "Сервер" параметр, що перевірив. Зображення можуть бути імпортовані в Visual C++. Переконайтеся, що дати малюнка ID 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-gt;TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
Point.x, point.y, AfxGetApp() - > m_pMainWnd)
Зверніть увагу, посилання на (AfxGetApp)-gt; m_pMainWnd. Коли сервер знаходиться на місці активовано, має головного вікна і m_pMainWnd встановлений, але це зазвичай невидимим. Крім того, це вікно відноситься до головного вікна додатка, вікна MDI кадру, що з'являється, коли сервер повністю відкрити або запустити автономний. Це не відноситься до активної рамки вікна — коли на місці активована саме вікно кадр, отриманих від COleIPFrameWnd. Щоб отримати правильний активного вікна, навіть тоді, коли на місці монтажу, ця версія MFC додає нові функції, AfxGetMainWnd. Як правило, ви повинні використовувати цю функцію, а не AfxGetApp() - > m_pMainWnd. Цей код повинен змінити наступним чином:
pMenu-gt;TrackPopupMenu(TPM_CENTERALI&GN | TPM_RIGHTBUTTON,
Point.x, point.y, AfxGetMainWnd())
Тепер у вас є OLE-сервер, мінімально включена для функціональної у місці активації. Але є ще багато можливостей, доступних у MFC/OLE 2, які були недоступні у MFC/Ole1, які потребують. Див більше ідей, зразок HIERSVR функцій, ви можете здійснити. Нижче наведено деякі функції, що реалізує HIERSVR:
Зразок HIERSVR на MFC 3.0 також використовує дещо інший дизайн для її елементів сервера. Це допомагає, економії пам'яті і робить ваші посилання більш гнучкими. З версії 2.0 HIERSVR кожен вузол у дереві є на COleServerItem. COleServerItem здійснює трохи більше накладних витрат, ніж є строго необхідним для кожного з цих вузлів, але COleServerItem є обов'язковим для кожного активного посилання. Але здебільшого, є дуже мало активних посилань в будь-який даний момент часу. Щоб зробити це більш ефективною, HIERSVR у цій версії MFC відокремлює вузол від COleServerItem. Він має з CServerNode і CServerItem клас. CServerItem (походить від COleServerItem) тільки створюється як необхідно. Після того, як контейнер (або контейнери) припинити використання цієї конкретної посиланням для цього конкретного вузла, CServerItem об'єкт пов'язаний з у CServerNode буде видалено. Цей дизайн є більш ефективним і більш гнучкими. Його гнучкість приходить при роботі з декількома вибору посилання. Жоден з цих двох версій HIERSVR підтримка декількох виділення, але це було б набагато простіше, щоб додати (і підтримувати посилання на такий вибір) з версії MFC 3.0 HIERSVR, оскільки COleServerItem відділена від рідної даних.
Технічні примітки за номером |nbsp; Технічні примітки за категоріями