Ogólnych zagadnień związanych z migracją
Jednym z celów projektu dla klasy OLE 2 w MFC 2.5 (lub nowszej) było zachować dużo o takiej samej architekturze wprowadzone w MFC 2.0 obsługę OLE 1.0. W związku z tym wiele z tych samych klas OLE 2.0 MFC nadal istnieją w tej wersji MFC (COleDocument, COleServerDoc, COleClientItem, COleServerItem). Ponadto wiele interfejsów API w tych klas są dokładnie takie same. OLE 2 jest jednak różni drastycznie OLE 1.0, więc można oczekiwać, że niektóre szczegóły uległy zmianie. Osoby zaznajomione z obsługą OLE1 MFC 2.0 będzie czujesz w domu z obsługą 2.0 MFC firmy.
Jeśli przełączenie istniejących aplikacji MFC/OLE1 i dodanie funkcji OLE 2, należy przeczytać tę notatkę po raz pierwszy. Uwaga ta obejmuje niektóre zagadnienia ogólne mogą wystąpić podczas przenoszenie użytkownika funkcji OLE1 do 2 MFC/OLE i omówiono problemy bez przykrycia podczas przenoszenie dwa wnioski zawarte w MFC 2.0: próbki MFC OLE OCLIENT i HIERSVR.
Ważne jest MFC widok i dokumentu architektury
Jeżeli aplikacja nie używa MFC firmy widok i dokumentu architektury i chcesz dodać obsługę OLE 2 do aplikacji, nadszedł czas, aby przejść do widoku i dokumentu. Wiele korzyści MFC firmy OLE 2 klasy są tylko realizowane po aplikacja korzysta z wbudowanych architektury i składniki MFC.
Implementacja serwera lub kontenera bez używania architektury MFC jest możliwe, ale nie jest to zalecana.
Użyj MFC wykonania zamiast z własnych
MFC "puszkach realizacji" klas takich jak CToolBar, CStatusBari CScrollView zostały wbudowane specjalny kod Sprawa obsługę OLE 2. Tak jeśli w aplikacji można użyć tych klas będziesz korzystać z wysiłku wprowadzane do nich uświadomić sobie OLE. Ponownie jest możliwe "rolki samodzielnego skręcania" klasy tutaj w tych celach, ale nie jest zalecane. Jeśli trzeba zaimplementować podobną funkcjonalność, kod źródłowy MFC jest doskonałym odniesienia dotyczące niektórych punktów drobniejsze OLE (szczególnie, gdy chodzi o aktywacji w miejscu).
Sprawdzić kod przykładowy MFC
Istnieje pewna liczba próbek MFC, które zawierają funkcje OLE. Każdy z tych aplikacji implementuje OLE z różnych kąt:
HIERSVR - przeznaczony głównie do użycia jako aplikacja serwera. Została uwzględniona w MFC 2.0 jako aplikacja MFC/OLE1 i został na 2 MFC/OLE i następnie rozszerzone tak, aby implementuje wiele funkcji OLE dostępne w OLE 2.
OCLIENT - jest to aplikacji autonomicznych kontenera, przeznaczona do wykazania wiele cech OLE z punktu widzenia kontenera. To zbyt została przeniesiona z MFC 2.0, a następnie przedłużone do obsługi wielu bardziej zaawansowane funkcje OLE, takich jak formaty niestandardowe Schowka i łącza do elementów osadzonych.
DRAWCLI - tej aplikacji implementuje wsparcia kontenera OLE znacznie tak jak robi to OCLIENT, z zastrzeżeniem, że robi w ramach istniejącego programu rysunku zorientowane obiektowo. To pokazuje jak może implementują obsługę kontenera OLE i zintegrowanie istniejących aplikacji.
SUPERPAD - tej aplikacji, jak również są dobrze aplikację autonomiczną, jest również serwerem OLE. Obsługa serwera, który implementuje jest całkiem minimalistyczny. Szczególnie interesujący jest jak wykorzystuje usługi Schowka OLE do kopiowania danych do Schowka, ale używa funkcji wbudowanych w system Windows "Edytuj" kontrola wdrażania Schowka Wklej funkcję. Pokazuje to interesujące wymieszać tradycyjnego użycia interfejsu API systemu Windows, jak również integracji z nowym OLE API.
Aby uzyskać więcej informacji na temat aplikacji przykładowych zobacz "MFC próbki pomoc".
Analiza przypadku: OCLIENT z MFC 2.0
Omówionego powyżej, OCLIENT została uwzględniona w MFC 2.0 i wdrożone OLE z MFC/OLE1. Poniżej opisano kroki, które ta aplikacja początkowo został przekonwertowany do używania klas MFC/OLE 2. Liczba funkcje zostały dodane po początkowym portu została ukończona aby lepiej zilustrować klas MFC/OLE. Te funkcje nie będzie tutaj; pokrytych Zapoznaj się próby więcej informacji na temat tych zaawansowanych funkcji.
Uwaga Błędy kompilatora i krok po kroku proces został utworzony z programem Visual C++ 2.0. Szczegółowe komunikaty i lokalizacje mogły ulec zmianie z Visual C++ 4.0, ale informacje koncepcyjne pozostaje ważne.
Wprowadzenie i z systemem
Podejście do portu OCLIENT próby MFC/OLE jest uruchomienie przez budowę i ustalające błędy kompilatora oczywiste, które powodują. Jeśli pobrać próbkę OCLIENT z MFC 2.0 i skompiluj go w tej wersji MFC, przekonasz się, że nie są to wiele błędów do rozwiązania. Poniżej opisano błędy w takiej kolejności, w której wystąpił.
Kompilacji i napraw błędy
\oclient\mainview.cpp(104): błąd C2660: "Draw": funkcja nie ma parametrów 4
Pierwszy błąd dotyczy COleClientItem::Draw. W MFC/OLE1 zajęło więcej parametrów nie ma wersji MFC/OLE. Dodatkowe parametry często nie były konieczne, jak i zazwyczaj NULL (tak jak w poniższym przykładzie). Ta wersja MFC automatycznie można określić wartości lpWBounds, gdy CDC, który jest rysowana do metaplik DC. Ponadto parametr pFormatDC już jest niezbędne, ponieważ ramach będzie zbudować jeden z "atrybut DC" pDC przekazany. Aby rozwiązać ten problem, wystarczy usunąć dwie dodatkowe NULL parametry wywołania Draw.
\oclient\mainview.cpp(273): błąd C2065: 'OLE_MAXNAMESIZE': identyfikator nielegalnej
\oclient\mainview.cpp(273): błąd C2057: oczekiwano wyrażenie stałe
\oclient\mainview.cpp(280): błąd C2664: 'CreateLinkFromClipboard': nie można przekonwertować parametr 1 z 'char [1]' na ' enum:: tagOLERENDER "
\oclient\mainview.cpp(286): błąd C2664: 'CreateFromClipboard': nie można przekonwertować parametr 1 z 'char [1]' na ' enum:: tagOLERENDER "
\oclient\mainview.cpp(288): błąd C2664: 'CreateStaticFromClipboard': nie można przekonwertować parametr 1 z 'char [1]' na ' enum:: tagOLERENDER "
Powyższych błędów wynika z faktu, że wymagane wszystkie funkcje COleClientItem::CreateXXXX w MFC/OLE1 przekazany unikatową nazwę do reprezentowania element. Było to wymogu podstawowego OLE API. Jest to nie konieczne w MFC/OLE 2 ponieważ OLE 2 nie używać DDE jako podstawowego mechanizmu komunikacji (nazwa używana była w konwersacji DDE). Aby rozwiązać ten problem, można usunąć funkcję CreateNewName także jako wszystkie odwołania do niego. To proste dowiedzieć się, jakie każda funkcja MFC/OLE oczekuje w tej wersji po prostu przez umieszczenie kursora na wywołanie i naciskając klawisz F1.
Inny obszar, który różni się znacząco jest Obsługa schowka OLE 2. Z OLE1 używany do Schowka systemu Windows, które interfejsów API interakcji ze Schowka. OLE 2 to zrobić za pomocą innego mechanizmu. API MFC/OLE1 założyć, że Schowka została otwarta przed rozpoczęciem kopiowania obiektu COleClientItem do Schowka. To nie jest już konieczne i spowoduje, że wszystkie operacje schowka MFC/OLE nie powiedzie się. Podczas edycji kodu do usunięcia zależności CreateNewName, należy także usunąć kod, który otwiera i zamyka schowka systemu Windows.
\oclient\mainview.cpp(332): błąd C2065: 'AfxOleInsertDialog': identyfikator nielegalnej
\oclient\mainview.cpp(332): błąd C2064: termin nie oceny do funkcji
\oclient\mainview.cpp(344): błąd C2057: oczekiwano wyrażenie stałe
\oclient\mainview.cpp(347): błąd C2039: 'CreateNewObject': nie jest członkiem "CRectItem"
Błędy te wynikają z obsługi CMainView::OnInsertObject . Obsługa polecenia "Wstaw nowy obiekt" jest kolejnym obszarem, gdzie things have changed trochę. W tym przypadku jest najłatwiejszym po prostu scalić Oryginalna implementacja z przewidzianego przez AppWizard nowych aplikacji kontenera OLE. W rzeczywistości jest to technika, który można zastosować do przenoszenie innych aplikacji. W MFC/OLE1 jest wyświetlane okno dialogowe "Wstaw obiekt" przez wywołanie funkcji AfxOleInsertDialog . W tej wersji konstruowania obiektu okna dialogowego COleInsertObject i wywołania DoModal. Ponadto nowe elementy OLE są tworzone z identyfikatora CLSID zamiast ciąg classname. Wynik końcowy powinno wyglądać mniej więcej tak
COleInsertDialog dlg;
Jeżeli (dlg.DoModal()! = IDOK)
nbsp; powrotu;
BeginWaitCursor();
CRectItem * pItem = NULL;
SPRÓBUJ
{
/ / Najpierw utworzyć obiekt C++
pItem = GetDocument() - > CreateItem();
ASSERT_VALID(pItem);
/ / Zainicjować elementu danych okno dialogowe.
Jeżeli (! dlg.CreateItem(pItem))
AfxThrowMemoryException();
/ / każdy wyjątek będzie wykonywać
ASSERT_VALID(pItem);
/ / run obiektu, jeśli właściwe
Jeżeli (dlg.GetSelectionType() == COleInsertDialog::createNewItem)
pItem - > DoVerb(OLEIVERB_SHOW, this);
/ aktualizacji natychmiast
pItem - > UpdateLink();
pItem - > UpdateItemRectFromServer();
/ / ustawić zaznaczenie na nowo wstawiony element
SetSelection(pItem);
pItem - > Invalidate();
}
POŁÓW (CException, e)
{/ / oczyszczania elementu
Jeżeli (pItem! = NULL)
GetDocument() - > DeleteItem(pItem);
AfxMessageBox(IDP_FAILED_TO_CREATE);
}
END_CATCH
EndWaitCursor()
Uwaga Wstaw nowy obiekt może być inna dla aplikacji):
Jest również obejmować lt;afxodlgs.h > zawierający deklarację klasy okno dialogowe COleInsertObject , jak również innych okien standardowe dostarczone przez MFC.
\oclient\mainview.cpp(367): błąd C2065: 'OLEVERB_PRIMARY': identyfikator nielegalnej
\oclient\mainview.cpp(367): błąd C2660: 'DoVerb': funkcja nie ma parametrów 1
Te błędy są powodowane przez fakt, że niektóre stałe OLE1 zmieniły się w OLE 2, chociaż pojęcia są takie same. W tym przypadku OLEVERB_PRIMARY została zmieniona na OLEIVERB_PRIMARY. Zarówno OLE1, jak i OLE 2 podstawowe czasownika jest zwykle wykonywane przez kontener, gdy użytkownik kliknie element.
Ponadto, DoVerb teraz trwa jako dodatkowy parametr — wskaźnik do widoku (CView*). Ten parametr jest używany wyłącznie do realizacji "Edycji wizualnej" (lub aktywacji w miejscu). Teraz ustawieniu tego parametru na wartość NULL, ponieważ są nie wykonania tej funkcji, w tym czasie.
Aby upewnić się, że ramy nigdy nie próby w miejscu aktywacji, należy zastąpić COleClientItem::CanActivate następująco
BOOL CRectItem::Ca&nActivate()
{
nbsp; return FALSE;
}
\oclient\rectitem.cpp(53): błąd C2065: 'GetBounds': identyfikator nielegalnej
\oclient\rectitem.cpp(53): błąd C2064: termin nie oceny do funkcji
\oclient\rectitem.cpp(84): błąd C2065: 'SetBounds()': identyfikator nielegalnej
\oclient\rectitem.cpp(84): błąd C2064: termin nie oceny do funkcji
W MFC/OLE1 COleClientItem::GetBounds i setBounds() zostały wykorzystane do kwerendy i manipulować w zakresie elementu ( lewego i górnego członków były zawsze zera). 2 MFC/OLE jest to bardziej bezpośrednio obsługiwane przez COleClientItem::GetExtent i SetExtent, które zajmują się rozmiar lub CSize zamiast.
Kod Twojego nowego SetItemRectToServer, i UpdateItemRectFromServer rozmowy wygląda jak to:
BOOL CRectItem::UpdateItemRectFromServer()
{
nbsp; Assert(m_bTrackServerSize);
CSize rozmiar;
if (!.GetExtent(&size))
return FALSE; / / puste
/ mapę z HIMETRIC do współrzędnych ekranu
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.LPtoDP(&size);
}
/ / wystarczy ustawić rozmiar elementu
Jeżeli (m_rect.Size()! = rozmiar)
{
/ / unieważnia Stary rozmiar lub pozycję
Invalidate();
m_rect.Right = m_rect.left + size.cx;
m_rect.bottom = m_rect.top + size.cy;
/ / jak nowy rozmiar lub pozycję
Invalidate();
}
Zwraca wartość PRAWDA;
}
BOOL CRectItem::SetItemRectToServer()
{
/ / set Urzędowym granice dla osadzonego elementu
Rozmiar CSize = m_rect.Size();
{
CClientDC screenDC(NULL);
screenDC.SetMapMode(MM_HIMETRIC);
screenDC.DPtoLP(&size);
}
SPRÓBUJ
{
SetExtent(size); / /, może to uczynić oczekiwania
}
POŁÓW (CException, e)
{
return FALSE; / / łącza nie zezwoli na setBounds()
}
END_CATCH
Zwraca wartość PRAWDA;
}
\oclient\frame.cpp(50): błąd C2039: 'InWaitForRelease': nie jest członkiem "COleClientItem"
\oclient\frame.cpp(50): błąd C2065: 'InWaitForRelease': identyfikator nielegalnej
\oclient\frame.cpp(50): błąd C2064: termin nie oceny do funkcji
W MFC/OLE1 synchroniczne wywołania interfejsu API z kontenerem serwera były symulowane, ponieważ OLE1 natury asynchronicznej w wielu przypadkach. Konieczne było sprawdzić połączenie asynchroniczne pozostających do spłaty w toku przed przetworzeniem polecenia od użytkownika. MFC/OLE1 przewidziane czyniąc funkcji COleClientItem::InWaitForRelease . 2 MFC/OLE nie jest to konieczne, więc można usunąć zastępowanie OnCommand w CMainFrame wszystkich razem.
W tym momencie OCLIENT będzie kompilować i łącza.
Inne niezbędne zmiany
Istnieje kilka rzeczy które nie sporządzono, które będą OCLIENT uruchamianie, jednak. Lepiej jest rozwiązać te problemy teraz zamiast później.
Przede wszystkim należy zainicjować biblioteki OLE. Robi się to przez wywołanie AfxOleInit z InitInstance:
if (!.AfxOleInit())
{
AfxMessageBox („nie można zainicjować biblioteki OLE");
return FALSE;
}
Należy również warto sprawdzić wirtualnego funkcje dla parametru lista zmian. Jedna taka funkcja jest COleClientItem::OnChange, zastąpiona w każdej aplikacji kontenera MFC/OLE. Patrząc na pomoc online, zobaczysz, że dodatkowe "DWORD dwParam" została dodana. Nowy CRectItem::OnChange wygląda następująco
void CRectItem::OnChange (OLE_NOTIFICATION wNotification, DWORD dwParam)
{
Jeżeli (m_bTrackServerSize amp; &
!UpdateItemRectFromServer())
{
/ / Pusty obiekt
Jeżeli (wNotification == OLE_CLOSED)
{
/ / żadne dane nie otrzymane dla obiektu - zniszczyć ją
POTWIERDZAJ (!.IsVisible());
GetDocument() - > DeleteItem(this);
powrotu; / / nie aktualizacji (pozycja is gone teraz)
}
}
Jeżeli (wNotification! = OLE_CLOSED)
Dirty();
Invalidate(); / / wszelkich zmian spowoduje, że odświeżanie
}
W MFC/OLE1 aplikacji kontenera uzyskane klasy dokumentu z COleClientDoc. 2 MFC/OLE została usunięta i zastąpiona przez COleDocument (ta nowa organizacja ułatwia tworzenie aplikacji kontenera/serwer) tej klasy. Istnieje, # define mapująca COleClientDoc na COleDocument aby uprościć przenoszenie aplikacji MFC/OLE1 2 MFC/OLE, takich jak OCLIENT. Jedną z cech nie dostarczonych przez COleDocument , który został dostarczony przez COleClientDoc jest zapisów mapy wiadomości polecenia standardowego. Robi się to tak, że aplikacje serwera, które również użyć COleDocument (pośrednio), nie niosą ze sobą obciążenia te obsługi polecenia chyba, że są one aplikację kontenera/serwer. Tak należy dodać następujące wpisy do mapy wiadomości 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)
Wdrożenie wszystkich tych poleceń jest COleDocument, który jest klasą bazową dla dokumentu.
W tym momencie OCLIENT jest funkcjonalności aplikacji kontenera OLE. Istnieje możliwość wstawiania elementów dowolnego typu (OLE1 lub OLE 2). Ponieważ kod niezbędne do umożliwienia aktywacji w miejscu nie jest zaimplementowana, elementy są edytowane w oddzielnym oknie, bardzo podobnie, jak w OLE1. Następna sekcja omawia koniecznych zmian, aby umożliwić, w miejsce edycji (czasami nazywany "Edycji wizualnej").
Dodawanie "Edycji wizualnej"
Jedną z najbardziej interesujących OLE jest w miejscu aktywacji (lub "Edycji wizualnej"). Ta funkcja umożliwia aplikacji serwera do przejęcia części interfejsu użytkownika kontenera przewidzianego bardziej edycji interfejs użytkownika. Do wykonania aktywacji w miejsce na OCLIENT, niektóre specjalne zasoby muszą zostać dodane, jak również niektóre dodatkowy kod. Te zasoby i kod są zazwyczaj świadczone przez AppWizard — w rzeczywistości była znaczna część tutaj kod pożyczonych bezpośrednio z świeżego AppWizard aplikacji z obsługą "Kontenera".
Po pierwsze należy dodać zasób menu, gdy istnieje element, który jest aktywny w miejscu. Ten zasób menu dodatkowych można utworzyć w programie Visual C++ kopiowanie zasobów IDR_OCLITYPE i usuwając wszystkie oprócz pliku i okien wyskakujących. Dwa bary separatora dodaje się między pliku i okien wyskakujących do wskazania oddzielenia grup (powinno wyglądać tak jak: plik || Okno). Więcej informacji na temat Co oznaczają te separatory i jak są scalane menu serwera i kontenera zobacz "Menu i zasobów: scalania Menu" OLE 2 klas.
Po uzyskaniu tych menu utworzonych, trzeba niech ramy wiedza o nich. Robi się to przez wywołanie CDocTemplate::SetContainerInfo w szablonie dokumentu przed dodaniem go do listy szablonów dokumentów w Twojej InitInstance. Nowy kod do zarejestrowania szablonu dokumentu wygląda
CDocTemplate * pTemplate = new CMultiDocTemplate (
nbsp; IDR_OLECLITYPE,
RUNTIME_CLASS(CMainDoc),
RUNTIME_CLASS(CMDIChildWnd), / / standardowe ramek podrzędnych MDI
RUNTIME_CLASS(CMainView));
pTemplate - > SetContainerInfo(IDR_OLECLITYPE_INPLACE);
AddDocTemplate(pTemplate)
Zasoby IDR_OLECLITYPE_INPLACE to specjalne zasoby w miejscu utworzone w programie Visual C++.
W celu umożliwienia aktywacji w miejscu, istnieje kilka rzeczy, które trzeba zmienić w CView (CMainView) uzyskane klasy, a także klasy COleClientItem pochodnych (CRectItem). Wszystkie te przesłonięcia są świadczone przez AppWizard i większość wykonania będą pochodzić bezpośrednio z domyślną aplikację AppWizard.
W pierwszym kroku tego portu w miejscu aktywacji został wyłączony z całkowicie nadrzędnym COleClientItem::CanActivate. To zastąpienie powinny zostać usunięte umożliwienia aktywacji w miejscu. Ponadto NULL został przekazany wszystkie wywołania DoVerb (ma dwóch z nich), ponieważ zapewnienie że widok tylko niezbędne dla aktywacji w miejscu. Do pełnego wdrożenia w miejscu aktywacji, należy przekazać odpowiednim widokiem wywołania DoVerb . Jeden z tych połączeń jest CMainView::OnInsertObject
pItem-> DoVerb(OLEIVERB_SHOW, this)
Inny jest w CMainView::OnLButtonDblClk
m_pSelection-> DoVerb(OLEIVERB_PRIMARY, this)
Należy zastąpić COleClientItem::OnGetItemPosition. To mówi serwerowi gdzie umieścić jej okno względem okna kontenera, gdy element znajduje się w miejscu aktywowany. Dla OCLIENT wykonania jest trywialny
void CRectItem::OnGetItemPosition (CRect& rPosition)
{
rPosition = m_rect;
}
Większość serwerów także implementować, co jest nazywane "w miejscu rozmiaru." Pozwala to okno serwer o rozmiarze i przeniesiony podczas, gdy użytkownik jest edytowanie elementu. Kontener muszą uczestniczyć w tej akcji, ponieważ przenoszenie lub zmiana rozmiaru okna zazwyczaj wpływa na położenie i rozmiar w dokumencie kontenera. Wykonania na OCLIENT synchronizuje wewnętrznego prostokąt utrzymywane przez m_rect z nową pozycję i rozmiar.
BOOL CRectItem::OnChangeItemPosition(const CRectamp; rectPos)
{
ASSERT_VALID(This);
if (!.COleClientItem::OnChangeItemPosition(rectPos))
return FALSE;
Invalidate();
m_rect = rectPos;
Invalidate();
GetDocument() - > SetModifiedFlag();
Zwraca wartość PRAWDA;
}
W tym momencie istnieje wystarczająco dużo kodu, aby umożliwić elementu w miejscu aktywowane i do czynienia z zmiany rozmiaru i przenoszenie towaru, gdy jest aktywny, ale nie ma żadnego kodu, który umożliwi użytkownikowi zakończyć sesji edycyjnej. Chociaż niektóre serwery zapewni tej funkcji same przez obsługę klawisz escape, proponuje się, że pojemniki zapewniają dezaktywacji elementu na dwa sposoby: (1) przez kliknięcie przycisku spoza elementu i (2) poprzez wciśnięcie klawisz escape.
Dla escape klucz dodać accelerator Visual C++, mapująca klucza VK_ESCAPE do polecenia, ID_CANCEL_EDIT jest dodawana do zasobów. Program obsługi dla tego polecenia następuje:
/ / Następujące obsługi polecenia zawiera standardowe
/ / klawiatury interfejs użytkownika, aby anulować w miejscu
/ / Edycja session.void CMainView::OnCancelEdit()
{
nbsp; / / Zamknij wszelkie w miejscu aktywnego elementu w tym widoku.
COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Jeżeli (pActiveItem! = NULL)
pActiveItem - > Close();
Assert(GetDocument()-> GetInPlaceActiveItem(this) == NULL);
}
Do obsługi w przypadku, gdy użytkownik kliknie poza element, możesz Dodaj następujący kod do rozpoczęcia CMainView::SetSelection
jeżeli (pNewSel! = m_pSelection || pNewSel == NULL)
{
nbsp; COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Jeżeli (pActiveItem! = NULL & & pActiveItem! = pNewSel)
pActiveItem - > Close();
}
& nbsp
Gdy element jest aktywny w miejscu, powinna mieć fokus. Aby upewnić się, że tak jest w przypadku OnSetFocus uchwyt, tak aby fokus jest zawsze przeniesione do aktywnego elementu, gdy otrzymuje fokus, widok:
/ / Wymagane są specjalne obsługi OnSetFocus i OnSize / / jeżeli obiekt jest edycji w miejscu.
void CMainView::OnSetFocus (CWnd * pOldWnd)
{
nbsp; COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Jeżeli (pActiveItem! = NULL & &
pActiveItem - > GetItemState() == COleClientItem::activeUIState)
{
/ / należy ustawić fokus do tego elementu, jeśli jest tego samego widoku
CWnd * pWnd = pActiveItem - > GetInPlaceWindow();
Jeżeli (pWnd! = NULL)
{
pWnd - > SetFocus(); / / Nie wywołuj klasy podstawowej
powrotu;
}
}
CView::OnSetFocus(pOldWnd);
}
Gdy zmieniany jest rozmiar widoku należy powiadomić czynnych element, który zmienił się prostokąta przycinania. W tym celu podajesz obsługi dla OnSize:
void CMainView::OnSize (UINT nType, int cx, int cy)
{
nbsp; CView::OnSize (nType, cx, cy);
COleClientItem * pActiveItem = GetDocument() - > GetInPlaceActiveItem(this);
Jeżeli (pActiveItem! = NULL)
pActiveItem - > SetItemRects();
}
Analiza przypadku: HIERSVR z MFC 2.0
HIERSVR została również uwzględniona w MFC 2.0 i wdrożone OLE z MFC/OLE1. Uwaga ta krótko opisano kroki, które ta aplikacja początkowo został przekonwertowany do używania klas MFC/OLE 2. Liczba funkcje zostały dodane po początkowym portu została ukończona aby lepiej zilustrować klas MFC/OLE 2. Te funkcje nie będzie tutaj; pokrytych Zapoznaj się próby więcej informacji na temat tych zaawansowanych funkcji.
Uwaga Błędy kompilatora i krok po kroku proces został utworzony z programem Visual C++ 2.0. Szczegółowe komunikaty i lokalizacje mogły ulec zmianie z Visual C++ 4.0, ale informacje koncepcyjne pozostaje ważne.
Wprowadzenie i z systemem
Podejście do portu HIERSVR próby MFC/OLE jest uruchomienie przez budowę i ustalające błędy kompilatora oczywiste, które powodują. Jeśli pobrać próbkę HIERSVR z MFC 2.0 i skompiluj go w tej wersji MFC, przekonasz się, że nie istnieje wiele błędów do rozwiązania (chociaż istnieje ponad próbką OCLIENT). Poniżej opisano błędy w takiej kolejności, w jakiej występują zwykle.
Kompilacji i napraw błędy
\hiersvr\hiersvr.cpp(83): błąd C2039: 'RunEmbedded': nie jest członkiem "COleTemplateServer"
Ten pierwszego błędu wskazuje dużo większy problem z funkcją InitInstance serwerów. Inicjowanie wymagane dla serwera OLE jest prawdopodobnie jednym z największych zmian, które trzeba będzie wprowadzić do aplikacji MFC/OLE1 go z systemem. Najwazniejsze zrobić jest przyjrzeć się AppWizard tworzy dla serwera OLE i modyfikować kodu jako właściwe. Oto niektóre punkty należy pamiętać o:
Konieczne jest zainicjowanie bibliotek OLE przez wywołanie AfxOleInit
Wywołanie SetServerInfo w obiekcie szablon dokumentu ustawić serwer zasobów uchwytów i informacje klasy runtime, że nie można ustawić z konstruktora CDocTemplate.
Nie wyświetlaj okna głównego aplikacji, jeśli za jest obecny w wierszu polecenia.
Potrzebny identyfikator GUID dla dokumentu. Jest to unikatowy identyfikator typu dokumentu (128 bitów). AppWizard spowoduje utworzenie jednej dla Ciebie — tak jeśli za pomocą technik opisanych tutaj kopiowania nowego kodu z nową aplikację serwera AppWizard generowane, użytkownik może po prostu "steal" GUID z tej aplikacji. Jeśli tak się nie stanie, można użyć GUIDGEN.Narzędzie EXE w katalogu BIN.
Jest "połączenia" obiektu COleTemplateServer w szablonie dokumentu przez wywołanie COleTemplateServer::ConnectTemplate.
Aktualizacja rejestru systemu, kiedy aplikacja jest uruchamiana autonomicznych. W ten sposób, jeśli użytkownik przesuwa.EXE dla aplikacji, uruchamiając ją z nowym położeniu zaktualizuje systemowej bazy danych rejestracji systemu Windows do nowej lokalizacji.
Po zastosowaniu, wszystkie te zmiany na podstawie AppWizard tworzy dla InitInstance, InitInstance (i związanych z nimi GUID) dla HIERSVR należy otrzymuje brzmienie:
// 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;
}
Można zauważyć, że powyższy kod odnosi się do nowy identyfikator zasobów, IDR_HIERSVRTYPE_SRVR_EMB. Jest to zasób menu, aby być używane podczas edycji dokumentu, który jest osadzony w innym kontenerem. W MFC/OLE1 do edycji elementu osadzone elementy menu zostały zmodyfikowane w locie. Za pomocą struktury całkowicie różnych menu podczas edytowania osadzonego elementu zamiast edycji dokument oparty na pliku sprawia, że jest ona znacznie łatwiej zapewnić interfejsów użytkownika dla tych dwóch trybów obowiązują oddzielne. Jak zobaczysz później, zasób całkowicie oddzielnych menu jest używana podczas edycji obiektu osadzonego w miejscu.
Aby utworzyć ten zasób, wczytać skrypt zasobów do Visual C++ i skopiować istniejący zasób menu IDR_HIERSVRTYPE. Zmień nazwę nowego zasobu na IDR_HIERSVRTYPE_SRVR_EMB (jest to tego samego konwencji nazewnictwa, która używa AppWizard). Następnie zmień "Zapisz plik" na "Aktualizacja pliku"; Nadaj ID polecenia ID_FILE_UPDATE. Również zmienić "Pliku Zapisz jako" "Plik zapisać kopię jako"; Nadaj ID polecenia ID_FILE_SAVE_COPY_AS. Ramach zapewnia realizację obu tych poleceń.
\hiersvr\svritem.h(60): błąd C2433: "OLESTATUS": "wirtualnych" nie zezwala na deklaracje danych
\hiersvr\svritem.h(60): błąd C2501: 'OLESTATUS': brak decl specyfikatory
\hiersvr\svritem.h(60): błąd C2146: błąd składni: brak ';' przed identyfikatorem "OnSetData"
\hiersvr\svritem.h(60): błąd C2061: błąd składni: identyfikator 'OLECLIPFORMAT'
\hiersvr\svritem.h(60): błąd C2501: 'OnSetData': brak decl specyfikatory
Istnieje pewna liczba błędów wynikających z zastępowanie OnSetData, ponieważ odwołuje się do typu OLESTATUS . OLESTATUS został sposób, w jaki OLE1 zwrócił błędy. Ta została zmieniona na HRESULT OLE 2, chociaż MFC zazwyczaj konwertuje HRESULT COleException zawierające błąd. W tym szczególnym przypadku zastępowania OnSetData jest już konieczne, więc najłatwiejszym go usunąć.
\hiersvr\svritem.cpp(30): błąd C2660: 'COleServerItem::COleServerItem': funkcja nie ma parametrów 1
Konstruktor COleServerItem przyjmuje jako dodatkowy parametr 'BOOL'. Flaga ta określa, jak zarządzanie pamięcią odbywa się na obiekty COleServerItem . Przez ustawienie jej na wartość TRUE, ramy obsługuje zarządzanie pamięcią tych obiektów — ich usuwania, gdy są one już potrzebne. HIERSVR używa obiektów CServerItem (pochodzące z COleServerItem) jako część jego danych w trybie macierzystym, więc ta flaga będzie ustawiona na FALSE. To pozwala HIERSVR określają, kiedy skreśla się każdego elementu serwera.
\hiersvr\svritem.cpp(44): błąd C2259: 'CServerItem': niedozwolona próba do utworzenia wystąpienia klasy abstrakcyjnej
\hiersvr\svritem.cpp(44): błąd C2259: 'CServerItem': niedozwolona próba do utworzenia wystąpienia klasy abstrakcyjnej
Jak błędy te zakładają, istnieją pewne 'czystego wirtualnej' funkcje, które nie zostały zastąpione w CServerItem. Najprawdopodobniej jest to spowodowane przez fakt, że OnDraw przez parametr lista serwerów ulega zmianie. Aby naprawić ten błąd, należy zmienić CServerItem::OnDraw następująco (jak również deklaracja w svritem.h)
BOOL CServerItem::OnDraw(CDC* pDC, CSizeamp; rSize)
{
/ / żądania z OLE, aby narysować węzeł
pDC - > SetMapMode(MM_TEXT); / / zawsze w pikselach
Zwraca DoDraw (pDC, CPoint(0,0), FALSE);
}
Nowy parametr jest "rSize". Dzięki temu można wypełnić rozmiar rysunku, jeśli wygodne. Wielkość ta musi być HIMETRIC. W tym przypadku nie jest wygodne do wypełnienia tę wartość, więc ramy wywołuje OnGetExtent do pobrania w zakresie. Dla tej pracy trzeba zaimplementować OnGetExtent:
BOOL CServerItem::OnGetExtent(DV&ASPECT dwDrawAspect, CSizeamp; rSize)
{
Jeżeli (dwDrawAspect! = DVASPECT_CONTENT)
Zwraca COleServerItem::OnGetExtent (dwDrawAspect, rSize);
rSize = CalcNodeSize();
Zwraca wartość PRAWDA;
}
\hiersvr\svritem.cpp(104): błąd C2065: 'm_rectBounds': identyfikator nielegalnej
\hiersvr\svritem.cpp(104): błąd C2228: lewym brzegu ".SetRect' musi mieć typ klasy/struct/Unii
\hiersvr\svritem.cpp(106): błąd C2664: ' void __pascal __far DPtoLP (struct:: tagPOINT __far *, int) __far stała ': nie można konwertować parametru 1 z ' int __far *' do ' struct:: tagPOINT __far * "
W CServerItem::CalcNodeSize funkcja rozmiar elementu jest konwertowane na HIMETRIC i przechowywane w m_rectBounds. Nie istnieje członek nieudokumentowane 'm_rectBounds' COleServerItem (został częściowo zastąpiony przez m_sizeExtent, ale w OLE 2 tego członka ma nieco inne niż w OLE1 m_rectBounds ). Zamiast ustawiania rozmiaru HIMETRIC do tego Państwa zmienną, będziesz zwraca je. Zwrócona wartość jest używana w OnGetExtent, wprowadzone wcześniej.
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);
/ / set sugerowany rozmiar HIMETRIC
Rozmiar CSize (m_sizeNode.cx, m_sizeNode.cy);
dcScreen.SetMapMode(MM_HIMETRIC);
dcScreen.DPtoLP(&size);
zwraca rozmiar;
}
CServerItem zastępuje również COleServerItem::OnGetTextData. Ta funkcja jest przestarzała w MFC/OLE i zastępuje inny mechanizm. Wersja MFC 3.0 próbki MFC OLE HIERSVR wykonuje tę funkcję nadrzędnym COleServerItem::OnRenderFileData. Ta funkcja nie jest ważne dla tego portu podstawowego, więc można usunąć zastępowanie OnGetTextData.
Istnieje wiele więcej błędów w svritem.cpp, które jeszcze nie zostały rozwiązane. Nie są one "real" błędów — tylko błędów spowodowanych błędami poprzedniego.
\hiersvr\svrview.cpp(325): błąd C2660: 'CopyToClipboard': funkcja nie ma parametrów 2
COleServerItem::CopyToClipboard nie obsługuje już Flaga 'bIncludeNative'. Dane macierzysty (dane zapisane przez funkcję Serialize elementu serwera) jest zawsze kopiowane, więc usunąć pierwszy parametr. Ponadto CopyToClipboard wygeneruje wyjątek, gdy zdarzy się błąd zamiast zwraca FALSE. Zmień kod dla CServerView::OnEditCopy w następujący sposób
void CServerView::OnEditCopy()
{
nbsp; Jeżeli (m_pSelectedNode == NULL)
AfxThrowNotSupportedException();
SPRÓBUJ
{
m_pSelectedNode - > CopyToClipboard(TRUE);
}
CATCH_ALL(e)
{
AfxMessageBox ("Kopiuj do Schowka nie powiodło się");
}
END_CATCH_ALL}
Chociaż było więcej błędów wynikających z kompilacji w wersji MFC 2.0 HIERSVR, niż były w tej samej wersji OCLIENT, zostały faktycznie mniej zmian.
W tym momencie HIERSVR będzie kompilować i łącza i działać jako serwer OLE, lecz bez funkcji edycji w miejscu, które będą wdrażane dalej.
Dodawanie "Edycji wizualnej"
Aby dodać do tej aplikacji serwera "Edycji wizualnej" (lub aktywacji w miejscu), istnieją tylko kilka rzeczy, które użytkownik musi zadbać o:
Zasób menu jest łatwe w tworzeniu. Uruchom Visual C++, skopiuj zasób menu IDR_HIERSVRTYPE do zasobu menu o nazwie IDR_HIERSVRTYPE_SRVR_IP. Modyfikowanie menu tak, aby pozostało tylko edycja i pomoc menu wyskakujących. Dodaj dwa separatory menu między menu Edycja i pomocy (powinno wyglądać tak jak: edycja || Pomoc). Więcej informacji na temat Co oznaczają te separatory i jak są scalane menu serwera i kontenera zobacz „menu i zasobów: scalania Menu" OLE 2 klas.
Mapa bitowa w pasku narzędzi podzbiór można łatwo utworzone przez kopiowanie jednej ze świeżych stosowania AppWizard generowanych za pomocą opcji "Serwer" kontrolowane. Tę mapę bitową następnie mogą być importowane do programu Visual C++. Pamiętaj o nadaniu mapy bitowej Identyfikatora IDR_HIERSVRTYPE_SRVR_IP.
Klasa pochodzi od COleIPFrameWnd mogą być kopiowane z aplikacji AppWizard generowane z obsługą serwera także. Skopiować obydwa pliki, IPFRAME.CPP i IPFRAME.H i dodać je do projektu. Upewnij się, że wywołanie LoadBitmap odnosi się do IDR_HIERSVRTYPE_SRVR_IP, bitowej utworzonej w poprzednim kroku.
Teraz, gdy tworzone są nowe zasoby i klasy, dodać potrzebny kod, tak aby ramach wie o te (i wie, że ta aplikacja obecnie obsługuje edycji w miejscu). Robi się to poprzez dodanie niektórych więcej parametrów SetServerInfo wywołanie funkcji InitInstance:
&pDocTemplate BT;SetServerInfo (IDR_HIERSVRTYPE_SRVR_EMB,
IDR_HIERSVRTYPE_SRVR_IP, RUNTIME_CLASS(CInPlaceFrame))
Jest teraz gotowa do uruchomienia w miejscu w jakimkolwiek pojemniku, który obsługuje też w miejscu aktywacji. Jednak istnieje jeden drobnych błędów recenzje ukryte w kodzie. HIERSVR obsługuje menu kontekstowe, wyświetlany, gdy użytkownik naciśnie przycisk prawym przyciskiem myszy. Menu to działa, gdy HIERSVR jest całkowicie otwarta, ale nie działa podczas edycji osadzania w miejscu. Powodem mogą przypięte w dół do tego jednej linii kodu w CServerView::OnRButtonDown
pMenu BT;TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
Point.x, point.y, AfxGetApp() - > m_pMainWnd)
Zwróć uwagę, odniesienie do (AfxGetApp)-gt; m_pMainWnd. Kiedy serwer jest miejsce aktywowany, posiada głównego okna i m_pMainWnd jest ustawiona, ale zazwyczaj niewidoczny. Ponadto w tym oknie odnosi się do głównego okna aplikacji, okna ramki MDI, który pojawia się, gdy serwer jest całkowicie otwarta lub Uruchom samodzielne. Nie odnosi się do okna aktywną ramkę — który w miejscu aktywowany po oknie ramki pochodzące z COleIPFrameWnd. Aby uzyskać poprawne aktywnego okna, nawet wtedy, gdy w miejscu edycji tej wersji MFC dodaje nową funkcję, AfxGetMainWnd. Ogólnie rzecz biorąc, należy użyć tej funkcji, a zamiast AfxGetApp() - > m_pMainWnd. Kod ten musi się zmienić w następujący sposób:
pMenu BT;TrackPopupMenu(TPM_CENTERALI&GN | TPM_RIGHTBUTTON,
Point.x, point.y, AfxGetMainWnd())
Teraz masz serwer OLE minimalny włączone dla funkcjonalnych w miejscu aktywacji. Jednakże nadal istnieje wiele funkcji dostępnych z 2 MFC/OLE, które nie były dostępne w MFC/OLE1. Zobacz próbki HIERSVR więcej pomysłów na funkcje, które warto wdrożyć. Niektóre funkcje, które implementuje HIERSVR są wymienione poniżej:
Próbki HIERSVR w MFC 3.0 używa również nieco inny wzór dla jego elementów serwera. To pomaga zachować więcej wolnej pamięci i sprawia, że łączy jest bardziej elastyczne. Z wersji 2.0 HIERSVR każdy węzeł w drzewie jest w COleServerItem. COleServerItem prowadzi nieco większe obciążenie niż jest to absolutnie niezbędne dla każdego z tych węzłów, ale COleServerItem jest wymagany dla każdego aktywnego łącza. Jednak w większości przypadków są bardzo niewiele aktywne łącza w danej chwili. Aby wprowadzić to bardziej skuteczne, HIERSVR w tej wersji MFC oddziela węzła z COleServerItem. Posiada zarówno CServerNode, jak i klasy CServerItem . CServerItem (pochodzące z COleServerItem) jest tworzony tylko w razie potrzeby. Po kontener (lub kontenery) zatrzymać, przy użyciu określonej łącze do tego określonego węzła, po usunięciu obiektu CServerItem związane z CServerNode. Ten projekt jest skuteczniejsze i bardziej elastyczne. Jego elastyczność pochodzi kontaktach z wielu łączy zaznaczenia. Żadna z tych dwóch wersji HIERSVR obsługuje wybór wielokrotny, ale byłoby znacznie łatwiejsze, Dodaj (i obsługuje łączy do takich zaznaczeń) w wersji MFC 3.0 HIERSVR, ponieważ COleServerItem jest oddzielony od danych w trybie macierzystym.
Uwagi techniczne przez liczbę |nbsp; Uwagi techniczne według kategorii