// LISTING #2 DRUGIE PODEJŚCIE
|
|
- Włodzimierz Przybylski
- 6 lat temu
- Przeglądów:
Transkrypt
1 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK LISTING #1 PIERWSZE PODEJŚCIE LISTING #2 DRUGIE PODEJŚCIE #include <iostream.h> #include <objbase.h> interfejs A interface IA virtual void stdcall fa() = 0; ; interfejs B interface IB virtual void stdcall fb() = 0; ; Składnik class CMyComp : public IA, public IB Implementacja interfejsu A virtual void stdcall fa(); Implementacja interfejsu B virtual void stdcall fb(); ; void CMyComp::fa() cout << "Jestem fa" << endl; void CMyComp::fb() cout << "Jestem fb" << endl; / Plik nagłówkowy interface.h #include <objbase.h> interfejs A interface IA : public IUnknown virtual void stdcall fa() = 0; ; interfejs B interface IB : public IUnknown virtual void stdcall fb() = 0; ; deklaracje identyfikatorów IID extern const IID IID_IA; extern const IID IID_IB; deklaracja funkcji tworzącej egzemplarz składnika IUnknown *CreateInstance(); / Definicja identyfikatorów IID 033E7EC7-50FA-404c-9C59-4CBA8892F054 static const GUID IID_IA = 0x33e7ec7, 0x50fa, 0x404c, 0x9c, 0x59, 0x4c, 0xba, 0x88, 0x92, 0xf0, 0x54 ; FD854FCC-6AE BB60-DC276E5DFC68 static const GUID IID_IB = 0xfd854fcc, 0x6ae2, 0x4876, 0xbb, 0x60, 0xdc, 0x27, 0x6e, 0x5d, 0xfc, 0x68 ; void main() CMyComp *pcomp = new CMyComp; wskaźnik do interfejsu A IA *pia = pcomp; pia->fa(); wskaźnik do interfejsu B IB *pib = pcomp; pib->fb(); delete pcomp; 1
2 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK / Aplikacja kliencka #include "interface.h" void main() inicjalizacja składnika IUnknown *punknown = CreateInstance(); IUnknown *CreateInstance() IUnknown *p = (IA*)new CMyComp; p->addref(); return p; chcemy skorzystać z interfejsu IA IA *pia = NULL; HRESULT hr = punknown->queryinterface(iid_ia, (void**)&pia); if (SUCCEEDED(hr)) pia->fa(); pia->release(); chcemy skorzystać z interfejsu IB IB *pib = NULL; hr = punknown->queryinterface(iid_ib, (void**)&pib); if (SUCCEEDED(hr)) pib->fb(); pib->release(); punknown->release(); delete punknown; / Moduł składnika #include "interface.h" #include <iostream.h> Klasa składnika class CMyComp : public IA, public IB Implementacja interfejsu IUnknown virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); Implementacja interfejsu A virtual void stdcall fa() cout << "Jestem fa" << endl; HRESULT _stdcall CMyComp::QueryInterface(REFIID iid, void **ppv) if (iid == IID_IUnknown) *ppv = (IA*)this; else if (iid == IID_IA) *ppv = (IA*)this; else if (iid == IID_IB) *ppv = (IB*)this; else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); ULONG _stdcall CMyComp::AddRef() return InterlockedIncrement(&m_nRef); ULONG _stdcall CMyComp::Release() if (InterlockedDecrement(&m_nRef) == 0) delete this; return 0; return m_nref; Implementacja interfejsu B virtual void stdcall fb() cout << "Jestem fb" << endl; public: CMyComp() : m_nref(0) private: long m_nref; ; 2
3 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK / Aplikacja kliencka - korzystająca z serwera COM LISTING #3 TRZECIE PODEJŚCIE / Plik nagłówkowy interface.h #include <objbase.h> interfejs A interface IA : public IUnknown virtual void stdcall fa() = 0; ; interfejs B interface IB : public IUnknown virtual void stdcall fb() = 0; ; deklaracje identyfikatorów IID extern const IID IID_IA; extern const IID IID_IB; #include "interface.h" void main() inicjalizacja podsystemu COM CoInitialize(NULL); inicjalizacja składnika IUnknown *punknown = NULL; HRESULT hr = CoCreateInstance(CLSID_Component, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&punknown); if (SUCCEEDED(hr)) chcemy skorzystać z interfejsu IA IA *pia = NULL; hr = punknown->queryinterface(iid_ia, (void**)&pia); if (SUCCEEDED(hr)) pia->fa(); pia->release(); / Definicja identyfikatorów IID 59F1DE0D a57-82CE-D6DBA3D28D28 static const GUID CLSID_Component = 0x59f1de0d, 0x8843, 0x4a57, 0x82, 0xce, 0xd6, 0xdb, 0xa3, 0xd2, 0x8d, 0x28 ; 033E7EC7-50FA-404c-9C59-4CBA8892F054 static const GUID IID_IA = 0x33e7ec7, 0x50fa, 0x404c, 0x9c, 0x59, 0x4c, 0xba, 0x88, 0x92, 0xf0, 0x54 ; FD854FCC-6AE BB60-DC276E5DFC68 static const GUID IID_IB = 0xfd854fcc, 0x6ae2, 0x4876, 0xbb, 0x60, 0xdc, 0x27, 0x6e, 0x5d, 0xfc, 0x68 ; dalej jak w listingu #2 punknown->release(); / Moduł składnika (serwer) #include "interface.h" #include <iostream.h> #include "registry.h" narzędzia do rejestru systemowego... Zmienne globalne static HMODULE g_hmodule = NULL; uchwyt modułu DLL static long g_ccomponents = 0 ; Licznik aktywnych składników static long g_cserverlocks = 0 ; Licznik dla LockServer Dane do rejestru systemowego const char g_szprogid[] = "COMLecture.Approach3.1"; const char g_szfriendlyname[] = "Wykład z COM, podejście 3"; const char g_szverindprogid[] = "COMLecture.Approach3"; 3
4 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK Klasa składnika Class Factory class CMyComp : public IA, public IB public: Implementacja interfejsu IUnknown virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); Implementacja interfejsu A virtual void stdcall fa() cout << "Jestem fa" << endl; Implementacja interfejsu B virtual void stdcall fb() cout << "Jestem fb" << endl; public: CMyComp() : m_nref(1) InterlockedIncrement(&g_cComponents); ~CMyComp() InterlockedDecrement(&g_cComponents); private: long m_nref; ; HRESULT _stdcall CMyComp::QueryInterface(REFIID iid, void **ppv) if (iid == IID_IUnknown) *ppv = (IA*)this; else if (iid == IID_IA) *ppv = (IA*)this; else if (iid == IID_IB) *ppv = (IB*)this; else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); ULONG _stdcall CMyComp::AddRef() return InterlockedIncrement(&m_nRef); ULONG _stdcall CMyComp::Release() if (InterlockedDecrement(&m_nRef) == 0) delete this; return 0; return m_nref; class CFactory : public IClassFactory public: Implementacja interfejsu IUnknown virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); Implementacja interfejsu IClassFactory virtual HRESULT stdcall CreateInstance( IUnknown* punknownouter, const IID& iid, void** ppv); virtual HRESULT stdcall LockServer(BOOL block); CFactory() : m_nref(1) private: long m_nref ; ; Class Factory interfejs IUnknown HRESULT stdcall CFactory::QueryInterface(const IID& iid, void** ppv) if ((iid == IID_IUnknown) (iid == IID_IClassFactory)) *ppv = (IClassFactory*)this; else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); ULONG stdcall CFactory::AddRef() return InterlockedIncrement(&m_nRef) ; ULONG stdcall CFactory::Release() if (InterlockedDecrement(&m_nRef) == 0) delete this ; return 0 ; return m_nref ; 4
5 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK Class Factory interfejs IClassFactory Funkcje eksportowane! HRESULT stdcall CFactory::CreateInstance(IUnknown* punknownouter, const IID& iid, void** ppv) if (punknownouter!= NULL) return CLASS_E_NOAGGREGATION; Utworzenie składnika CMyComp* pmycomp = new CMyComp; if (!pmycomp) return E_OUTOFMEMORY; Utworzenie żądanego interfejsu HRESULT hr = pmycomp->queryinterface(iid, ppv); pmycomp->release(); return hr; HRESULT stdcall CFactory::LockServer(BOOL block) if (block) InterlockedIncrement(&g_cServerLocks) ; else InterlockedDecrement(&g_cServerLocks) ; return S_OK ; Inicjalizacja DLL BOOL APIENTRY DllMain(HMODULE hmodule, DWORD ul_reason_for_call, LPVOID lpreserved) if (ul_reason_for_call == DLL_PROCESS_ATTACH) g_hmodule = hmodule; return TRUE ; STDAPI DllCanUnloadNow() if ((g_ccomponents == 0) && (g_cserverlocks == 0)) else return S_FALSE; STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv) Czy możemy utworzyć taki składnik? if (clsid!= CLSID_Component) return CLASS_E_CLASSNOTAVAILABLE ; Utwórz fabrykę klas CFactory* pfactory = new CFactory; if (pfactory == NULL) return E_OUTOFMEMORY; Zwróć żądany interfejs HRESULT hr = pfactory->queryinterface(iid, ppv); pfactory->release(); return hr; STDAPI DllRegisterServer() return RegisterServer(g_hModule, CLSID_Component, g_szfriendlyname, g_szverindprogid, g_szprogid); STDAPI DllUnregisterServer() return UnregisterServer(CLSID_Component, g_szverindprogid, g_szprogid); / Plik COMPONENT.DEF LIBRARY Component.dll DESCRIPTION 'Przykład do wykładu COM, (C) Jarosław Francik 2001' EXPORTS PRIVATE PRIVATE PRIVATE PRIVATE 5
6 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK / Aplikacja kliencka - korzystająca z serwera COM LISTING #4 CZWARTE PODEJŚCIE (SERWER EXE) / Specyfikacja mytypes.idl import "unknwn.idl"; Interface IA [ object, uuid(b5db b7db-30da5e75d347), helpstring("ia Interface"), pointer_default(unique) ] interface IA : IUnknown HRESULT fa(); ; Interface IB [ object, uuid(10ae43a2-2d3f-48a9-8ed3-d3f1f21cc898), helpstring("ib Interface"), pointer_default(unique) ] interface IB : IUnknown HRESULT fb(); ; Biblioteka typów + clsid składników [ uuid(3221ccff-68b2-442b-afdc-fa9c767f1fc4), version(1.0), helpstring("biblioteka typów Approach3a") ] library MyTypeLib importlib("stdole32.tlb") ; [ uuid(e843265d-b374-4d56-a980-0ec5e9188b47), helpstring("klasa komponentu Approach3a") ] coclass Component [default] interface IA; interface IB; ; ; #include "..\\mytypes.h" #include "..\\mytypes_i.c" void main() inicjalizacja podsystemu COM CoInitialize(NULL); inicjalizacja składnika IUnknown *punknown = NULL; HRESULT hr = CoCreateInstance(CLSID_Component, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&punknown); / Moduł proxy zawiera wyłącznie pliki utworzone przez midl: dlldata.c, abc_i.c, abc_p.c, linkowane z rpcndr.lib, rpcns4.lib i rpcrt4.lib Oto plik PROXY.DEF: LIBRARY proxy.dll DESCRIPTION 'Przykład do wykładu COM, (C) Jarosław Francik 2001' EXPORTS PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE / Moduł składnika (serwer) #include "..\\mytypes.h" #include "..\\mytypes_i.c" #include <iostream.h> #include <memory.h> #include "registry.h" narzędzia do rejestru systemowego... Zmienne globalne usunieto zmienną g_hmodule ponadto jak w podejściu Trzecim 6
7 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK Klasa składnika class CMyComp : public IA, public IB public: Implementacja interfejsu IUnknown jak w Podejściu Trzecim Implementacja interfejsu A virtual HRESULT stdcall fa() MessageBox(0, "Jestem fa", "Jestem fa", 0); Implementacja interfejsu B virtual HRESULT stdcall fb() MessageBox(0, "Jestem fb", "Jestem fb", 0); public: CMyComp() : m_nref(1) InterlockedIncrement(&g_cComponents); ~CMyComp() InterlockedDecrement(&g_cComponents); if (g_ccomponents == 0 && g_cserverlocks == 0) PostQuitMessage(0); private: long m_nref; ; Implementacja klasy CMyComp jak w Podejściu Trzecim Class Factory Deklaracja i implementacja fabryki klas jak w Podejściu Trzecim; jedyna różnica dotyczy poniższej funkcji: HRESULT stdcall CFactory::LockServer(BOOL block) if (block) InterlockedIncrement(&g_cServerLocks); else InterlockedDecrement(&g_cServerLocks); if (g_ccomponents == 0 && g_cserverlocks == 0) PostQuitMessage(0); return S_OK ; Część aplikacyjna + obsługa COM LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) Inicjalizacja COM flaga określająca tryb pracy bool bembedding = false; Inicjalizacja COM HRESULT hr = CoInitialize(NULL) ; if (FAILED(hr)) return 0 ; Odczyt linii wywołania char sztokens[] = "-/"; char* sztoken = strtok(lpcmdline, sztokens) ; while (sztoken!= NULL) if (_stricmp(sztoken, "UnregServer") == 0) UnregisterServer(FALSE, CLSID_Component, g_szverindprogid, g_szprogid); CoUninitialize(); return 0; else if (_stricmp(sztoken, "RegServer") == 0) RegisterServer(FALSE, hinstance, CLSID_Component, g_szfriendlyname, g_szverindprogid, g_szprogid); CoUninitialize(); return 0; else if (_stricmp(sztoken, "Embedding") == 0) bembedding = true; break ; sztoken = strtok(null, sztokens); 7
8 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK Rejestracja fabryki klas DWORD dregister; CFactory *pfactory = new CFactory; hr = ::CoRegisterClassObject(CLSID_Component, pfactory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dregister); if (FAILED(hr)) pfactory->release() ; return FALSE ; / Standardowa część aplikacji if (!bembedding) Rejestracja klasy okna WNDCLASS wc; memset(&wc, 0, sizeof(wc)); wc.lpfnwndproc = (WNDPROC)WndProc; wc.hinstance = hinstance; wc.hcursor = LoadCursor(NULL, IDC_ARROW); wc.hbrbackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszclassname = "my_class1"; RegisterClass(&wc); Utworzenie okna HWND hwnd; hwnd = CreateWindow("my_class1", "Tytuł", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance, NULL); if (!hwnd) return FALSE; ShowWindow(hWnd, ncmdshow); UpdateWindow(hWnd); / Końcowa deinicjalizacja systemu COM! CoRevokeClassObject(dRegister); CoUninitialize(); return msg.wparam; Funkcja okienkowa LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) switch (message) case WM_DESTROY: nie pozwala zamknąć aplikacji, dopóki klienci korzystają z serwera if (g_ccomponents == 0 && g_cserverlocks == 0) PostQuitMessage(0); break ; case WM_CLOSE: znosi blokadę na czas używania interfejsu użytkownika ::InterlockedDecrement(&g_cServerLocks); return (DefWindowProc(hWnd, message, wparam, lparam)) ; default: return DefWindowProc(hWnd, message, wparam, lparam); return 0; Blokuje serwer na czas używania interfejsu użytkownika InterlockedIncrement(&g_cServerLocks); Pętla komunikatów MSG msg; while (GetMessage(&msg, NULL, 0, 0)) TranslateMessage(&msg); DispatchMessage(&msg); 8
9 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK / Moduł składnika (serwer) LISTING #5 PIĄTE PODEJŚCIE (DISPINTERFEJSY) / Specyfikacja mytypes.idl import "unknwn.idl"; Interface IA [ object, uuid(b5db b7db-30da5e75d347), helpstring("ia Interface"), pointer_default(unique), dual, oleautomation ] interface IA : IDispatch HRESULT fa(); ; reszta bez zmian / Aplikacja kliencka - korzystająca z interfejsu vtable BEZ ŻADNYCH ZMIAN / Moduł proxy bez zmian rozszerzenie klasy CMyComp obejmuje implementację interfejsu IDispatch class CMyComp : public IA, public IB public: Implementacja interfejsu IDispatch virtual HRESULT stdcall GetTypeInfoCount( UINT RPC_FAR *pctinfo); virtual HRESULT stdcall GetTypeInfo( UINT itinfo, LCID lcid, ITypeInfo RPC_FAR * RPC_FAR *pptinfo); virtual HRESULT stdcall GetIDsOfNames( REFIID riid, LPOLESTR RPC_FAR *rgsznames, UINT cnames, LCID lcid, DISPID RPC_FAR *rgdispid); virtual HRESULT stdcall Invoke( DISPID dispidmember, REFIID riid, LCID lcid, WORD wflags, DISPPARAMS RPC_FAR *pdispparams, VARIANT RPC_FAR *pvarresult, EXCEPINFO RPC_FAR *pexcepinfo, UINT RPC_FAR *puargerr); protected: ITypeInfo *m_pitypeinfo; HRESULT InitTypeInfo(); public: rzeczy pomocne uzupełnienie konstruktora: CMyComp() : m_nref(1) InterlockedIncrement(&g_cComponents); InitTypeInfo(); ; RESZTA BEZ ZMIAN 9
10 OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK Funkcja tworząca obiekt informacji o typach Implementacja interfejsu IDispatch opiera się na wykorzystaniu funkcjonalności obiektu informacji o typach HRESULT stdcall CMyComp::GetTypeInfoCount(UINT RPC_FAR *pctinfo) *pctinfo = 1; HRESULT stdcall CMyComp::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo RPC_FAR * RPC_FAR *pptinfo) *pptinfo = NULL; if (itinfo!= 0) return DISP_E_BADINDEX; m_pitypeinfo->addref(); *pptinfo = m_pitypeinfo; HRESULT stdcall CMyComp::GetIDsOfNames(REFIID riid, LPOLESTR RPC_FAR *rgsznames, UINT cnames, LCID lcid, DISPID RPC_FAR *rgdispid) if (riid!= IID_NULL) return DISP_E_UNKNOWNINTERFACE; HRESULT hr; hr = m_pitypeinfo->getidsofnames(rgsznames, cnames, rgdispid); return hr; HRESULT stdcall CMyComp::Invoke( DISPID dispidmember, REFIID riid, LCID lcid, WORD wflags, DISPPARAMS RPC_FAR *pdispparams, VARIANT RPC_FAR *pvarresult, EXCEPINFO RPC_FAR *pexcepinfo, UINT RPC_FAR *puargerr) if (riid!= IID_NULL) return DISP_E_UNKNOWNINTERFACE; HRESULT hr = m_pitypeinfo->invoke((ia*)this, dispidmember, wflags, pdispparams, pvarresult, pexcepinfo, puargerr); return hr; HRESULT CMyComp::InitTypeInfo() HRESULT hr; spróbuj załadować bibliotekę typów z rejestru systemowego ITypeLib *ptypelib = NULL; hr = LoadRegTypeLib(LIBID_MyTypeLib, 1, 0, 0x00, &ptypelib); if (FAILED(hr)) załaduj z pliku ustal nazwę pliku exe i podziel ją na czynniki pierwsze char szmodule[512] ; DWORD dwresult = ::GetModuleFileName(g_hInstance, szmodule, 512); char szdrive[_max_drive]; char szdir[_max_dir]; _splitpath(szmodule, szdrive, szdir, NULL, NULL); Określ nazwę pliku TLB char sztypelibfullname[_max_path]; sprintf(sztypelibfullname, "%s%s%s", szdrive, szdir, "mytypes.tlb"); convert to wide char wchar_t wsztypelibfullname[_max_path]; mbstowcs(wsztypelibfullname, sztypelibfullname, _MAX_PATH); hr = LoadTypeLib(wszTypeLibFullName, &ptypelib); if (FAILED(hr)) return hr; na wszelki wypadek zarejestruj hr = RegisterTypeLib(pTypeLib, wsztypelibfullname, NULL); if (FAILED(hr)) return hr; pobierz TypeInfo dla IA m_pitypeinfo = NULL; hr = ptypelib->gettypeinfoofguid(iid_ia, &m_pitypeinfo); ptypelib->release(); if (FAILED(hr)) return hr; Podnadto uzupełniono CMyComp::QueryInterface tak, by zwracała w razie potrzeby wskaźnik na IDispatch 10
11 Aternatywna Aplikacja kliencka Aplikacja korzysta z dispinterfejsu #include <objbase.h> #include <assert.h> OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK Klient w Visual Basicu: Dim x As Object Set x = CreateObject(COMLecture.Approach5 ) x.fa void main() inicjalizacja podsystemu COM CoInitialize(NULL); wchar_t progid[] = L"COMLecture.Approach5"; CLSID clsid; CLSIDFromProgID(progid, &clsid); / Klient w MFC (po utworzeniu klasy wrapper IA ia; ia.createdispatch("comlecture.approach5"); ia.fa(); IDispatch *pidispatch = NULL; HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&pidispatch); assert(succeeded(hr)); DISPID dispid; OLECHAR *name = L"fa"; hr = pidispatch->getidsofnames(iid_null, &name, 1, GetUserDefaultLCID(), &dispid); assert(succeeded(hr)); VARIANTARG varg; VariantInit(&varg); varg.vt = VT_EMPTY; DISPPARAMS param; param.cargs = 0; param.rgvarg = &varg; param.cnamedargs = 0; param.cargs = NULL; hr = pidispatch->invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, ¶m, NULL, NULL, NULL); assert(succeeded(hr)); 11
12 Wstęp do programowania składnikowego Programowanie składnikowe Złota zasada: Interfejsem jest wszystko CZĘŚĆ 1: składniki i interfejsy Interfejsy lepiej oddają funkcjonalność obiektów niż dziedziczenie Jarosław Francik Założenia: 1. Programowanie składnikowe to sposób programowania (filozofia) 2. COM to tylko jedna ze specyfikacji wspierających programowanie składnikowe 3. W ramach wykładu korzystamy ze zwykłego C++ by tworzyć oprogramowanie składnikowe 4. W miarę potrzeb będziemy wprowadzać elementy COM Pierwsze podejście... Interfejs = klasa abstrakcyjna Składnik = klasa implementująca abstrakcyjny interfejs (dziedzicząca po klasie abstrakcyjnej) Wiele interfejsów = dziedz. wielobazowe #include <iostream.h> interfejs A class IA public: virtual void fa() = 0; ; interfejs B class IB public: virtual void fb() = 0; ; Składnik class CMyComp : public IA, public IB Implementacja interfejsu A virtual void fa(); void CMyComp::fa() cout << "Jestem fa" << endl; void CMyComp::fb() cout << "Jestem fb" << endl; void main() CMyComp *pcomp = new CMyComp; wskaźnik do interfejsu A IA *pia = pcomp; pia->fa(); wskaźnik do interfejsu B IB *pib = pcomp; pib->fb(); Model komunikacji klient-składnik Klient Składnik ; Implementacja interfejsu B virtual void fb(); delete pcomp; 1
13 Pierwsze podejście... Specyfikacja COM nie wymusza stosowania klas C++, jednak: binarny format tablicy funkcji wirtualnych C++ jest zgodny ze specyfikacją COM Pierwsze podejście... Wprowadzamy ułatwienia i wymogi COM: include <objbase.h> interface (słowo kluczowe C++) stdcall konwencja wywołania Pierwsze podejście... [ listing #1 ] Słaby punkt: wykorzystujemy bezpośrednio wskaźnik na klasę komponentu w ten sposób zbyt mocno wiążemy klienta z implementacją składnika Rozwiązanie: stworzyć odrębną funkcję CreateInstance, której implementacja jest wewnętrznym szczegółem modułu składnika Lepsze podejście... Publicznie widzimy: interfejsy deklarację funkcji CreateInstance narzędzie do uzyskiwania wskazanych interfejsów? oczywiście też interfejs: IUnknown 2
14 Wstęp do programowania składnikowego CZĘŚĆ 2: interfejs Iunknown Jarosław Francik Interfejs IUnknown interface IUnknown virtual HRESULT stdcall QueryInterface (const IID &iid, void **ppc) = 0; virtual ULONG stdcall AddRef() = 0; virtual ULONG stdcall Release() = 0; ; Każdy interfejs COM dziedziczy po IUnknown IUnknown::QueryInterface Klient 1. Klient wywołuje QueryInterface(IID) 2. Obiekt zwraca wskaźnik na interfejs 3. Klient może wywoływać metody Składnik COM HRESULT QueryInterface(const IID &iid, void **p); IUnknown::QueryInterface (użycie przez klienta) inicjalizacja składnika IUnknown *pcomp = CreateInstance(); chcemy skorzystać z interfejsu IA IA *pia = NULL; HRESULT hr = pcomp->queryinterface (IID_IA, (void**)&pia); if (SUCCEEDED(hr)) pia->fa(); identyfikator interfejsu IID (GUID) IUnknown::QueryInterface (implementacja) HRESULT _stdcall CMyComp::QueryInterface(REFIID iid, void **ppv) if (iid == IID_IUnknown) *ppv = (IA*)this; else if (iid == IID_IA) *ppv = (IA*)this; else if (iid == IID_IB) *ppv = (IB*)this; else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); Funkcja CreateInstance IUnknown *CreateInstance() IUnknown *p = (IA*)new CMyComp; p->addref(); return p; W bibliotece COM API dostępna jest funkcja CoCreateInstance o podobnym działaniu 1
15 Drugie podejście T T Co widzi klient? T interfejsy T identyfikatory interfejsów (IID) T nagłówek funkcji CreateInstance (w COM korzystamy raczej z funkcji bibliotecznej CoCreateInstance) Co implementuje składnik? T klasa implementująca interfejs IUnknown oraz własne interfejsy T funkcja CreateInstance [ listing #2 ] Nie używamy dziedziczenia wirtualnego! Jest ono niezgodne z formatem binarnym COM QueryInterface QueryInterface możemy stosować do dowolnego interfejsu, nie tylko do IUnknown gdyż wszystkie interfejsy dziedziczą po IUnknown QueryInterface IUnknown *p = CreateInstance(); IA *pia = NULL; hr = p->queryinterface(iid_ia, (void**)&pia); if (!SUCCEEDED(hr)) return; Interfejs IB otrzymujemy z IA IB *pib = NULL; hr = pia->queryinterface(iid_ib, (void**)&pib); if (!SUCCEEDED(hr)) return; Interfejs IUnknown otrzymujemy z IB IUnknown * punknown = NULL; hr = pib->queryinterface(iid_iunknown, (void**)&punknown); if (!SUCCEEDED(hr)) return; QueryInterface T T T T Za każdym razem otrzymuję ten sam interfejs IUnknown Zawsze mogę otrzymać interfejs, który już kiedyś uzyskałem Zawsze mogę uzyskać interfejs, który już mam Jeśli mogę otrzymać interfejs gdziekolwiek, to mogę go otrzymać wszędzie 2
16 QueryInterface T definiuje obiekt T pozwala udostępniać różne wersje interfejsów dla tego samego obiektu T pomaga utrzymać kompatybilność wstecz przy wypuszczaniu nowej wersji produktu T ALE: wymaga to dotrzymania założeń przez projektanta nowej wersji!!! Zliczanie referencji: AddRef/Release T Klasa składnika zawiera licznik referencji T AddRef zwiększa licznik T Release zmniejsza licznik i w razie potrzeby usuwa składnik z pamięci T Utworzenie obiektu = AddRef T Porzucenie obiektu = Release Zliczanie referencji: AddRef/Release ULONG _stdcall CMyComp::AddRef() return InterlockedIncrement(&m_nRef); ULONG _stdcall CMyComp::Release() if (InterlockedDecrement(&m_nRef) == 0) delete this; return 0; return m_nref; AddRef/Release: trzy proste zasady T Wywołaj AddRef zanim zwrócisz wynik T jeśli zwracasz interfejs jako wartość funkcji. Dotyczy też QueryInterface i CreateInstance! T Wywołaj Release kiedy skończysz T gdy nie będziesz już dłużej wykorzystywał interfejsu T Wywołaj AddRef gdy robisz przypisanie T AddRef/Release: Optymalizacja Nie musisz stosować AddRef/Release w przypadku użycia wskaźnika o zagnieżdżonym zasięgu (w obrębie zasięgu innego wskaźnika) T T T T T T parametr wejściowy nic (jest zagnieżdżony) parametr wyjściowy AddRef parametr wejściowo-wyjściowy być może AddRef + Release zmienna lokalna nic (jest zagnieżdżona) zmienna globalna AddRef + Release w przypadku wątpliwości AddRef + Release Drugie podejście... T Słaby punkt: T funkcja CreateInstance zbyt mocno wiąże klienta z serwerem T Rozwiązanie: T skorzystamy z technologii COM... 3
17 Wstęp do programowania składnikowego CZĘŚĆ 3: Funkcja CoCreateInstance, fabryki klas i serwery COM Jarosław Francik Podstawy technologii COM HRESULT standardowy typ wartości zwracanych przez funkcje S_OK S_FALSE E_UNEXPECTED E_NOTIMPL E_NOINTERFACE E_OUTOFMEMORY Bity: 0-15 return code co się stało facility code id części systemu 31 sukces czy porażka Makro SUCCEEDED Funkcja FormatMessage Podstawy technologii COM Rejestr Windows HKEY_CLASSES_ROOT CLSID 59F1DE0D A57-82CE-D6DBA3D28D28: Wykład COM, podejście 3 T InProcServer32: c:\windows\system32\component.dll T ProgID: COMLecture.Approach3.1 T VersionIndependentProgID: COMLecture.Approach3 COMLecture.Approach3.1: Wykład COM, podejście 3 CLSID: 59F1DE0D A57-82CE-D6DBA3D28D28 COMLecture.Approach3: Wykład COM, podejście 3 CLSID: 59F1DE0D A57-82CE-D6DBA3D28D28 CurVer: COMLecture.Approach3.1 Podstawy technologii COM Rejestr Windows (c.d.) Przydatne funkcje: CLSIDFromProgID Rejestrowanie serwerów COM Serwer musi sam dostarczyć eksportowanych funkcji: DllRegisterServer DllUnregisterServer Przydatne narzędzia: RegOpenKeyEx, RegCreateKeyEx, RegSetValueEx, RegEnumKeyEx, RegDeleteKey, RegCloseKey Pliki Registry.h i Registry.cpp można znaleźć wraz z programem przykładowym approach3 Podstawy technologii COM Przydatne funkcje: CoInitialize(NULL); dla każdego procesu osobno! CoUninitialize StringFromCLSID StringFromIID CLSIDFromString IIDFromString CoTaskMemAlloc CoTaskMemFree Podstawy technologii COM CoCreateInstance ( const CLSID &clsid, IUnknown *piunknownouter, DWORD dwclscontext, const IID &iid, void **ppv); 1
18 Trzecie podejście - klient Zastępujemy dotychczasowy CreateInstance wywołaniem CoCreateInstance Powiązanie między klientem a serwerem już tylko poprzez CLSID! Trzecie podejście - klient CoInitialize(NULL); IA *pia = NULL; HRESULT hr = CoCreateInstance( CLSID_MyComponent, NULL, CLSCTX_INPROC_SERVER, IID_IA, (void**)&pia); if (SUCCEEDED(hr)) pia->fa(); pia->release(); Fabryka klas IClassFactory interfejs służący do tworzenia egzemplarzy klas (obiektów) interface IClassFactory HRESULT stdcall CreateInstance (IUnknown *punknownouter, const IID& iid, void **ppv); HRESULT stdcall LockServer(BOOL b); w wywołaniu CreateInstance brakuje CLSID Fabryka klas służy do tworzenia obiektów określonej klasy Fabryka klas Funkcja CoGetClassObject zwraca wskaźnik na fabrykę klas dla określonego CLSID HRESULT stdcall CoGetClassObject( const CLSID &clsid, DWORD dwclscontext, COSERVERINFO *pserverinfo, const IID &iid, void **ppv); CoGetClassObject wywołuje DllGetClassObject: funkcję obowiązkowo eksportowaną przez serwery COM Fabryka klas Fabryka klas CoCreateInstance vc CoGetClassObject HRESULT stdcall CoCreateInstance (...) *ppv = NULL; IClassFactory *pfactory = NULL; HRESULT hr = CoGetClassObject(clsid,..., IID_IClassFactory, &pfactory); if (SUCCEEDED(hr)) hr = pfactory->createinstance(..., iid, ppv); pfactory->release; return hr; Klient CoCreateInstance COM API CoGet- ClassObject IA* DLL DllGetClassObject Class Factory new CFactory IClassFactory* IClassFactory::CreateInstance IClassFactory::Release pia->fa Składnik new CMyComp QueryInterface 2
19 Trzecie podejście - serwer Implementacja klasy składnika: prawie bez zmian Implementacja fabryki klas: implementacja IUnknown standardowa implementacja IClassFactory::CreateInstance implementacja IClassFactory::LockServer Implementacja eksportowanych funkcji: DllCanUnloadNow wymaga zliczania instancji DllGetClassObject DllRegisterServer / DllUnRegisterServer [ listing #3 ] Trzecie podejście co dalej? Serwer COM rejestrujemy za pomocą programu regsrv32 Interfejsy mają stałe IID Aplikacje wcale nie muszą korzystać stale z tych samych CLSID 3
20 TWORZENIE SKŁADNIKÓW WEWNĄTRZPROCESOWYCH Poniższy zwięzły opis przedstawia najważniejsze kroki niezbędne dla uzyskania klienta i serwera wewnątrzprocesowego COM. Ilustracją poniższej instrukcji są kody źródłowe approach3 i approach3a, a także inne materiały dostępne na stronie sun.iinf.polsl.gliwice.pl/~jfrancik/lectures/com.html. 1. STWORZENIE SPECYFIKACJI IDL Plik IDL zawiera specyfikację tworzonych interfejsów i klas składników (a także biblioteki typów). Wynikiem kompilacji pliku abc.idl są między innymi pliki abc.h (deklaracje interfejsów w języku C/C++) oraz abc_i.c (definicje identyfikatorów iid i clsid). [Krok ten eliminuje potrzebę tworzenia pliku nagłówkowego interface.h oraz definiowania explicite identyfikatorów iid / clsid por. listing approach 3] 2. STWORZENIE APLIKACJI KLIENCKIEJ Aplikacja kliencka powinna obejmować obydwa pliki wynikowe kompilacji specyfikacji IDL wspomniane w poprzednim punkcie. Aplikacja inicjalizuje system COM (CoInitialize), zakłada nowy egzemplarz składnika za pomocą funkcji CoCreateInstance i otrzymuje wskaźnik na podany interfejs. Wskaźnik na dowolny, inny interfejs aplikacja może otrzymać wywołując funkcję QueryInterface już posiadanego interfejsu. Aplikacja jest zobowiązana wywoływać funkcje AddRef/Release zgodnie z obowiązującymi zasadami (por. prezentacja approach2.pdf). 3. STWORZENIE MODUŁU DLL SERWERA Na stworzenie modułu serwera składają się następujące czynności: 1. Wprowadzenie do projektu plików wynikowych kompilacji specyfikacji IDL wyszczególnionych w p Założenie globalnych liczników: aktywnych składników oraz blokad serwera. 3. Stworzenie klasy składnika. Wszystkie implementowane interfejsy powinny być wyszczególnione jako klasy bazowe. Należy zaimplementować wszystkie funkcje składowe tych interfejsów, a także funkcje składowe interfejsu IUnknown: QueryInterface, AddRef oraz Release. [Użycie specyfikacji IDL wymusza, by wszystkie funkcje składowe zwracały HRESULT. Listing Approach3 nie spełnia tego wymogu; stosowną poprawkę można znaleźć w listingu Approach3a] 4. Stworzenie klasy implementującej interfejs IClassFactory (fabrykę klas). Należy zaimplementować zarówno funkcje składowe interfejsu IClassFactory (CreateInstance i LockServer), jak i wyszczególnione wcześniej funkcje składowe interfejsu IUnknown. 5. Implementacja punktu wejściowego DLL (DllMain). W obrębie tej funkcji należy zachować uchwyt modułu DLL HMODULE. 6. Implementacja obowiązkowych funkcji eksportowanych: - DllCanUnloadNow na podstawie wspomnianych w p. 3-2 globalnych liczników ustala, czy serwer może być usunięty z pamięci. - DllGetClassObject sprawdza podany clsid i tworzy odpowiadającą mu fabrykę klas. Zwraca wskaźnik do wskazanego w parametrze interfejsu fabryki klas. - DllRegisterServer na podstawie zachowanego w funkcji DllMain uchwytu modułu DLL oraz dodatkowych, pomocniczych zmiennych globalnych, przeprowadza rejestrację serwera. Pomocne są tu pliki registry.h i registry.cpp ( Dale Rogerson) zawierające pomocne funkcje. - DllUnregisterServer na podstawie dodatkowych, pomocniczych zmiennych globalnych, przeprowadza wyrejestrowanie serwera. Pomocne są tu pliki registry.h i registry.cpp ( Dale Rogerson) zawierające pomocne funkcje. 7. Rejestracja modułu w systemie (za pomocą opcji Tools Register Control w Visual Studio lub wywołując program regsvr32). opracowanie: Jarosław Francik
21 IDL EKSPRESOWE WPROWADZENIE Jarosław Francik PRZYKŁAD DEFINICJI INTERFEJSU: OBJAŚNIENIA: import "unknwn.idl"; [ object, uuid(b5db b7db-30da5e75d347), helpstring("przykładowy interfejs IA"), pointer_default(unique) ] interface IA : IUnknown HRESULT fun([in] int x, [out] int &r); ; Powyższa definicja odpowiada następującej klasie C++: interface IA : public IUnknown virtual void stdcall fa() = 0; ; Specyfikacja klasy jest poprzedzona fragmentem znajdującym się w nawiasach kwadratowych. Są to rozszerzenia IDL w stosunku do C++: import wstawia plik w IDL (w tym przypadku: definicję klasy IUnknown) object wyróżnik obiektu COM (IDL ma zastosowania szersze niż tylko COM) uuid identyfikator GUID helpstring zwięzły opis w języku naturalnym, udostępniany na poziomie biblioteki typów pointer_default domyślny tryb marshalingu wskaźników; dostepne wartości to: ref wskaźniki są traktowane jak referencje: nie mogą zawierać NULL, nie mogą być zmieniane, w obrębie funkcji nie mogą być tworzone aliasy unique wskaźniki mogą zawierać NULL, mogą być zmieniane, ale w obrębie funkcji nie mogą być tworzone aliasy ptr wszystko powyższe jest dozwolone Specyfikacja funkcji składowych. Wszystkie funkcji w IDL muszą zwracać wartość HRESULT. Poszczególne parametry mogą zawierać dodatkowe określniki, stanowiące rozszerzenia IDL w stosunku do C++. Są one niezbędne dla zapewnienia prawidłowego marshalingu parametrów. Do zdefiniowania parametrów marshalingu są potrzebne: adres przesyłanej zmiennej, kierunek przesyłu argumentu, rozmiar przesyłanego bloku. Pierwszy z powyższych parametrów jest znany podczas wykonania programu. Kierunek przesyłu argumentu określa się za pomocą następujących określników: in out in, out wyróżnik argumentu wejściowego funkcji wyróżnik argumentu wyjściowego (wyniku) funkcji (na ogół wskaźnika lub referencji) wyróżnik argumentu będącego jednocześnie wejściowym i wyjściowym Rozmiar przesyłanego bloku jest najczęściej jednoznacznie określany na podstawie typu przesyłanych danych. W kolejnych podpunktach zostaną przedstawione elementy języka IDL pozwalające na określenie rozmiaru przesyłanych danych w przypadkach, gdy nie może on być ustalony tylko na podstawie typu danych. Przesyłanie łańcuchów wymaga użycia określnika string. Należy pamiętać, że COM obsługuje wyłącznie łańcuchy Unicode (wchar_t zamiast char): HRESULT strfun([in, string] wchar_t *pin, [out, string] wchar_t **pout);
22 Przesyłanie tablic wymaga określenia rozmiaru tablicy za pomocą określnika size_is. Pozwala on na podanie rozmiaru posługując się innym parametrem, który powinien zawierać rozmiar tablicy: HRESULT arrfunin([in] long nsize, [in, size_is(nsize)] long array[]); HRESULT arrfunout([out, in] long *nsize, [out, size_is(nsize)] long array[]); należy zauważyć, że parametr użyty w size_in może być tylko wejściowy [in] lub wejściowo-wyjściowy [in, out]. Wynika z tego, że COM będzie zawsze wiedzieć, jak dużą tablicę udostępnił klient. Serwer może zapełnić tylko część tej tablicy, stosownie ustawiając parametr nsize. Z tego względu warto rozważyć następującą modyfikację funkcji arrfunout, w której rozdzielono parametr wejściowy i wyjściowy: HRESULT arrfunout2([in] nsizein, [out, size_is(nsizein)] long array[], [out] long *nsizeout); Przekazywanie struktur jest łatwe, gdyż IDL pozwala na bezpośrednie definiowanie struktur: typedef struct Date int D; int M; int Y; ;... HRESULT structfun([in] Date birthdate); Sprawa się komplikuje, gdy elementami struktury są wskaźniki na inne struktury, które również powinny być odwzorowane w ramach marshalingu. Kompilator IDL musi dokładnie wiedzieć, na co wskazuje wskaźnik nie należy więc raczej stosować typu void*. Jeśli przekazywany jest wskaźnik na interfejs COM, dobrym pomysłem jest przekazanie w osobnym parametrze jego IID. Służy temu specjalny określnik iid_is: HRESULT intfun([in] const IID &iid, [out, iid_is(iid)] IUnknown **ppv); Oczywiście mniej więcej to samo można uzyskać przekazując typ interfejsu wprost, np.: HRESULT intfun_naive([out] IMyInterface **ppv); rozwiązanie takie zemści się jednak, gdy zamiast wskaźnika na IMyInterface zechcemy przesłać coś, co wskazuje na jakąś klasę wywiedzoną z IMyInterface. PRZYKŁAD DEFINICJI BIBLIOTEKI TYPÓW: OBJAŚNIENIA: library coclass [ uuid(3221ccff-68b2-442b-afdc-fa9c767f1fc4), version(1.0), helpstring("przykładowa biblioteka typów") ] library MyTypeLib importlib("stdole32.tlb") ; [ uuid(e843265d-b374-4d56-a980-0ec5e9188b47), helpstring("klasa komponentu") ] coclass Component [default] interface IA; interface IB; ; ; definiuje bibliotekę typów o podanym GUID (LIBID). Biblioteka może zawierać jeden lub więcej komponentów klas składników definiuje klasę składników o podanym GUID (CLSID). Klasa może udostępniać jeden lub więcej interfejsów. Jeden z nich może być domyślny, (istotne dla języków makr i VB). Opis powyższy ma charakter wstępny; w szczególności pominięto zagadnienia związane z definiowaniem dispinterfejsów (dipinterface, propget, propput, dual, oleautomation). Wyczerpujący opis języka IDL można znaleźć w MSDN; dobrym sposobem nauki IDL jest też analizowanie różnych dostępnych definicji klas.
23 TWORZENIE SKŁADNIKÓW ZEWNĄTRZPROCESOWYCH Poniższy zwięzły opis przedstawia najważniejsze kroki niezbędne dla uzyskania klienta i serwera zewnątrzprocesowego COM (serwer w pliku EXE). Tekst ten powinien być używany łącznie z instrukcją dot. tworzenia składników wewnątrzprocesowych (inproc). Ilustracją jest też kod źródłowy approach4, a także inne materiały dostępne na stronie sun.iinf.polsl.gliwice.pl/~jfrancik/lectures/com.html. 1. STWORZENIE SPECYFIKACJI IDL Ten krok przebiega tak samo, jak w przypadku składników inproc. 2. STWORZENIE APLIKACJI KLIENCKIEJ Jedyną różnicą pomiędzy aplikacją korzystającą ze składnika zewnątrzprocesowego (w stosunku do aplikacji używającej składnika inproc) jest wartość trzeciego parametru funkcji CoCreateinstance, która musi zawierać ustawiony bit CLSCTX_LOCAL_SERVER. 3. STWORZENIE MODUŁU DLL PROXY Moduł proxy jest niezbędny przy komunikacji klienta z serwerem zewnątrzprocesowym, nie wymaga jednak specjalnego kodowania. Wystarczy w tym celu: - Stworzyć projekt DLL obejmujący następujące pliki źródłowe, automatycznie generowane podczas kompilacji specyfikacji IDL: dlldata.c, abc_i.c, abc_p.c (przy założeniu, że kompilowano plik abc.idl). - Włączyć linkowanie nastepujących bibliotek (poza standardowymi): rpcndr.lib, rpcns4.lib i rpcrt4.lib. - Dodać definicję symbolu REGISTER_PROXY_DLL - Dołączyć plik def (por. przykład approach4) - Skompilować i zlinkować projekt. - Zarejestrować otrzymany plik DLL (za pomocą opcji Tools Register Control w Visual Studio lub wywołując program regsvr32). 4. STWORZENIE MODUŁU EXE SERWERA Większa część kodu źródłowego serwerów zewnątrz- i wewnątrzprocesowych jest taka sama. W szczególności punkty 1 4 w części instrukcji dotyczącej tworzenia serwerów inproc można zastosować do serwerów zewnątrzprocesowych. Punkty 5 7 tej instrukcji nie odnoszą się do serwerów w plikach EXE, w szczególności nie ma tu funkcji eksportowanych. Oto specyficzne dla tego typu serwerów czynności dodatkowe: 1. Stworzenie funkcji WinMain jak w przykładzie Approach4. Poniżej przedstawiono najważniejsze elementy: - Inicjalizacja systemu COM (CoInitialize). - Analiza linii wywołania: parametrów RegServer (rejestracja serwera), UnregServer (wyrejestrowanie serwera) i Embedding (praca tylko w trybie serwera, a nie aplikacji zwykle powoduje wyłączenie wyświetlenia okna aplikacji). [Uwaga wśród plików projektu Approach4 znajduja się pliki Registry.h i Registry.cpp z modyfikacjami niezbędnymi przy obsłudze składników zewnątrzprocesowych] - Utworzenie i rejestracja fabryk(i) klas (funkcja CoRegisterClassObject). - Wyświetlenie okna (zwykle z wyjątkiem trybu /Embedding) i petla komunikatów - Wyrejestrowanie fabryk(i) klas (CoRevokeClassObject) i deinicjalizacja COM (CoUninitialize) 2. Implementacja zarządzania usuwaniem aplikacji z pamięci. Wymaga to: - przy dekrementacji globalnych liczników (g_ccomponents i g_cserverlocks) sprawdzenia, czy aplikacja nie powinna być usunięta z pamięci: - if (g_ccomponents == 0 && g_cserverlocks == 0) PostQuitMessage(0); - Blokady usuwania aplikacji, gdy używany jest interfejs użytkownika (okno aplikacji): - InterlockedIncrement(&g_cServerLocks); wywołane tuż po otwarciu okna - Zniesienia powyższej blokady w chwili zamknięcia okna aplikacji: - case WM_CLOSE: ::InterlockedDecrement(&g_cServerLocks); w funkcji okienkowej - Dodatkowej kontroli podczas obsługi komunikatu WM_DESTROY: case WM_DESTROY: if (g_ccomponents == 0 && g_cserverlocks == 0) PostQuitMessage(0); 3. Zarejestrowanie serwera poprzez wywołanie go z parametrem /RegServer. opracowanie: Jarosław Francik
24 Interfejs IDispatch, dispinterfejsy i automatyzacja Jarosław Francik Interface Idispatch : IUnknown HRESULT GetTypeInfoCount([out] UINT RPC_FAR *pctinfo); HRESULT GetTypeInfo( [in] UINT itinfo, [in] LCID lcid, [out] ITypeInfo RPC_FAR * RPC_FAR *pptinfo); HRESULT GetIDsOfNames( [in] REFIID riid, [in] LPOLESTR RPC_FAR *rgsznames, [in] UINT cnames, [in] LCID lcid, [out, size_is(cnames)] DISPID RPC_FAR *rgdispid); HRESULT Invoke( [in] DISPID dispidmember, [in] REFIID riid, [in] LCID lcid, [in] WORD wflags, [in] DISPPARAMS RPC_FAR *pdispparams, [out] VARIANT RPC_FAR *pvarresult, [out] EXCEPINFO RPC_FAR *pexcepinfo, [out] UINT RPC_FAR *puargerr); ; interfejs IDispatch (IDL) Dispinterface Dispinterface Klient IDispatch QueryInterface Składnik COM Klient IDispatch QueryInterface Składnik COM AddRef Release GetTypeInfoCount dispinterface "fun1" 1 "fun2" 2 AddRef Release GetTypeInfoCount dispinterface "fun1" 1 "fun2" 2 GetTypeInfo GetIDsOfNames Invoke "fun3" 3 1 fun1 2 fun2 GetTypeInfo GetIDsOfNames Invoke "fun3" 3 pvtbl fun1 fun2 3 fun3 fun3 dual interface IDispatch Klient QueryInterface AddRef Release GetTypeInfoCount GetTypeInfo GetIDsOfNames Invoke fun1 fun2 fun3 Składnik COM dispinterface "fun1" 1 "fun2" 2 "fun3" 3 Parametry wywołania Invoke dispidmember dispid wywoływanej funkcji riid zarezerwowany, ma być IID_NULL lcid użyj GetUserDefaultLCID() wflags rodzaj funkcji: DISPATCH_METHOD, DISPATCH_PROPERTYGET, DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF pdispparams tablica parametrów wywołania tagdispparams pvarresult wynik funkcji (wskaźnik na wariant) pexcepinfo, puargerr sytuacje wyjątkowe 1
25 DISPPARAMS i Warianty struct tagdispparams VARIANTARG *rgvarg; /*... */ ; struct tagvariant /*... */ VARTYPE vt; /*... */ stałe VT_* union LONG lval; VT_I4 BYTE bval; VT_UI1 SHORT ival; VT_I2 /*... */ BSTR bstrval; VT_BYREF VT_BSTR Ciekawe funkcje: SysAllocString VariantChangeType wchar_t progid[] = L"COMLecture.Approach5.1"; CLSID clsid; CLSIDFromProgID(progid, &clsid); IDispatch *pidispatch = NULL; HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void**)&pidispatch); DISPID dispid; OLECHAR *name = L"fa"; hr = pidispatch->getidsofnames(iid_null, &name, 1, GetUserDefaultLCID(), &dispid); VARIANTARG varg; VariantInit(&varg); varg.vt = VT_EMPTY; DISPPARAMS param; param.cargs = 0; param.rgvarg = &varg; param.cnamedargs = 0; param.cargs = NULL; hr = pidispatch->invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, ¶m, NULL, NULL, NULL); Klient dla dispinterface Visual C++ i MFC: IA ia; ia.createdispatch("comlecture.approach5.1 ) ia.fa(); Visual Basic: Dim x As Object CreateObject("COMLecture.Approach5.1 ) x.fa Klienci dla dispinterface 2
26 / Kalkulator (prosty) - wersja agregowalna import "unknwn.idl"; Interface ICalc [ object, uuid(892753ed-d14e-4d2f-b e0c01f5f3), helpstring("kalkulator (prosty), wersja agregowalna"), pointer_default(unique) ] interface ICalc : IUnknown HRESULT digit([in] int n); HRESULT comma(); HRESULT sign(); HRESULT op([in] int n); HRESULT eq(); HRESULT c(); HRESULT ce(); [propget, id(1), helpstring("wyświetlacz")] HRESULT display([out, retval] double *pval); [propput, id(1), helpstring("wyświetlacz")] HRESULT display([in] double newval); ; Biblioteka typów + clsid składników [ uuid(7fb7b bd-4360e0147dd8), version(1.0), helpstring("kalkulator (prosty), wersja agregowalna, bibl.typów") ] library CalcAggrTypeLib importlib("stdole32.tlb") ; [ uuid(4d3b9d9b-8dcc-4443-bac8-1dcae ), helpstring("kalkulator (prosty), wersja agregowalna") ] coclass CalcSimple [default] interface ICalc; ; ; Serwer prostego kalkulatora - wersja agregowalna Copyright (c) 2001 by Jarosław Francik #include "stdafx.h" #include "calc2.h" plik automatycznie utworzony przez MIDL #include "calc2_i.c" plik automatycznie utworzony przez MIDL #include <iostream.h> #include "registry.h" pomocnicze narzędzia do rejestru systemowego... Zmienne globalne static HMODULE g_hmodule = NULL ; static long g_ccomponents = 0 ; static long g_cserverlocks = 0 ; uchwyt modułu DLL Licznik aktywnych składników Licznik dla LockServer Dane do rejestru systemowego const char g_szprogid[] = "Calc.SimpleAggr.2"; const char g_szfriendlyname[] = "Prosty kalkulator COM - wersja agregowalna"; const char g_szverindprogid[] = "Calc.SimpleAggr"; Interfejs INondelegatingUnknown interface INondelegatingUnknown virtual HRESULT stdcall NondelegatingQueryInterface(const IID&, void**) = 0 ; virtual ULONG stdcall NondelegatingAddRef() = 0 ; virtual ULONG stdcall NondelegatingRelease() = 0 ; ; Klasa składnika class CCalc : public ICalc, INondelegatingUnknown public: Implementacja interfejsu IUnknown virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); Implementacja interfejsu INondelegatingUnknown virtual HRESULT _stdcall NondelegatingQueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall NondelegatingAddRef(); virtual ULONG _stdcall NondelegatingRelease(); Implementacja interfejsu ICalc virtual HRESULT stdcall digit(int n); virtual HRESULT stdcall comma(); virtual HRESULT stdcall sign(); virtual HRESULT stdcall op(int n); virtual HRESULT stdcall eq(); virtual HRESULT stdcall c(); virtual HRESULT stdcall ce(); virtual HRESULT stdcall get_display(double RPC_FAR *pval); virtual HRESULT stdcall put_display(double newval); Implementacja wewnętrzna double m_display, m_reg; wyświetlacz i drugi rejestr int m_op; kod operacji; 0=nic, 1-4 = + - * / bool m_bappenddisp; tryb dodawania do wyświetlacza; public: CCalc(IUnknown *punknownouter) : m_nref(1), m_display(0.0), m_reg(0.0), m_op(0), m_bappenddisp(false) InterlockedIncrement(&g_cComponents); if (punknownouter) m_punknownouter = punknownouter; zostaliśmy zagregowani! else m_punknownouter = (IUnknown*)(INondelegatingUnknown*)this; ~CCalc() InterlockedDecrement(&g_cComponents); private: long m_nref; IUnknown *m_punknownouter; obiekt do którego delegujemy odwołania ;
27 Implementacja interfejsu ICalc HRESULT stdcall CCalc::digit(int n) if (!m_bappenddisp) m_display = n; else m_display = m_display * 10 + n; m_bappenddisp = true; HRESULT stdcall CCalc::comma() return E_NOTIMPL; HRESULT stdcall CCalc::sign() m_display = -m_display; HRESULT stdcall CCalc::op(int n) eq(); m_op = n; HRESULT stdcall CCalc::eq() switch (m_op) case 1: m_display = m_reg + m_display; break; case 2: m_display = m_reg - m_display; break; case 3: m_display = m_reg * m_display; break; case 4: m_display = m_reg / m_display; break; m_reg = m_display; m_bappenddisp = false; HRESULT stdcall CCalc::c() m_reg = m_display = m_op = 0; m_bappenddisp = false; HRESULT stdcall CCalc::ce() m_display = 0; m_bappenddisp = false; HRESULT stdcall CCalc::get_display(double RPC_FAR *pval) *pval = m_display; HRESULT stdcall CCalc::put_display(double newval) m_display = newval; Implementacja interfejsu IUnknown HRESULT _stdcall CCalc::QueryInterface(REFIID iid, void **ppv) return m_punknownouter->queryinterface(iid, ppv); ULONG _stdcall CCalc::AddRef() return m_punknownouter->addref(); ULONG _stdcall CCalc::Release() return m_punknownouter->release(); Implementacja interfejsu INondelegatingUnknown HRESULT _stdcall CCalc::NondelegatingQueryInterface(REFIID iid, void **ppv) if (iid == IID_IUnknown) *ppv = (INondelegatingUnknown*)this; else if (iid == IID_ICalc) *ppv = (ICalc*)this; else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); ULONG _stdcall CCalc::NondelegatingAddRef() return InterlockedIncrement(&m_nRef); ULONG _stdcall CCalc::NondelegatingRelease() if (InterlockedDecrement(&m_nRef) == 0) delete this; return 0; return m_nref;
28 Class Factory class CFactory : public IClassFactory standardowa deklaracja interfejsu IClassFactory ; HRESULT stdcall CFactory::QueryInterface(const IID& iid, void** ppv) standardowa implementacja ULONG stdcall CFactory::AddRef() standardowa implementacja ULONG stdcall CFactory::Release() standardowa implementacja HRESULT stdcall CFactory::CreateInstance(IUnknown* punknownouter, const IID& iid, void** ppv) if (punknownouter!= NULL && iid!= IID_IUnknown) return CLASS_E_NOAGGREGATION; Utworzenie składnika CCalc* pcalc = new CCalc(pUnknownOuter); if (!pcalc) return E_OUTOFMEMORY; Utworzenie żądanego interfejsu HRESULT hr = pcalc->nondelegatingqueryinterface(iid, ppv); pcalc->nondelegatingrelease(); return hr; HRESULT stdcall CFactory::LockServer(BOOL block) standardowa implementacja Funkcje eksportowane! standardowa implementacja / Kalkulator naukowy (z wykorzystaniem agregacji) import "unknwn.idl"; Interface ICalcScientific [ object, uuid(22e6b303-cefe-4f65-9bed-8623af83903e), helpstring("kalkulator naukowy"), pointer_default(unique) ] interface ICalcScientific : IUnknown HRESULT sqroot(); ; Biblioteka typów + clsid składników [ uuid(f3b7ad02-3d70-46e d479b95e4089), version(1.0), helpstring("kalkulator naukowy, biblioteka typów") ] library CalcSciTypeLib importlib("stdole32.tlb") ; [ uuid(ba e2-42ce-b a6388e), helpstring("kalkulator naukowy - komponent zagregowany") ] coclass CalcScientific [default] interface ICalcScientific; interface ICalc; ; ; Serwer kalkulatora naukowego (z pierwiastkowaniem) Moduł agreguje składnik Calc2 - prosty kalkulator Copyright (c) 2001 by Jarosław Francik #include "stdafx.h" #include "calcsci.h" plik automatycznie utworzony przez MIDL #include "calcsci_i.c" plik automatycznie utworzony przez MIDL #include <iostream.h> #include "registry.h" pomocnicze narzędzia do rejestru systemowego... #include <math.h> #include "..\\calc2\\calc2.h" #include "..\\calc2\\calc2_i.c" Zmienne globalne jak w poprzednim przykładzie...
29 Klasa składnika class CCalcScientific : public ICalcScientific public: Implementacja interfejsu IUnknown virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); Implementacja interfejsu ICalcScientific virtual HRESULT stdcall sqroot(); Funkcja inicjalizująca obiekt wewnętrzny (wywoływana przez fabrykę klas) HRESULT Init() return CoCreateInstance(CLSID_CalcSimple, (IUnknown*)this, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&m_punknowninner); public: IUnknown *m_punknowninner; CCalcScientific() : m_nref(1) InterlockedIncrement(&g_cComponents); ~CCalcScientific() InterlockedDecrement(&g_cComponents); private: long m_nref; ; Implementacja interfejsu ICalcScientific HRESULT stdcall CCalcScientific::sqroot() ICalc *pcalc = NULL; HRESULT hr = m_punknowninner->queryinterface(iid_icalc, (void**)&pcalc); if (SUCCEEDED(hr)) double ddisp; pcalc->get_display(&ddisp); ddisp = sqrt(ddisp); pcalc->put_display(ddisp); return hr; Implementacja interfejsu IUnknown HRESULT _stdcall CCalcScientific::QueryInterface(REFIID iid, void **ppv) if (iid == IID_IUnknown) *ppv = (ICalcScientific*)this; else if (iid == IID_ICalcScientific) *ppv = (ICalcScientific*)this; else if (iid == IID_ICalc) return m_punknowninner->queryinterface(iid, ppv); else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); ULONG _stdcall CCalcScientific::AddRef() ULONG _stdcall CCalcScientific::Release() standardowe implementacje Class Factory standardowa implementacja fabryki klas (jak w pierwszym przykładzie) zmiany dotyczą tylko poniższego: HRESULT stdcall CFactory::CreateInstance(IUnknown* punknownouter, const IID& iid, void** ppv) if (punknownouter!= NULL) return CLASS_E_NOAGGREGATION; Utworzenie składnika CCalcScientific* pcalcscientific = new CCalcScientific; if (!pcalcscientific) return E_OUTOFMEMORY; Utworzenie wewnętrznego składnika HRESULT hr = pcalcscientific->init(); if (!SUCCEEDED(hr)) return CLASS_E_NOAGGREGATION; Utworzenie żądanego interfejsu hr = pcalcscientific->queryinterface(iid, ppv); pcalcscientific->release(); return hr; Funkcje eksportowane! standardowa implementacja
30 / Kalkulator (prosty) wersja z punktami połączeń import "unknwn.idl"; Interface ICalc [ object, uuid(14169cfc-8cc3-45ec-8c46-d080c8de6d39), helpstring("kalkulator (prosty), wersja z punktami połączenia"), pointer_default(unique) ] interface ICalc : IUnknown HRESULT digit([in] int n); HRESULT comma(); HRESULT sign(); HRESULT op([in] int n); HRESULT eq(); HRESULT c(); HRESULT ce(); [propget, id(1), helpstring("wyświetlacz")] HRESULT display([out, retval] double *pval); [propput, id(1), helpstring("wyświetlacz")] HRESULT display([in] double newval); ; Interfejs wychodzący [ object, uuid(a1284ed8-990e a-26da646245c8), helpstring("kalkulator - Interfejs wychodzący"), pointer_default(unique) ] interface IOutgoingCalc : IUnknown HRESULT changed([in] double val); HRESULT errorb([in] BSTR msg); ; Biblioteka typów + clsid składników [ uuid(af b a d21340d47), version(1.0), helpstring("kalkulator (prosty), wersja z punktami połączenia, biblioteka typów") ] library CalcAggrTypeLib importlib("stdole32.tlb") ; [ uuid(0d49456b-4a4b-423c b7299a), helpstring("kalkulator (prosty), wersja z punktami połączenia") ] coclass CalcSimple [default] interface ICalc; [source] interface IOutgoingCalc; ; ; Serwer prostego kalkulatora - wersja z punktami połączenia Copyright (c) 2001 by Jarosław Francik #include "stdafx.h" #include "calccp.h" #include "calccp_i.c" #include <iostream.h> #include "registry.h" #include <ocidl.h> plik automatycznie utworzony przez MIDL plik automatycznie utworzony przez MIDL pomocnicze narzędzia do rejestru systemowego... IConnectionPoint, IConnectionPointContainer Zmienne globalne static HMODULE g_hmodule = NULL ; static long g_ccomponents = 0 ; static long g_cserverlocks = 0 ; uchwyt modułu DLL Licznik aktywnych składników Licznik dla LockServer Dane do rejestru systemowego const char g_szprogid[] = "Calc.SimpleCP.2"; const char g_szfriendlyname[] = "Prosty kalkulator - wersja z CP ; const char g_szverindprogid[] = "Calc.SimpleCP"; Wskaźnik do interfejsu ujścia IOutgoingCalc *g_poutgoingcalc; Interfejs INondelegatingUnknown jak w pierwszym przykładzie Klasa składnika class CCalc : public ICalc, INondelegatingUnknown, IConnectionPoint, IConnectionPointContainer public: Implementacja interfejsu IUnknown virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall AddRef(); virtual ULONG _stdcall Release(); Implementacja interfejsu INondelegatingUnknown virtual HRESULT _stdcall NondelegatingQueryInterface(REFIID iid, void **ppv); virtual ULONG _stdcall NondelegatingAddRef(); virtual ULONG _stdcall NondelegatingRelease();
31 ; Implementacja interfejsu IConnectionPoint virtual HRESULT _stdcall GetConnectionInterface(IID RPC_FAR *piid); virtual HRESULT _stdcall GetConnectionPointContainer(IConnectionPointContainer RPC_FAR * RPC_FAR *ppcpc); virtual HRESULT _stdcall Advise(IUnknown RPC_FAR *punksink, DWORD RPC_FAR *pdwcookie); virtual HRESULT _stdcall Unadvise(DWORD dwcookie); virtual HRESULT _stdcall EnumConnections(IEnumConnections RPC_FAR * RPC_FAR *ppenum); Implementacja interfejsu IConnectionPointContainer virtual HRESULT _stdcall EnumConnectionPoints(IEnumConnectionPoints RPC_FAR * RPC_FAR *ppenum); virtual HRESULT _stdcall FindConnectionPoint(REFIID riid, IConnectionPoint RPC_FAR * RPC_FAR *ppcp); dalej jak w pierwszym przykładzie... Implementacja interfejsu Icalc jak w pierwszym przykładzie Implementacja interfejsu IUnknown jak w pierwszym przykładzie Implementacja interfejsu INondelegatingUnknown HRESULT _stdcall CCalc::NondelegatingQueryInterface(REFIID iid, void **ppv) if (iid == IID_IUnknown) *ppv = (INondelegatingUnknown*)this; else if (iid == IID_ICalc) *ppv = (ICalc*)this; else if (iid == IID_IConnectionPoint) *ppv = (IConnectionPoint*)this; else if (iid == IID_IConnectionPointContainer) *ppv = (IConnectionPointContainer*)this; else ppv = NULL; return E_NOINTERFACE; ((IUnknown*)(*ppv))->AddRef(); ULONG _stdcall CCalc::NondelegatingAddRef() standardowa implementacja ULONG _stdcall CCalc::NondelegatingRelease() standardowa implementacja Implementacja interfejsu IConnectionPoint HRESULT _stdcall CCalc::GetConnectionInterface(IID RPC_FAR *piid) return E_NOTIMPL; HRESULT _stdcall CCalc::GetConnectionPointContainer(IConnectionPointContainer RPC_FAR * RPC_FAR *ppcpc) return E_NOTIMPL; HRESULT _stdcall CCalc::Advise(IUnknown RPC_FAR *punksink, DWORD RPC_FAR *pdwcookie) Wartość cookie jest nieistotna przy jednym połączeniu *pdwcookie = 1; oto wskaźnik do interfejsu ujścia return punksink->queryinterface(iid_ioutgoingcalc, (void**)&g_poutgoingcalc); HRESULT _stdcall CCalc::Unadvise(DWORD dwcookie) g_poutgoingcalc->release(); g_poutgoingcalc = NULL; HRESULT _stdcall CCalc::EnumConnections(IEnumConnections RPC_FAR * RPC_FAR *ppenum) return E_NOTIMPL; Implementacja interfejsu IConnectionPointContainer HRESULT _stdcall CCalc::EnumConnectionPoints(IEnumConnectionPoints RPC_FAR * RPC_FAR *ppenum) return E_NOTIMPL; HRESULT _stdcall CCalc::FindConnectionPoint(REFIID riid, IConnectionPoint RPC_FAR * RPC_FAR *ppcp) if (riid == IID_IOutgoingCalc) return QueryInterface(IID_IConnectionPoint, (void**)ppcp); return E_NOINTERFACE; Class Factory I funkcje eksportowane standardowa implementacja fabryki klas (jak w pierwszym przykładzie)
32 Zawieranie i agregacja Zawieranie (Containment) Powtórne użycie (reuse) Dziedziczenie implementacji Przesłanianie tożsamości obiektów Zawieranie = Containment Agregacja = Aggregation ICalcScientific ICalc CalcScientific ICalc CalcSimple IUnknown IUnknown Agregacja (Aggregation) Punkty połączeń IUnknown SERWER ICalcScientific CalcScientific INondelegatingUnknown IUnknown IConnectionPoint ICalc CalcSimple KLIENT ujście (sink) IConnectionPoint Punkty połączeń interface IConnectionPoint : IUnknown Wymień dostępne punkty połączenia HRESULT GetConnectionInterface([out] IID RPC_FAR *piid); Podaj pojemnik punktów połączenia HRESULT GetConnectionPointContainer( [out] IConnectionPointContainer *ppcpc); Przyjmij wskaźnik do mojego ujścia HRESULT Advise( [in] IUnknown *punksink, [out] DWORD *pdwcookie); Nie wywołuj już mojego ujścia HRESULT Unadvise([in] DWORD dwcookie); Wymień połączenia HRESULT EnumConnections([out] IEnumConnections *ppenum); ; Punkty połączeń IConnectionPointContainer : public IUnknown Wymień dostępne punkty połączenia HRESULT EnumConnectionPoints([out] IEnumConnectionPoints *ppenum); ; Znajdź wskazany punkt połączenia HRESULT FindConnectionPoint([in] REFIID riid, [out] IConnectionPoint *ppcp); 1
33 Wielowątkowość w Windows Wielowątkowość w COM Marek Mittmann Grudzień 2002 Wątek (ang.( thread) ) to sekwencja wykonywana przez proces, każdy proces ma do wykonania jeden lub więcej wątków Tam, gdzie wątki korzystają ze współdzielonych danych, konieczna jest synchronizacja Do synchronizacji wykorzystujemy: zdarzenia, sekcje krytyczne, semafory i wzajemne wykluczanie obiektów (mutex) Przedziały Typy przedziałów Przedział (ang.( apartment) ) to kolekcja obiektów wraz z ich kontekstami Każdy obiekt należy do dokładnie jednego przedziału Przedziały określają zestaw zasad dla danej grupy obiektów, wymaganych do poprawnej pracy w środowisku wielowątkowym Jednowątkowe (STA) Mają po jednym wątku, proces może mieć wiele STA Synchronizowane przy pomocy kolejki komunikatów Wielowątkowe (MTA) Mają wiele wątków, proces może mieć tylko jeden MTA Brak synchronizacji Neutralne (NA) Proces może mieć jeden NA Proces Proces Przedziały a wątki STA STA STA MTA MTA Przedziały jednowątkowe Każdy STA ma tylko jeden wątek, w pojedynczym procesie może istnieć wiele STA Wszystkie komponenty nie obsługujące modelu wielowątkowego działają w głównym STA Wątek deklaruje obsługę modelu STA przez wywołanie CoInitializeEx z drugim parametrm równym COINIT_APARTMENTTHREAD
34 Przedziały jednowątkowe c.d. Przedziały wielowątkowe Wywołania metod w STA są automatycznie synchronizowane i dysponowane przy użyciu kolejek komunikatów Każdy komponent zewnątrzprocesowy, który obsługuje model STA, musi zawierać pętlę komunikatów Komponent wykonywalny może blokować wywołania metod w STA za pomocą filtrów komunikatów (interfejs IMessageFilter) W pojedynczym procesie może istnieć tylko jeden MTA, który z kolei może zawierać wiele wątków Wywołania metod w MTA nie są automatycznie synchronizowane Wątek deklaruje obsługę modelu STA przez wywołanie CoInitializeEx z drugim parametrm = COINIT_MULTITHREAD Przedziały neutralne W pojedynczym procesie może istnieć tylko jeden NA Nie ma stałych wątków, obiekty z NA są zawsze wykonywane przez wątek wywołujący Brak wbudowanej synchronizacji Przedziały neutralne są obsługiwane tylko przez komponenty wewnątrzprocesowe Przedziały a komponenty wewnątrzprocesowe Komponenty wewnątrzprocesowe nie wywołują CoInitializeEx,, obsługiwany model wielowątkowości deklarują za pomocą wpisu w rejestrze (klucz CLSID\InprocServer32 InprocServer32). Dopuszczalne wartości to: Apartment STA Neutral NA Free MTA Both obsługuje STA, NA i MTA brak komponent jednowątkowy Przypisywanie do przedziałów Współdziałanie przedziałów Typ przedziału twórcy Model wielowątkowości komponentu Nieokreślony Apartment Free Both Neutral Proces Główny STA główny STA główny STA MTA główny STA NA Obiekt Pośrednik Obiekt Lekki pośrednik STA główny STA STA wywołującego MTA STA wywołującego NA STA MTA MTA główny STA macierzysty STA MTA MTA NA Obiekt Lekki pośrednik Obiekt NA (wątek STA) główny STA STA wywołującego MTA NA NA STA NA NA (wątek MTA) główny STA macierzysty STA MTA NA NA
35 Współdziałanie przedziałów Typ przedziału twórcy Główny STA Model wielowątkowości komponentu Nieokreślony Apartment Free Both Neutral bezpośredni dostęp bezpośredni dostęp dostęp przez pośrednika bezpośred ni dostęp dostęp przez lekkiego pośrednika Przekazywanie interfejsów pomiędzy przedziałami STA1 IMyInterface* pmyinterface; CoCreateInstance(CLSID_MyCOMClass, NULL, CLSCTX_LOCAL_SERVER, IID_IMyInterface, (void**)&pmyinterface); void MyThread(IStream* pscream) Utwórz STA2 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); STA MTA NA (wątek STA) dostęp przez pośrednika dostęp przez pośrednika dostęp przez pośrednika bezpośredni dostęp dostęp przez pośrednika dostęp przez lekkiego pośrednika dostęp przez pośrednika bezpośredni dostęp dostęp przez pośrednika bezpośred ni dostęp bezpośred ni dostęp bezpośred ni dostęp dostęp przez lekkiego pośrednika dostęp przez lekkiego pośrednika bezpośredni dostęp IStream* pstream; CoMarshalInterThreadInterfaceInStream( IID_IMyInterface, pmyinterface, &pstream); DWORD threadid; CreateThread(0, 0, (LPTHREAD_START_ROUTINE) MyThread, (void*)pstream, 0, &threadid); IMyInterface* pmyinterface; CoGetInterfaceAndReleaseStream( pstream, IID_IMyInterface, (void**) &pmyinterface);... pmyinterface->release(); NA (wątek MTA) dostęp przez pośrednika dostęp przez pośrednika dostęp przez lekkiego pośrednika bezpośred ni dostęp bezpośredni dostęp... pmyinterface->release(); CoUninitialize(); Podsumowanie Podsumowanie c.d. Każdy STA może mieć tylko jeden wątek Komponenty wykorzystujace wątki STA muszą pobierać i dysponować komunikaty okna Przekazywanie wskaźników interfejsów pomiedzy wątkami z różnych przedziałów powinno odbywać się za pośrednictwem szeregowania Każdy wątek korzystający z COM powinien wywołać CoInitializeEx Każdy obiekt jest związany tylko z jednym, ale przedział może zawierać wiele obiektów Główny STA jest tworzony przez wątek, który pierwszy wywoła CoInitializeEx z COINIT_APARTMENTTHREAD Proces może mieć wiele STA, ale tylko jeden MTA i jeden NA Dla obiektów wewnątrzprocesowych należy zdefiniować w rejestrze ThreadingModel
36 Kategorie komponentów Programowanie składnikowe w modelu COM Jarosław Francik maj 2002 Kategorie komponentów Cel: usprawnienie wyszukiwania klas komponentów Pozycje rejestru systemowego: W HKEY_CLASSES_ROOT: Component Categories zestawienie kategorii (CATID) dla poszczególnych klas: Implemented Categories Required categories Kategorie komponentów Domyślne klasy można je tworzyć nie znając CLSID, a tylko CATID! Emulacja klas: klucz TreatAs funkcja CoTreatAsClass Component Categories Manager interface ICatRegister interface ICatInformation 1
37 Programowanie składnikowe w modelu COM Jarosław Francik maj 2002 Trwałość (Persistency) PODSTAWOWE INTERFEJSY TRWAŁOŚCI: IPersist IPersistStream IPersistStreamInit IPersistStorage IPersistFile IPersistPropertyBag PODSTAWOWY INTERFEJS IPERSIST interface IPersist : IUnknown HRESULT GetClassID([out] CLSID *pclsid); ; OBSŁUGA STRUMIENI interface IPersistStreamInit : IPersist HRESULT IsDirty(); HRESULT Load([in, unique] IStream *pstr); HRESULT Save([in, unique] IStream *pstr, [in] BOOL fcleardirty); HRESULT GetSizeMax([out] ULARGE_INTEGER *psize); HRESULT InitNew(); ; ZAPIS TRWAŁEGO OBIEKTU pobieramy clsid klasy CLSID clsid; hr = ppersistent->getclassid(&clsid); zapisujemy clsid (standardowa funkcja) hr = WriteClassStm(pStream, clsid) zapisujemy dane obiektu hr = ppersistent->save(pstream, TRUE); interface ISequentialStream : IUnknown HRESULT Read([out, size_is(cb), length_is(*pread)] void *p, [in] ULONG cb, [out] ULONG *pread); HRESULT Write( [out, size_is(cb)] void *p, [in] ULONG cb, [out] ULONG *pwritten); ; ODCZYT TRWAŁEGO OBIEKTU pobieramy CLSID CLSID clsid; hr = ReadClassStm(pStream, &clsid); tworzymy nowe wystąpienie obiektu IPersistStream *ppersistent; hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IPersistStream, (void**)ppersistent); PRACA Z ZESTAWAMI WŁAŚCIWOŚCI Wciągamy dane obiektu ppersistent->load(pstream); SPRYTNE FUNKCJE STANDARDOWE hr = OleSaveToStream(pPersistent, pstream); hr = OleLoadFromStream(pPersistent, pstream); interface IPersistPropertyBag : IPersist HRESULT IsDirty(); HRESULT Load([in] IPropertyBag *ppropbag, [in] IErrorLog *perrorlog); HRESULT Save([in] IPropertyBag *ppropbag, [in] BOOL fcleardirty, [in[ BOOL bsaveallprops); HRESULT GetSizeMax([out] ULARGE_INTEGER *psize); HRESULT InitNew(); ; interface IPropertyBag : IUnknown HRESULT Read([in] LPCOLESTR ppropname, [in, out] VARIANT *pvar, [in] IErrorLog *perrorlog); ; HRESULT Write([in] LPCOLESTR ppropname, [in] VARIANT *pvar); opracowanie: Jarosław Francik
//////////////////////////////////////////////////////////// // Kalkulator (prosty) - wersja agregowalna import "unknwn.idl";
/ Kalkulator (prosty) - wersja agregowalna import "unknwn.idl"; Interface ICalc uuid(892753ed-d14e-4d2f-b812-041e0c01f5f3), helpstring("kalkulator (prosty), wersja agregowalna"), interface ICalc : IUnknown
Bardziej szczegółowo// LISTING #2 DRUGIE PODEJŚCIE
OD KLASY C++ DO SERWERA COM: PROGRAMY PRZYKŁADOWE DO WYKŁADU PROGRAMOWANIE SKŁADNIKOWE W MODELU COM OPRACOWANIE: JAROSŁAW FRANCIK // LISTING #1 PIERWSZE PODEJŚCIE // LISTING #2 DRUGIE PODEJŚCIE #include
Bardziej szczegółowoObiekty w plikach wykonywalnych, marshaling
Obiekty w plikach wykonywalnych, marshaling Komponent w pliku exe Odczyt IClassFactory komponencie umieszczonym w pliku dll ładowanym w przestrzeń adresową klienta następuje poprzez wywołanie eksportowanej
Bardziej szczegółowoTechnologie COM i ActiveX COM - Component Object Model
Technologie COM i COM - Component Object Model Jarosław Francik COM - Common Object Model Program - monolit Program składnikowy Składnik A Składnik B Składnik C Składnik D Składnik E Architektura składnikowa
Bardziej szczegółowoDroga do DCOM DCOM (1996) Windows clipboard (1987) OLE 1 DDE (1992) OLE 2 (1993) COM (1995) Distributed computing (1980s)
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
Bardziej szczegółowoAgregacja. Wykorzystanie innego komponentu bez użycia agregacji. Simple calculator. Extended calculator
Agregacja Agregacja Agregacja jest to wykorzystywanie przez komponent nadrzędny innego komponentu w taki sposób, że udostępnia jego interfejs jako własny. Aby komponent mógł być użyty jako agregat, metody
Bardziej szczegółowoMicrosoft Interface Definition Language
Microsoft Interface Definition Language IDL IDL (Interface Definition Language) kompilowany jest przez MIDL.exe: Tworzy pliki nagłówkowe klas abstrakcyjnych dla zdefiniowanych w pliku *.idl interfejsów
Bardziej szczegółowoHenryk Budzisz. materiały przygotowane w ramach projektu ZPORR nr POKL.04.01.01-00-449/08-00
Henryk Budzisz ZPORR nr POKL.04.01.01-00-449/08-00 Koszalin 2009 Technologia COM Wprowadzenie COM Interfejsy Technologia COM w Visual C++ Globally Unique Identifiers (GUIDs) Biblioteka COM Tworzenie obiektu
Bardziej szczegółowoZdarzenia (events, connection points)
(events, connection points) Serwer komunikuje się z klientem za pomocą zgłoszenia zdarzenia. Pozwala to na asynchroniczną pracę serwera, który zgłasza zaistnienie określonego stanu za pomocą serii zdarzeń.
Bardziej szczegółowo1.1. Kontrolki ActiveX. Kontrolki ActiveX. Technologia ActiveX. Technologia ActiveX. Technologia ActiveX. Technologia ActiveX.
1 Katedra Optoelektroniki i Systemów Elektronicznych 2 Kontrolki Oprogramowanie Systemów Elektronicznych Zagadnienia: Temat wykładu Kontrolki 1. Technologia 2. 3. Rejestrowanie kontrolek 4. Projektowanie
Bardziej szczegółowo4 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.
Zgłaszanie błędów HRESULT Każda metoda interfejsu COM zwraca informację o błędzie w postaci typu HRESULT (long int). Struktura reprezentacji bitowej HRESULT podzielona jest na 4 sekcje: 1 bit błędu 4 bity
Bardziej szczegółowoComponent Object Model laboratorium 2013 K.M. Ocetkiewicz, T. Goluch
Component Model laboratorium 2013 K.M. Ocetkiewicz, T. Goluch 1. Wstęp COM jest standardem tworzenia komponentów w systemie Windows. Standard ten jest binarny dotyczy skompilowanego kodu (a nie języka
Bardziej szczegółowoIFiZR Laboratorium 5 Info
IFiZR Laboratorium 5 Info File->New->Project->Windows Application (DevC++) Kurs WinAPI: http://cpp0x.pl/kursy/kurs-winapi-c++/167 #include #include #include #include
Bardziej szczegółowoInterfejs IUnknown. Każdy obiekt COM musi implementować interfejs IUnknown, który zawiera trzy metody:
Plan wykładu 1. Technologia COM (DCOM) wprowadzenie, korzystanie z obiektu COM, program klienta, schemat programu serwera. 2. Porównanie DCOM, CORBA i RMI. Wprowadzenie Opracowana przez Microsoft technologia
Bardziej szczegółowoProgramowanie obiektowe
Programowanie obiektowe Wykład 2 Marcin Młotkowski 4 marca 2015 Plan wykładu 1 2 3 4 5 Marcin Młotkowski Programowanie obiektowe 2 / 47 Krótki opis C Obiektowy, z kontrolą typów; automatyczne odśmiecanie;
Bardziej szczegółowo1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość
1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość 2. Poprawna definicja wskażnika b to: a) float *a, **b = &a; b) float
Bardziej szczegółowoProgramowanie 2. Język C++. Wykład 3.
3.1 Programowanie zorientowane obiektowo... 1 3.2 Unie... 2 3.3 Struktury... 3 3.4 Klasy... 4 3.5 Elementy klasy... 5 3.6 Dostęp do elementów klasy... 7 3.7 Wskaźnik this... 10 3.1 Programowanie zorientowane
Bardziej szczegółowoWykład 8: klasy cz. 4
Programowanie obiektowe Wykład 8: klasy cz. 4 Dynamiczne tworzenie obiektów klas Składniki statyczne klas Konstruktor i destruktory c.d. 1 dr Artur Bartoszewski - Programowanie obiektowe, sem. 1I- WYKŁAD
Bardziej szczegółowoTEMAT : KLASY DZIEDZICZENIE
TEMAT : KLASY DZIEDZICZENIE Wprowadzenie do dziedziczenia w języku C++ Język C++ możliwa tworzenie nowej klasy (nazywanej klasą pochodną) w oparciu o pewną wcześniej zdefiniowaną klasę (nazywaną klasą
Bardziej szczegółowoProgramowanie składnikowe. Programowanie składnikowe w modelu COM. COM - Component Object Model. wprowadzenie. Programowanie składnikowe
Programowanie składnikowe w modelu COM wprowadzenie Jarosław Francik COM - Component Object Model Programowanie składnikowe Programowanie składnikowe 1 Program - monolit 1 Program składnikowy Składnik
Bardziej szczegółowoPodstawy wykorzystania bibliotek DLL w skryptach oprogramowania InTouch
INFORMATOR TECHNICZNY WONDERWARE Informator Techniczny nr 60 04-12-2002 Podstawy wykorzystania bibliotek DLL w skryptach oprogramowania InTouch Wstęp PoniŜsza dokumentacja oparta na przykładach stworzonych
Bardziej szczegółowoJęzyk ludzki kod maszynowy
Język ludzki kod maszynowy poziom wysoki Język ludzki (mowa) Język programowania wysokiego poziomu Jeśli liczba punktów jest większa niż 50, test zostaje zaliczony; w przeciwnym razie testu nie zalicza
Bardziej szczegółowoProgramowanie obiektowe
Wykład 2 28 lutego 2019 Plan wykładu 1 2 3 4 5 Plan wykładu 1 2 3 4 5 Krótki opis C Obiektowy, z kontrolą typów; automatyczne odśmiecanie; standardy ISO i ECMA; podobny składniowo do C++; Język C Krótka
Bardziej szczegółowoComponent Object Model laboratorium 2017 K.M. Ocetkiewicz, T. Goluch
Component Model laboratorium 2017 K.M. Ocetkiewicz, T. Goluch 1. Wstęp COM jest standardem tworzenia komponentów w systemie Windows. Standard ten jest binarny dotyczy skompilowanego kodu (a nie języka
Bardziej szczegółowoInformacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;
Klasy w C++ są bardzo ważnym narzędziem w rękach programisty. Klasy są fundamentem programowania obiektowego. Z pomocą klas będziesz mógł tworzyć lepszy kod, a co najważniejsze będzie on bardzo dobrze
Bardziej szczegółowoJAVA W SUPER EXPRESOWEJ PIGUŁCE
JAVA W SUPER EXPRESOWEJ PIGUŁCE Obiekt Obiekty programowe to zbiór własności i zachowań (zmiennych i metod). Podobnie jak w świecie rzeczywistym obiekty posiadają swój stan i zachowanie. Komunikat Wszystkie
Bardziej szczegółowo1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.
1. Pierwszy program // mój pierwszy program w C++ #include using namespace std; cout
Bardziej szczegółowoKurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016
Wykład 1 3 marca 2016 Słowa kluczowe języka Java abstract, break, case, catch, class, const, continue, default, do, else, enum, extends, final, finally, for, goto, if, implements, import, instanceof, interface,
Bardziej szczegółowoZaawansowane programowanie w języku C++ Programowanie obiektowe
Zaawansowane programowanie w języku C++ Programowanie obiektowe Prezentacja jest współfinansowana przez Unię Europejską w ramach Europejskiego Funduszu Społecznego w projekcie pt. Innowacyjna dydaktyka
Bardziej szczegółowoProgramowanie obiektowe
Programowanie obiektowe Wykład 2: Wstęp do języka Java 3/4/2013 S.Deniziak: Programowanie obiektowe - Java 1 Cechy języka Java Wszystko jest obiektem Nie ma zmiennych globalnych Nie ma funkcji globalnych
Bardziej szczegółowoIMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi
IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi EGZAMIN PIERWSZY (25 CZERWCA 2013) JĘZYK C++ poprawiam ocenę pozytywną z egzaminu 0 (zakreśl poniżej x) 1. Wśród poniższych wskaż poprawną formę definicji
Bardziej szczegółowoTworzenie projektu asemblerowego dla środowiska Visual Studio 2008.
Dwiczenie 5. TEMAT: CEL: Tworzenie projektu asemblerowego dla środowiska Visual Studio 2008. Celem dwiczenia jest poznanie możliwości VS 2008 w zakresie tworzenia i uruchamiania aplikacji z kodem mieszanym
Bardziej szczegółowoMETODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02
METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE Wykład 02 NAJPROSTSZY PROGRAM /* (Prawie) najprostszy przykład programu w C */ /*==================*/ /* Między tymi znaczkami można pisać, co się
Bardziej szczegółowo1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?
1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie? a) konstruktor b) referencje c) destruktor d) typy 2. Które z poniższych wyrażeń są poprawne dla klasy o nazwie
Bardziej szczegółowoTechniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.
Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni Wykład 3 Karol Tarnowski karol.tarnowski@pwr.edu.pl A-1 p. 411B Plan prezentacji Abstrakcja funkcyjna Struktury Klasy hermetyzacja
Bardziej szczegółowoTechniki programowania INP001002Wl rok akademicki 2017/18 semestr letni. Wykład 4. Karol Tarnowski A-1 p.
Techniki programowania INP001002Wl rok akademicki 2017/18 semestr letni Wykład 4 Karol Tarnowski karol.tarnowski@pwr.edu.pl A-1 p. 411B Plan prezentacji Dziedziczenie Przestrzenie nazw Na podstawie: A.
Bardziej szczegółowoKlasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np
Klasy Klasa jest nowym typem danych zdefiniowanym przez użytkownika Wartości takiego typu nazywamy obiektami Najprostsza klasa jest po prostu strukturą, np struct Zespolona { Klasy jako struktury z operacjami
Bardziej szczegółowoPodstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1
Podstawy programowania. Wykład Funkcje Krzysztof Banaś Podstawy programowania 1 Programowanie proceduralne Pojęcie procedury (funkcji) programowanie proceduralne realizacja określonego zadania specyfikacja
Bardziej szczegółowoProjektowanie obiektowe. Roman Simiński Wzorce projektowe Wybrane wzorce strukturalne
Projektowanie obiektowe Roman Simiński roman.siminski@us.edu.pl www.siminskionline.pl Wzorce projektowe Wybrane wzorce strukturalne Fasada Facade Pattern 2 Wzorzec Fasada Facade Pattern koncepcja 3 Wzorzec
Bardziej szczegółowoKurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016
Wykład 2 17 marca 2016 Dziedziczenie Klasy bazowe i potomne Dziedziczenie jest łatwym sposobem rozwijania oprogramowania. Majac klasę bazowa możemy ja uszczegółowić (dodać nowe pola i metody) nie przepisujac
Bardziej szczegółowoW2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :
Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy : class nazwa_klasy prywatne dane i funkcje public: publiczne dane i funkcje lista_obiektów;
Bardziej szczegółowoPodstawy programowania skrót z wykładów:
Podstawy programowania skrót z wykładów: // komentarz jednowierszowy. /* */ komentarz wielowierszowy. # include dyrektywa preprocesora, załączająca biblioteki (pliki nagłówkowe). using namespace
Bardziej szczegółowo1 Atrybuty i metody klasowe
1 Atrybuty i metody klasowe Składowe klasowe (statyczne) Każdy obiekt klasy posiada własny zestaw atrybutów. Metody używają atrybutów odpowiedniego obiektu. Czasem potrzeba atrybutów wspólnych dla wszystkich
Bardziej szczegółowoWykład 5 Okna MDI i SDI, dziedziczenie
Wykład 5 Okna MDI i SDI, dziedziczenie Autor: Zofia Kruczkiewicz Zagadnienia 1. Aplikacja wielookienkowa. Zakładanie projektu typu CLR Windows Forms 1.1. Aplikacja typu MDI 1.2. Aplikacja typu SDI 2. Dziedziczenie
Bardziej szczegółowoPola i metody statyczne. Klasy zawierające pola i metody statyczne
Instrukcja laboratoryjna nr 1 Programowanie w języku C 2 (C++ poziom zaawansowany) Pola i metody statyczne. Klasy zawierające pola i metody statyczne dr inż. Kaczmarek Tomasz mgr inż. Lasota Maciej dr
Bardziej szczegółowoProgramowanie w Internecie. Java
Programowanie w Internecie Java Autor: dr inż. Zofia Kruczkiewicz Literatura: L. Lemay, R. Cadenhead P. Naughton Krzysztof Barteczko Boone Barry Java 2 dla każdego Podręcznik Języka Programowania Java
Bardziej szczegółowoKlasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C
#import "Fraction.h" #import @implementation Fraction -(Fraction*) initwithnumerator: (int) n denominator: (int) d { self = [super init]; } if ( self ) { [self setnumerator: n anddenominator:
Bardziej szczegółowoCzęść 4 życie programu
1. Struktura programu c++ Ogólna struktura programu w C++ składa się z kilku części: część 1 część 2 część 3 część 4 #include int main(int argc, char *argv[]) /* instrukcje funkcji main */ Część
Bardziej szczegółowoStructured storage, Monikers, Running Object Table
Structured storage, Monikers, Running Object Table Structured storage Structured storage jest sposobem zorganizowanego zapisywania danych w pliku. Struktura danych ma postać drzewa i obiektów danych podobną
Bardziej szczegółowoInstrukcja laboratoryjna cz.3
Języki programowania na platformie.net cz.2 2015/16 Instrukcja laboratoryjna cz.3 Język C++/CLI Prowadzący: Tomasz Goluch Wersja: 2.0 I. Utworzenie projektu C++/CLI z interfejsem graficznym WPF 1 Cel:
Bardziej szczegółowoC++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU
Inicjalizacja agregatowa zmiennej tablicowej int a[5] = 1,2,3,4,5 INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU Struktury są również agregatami, dlatego: struct X double f; char c; X x1 = 1, 2.2, 'c' Ale
Bardziej szczegółowoProgramowanie obiektowe
Programowanie obiektowe IV. Interfejsy i klasy wewnętrzne Małgorzata Prolejko OBI JA16Z03 Plan Właściwości interfejsów. Interfejsy a klasy abstrakcyjne. Klonowanie obiektów. Klasy wewnętrzne. Dostęp do
Bardziej szczegółowoSzablony klas, zastosowanie szablonów w programach
Szablony klas, zastosowanie szablonów w programach 1. Szablony klas i funkcji 2. Szablon klasy obsługującej uniwersalną tablicę wskaźników 3. Zastosowanie metody zwracającej przez return referencję do
Bardziej szczegółowoWykład 2 Wybrane konstrukcje obiektowych języków programowania (1)
MAS dr. Inż. Mariusz Trzaska Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1) Zagadnienia o Podstawy o Kontrolowanie sterowania o Klasy o Interfejsy o Obsługa błędów o Pojemniki o System
Bardziej szczegółowoDzisiejszy wykład. Wzorce projektowe. Visitor Client-Server Factory Singleton
Dzisiejszy wykład Wzorce projektowe Visitor Client-Server Factory Singleton 1 Wzorzec projektowy Wzorzec nazwana generalizacja opisująca elementy i relacje rozwiązania powszechnie występującego problemu
Bardziej szczegółowoAplikacje RMI https://docs.oracle.com/javase/tutorial/rmi/overview.html
Aplikacje RMI https://docs.oracle.com/javase/tutorial/rmi/overview.html Dr inż. Zofia Kruczkiewicz wykład 4 Programowanie aplikacji internetowych, wykład 4 1 1. Zadania aplikacji rozproszonych obiektów
Bardziej szczegółowoFunkcje przeciążone, konstruktory kopiujące, argumenty domyślne
Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne Przeciążenie funkcji polega na użyciu funkcji z tą samą nazwą, które mają różne listy argumentów(różne typy, różna ilość lub to i inne).
Bardziej szczegółowoLaboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:
Zakres laboratorium: definiowanie struktur terminologia obiektowa definiowanie klas funkcje składowe klas programy złożone z wielu plików zadania laboratoryjne Laboratorium nr 12 Temat: Struktury, klasy.
Bardziej szczegółowoWykład 4: Klasy i Metody
Wykład 4: Klasy i Metody Klasa Podstawa języka. Każde pojęcie które chcemy opisać w języku musi być zawarte w definicji klasy. Klasa definiuje nowy typ danych, których wartościami są obiekty: klasa to
Bardziej szczegółowoUML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.
UML a kod w C++ i Javie Projektowanie oprogramowania Dokumentowanie oprogramowania Diagramy przypadków użycia Przewoznik Zarzadzanie pojazdami Optymalizacja Uzytkownik Wydawanie opinii Zarzadzanie uzytkownikami
Bardziej szczegółowoProjektowanie i programowanie aplikacji biznesowych. Wykład 2
Projektowanie i programowanie aplikacji biznesowych Wykład 2 Kontrolki w Windows API Aby korzystać z kontrolek należy dołączyć plik nagłówkowy o nazwie commctrl.h oraz bibliotekę o nazwie libcomctl32.a.
Bardziej szczegółowopublic: // interfejs private: // implementacja // składowe klasy protected: // póki nie będziemy dziedziczyć, // to pole nas nie interesuje
Zbudujemy klasę Definicję klasy zapiszmy w pliku tstring.h #ifndef TSTRING_H #define TSTRING_H #include // w pliku nagłówkowym NIE // otwieramy przestrzeni std // interfejs private: // implementacja
Bardziej szczegółowoPodstawy Programowania Obiektowego
Podstawy Programowania Obiektowego Wprowadzenie do programowania obiektowego. Pojęcie struktury i klasy. Spotkanie 03 Dr inż. Dariusz JĘDRZEJCZYK Tematyka wykładu Idea programowania obiektowego Definicja
Bardziej szczegółowoZarządzanie pamięcią
System COM, aby mógł śledzić zmiany w alokacji pamięcią podczas wywołań, obsługuje pamięć niezależnie od Runtime Library (RT) C++ i korzysta ze sterty bieżącego procesu. Do obsługi pamięci COM, zdefiniowany
Bardziej szczegółowoLaboratorium 03: Podstawowe konstrukcje w języku Java [2h]
1. Typy. Java jest językiem programowania z silnym systemem kontroli typów. To oznacza, że każda zmienna, atrybut czy parametr ma zadeklarowany typ. Kompilator wylicza typy wszystkich wyrażeń w programie
Bardziej szczegółowoStrona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta 16.09.2006. Strona 1 z 26. Powrót. Full Screen. Zamknij.
Programowanie Sobera Jolanta 16.09.2006 Strona 1 z 26 1 Wprowadzenie do programowania 4 2 Pierwsza aplikacja 5 3 Typy danych 6 4 Operatory 9 Strona 2 z 26 5 Instrukcje sterujące 12 6 Podprogramy 15 7 Tablice
Bardziej szczegółowoMateriały do zajęć VII
Spis treści I. Klasy Materiały do zajęć VII II. III. Konstruktor Właściwości i indeksatory Klasy Programowanie obiektowe wiadomości wstępne Paradygmat programowania obiektowego Abstrakcja Hermetyzacja
Bardziej szczegółowoJava: kilka brakujących szczegółów i uniwersalna nadklasa Object
Java: kilka brakujących szczegółów i uniwersalna nadklasa Object Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak PLAN WYKŁADU Konstrukcja obiektów Niszczenie obiektów i zwalnianie zasobów
Bardziej szczegółowoProgramowanie obiektowe
Programowanie obiektowe Laboratorium 1. Wstęp do programowania w języku Java. Narzędzia 1. Aby móc tworzyć programy w języku Java, potrzebny jest zestaw narzędzi Java Development Kit, który można ściągnąć
Bardziej szczegółowoDokumentacja do API Javy.
Dokumentacja do API Javy http://java.sun.com/j2se/1.5.0/docs/api/ Klasy i obiekty Klasa jest to struktura zawierająca dane (pola), oraz funkcje operujące na tych danych (metody). Klasa jest rodzajem szablonu
Bardziej szczegółowoPraca w środowisku Visual Studio 2008, Visual C
Praca w środowisku Visual Studio 2008, Visual C++ 2008 mgr inż. Tomasz Jaworski tjaworski@kis.p.lodz.pl http://tjaworski.kis.p.lodz.pl/ Tworzenie aplikacji konsolowych 2 3 Tworzenie nowego projektu aplikacji
Bardziej szczegółowoObszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),
Tworzenie obiektów Dostęp do obiektów jest realizowany przez referencje. Obiekty w języku Java są tworzone poprzez użycie słowa kluczowego new. String lan = new String( Lancuch ); Obszary pamięci w których
Bardziej szczegółowoProgramowanie obiektowe w C++ Wykład 12
Programowanie obiektowe w C++ Wykład 12 dr Lidia Stępień Akademia im. Jana Długosza w Częstochowie L. Stępień (AJD) 1 / 22 Zakresowe pętle for double tab[5] {1.12,2.23,3.33,4.12,5.22 for(double x: tab)
Bardziej szczegółowoWykład 5: Klasy cz. 3
Programowanie obiektowe Wykład 5: cz. 3 1 dr Artur Bartoszewski - Programowanie obiektowe, sem. 1I- WYKŁAD - podstawy Konstruktor i destruktor (część I) 2 Konstruktor i destruktor KONSTRUKTOR Dla przykładu
Bardziej szczegółowoPROE wykład 4 pozostałe operatory, forward declaration, dziedziczenie. dr inż. Jacek Naruniec
PROE wykład 4 pozostałe operatory, forward declaration, dziedziczenie dr inż. Jacek Naruniec Kolokwium wykładowe Pierwsze kolokwium 6 kwietnia Drugie kolokwium 1 czerwca Kolokwium poprawkowe 8 czerwca
Bardziej szczegółowoProgramowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27
Programowanie w C++ Wykład 14 Katarzyna Grzelak 3 czerwca 2019 K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27 Na ostatnim wykładzie: Konstruktor standardowy (domyślny) to taki, który nie ma żadnych argumentów
Bardziej szczegółowoWprowadzenie do programowanie obiektowego w języku C++
Wprowadzenie do programowanie obiektowego w języku C++ Część czwarta Autor Roman Simiński Kontakt roman.siminski@us.edu.pl www.us.edu.pl/~siminski Niniejsze opracowanie zawiera skrót treści wykładu, lektura
Bardziej szczegółowoWstęp do Programowania 2
Wstęp do Programowania 2 dr Bożena Woźna-Szcześniak bwozna@gmail.com Akademia im. Jana Długosza Wykład 5 W programowaniu obiektowym programista koncentruje się na obiektach. Zadaje sobie pytania typu:
Bardziej szczegółowoSingleton. Cel: Przykład: Zastosowanie: Zapewnienie, że klasa ma tylko jedną instancję i dostarczenie globalnego dostępu do niej.
1/8 Singleton Cel: Zapewnienie, że klasa ma tylko jedną instancję i dostarczenie globalnego dostępu do niej. Przykład: Niekiedy ważne jest, aby tworzyć tylko jedną instancję jakiejś klasy. Globalne zmienne
Bardziej szczegółowoSzablony funkcji i szablony klas
Bogdan Kreczmer bogdan.kreczmer@pwr.wroc.pl Zakład Podstaw Cybernetyki i Robotyki Instytut Informatyki, Automatyki i Robotyki Politechnika Wrocławska Kurs: Copyright c 2011 Bogdan Kreczmer Niniejszy dokument
Bardziej szczegółowoLaboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.
Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych. 1. Przygotowanie środowiska programistycznego. Zajęcia będą
Bardziej szczegółowoSwift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)
Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.) przeznaczony do programowania zarówno pod ios jak i Mac OS X bazuje na logice Objective-C bez kompatybilności
Bardziej szczegółowoProgramowanie w C++ Wykład 12. Katarzyna Grzelak. 28 maja K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27
Programowanie w C++ Wykład 12 Katarzyna Grzelak 28 maja 2018 K.Grzelak (Wykład 12) Programowanie w C++ 1 / 27 Klasy cd K.Grzelak (Wykład 12) Programowanie w C++ 2 / 27 Klasy - powtórzenie Klasy typy definiowane
Bardziej szczegółowoI - Microsoft Visual Studio C++
I - Microsoft Visual Studio C++ 1. Nowy projekt z Menu wybieramy File -> New -> Projekt -> Win32 Console Application w okienku Name: podajemy nazwę projektu w polu Location: wybieramy miejsce zapisu i
Bardziej szczegółowoProgramowanie obiektowe
Programowanie obiektowe Literatura: Autor: dr inŝ. Zofia Kruczkiewicz Java P. L. Krzysztof Lemay, Naughton Barteczko R. Cadenhead JAVA, Java Podręcznik 2 wykłady dla kaŝdego Języka i ćwiczenia Programowania
Bardziej szczegółowoĆwiczenie 7 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania. Zofia Kruczkiewicz
Ćwiczenie 7 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania Zofia Kruczkiewicz Zakres Funkcje przetwarzające teksty (biblioteka ) - tworzenie własnych
Bardziej szczegółowoJava. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak
Java język programowania obiektowego Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak 1 Język Java Język Java powstał w roku 1995 w firmie SUN Microsystems Java jest językiem: wysokiego
Bardziej szczegółowoWskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:
Wskaźniki są nieodłącznym elementem języka C. W języku C++ także są przydatne i korzystanie z nich ułatwia pracę, jednak w odróżnieniu do C wiele rzeczy da się osiągnąć bez ich użycia. Poprawne operowanie
Bardziej szczegółowoWstęp do programowania obiektowego, wykład 7
Wstęp do programowania obiektowego, wykład 7 Klasy i funkcje abstrakcyjne Przeciążanie funkcji Definiowanie i interpretacja złożonych typów danych w C++ Wskaźniki do funkcji 1 KLASA ABSTRAKCYJNA 2 Klasa
Bardziej szczegółowoPodczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.
Polimorfizm jest filarem programowania obiektowego, nie tylko jeżeli chodzi o język C++. Daje on programiście dużą elastyczność podczas pisania programu. Polimorfizm jest ściśle związany z metodami wirtualnymi.
Bardziej szczegółowoInformatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018
Informatyka I Klasy i obiekty. Podstawy programowania obiektowego dr inż. Andrzej Czerepicki Politechnika Warszawska Wydział Transportu 2018 Plan wykładu Pojęcie klasy Deklaracja klasy Pola i metody klasy
Bardziej szczegółowoProgramowanie obiektowe i zdarzeniowe
Marek Tabędzki Programowanie obiektowe i zdarzeniowe 1/23 Programowanie obiektowe i zdarzeniowe wykład 6 polimorfizm Na poprzednim wykładzie: dziedziczenie jest sposobem na utworzenie nowej klasy na podstawie
Bardziej szczegółowoObiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.
Zrozumienie funkcji danych statycznych jest podstawą programowania obiektowego. W niniejszym artykule opiszę zasadę tworzenia klas statycznych w C#. Oprócz tego dowiesz się czym są statyczne pola i metody
Bardziej szczegółowo10. Programowanie obiektowe w PHP5
Ogólnie definicja klasy wygląda jak w C++. Oczywiście elementy składowe klasy są zmiennymi PHP, stąd nieśmiertelne $. Warto zauważyć, że mogą one mieć wartość HHH mgr inż. Grzegorz Kraszewski TECHNOLOGIE
Bardziej szczegółowoKlasy abstrakcyjne i interfejsy
Klasy abstrakcyjne i interfejsy Streszczenie Celem wykładu jest omówienie klas abstrakcyjnych i interfejsów w Javie. Czas wykładu 45 minut. Rozwiązanie w miarę standardowego zadania matematycznego (i nie
Bardziej szczegółowoPROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec
PROE wykład 3 klasa string, przeciążanie funkcji, operatory dr inż. Jacek Naruniec Przypomnienie z ostatnich wykładów Konstruktory/destruktory i kolejność ich wywołania w złożonej klasie. Referencja Obiekty
Bardziej szczegółowoJava - tablice, konstruktory, dziedziczenie i hermetyzacja
Java - tablice, konstruktory, dziedziczenie i hermetyzacja Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak PLAN WYKŁADU zmienne tablicowe konstruktory klas dziedziczenie hermetyzacja
Bardziej szczegółowoPARADYGMATY PROGRAMOWANIA Wykład 4
PARADYGMATY PROGRAMOWANIA Wykład 4 Metody wirtualne i polimorfizm Metoda wirualna - metoda używana w identyczny sposób w całej hierarchii klas. Wybór funkcji, którą należy wykonać po wywołaniu metody wirtualnej
Bardziej szczegółowoRPC. Zdalne wywoływanie procedur (ang. Remote Procedure Calls )
III RPC Zdalne wywoływanie procedur (ang. Remote Procedure Calls ) 1. Koncepcja Aplikacja wywołanie procedury parametry wyniki wykonanie procedury wynik komputer klienta komputer serwera Zaletą takiego
Bardziej szczegółowoProgramowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz
Programowanie obiektowe Literatura: Autor: dr inŝ. Zofia Kruczkiewicz Java P. L. Lemay, Naughton R. Cadenhead Java Podręcznik 2 dla kaŝdego Języka Programowania Java Linki Krzysztof Boone oprogramowania
Bardziej szczegółowo