Droga do DCOM DCOM (1996) Windows clipboard (1987) OLE 1 DDE (1992) OLE 2 (1993) COM (1995) Distributed computing (1980s)



Podobne dokumenty
Agregacja. Wykorzystanie innego komponentu bez użycia agregacji. Simple calculator. Extended calculator

Henryk Budzisz. materiały przygotowane w ramach projektu ZPORR nr POKL /08-00

Obiekty w plikach wykonywalnych, marshaling

4 bity zarezerwowane dla przyszłych zastosowań 11 bitów określających źródło błędu 16 bitów określających rodzaj błędu.

//////////////////////////////////////////////////////////// // Kalkulator (prosty) - wersja agregowalna import "unknwn.idl";

Zdarzenia (events, connection points)

Microsoft Interface Definition Language

Technologie COM i ActiveX COM - Component Object Model

Interfejs IUnknown. Każdy obiekt COM musi implementować interfejs IUnknown, który zawiera trzy metody:

Komunikacja i wymiana danych

Zaawansowane programowanie w języku C++ Programowanie obiektowe

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Programowanie obiektowe, wykład nr 6. Klasy i obiekty

Klasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Structured storage, Monikers, Running Object Table

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

PARADYGMATY PROGRAMOWANIA Wykład 4

// LISTING #2 DRUGIE PODEJŚCIE

Oracle PL/SQL. Paweł Rajba.

// LISTING #2 DRUGIE PODEJŚCIE

Programowanie 2. Język C++. Wykład 3.

Zdalne uruchamianie obiektów COM

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

JAVA W SUPER EXPRESOWEJ PIGUŁCE

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Aplikacje RMI

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Zaawansowane programowanie w języku C++ Klasy w C++

Wywoływanie metod zdalnych

Podstawy wykorzystania bibliotek DLL w skryptach oprogramowania InTouch

Typy zmiennych proste i złożone. Programowanie komputerów. Tablica. Złożone typy zmiennych. Klasa. Struktura

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Laboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

Materiały do zajęć VII

Dzisiejszy wykład. Wzorce projektowe. Visitor Client-Server Factory Singleton

Programowanie obiektowe

Podstawy Programowania Obiektowego

Wywoływanie metod zdalnych

PHP 5 język obiektowy

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Serwery Statefull i Stateless

Wstęp do wiadomości teoretycznych (nie, nie jest to masło maślane ani wstęp, wstępów proszę cierpliwie czytać)

Wstęp do Programowania 2

Kurs WWW. Paweł Rajba.

Programowanie 2. Język C++. Wykład 9.

Component Object Model laboratorium 2013 K.M. Ocetkiewicz, T. Goluch

Programowanie składnikowe. Programowanie składnikowe w modelu COM. COM - Component Object Model. wprowadzenie. Programowanie składnikowe

Zdalne wywołania procedur. Jarosław Kuchta Programowanie Współbieżne

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Listy powiązane zorientowane obiektowo

PARADYGMATY PROGRAMOWANIA Wykład 3

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Java Język programowania

Zaawansowane programowanie w C++ (PCP)

Dokumentacja do API Javy.

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Podstawy programowania skrót z wykładów:

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Wzorce Strukturalne. Adapter: opis. Tomasz Borzyszkowski

Język programowania. Andrzej Bobyk

Szablony funkcji i szablony klas

Qt sygnały i designer

Zarządzanie pamięcią

Programowanie obiektowe

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Wstęp do programowania obiektowego. Wykład 2

Programowanie obiektowe

wykład V uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C++ klasy i obiekty wykład V dr Jarosław Mederski Spis Język C++ - klasy

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

wykład IV uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C, a C++. wykład IV dr Jarosław Mederski Spis Język C++ - wstęp

Wstęp do programowania obiektowego, wykład 7

Programowanie obiektowe

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Singleton. Cel: Przykład: Zastosowanie: Zapewnienie, że klasa ma tylko jedną instancję i dostarczenie globalnego dostępu do niej.

Programowanie II. Lista 3. Modyfikatory dostępu plik TKLientBanku.h

Enkapsulacja, dziedziczenie, polimorfizm

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Temat 1. Podstawy Środowiska Xcode i wprowadzenie do języka Objective-C

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Język ludzki kod maszynowy

