[ Pobierz całość w formacie PDF ]
.12.Listing 32.12.Implementacja obs³ugi dzielenia serwera CTracker//.EnableAutomation ( ) ;// upewniamy siê, ¿e aplikacja nie zostanie wy³adowana przed // wyzerowaniem licznika odwo³añ : :Afx01eLockApp( ) ;// zerujemy sk³adow¹ m_dwRegister = NULL;// QI dla lUnknown = pamiêtajmy, ¿e bez AddRef LPUNKNOWN plUnknown = this->Get!nterface ( &IID_IUnknown) ;// jeœli mamy lUnknownif (plUnknown){// rejestrujemy clsid jako aktywny obiekt, dziêki czemu // inne aplikacje otrzymaj¹ ten sam obiekt if (: :RegisterActiveObject (plUnknown, CLSID_TRACKER, ACTIVEOBJECT_STRONG, &m_dwRegister ) != S_OK) // zerujemy odwo³anie m_dwRegister = NULL;}// ustawiamy rozdzielczoœæ timeram_lTimeBegin = timeBeginPeriod (1) ;m IHiResTime = m ILastHiResTime = timeGetTime//.W naszej implementacji pierwszym krokiem jest wyzerowanie zmiennej sk³adowej.Implementacja jest zale¿na od tej zmiennej przy sprawdzaniu, czy serwer zosta³ poprawnie zarejestrowany jako dzia³aj¹cy.Nastêpnie musimy pobraæ interfejs lUnknown obiektu i, jeœli to siê powiedzie, przekazaæ go wraz z adresem zmiennej sk³adowej do funkcji RegisterActiveObject ().Wymagamy „mocnej" rejestracji, powoduj¹cej dodatkowe zwiêkszenie liczby odwo³añ do serwera w celu utrzymania go w pamiêci.Jeœli nie powiod³o siê zarejestrowanie serwera, dla pewnoœci i tak zerujemy zmienn¹ sk³adow¹.Ostatnim krokiem jest wywo³anie funkcji RevokeActiveObject () w celu usuniêcia serwera z tablicy dzia³aj¹cych obiektów.Ten krok jest najbardziej krytycznym aspektem obs³ugi dzielonych obiektów.Nie nale¿y jednak dodawaæ tego kodu do destruktora serwera, gdy¿ nigdy nie zostanie wywo³any.Destruktor jest wywo³ywany w odpowiedzi na niszczenie serwera, nastêpuj¹ce w momencie, gdy licznik odwo³añ do serwera osi¹gnie zero.Jednak poniewa¿ w wywo³aniu RegisterActiveObject () za¿¹daliœmy dodatkowego zwiêkszenia licznika odwo³añ, licznik nigdy nie osi¹gnie tego stanu.W celu zapewnienia poprawnego usuniêcia serwera z tabeli najlepiej jest zaimplementowaæ ponownie funkcjê ReleaseO interfejsu lUnknown serwera, dziêki której bêdzie mo¿na monitorowaæ licznik odwo³añ do serwera.Implementacja funkcji Release () usuwaj¹cej obiekt z tablicy dzia³aj¹cych obiektów zosta³a przedstawiona na listingu 32.13.Listing 32.13.Implementacja funkcji Release()//.ULONG FAR EXPORT CTracker::KSubDispatch::Release(} {METHOD_PROLOGUE(CTracker, SubDispatch)// wywo³anie funkcji i sprawdzenie licznika odwo³añ long IRefCount = pThis->ExternalRelease();// gdy jesteœmy zarejestrowani jako dzia³aj¹cy serwer// i jest to jedyne odwo³anieif(pThis->m_dwRegister && IRefCount == 1){// zwiêkszamy licznik odwo³añ, abyœmy siê nie zniszczyli// przed zakoñczeniem funkcjipThis->ExternalAddRef();// pobieramy identyfikator rejestracji DWORD tdwRegister = pThis->m_dwRegister;// zerujemy zmienn¹ sk³adow¹, aby zabezpieczyæ siê przed // ponownym wywo³aniem tej metody pThis->m_dwRegister = 0;// usuwamy interfejs z tablicy dzia³aj¹cych obiektów ::RevokeActiveObject(tdwRegister, NULL);// To wywo³anie powinno zniszczyæ nasz serwer, wiêc // musimy zmniejszyæ licznik odwo³añ, return pThis->ExternalRelease();}// wyjœcie return IRefCount;}//.Za ka¿dym razem gdy program wywo³uje funkcjê Release (), zaczyna ona dzia³anie od zmniejszenia licznika odwo³añ do obiektu i zachowania zwróconej wartoœci.Nastêpnie funkcja sprawdza, czy serwer zosta³ zarejestrowany jako dzia³aj¹cy (o zarejestrowaniu serwera œwiadczy niezerowa wartoœæ zmiennej sk³adowej).Funkcja sprawdza tak¿e, czy licznik odwo³añ ma wartoœæ 1.Jeœli tak, oznacza to, ¿e serwer jest gotów do usuniêcia, gdy¿ jedyn¹ aplikacj¹, która siê do niego odwo³uje, jest tablica dzia³aj¹cych obiektów.Jednak przed wywo³aniem funkcji RevokeActiveObject () wa¿ne jest, by zwiêkszyæ licznik odwo³añ i wyzerowaæ zmienn¹ sk³adow¹.Funkcja RevokeActiveObject () re-kursywnie wywo³uje funkcjê Release (), a nie chcemy, by serwer zosta³ natychmiast zniszczony (gdy¿ spowodowa³oby to naruszenie pamiêci i za³amanie programu).Po powrocie z funkcji RevokeActiveObject () wywo³ujemy ostatni raz funkcjê Release (), aby rzeczywiœcie zniszczyæ serwer i usun¹æ go z pamiêci.W czasie istnienia serwera mo¿emy otrzymywaæ ten sam egzemplarz serwera i u¿ywaæ go w wielu ró¿nych aplikacjach.W Visual Basicu do pobierania dzia³aj¹cego egzemplarza serwera s³u¿y funkcja Getobject (), zaœ w Yisual C++ funkcja GetActiveObject ().Gdy kontener otrzyma wskaŸnik do serwera, mo¿e z niego korzystaæ tak, jakby utworzy³ go poprzez standardowe mechanizmy OLE.Ta metoda dzielenia obiektów jest poprawna, lecz wymaga, by aplikacja korzystaj¹ca z serwera bra³a czynn¹ rolê w decydowaniu, czy powinna korzystaæ ze wspólnego obiektu czy te¿ stworzyæ w³asny obiekt.Mo¿na przyj¹æ inne podejœcie: mo¿esz dostarczyæ egzemplarz dzia³aj¹cego serwera aplikacji wywo³uj¹cej funkcjê CreateObject (), zamiast polegaæ na wywo³aniu przez aplikacjê funkcji Getobject o.Taki serwer jest nazywany serwerem w pojedynczym egzemplarzu, gdy¿ programy kontenerów nie mog¹ tworzyæ wiêcej ni¿ pojedynczy egzemplarz obiektu.Serwer w pojedynczym egzemplarzuAby stworzyæ serwer w pojedynczym egzemplarzu, konieczne jest wykonanie wszystkich kroków opisanych w poprzedniej sekcji, „Tworzenie dzielonych serwerów", lecz nie z wnêtrza samej implementacji serwera, ale poprzez fabrykê klas dla serwera.Implementuj¹c obiekt dzielenia serwera wewn¹trz fabryki klas, jesteœmy w stanie kontrolowaæ iloœæ egzemplarzy obiektu bez koniecznoœci opierania siê na dobrej woli aplikacji korzystaj¹cych z serwera.Niestety, MFC nie umo¿liwia w prosty sposób dostêpu do klasy coieObjectFactory, odpowiedzialnej za tworzenie serwerów OLE i umo¿liwiaj¹cej ten rodzaj implementacji.Jednak dziêki dziedziczeniu klas C++ mo¿emy stworzyæ now¹, specjaln¹ wersjê klasy coieObjectFactory obs³uguj¹c¹ dzielenie egzemplarzy serwera.W celu umo¿liwienia obs³ugi dzielenia serwera musimy dodaæ dwa makra do deklaracji i implementacji klasy serwera.W pliku Ÿród³owym serwera makro DECLARE_OLECREATE_SHARED musi zast¹piæ makro DECLARE_OLECREATE, zaœ makro IMPLEMENT_OLECREATE musi byæ zast¹pione makrem IMPLEMENT_OLECREATE_SHARED.Jedyna ró¿nica w nowych makrach polega na tym, ¿e do serwera zamiast klasy coieObjectFactory jest dodawana klasa coieObjectFactoryShared.Tworzenie kodu obs³uguj¹cego serwer w pojedynczym egzemplarzu jest podobne do tworzenia kodu obs³uguj¹cego normalny dzielony serwer.Kod implementuj¹cy serwer w pojedynczym egzemplarzu jest zawarty w plikach sharedobject.cpp oraz sharedobject.h umieszczonych na do³¹czonej do ksi¹¿ki p³ytce CD-ROM, w kartotece Rozdz32\MFCServer.PodsumowanieW tym rozdziale nauczy³eœ siê tworzyæ podstawow¹ implementacjê serwera automatyzacji MFC.Nauczy³eœ siê równie¿ rozbudowywaæ podstawowy szkielet dostarczony przez MFC o nowe, interesuj¹ce elementy implementacji.Do innych obszarów implementacji serwera, które mo¿na rozbudowaæ, nale¿y dodawanie do serwera interfejsu u¿ytkownika, tak¿e w formie okien dialogowych oraz interfejsów zdarzeñ.U¿ycie standardowych okien dialogowych MFC sprawia, ¿e implementacja interfejsu u¿ytkownika jest ³atw¹ i przyjemn¹ czêœci¹ implementacji.Jednak obecnie ¿adna z aplikacji kontenera nie potrafi skorzystaæ z ¿adnego z takich elementów serwera.Jeœli aplikacja ma takie wymagania, musisz sam okreœliæ, jak je zaimplementowaæ.Mo¿liwoœæ tworzenia us³ug i zdalnych serwerów tak¿e sprawia, ¿e tworzenie serwerów automatyzacji mo¿e byæ bardzo interesuj¹ce.Ka¿dego dnia coraz wiêcej programistów korzysta z automatyzacji i do³¹cza j¹ do podstawowych elementów swoich aplikacji.O ile dawniej przy wymianie danych mo¿na by³o korzystaæ tylko z mechanizmu DDE lub, co gorsza, z wymiany danych poprzez pliki, obecnie w ka¿dej sytuacji wymagaj¹cej przekazania danych pomiêdzy aplikacjami mo¿na korzystaæ z automatyzacji OLE
[ Pobierz całość w formacie PDF ]