Szablony klas, zastosowanie szablonów w programach

Podział programu na moduły

Programowanie w języku C++

Zaawansowane programowanie w C++ (PCP)

.NET Klasy, obiekty. ciąg dalszy

Programowanie obiektowe w języku

Zdalne wywołanie procedur. Krzysztof Banaś Systemy rozproszone 1

Kurs programowania. Wykład 13. Wojciech Macyna. 14 czerwiec 2017

Projektowanie klas c.d. Projektowanie klas przykład

Co to jest klasa? Z programistycznego punktu widzenia klasa stanowi typ danych, który odwzorowuje wspólne cechy jakiegoś obiektu.

Praca z aplikacją designer

Programowanie współbieżne i rozproszone

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Języki i paradygmaty programowania Wykład 2. Dariusz Wardowski. dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/18

Lista dwukierunkowa - przykład implementacji destruktorów

Projektowanie obiektowe. Roman Simiński Wzorce projektowe Wybrane wzorce strukturalne

Transkrypt:

COM jako standard

Droga do DCOM Windows clipboard (1987) OLE 1 DDE (1992) OLE 2 (1993) COM (1995) Distributed computing (1980s) Open Software Foundation Distributed Computing Environment Remote Procedure Calls (OSF DCE RPC) (1992) DCOM (1996)

Co to jest COM? COM Component Object Model: Definiuje standardowy sposób tworzenia komponentów Definiuje binarny standard komponentu

Cechy COM Dedykowany do programowania zorientowanego obiektowo: Enkapsulacja danych i kodu Polimorfizm Dziedziczenie Luźne powiązanie z aplikacją Bezpieczna zmiana wersji komponentu Przeźroczystość lokalizacji

DLL a COM DLL jest również binarnym standardem DLL również w ograniczony sposób przeprowadza enkapsulację DLL nie definiuje takich zagadnień jak: Alokacja pamięci Czas życia obiektów Standardowy dostęp do obiektów DLL jest wystarczającym standardem aby mógł zawierać w sobie komponenty COM.

Interfejs COM Klient i serwer komunikują się ze sobą za pomocą interfejsów. Komponent poprzez jeden lub większą liczbę interfejsów wyraża swoją funkcjonalność i jedynie poprzez nie może być udostępniany. Interfejs jest realizowany w postaci wirtualnych tablic funkcji (vtable).

Interfejs COM Interfejs jest zestawem definicji funkcji, tzn. ich nazw, zwracanych wartości i parametrów. Odpowiednikiem interfejsu w C++ są abstrakcyjne klasy. Interfejs może zawierać jedynie metody. Dostęp do danych może odbywać się jedynie poprzez funkcje zdefiniowane w interfejsie. Dane dostępne poprzez specjalnie zdefiniowane metody nazywa się właściwościami (properties).

Interfejs COM Komponent może zawierać więcej niż jeden interfejs. Wielokrotne interfejsy mogą służyć rozszerzaniu funkcjonalności lub stanowić kolejne wersje komponentu. Database Recordset Fields DAOComp Compress3 Compress1 Compress2 Compress v.2.0 Compress v.1.0

Interfejs COM Gdy komponent został już udostępniony do ogólnego użytku, interfejs nie powinien być modyfikowany zarówno pod względem struktury (vtable), jak również funkcjonalności. Konieczność jego zmiany wymaga stworzenia nowego interfejsu.

Interfejs COM Interfejs nie jest unikalny w systemie. Kilka komponentów może zawierać ten sam interfejs (polimorfizm). Klient spodziewa się, że interfejs udostępniany przez komponent jest w pełni zrealizowany i może korzystać ze wszystkich metod. Jeżeli komponent udostępnia dany interfejs, musi on być w pełni zaimplementowany.

Interfejs COM COM definiuje dużą liczbę standardowych interfejsów. Wszystkie ich nazwy zaczynają się literą I: IClassFactory, IDispatch, IUnknown Taka forma nazewnictwa nie jest wymagana dla własnych interfejsów, jednak podobnie jak dla nazewnictwa klas świadczy o dobrym stylu programisty. Implementacja interfejsu najczęściej jest tą samą nazwą zaczynającą się od C: CCompress (implementacja interfejsu ICompress)

Interfejs COM W standardzie COM interfejs jest skonstruowany jako vtable. Ta tablica wskaźników do funkcji ma ściśle określony układ (standard binarny). Vtable ma identyczną strukturę jak dla klas abstrakcyjnych w C++. Dostęp do metod serwera COM następuje poprzez wskaźnik do vtable komponentu, a nie poprzez bezpośrednie wywoływanie funkcji. Client.exe Compress.dll ICompress pointer= Vtable pointer......... &pcomobj::compress CCompress......... COMObj::Compress

Komponent Każdy komponent spełniający wymagania standardu COM musi: wywodzić się z bazowego interfejsu IUnknown, który realizuje podstawową funkcjonalność każdego interfejsu, posiadać odpowiadający mu obiekt Class Factory odpowiedzialny tworzenie instancji komponentu. Ma on cechy typowego komponentu (wywodzi się z IUnknown), nie posiada jednak swojego obiektu Class Factory

IUnknown IUnknown jest standardowym interfejsem COM. Interfejs ten musi być zaimplementowany przez wszystkie obiekty COM. IUnknown definiuje 3 metody: QueryInterface() AddRef() Release()

IUnknown::QueryInterface() Sprawdza czy żądany przez klienta interfejs jest implementowany przez komponent Jeśli żądany interfejs istnieje, zwraca do niego wskaźnik. W przeciwnym przypadku zwracany jest kod błędu E_NOINTERFACE.

Klasa/interfejs IUnknown Cechy QueryInterface Podstawowe reguły QueryInterface Zestaw interfejsów komponentu nie może się zmienić w czasie w trakcie jego działania. Za pomocą każdego interfejsu w komponencie można zażądać dowolnego innego interfejsu w tym komponencie. Kolejne żądania tego samego interfejsu z jednego wątku klienta w ramach tej samej instancji komponentu powinny zwrócić ten sam wskaźnik. Z powyższych wynikają następujące cechy QueryInterface: Symetria (symmetry): dla istniejącego interfejsu IA operacja zażądania interfejsu IA powinna się powieść Zwrotność (reflexivity): jeśli dla istniejącego interfejsu IA żądanie interfejsu IB przebiegło poprawnie, to z interfejsu IB operacja zażądania interfejsu IA powinna się powieść Przechodniość (transitivity): jeśli dla istniejącego interfejsu IA żądanie interfejsu IB przebiegło poprawnie, a następnie dla interfejsu IB żądanie interfejsu IC przebiegło poprawnie, to z interfejsu IC operacja zażądania interfejsu IA powinna się powieść

IUnknown::AddRef(), IUnknown::Release() Metody AddRef() i Release() odpowiedzialne są za zarządzanie licznikiem odwołań (reference counter). Każdy obiekt, który łączy się z komponentem lub tworzy kopię wskaźnika do interfejsu powinien wywołać AddRef(), gdy natomiast nie zamierza dalej z niego korzystać Release(). Gdy licznik odwołań osiąga wartość 0, komponent może wywołać swój destruktor. QueryInterface() zwracając wskaźnik do interfejsu zwiększa licznik odwołań (wywołuje wewnętrznie AddRef()).

IUnknown Client.exe Compress.dll IUnknown pointer Wywołanie QueryInterface ICompress pointer IUnknown &pcomobj::queryinterface &pcomobj::addref &pcomobj::release ICompress &pcomobj::queryinterface &pcomobj::addref &pcomobj::release &pcomobj::compress CCompress COMObj::QueryInterface COMObj::AddRef COMObj::Release COMObj::Compress

Interfejs IUnknown class IUnknown public: virtual HRESULT stdcall QueryInterface( REFIID riid, void **ppvobject) = 0; virtual unsigned long stdcall AddRef() = 0; virtual unsigned long stdcall Release() = 0; ;

IClassFactory Każdy komponent COM posiada skojarzoną Class Factory. Jest on odpowiedzialny za konstrukcję komponentu i czas życia modułu. class IClassFactory : public IUnknown public: virtual HRESULT stdcall CreateInstance( IUnknown *punkouter, REFIID riid, void **ppvobject) = 0; virtual HRESULT stdcall LockServer( BOOL flock) = 0; );

Przykład Stopwatch serwer Klasa wirtualna IStopwatch Na przykładzie realizacji klasy CStopwatch przedstawione zostaną podstawowe elementy komponentu COM. Rozważmy następującą klasę abstrakcyjną: class CStopwatch public: virtual HRESULT stdcall Start() = 0; virtual HRESULT stdcall ElapsedTime(float *Time) = 0;

Przykład Stopwatch serwer Implementacja (klasa CStopwatch) ElapsedTime = StopCounter StartCounter Frequency class CStopwatchHFT : public CStopwatch public: CStopwatchHFT(); virtual ~CStopwatchHFT(); private: // The frequency of the counter // returned by QueryPerformanceCounter() LARGE_INTEGER m_nfrequency; Overhead // The counter value when the start method was last called. LARGE_INTEGER m_nstarttime; public: HRESULT stdcall Start(); HRESULT stdcall ElapsedTime(float *Time); ;

Przykład Stopwatch serwer Implementacja (klasa CStopwatch) CStopwatchHFT::CStopwatchHFT() // Initialize the member variables m_nstarttime.quadpart = 0; // Save the frequency of the performance counters QueryPerformanceFrequency ((LARGE_INTEGER*) &m_nfrequency); HRESULT stdcall CStopwatchHFT::Start() if (QueryPerformanceCounter((LARGE_INTEGER*) &m_nstarttime)) return S_OK; else return E_FAIL;

Przykład Stopwatch serwer Implementacja (klasa CStopwatch) HRESULT stdcall CStopwatchHF::ElapsedTime(float *Time) HRESULT hr; LARGE_INTEGER nstoptime; // Set the stop time immediately so that a minimum amount of // timer code is executed between the start and stop times if (!QueryPerformanceCounter((LARGE_INTEGER*) &nstoptime) (m_nstarttime.quadpart == 0)) // Either QPC failed or // start was not called before stop hr = E_FAIL; else *Time = (float) (nstoptime.quadpart - m_nstarttime.quadpart); *Time = (*Time / m_nfrequency.quadpart); hr = S_OK; return hr;

Przykład Stopwatch serwer Zarządzanie obiektem CStopwatch Klient nie zarządza bezpośrednio konstrukcją i zwalnianiem obiektu serwera. extern "C" HRESULT stdcall DllGetClassObject( LPVOID* ppv) *ppv = static_cast<cstopwatch*>(new CStopwatchHFT); return S_OK;

Przykład Stopwatch serwer Zarządzanie obiektem CStopwatch class CStopwatch public: unsigned long stdcall Release() =0; virtual HRESULT stdcall Start() =0; virtual HRESULT stdcall ElapsedTime(float *Time) =0; unsigned long stdcall CStopwatchHFT::Release() delete this; return 0;

Przykład Stopwatch serwer Moduł DLL zawierający CStopwatch extern "C" BOOL stdcall DllMain(HINSTANCE hinstance, DWORD dwreason, LPVOID /*lpreserved*/) return TRUE; LIBRARY "Timers.DLL" EXPORTS DllGetClassObject @1 PRIVATE

Przykład Stopwatch klient // StopwatchClient.cpp : // Defines the entry point for the console application. // // std::out etc #include <iostream> #include "..\Timers\Stopwatch.h" #define TIMERSDLL "..\\Timers\\Timers.dll" typedef HRESULT ( stdcall *DLLGETCLASSOBJECT)(LPVOID* ppv);

Przykład Stopwatch klient // Instantiates a stopwatch object and returns it by reference HRESULT CreateInstance(void** ppv) HRESULT hr = E_FAIL; HINSTANCE hinstdll; DLLGETCLASSOBJECT DllGetClassObject; hinstdll = LoadLibrary(TIMERSDLL); if (hinstdll == NULL) std::cout << "Unable to load \"" TIMERSDLL "\"" << std::endl; else DllGetClassObject = (DLLGETCLASSOBJECT) GetProcAddress( hinstdll, "DllGetClassObject"); if (DllGetClassObject!= NULL) hr = DllGetClassObject(ppv); return hr;

Przykład Stopwatch klient int main(int argc, char* argv[]) float nelapsedtime; CStopwatch* pstopwatch = NULL; hr = CreateInstance((void**) &pstopwatch); if (!SUCCEEDED(hr)) std::cout << "ERROR: Unable to create Stopwatch!!"; else pstopwatch->start(); pstopwatch->elapsedtime(&nelapsedtime); std::cout << "The overhead time is " << nelapsedtime << std::endl; pstopwatch->release(); pstopwatch = NULL; return 0;

Przykład Stopwatch serwer Klasa/interfejs IUnknown class IStopwatch : public IUnknown public: // unsigned long stdcall Release() =0; virtual HRESULT stdcall Start() =0; virtual HRESULT stdcall ElapsedTime(float *Time) =0; class CStopwatchHFT : public IStopwatch... public: // IUnknown methods HRESULT stdcall QueryInterface( REFIID riid, void **ppvobject); unsigned long stdcall AddRef(); unsigned long stdcall Release();... ;

Przykład Stopwatch serwer Metoda QueryInterface() Komponent i każdy interfejs posiadają unikalny identyfikator (UUID): // EEBF6D1E-8EF1-4acf-9E5F-4D95E01D698A const IID IID_IStopwatch = 0xeebf6d1e, 0x8ef1, 0x4acf, 0x9e, 0x5f, 0x4d, 0x95, 0xe0, 0x1d, 0x69, 0x8a ; // 83DC3C46-1259-4f95-A2D1-CD11A8819E2E const CLSID CLSID_Stopwatch = 0x83dc3c46, 0x1259, 0x4f95, 0xa2, 0xd1, 0xcd, 0x11, 0xa8, 0x81, 0x9e, 0x2e ; Standardowe interfejsy posiadają predefiniowane UUID, np.: //IUnknown 00000000-0000-0000-C000-000000000046

Przykład Stopwatch serwer Metoda QueryInterface() HRESULT stdcall CStopwatchHFT::QueryInterface( REFIID riid, void **ppvobject) HRESULT hr = S_OK; if (riid == IID_IUnknown) *ppvobject = static_cast<iunknown*>(static_cast<cstopwatch*>(this)); else if (riid == IID_IStopwatch) *ppvobject = static_cast<istopwatch*>(this); else ppvobject = NULL; hr = E_NOINTERFACE; if (SUCCEEDED(hr)) (static_cast<iunknown*>(*ppvobject))->addref(); return hr;

Przykład Stopwatch serwer Zarządzanie obiektem CStopwatch extern "C" HRESULT stdcall DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID* ppv) HRESULT hr; if (rclsid == CLSID_Stopwatch) CStopwatchHFT* stopwatch = new CStopwatch; hr = stopwatch->queryinterface(riid, ppv); else hr = CLASS_E_CLASSNOTAVAILABLE; return hr;

Przykład Stopwatch serwer Metody AddRef(), Release() class CStopwatchHFT : public IStopwatch... private: // Reference counting long m_nreferencecount;... ; CStopwatchHFT::CStopwatchHFT () // Initialize the member variables m_nstarttime.quadpart = 0; m_nreferencecount = 0; // Save the frequency of the performance counters QueryPerformanceFrequency ((LARGE_INTEGER*) &m_nfrequency);

Przykład Stopwatch serwer Metody AddRef(), Release() unsigned long stdcall CStopwatchHFT::AddRef() return InterlockedIncrement( &m_nreferencecount ); unsigned long stdcall CStopwatchHFT::Release() if (InterlockedDecrement( &m_nreferencecount ) == 0) delete this; return 0; return m_nreferencecount;

Przykład Stopwatch serwer Metody AddRef(), Release() Zasady, których należy przestrzegać licznikiem odwołań do komponentu: w związku z 1. Gdy do zmiennej przypisujemy wskaźnik do interfejsu, AddRef() powinien zostać wywołany na rzecz tego interfejsu 2. Release() powinien zostać wywołany, gdy niezerowy wskaźnik do interfejsu wychodzi poza zasięg zmiennej, lub gdy zostaje przypisany nowy wskaźnik 3. Pominięcie niektórych wywołań AddRef()i Release() jest możliwe, gdy mamy dodatkowe informacje o czasie życia komponentu

Przykład Stopwatch klient // Instantiates a stopwatch object and returns it by reference HRESULT CreateInstance(REFCLSID rclsid, REFIID riid, void** ppv) HRESULT hr = E_FAIL; HINSTANCE hinstdll; DLLGETCLASSOBJECT DllGetClassObject; hinstdll = LoadLibrary(TIMERSDLL); if (hinstdll == NULL) std::cout << "Unable to load \"" TIMERSDLL "\"" << std::endl; else DllGetClassObject = (DLLGETCLASSOBJECT) GetProcAddress( hinstdll, "DllGetClassObject"); if (DllGetClassObject!= NULL) hr = DllGetClassObject(rclsid, riid, ppv); return hr;

Przykład Stopwatch klient int main(int argc, char* argv[]) float nelapsedtime; IUnknown* punknown = NULL; CStopwatch* pstopwatch = NULL; hr=createinstance(clsid_stopwatch, IID_IUnknown, (void**) &punknown); if (!SUCCEEDED(hr)) std::cout << "ERROR: Unable to create Stopwatch!!"; else hr=punknown->queryinterface(iid_istopwatch, (void**) &pstopwatch); if (!SUCCEEDED(hr)) std::cout << "ERROR: Unable to retrive IStopwatch!!"; else pstopwatch->start(); pstopwatch->elapsedtime(&nelapsedtime); std::cout << "The overhead time is " << nelapsedtime << std::endl; pstopwatch->release(); pstopwatch = NULL; punknown->release(); return 0;

Przykład Stopwatch serwer Komponent IClassFactory class CStopwatchClassFactory : public IClassFactory public: CStopwatchClassFactory(); virtual ~CStopwatchClassFactory(); private: // Reference counting long m_ncfreferencecount; public: // IUnknown methods HRESULT stdcall QueryInterface(REFIID riid, void **ppvobject); unsigned long stdcall AddRef(); unsigned long stdcall Release(); // IClassFactory HRESULT stdcall CreateInstance( IUnknown *punkouter, REFIID riid, void **ppvobject); HRESULT stdcall LockServer(BOOL flock); ;

Przykład Stopwatch serwer Komponent IClassFactory extern long g_nserverlockcount; CStopwatchClassFactory::CStopwatchClassFactory() m_ncfreferencecount = 0; CStopwatchClassFactory::~CStopwatchClassFactory() HRESULT stdcall CStopwatchClassFactory::QueryInterface( REFIID riid, void **ppvobject) HRESULT hr = S_OK; if (riid == IID_IUnknown) *ppvobject=static_cast<iunknown*>(static_cast<iclassfactory*>(this)); else if (riid == IID_IClassFactory) *ppvobject = static_cast<iclassfactory*>(this); else ppvobject = NULL; hr = E_NOINTERFACE; if (SUCCEEDED(hr)) (static_cast<iunknown*>(*ppvobject))->addref(); return hr;

Przykład Stopwatch serwer Komponent IClassFactory HRESULT stdcall CStopwatchClassFactory::CreateInstance( IUnknown *punkouter, REFIID riid, void **ppvobject ) HRESULT hr; CStopwatchHFT* pstopwatch = new CStopwatchHFT; if (punkouter!= NULL) return CLASS_E_NOAGGREGATION; hr = pstopwatch->queryinterface(riid, ppvobject); if (FAILED(hr)) delete pstopwatch; return hr; HRESULT stdcall CStopwatchClassFactory::LockServer( BOOL flock ) if (flock) InterlockedIncrement( &g_nserverlockcount ); else InterlockedDecrement( &g_nserverlockcount ); return S_OK;

Przykład Stopwatch serwer Komponent IClassFactory unsigned long stdcall CStopwatchClassFactory::AddRef() if(interlockedincrement( &m_ncfreferencecount ) == 1) InterlockedIncrement( &g_nserverlockcount ); return m_nreferencecount; unsigned long stdcall CStopwatchClassFactory::Release() if (InterlockedDecrement( &m_ncfreferencecount ) == 0) delete this; InterlockedDecrement( &g_nserverlockcount ); return 0; return m_nreferencecount;

Przykład Stopwatch serwer Zarządzanie licznikiem odwołań modułu unsigned long stdcall CStopwatchHFT::AddRef() if(interlockedincrement( &m_nreferencecount ) == 1) InterlockedIncrement( &g_nserverlockcount ); return m_nreferencecount; unsigned long stdcall CStopwatchHFT::Release() if (InterlockedDecrement( &m_nreferencecount ) == 0) delete this; InterlockedDecrement( &g_nserverlockcount ); return 0; return m_nreferencecount;

Przykład Stopwatch serwer Czas życia modułu Każdy moduł zawierający komponenty COM ma zaimplementowaną funkcję DllCanUnloadNow(). Informuje ona system czy dany moduł nie posiada już żadnych zaalokowanych komponentów i czy może być on usunięty. HRESULT stdcall DllCanUnloadNow(void) return (g_nserverlockcount == 0 )? S_OK : S_FALSE;

Przykład Stopwatch serwer Zarządzanie komponentem extern "C" HRESULT stdcall DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID* ppv) HRESULT hr; if (rclsid == CLSID_Stopwatch) CStopwatchClassFactory* pstopwatchclassfactory = new CStopwatchClassFactory; hr = pstopwatchclassfactory->queryinterface(riid, ppv); if(failed(hr)) delete pstopwatchclassfactory; else hr = CLASS_E_CLASSNOTAVAILABLE; return hr;

Przykład Stopwatch serwer ; Timers.def : Declares the module parameters. LIBRARY "Timers.DLL" EXPORTS DllGetClassObject @1 PRIVATE DllCanUnloadNow @2 PRIVATE

Przykład Stopwatch klient HRESULT CreateInstance(REFCLSID rclsid, REFIID riid, void** ppv) HRESULT hr = E_FAIL; HINSTANCE hinstdll; DLLGETCLASSOBJECT DllGetClassObject; IClassFactory* pclassfactory; hinstdll = LoadLibrary(TIMERSDLL); if (hinstdll == NULL) std::cout << "Unable to load \"" TIMERSDLL "\"" << std::endl; else DllGetClassObject = (DLLGETCLASSOBJECT) GetProcAddress( hinstdll, "DllGetClassObject"); if (DllGetClassObject!= NULL) hr=dllgetclassobject(rclsid, IID_IClassFactory, (void**)&pclassfactory); if (SUCCEEDED(hr)) hr=pclassfactory->createinstance(null, riid, ppv); pclassfactory->release(); pclassfactory=null; return hr;

Funkcje systemowe zarządzające obiektami COM Do zarządzania obiektami COM istnieją specjalne funkcje systemowe odpowiedzialne za ładowanie bibliotek, inicjalizację i deinicjalizację obiektów. Korzystają one z informacji zawartych w rejestrze systemowym, który wiąże identyfikator obiektu z właściwym plikiem i sposobem jego uruchomienia.

CoInitialize(), CoInitializeEx(), CoUninitialize() CoInitialize(), CoInitializeEx(): Inicjalizuje bibliotekę COM w bieżącym wątku. Specyfikuje model współpracy dla biblioteki (wielowątkowy, jednowątkowy,...) CoUninitialize(): Deaktyewuje bibliotekę COM w bieżącym wątku.

CoCreateInstance() Na podstawie ustawień w rejestrze ładuje moduł COM, inicjalizuje wskazany obiekt i zwraca jego wskaźnik. HRESULT CoCreateInstance( REFCLSID rclsid, //Class identifier (CLSID) of the object LPUNKNOWN punkouter, //Pointer to controlling IUnknown DWORD dwclscontext, //Context for running executable code REFIID riid, //Reference to the identifier of the interface LPVOID * ppv //Address of output variable that receives // the interface pointer requested in riid ); rclsid riid dwclscontext np. CLSID_Stopwatch - najczęściej IDD_IUnknown - sposób uruchomienia serwera

Przykład Stopwatch klient Funkcje systemowe COM int main(int argc, char* argv[]) HRESULT hr; IStopwatch* pstopwatch = NULL; CoInitialize(NULL); hr = CoCreateInstance( CLSID_Stopwatch, NULL, CLSCTX_ALL, IID_IStopwatch, (void**) &pstopwatch); if (!SUCCEEDED(hr)) std::cout << "ERROR: Unable to create Stopwatch!!\n"; else pstopwatch->start();... pstopwatch->elapsedtime(&nelapsedtime); std::cout << "The overhead time is " << nelapsedtime << std::endl; pstopwatch->release(); pstopwatch = NULL; CoUninitialize(); return 0;