Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Komponentowe systemy rozproszone COM i inni. Komunikacja/komponenty w WINDOWS w ujęciu historycznym 1. Schowek 2. DDE 3. 16-bitowe OLE 1.0 4. 16-bitowe.

Podobne prezentacje


Prezentacja na temat: "Komponentowe systemy rozproszone COM i inni. Komunikacja/komponenty w WINDOWS w ujęciu historycznym 1. Schowek 2. DDE 3. 16-bitowe OLE 1.0 4. 16-bitowe."— Zapis prezentacji:

1 Komponentowe systemy rozproszone COM i inni

2 Komunikacja/komponenty w WINDOWS w ujęciu historycznym 1. Schowek 2. DDE 3. 16-bitowe OLE 1.0 4. 16-bitowe OLE 2.0 5. OLE 2.0 = COM = ActiveX (1996) 6. 32-bitowe OLE 7. Dcom 8. COM+ = COM + MTS + MSMQ (W2000)

3 Component Object Model Binarny standard komunikacji Nie jest językiem Nie wymaga konketnego języka Niezależny od języka Interfejsy – standard komunikacji Identyfikacja obiektów i usług (Pół)Automatyczne metody marszalingu danych Wspiera: enkapsulację, dziedziczenie interfejsu i implementacji, polimorfizm Elementy zarządzanie zasobami

4 Obiektowy model klient - serwer

5 Rodzaje serwerów COM serwer w procesie=biblioteka dynamiczna InprocServer / InprocServer32 serwer lokalny=oddzielny proces wykonywalny lokalnie LocalServer / LocalServer32 serwer zdalny=proces wykonywalny zdalnie RemoteServer / RemoteServer32

6 In-proc serwer = DLL if (! FAILED(CoInitialize(NULL))) { err = (CoCreateInstance(CLSID_TESTCLASS, NULL, CLSCTX_INPROC_SERVER, IID_TESTINTERFACE, (void **)&pInterface) ); //użycie COM-a pInterface->DoSmthg(5); //zwolnienie COM-a pInterface->Release(); CoUninitialise(); } Wywołania metod lokalnych serwer ładowany jest do przestrzeni procesu klienta

7 Local/Remote Server = EXE – marszaling danych między procesami- wymagane jest zarejestrowanie interfejsów if (! FAILED(CoInitialize(NULL))) { err = (CoCreateInstance(CLSID_TESTCLASS, NULL, CLSCTX_INPROC_SERVER, IID_TESTINTERFACE, (void **)&pInterface) ); //użycie COM-a pInterface->DoSmthg(5); //zwolnienie COM-a pInterface->Release(); CoUninitialise(); } if (! FAILED(CoInitialize(NULL))) { err = (CoCreateInstance(CLSID_TESTCLASS, NULL, CLSCTX_INPROC_SERVER, IID_TESTINTERFACE, (void **)&pInterface) ); //użycie COM-a pInterface->DoSmthg(5); //zwolnienie COM-a pInterface->Release(); CoUninitialise(); }

8 COM – identyfikacja klas GUID - globalnie unikalny identyfikator: 128-bitowa liczba np.: B77D61E0-47D8-11d0-B53F-444553540000 CLSID - GUID identyfikujący klasę obiektu IID - GUID identyfikujący interfejs (niezbędny gdy mamy do czynienia z marszalingiem danych) Generowanie GUID:  przez użytkownika - GUIDGEN.EXE, UUIDGEN.EXE  Przez środowisko np.NET, VB, VC++  przez API - funkcja CoCreateGuid

9 Powiązanie obiektu z serwerem systemowa baza danych (rejestr systemu) - REGEDIT.EXE: HKEY_CLASSES_ROOT CLSID {GUID klasy obiektu} = Opis klasy obiektu ProgID = Producent.Serwer.Wersja VersionIndependentProgID = Producent.Serwer RodzajSerwera = Pełna nazwa (ze ścieżką) Insertable Producent.Serwer.Wersja = Opis klasy obiektu CLSID = {GUID klasy obiektu} Producent.Program = Opis klasy obiektu (bez wersji) CurVer = Producent.Serwer.Wersja funkcje: ProgIDFromCLSID  CLSIDFromProgID

10 COM - interfejsy Koncepcja interfejsu:  kontrakt na realizację pakietu usług  niezależny od języków programowania sposób opisu: IDL Biblioteki typów TLB  odpowiednik tablicy wskaźników do funkcji: C, C++, Pascal Java VB

11 Interfejsy - rejestracja HKEY_CLASSES_ROOT CLSID {a123x3y1-4ce6-4ce6-4ce6-2a212123223} = My Prog Proxy = Ole2.dll InprocServer32 = c:\\coms\\myserver.dll LocalServer32 = c:\\coms\\myserver.exe {x111111-4ce6-4ce6-4ce6-2a212123223} InprocServer32 = c:\\coms\\mystub.dll Interface {a123x3y1-4ce6-4ce6-4ce6-2a212123223} NumMethods BaseInterface ProxyStubClsId = {x111111-4ce6-4ce6-4ce6-2a212123223}

12 Rejestracja COM-a ”ręczne” uruchomienie pliku typu.REG automatyczny import pliku.REG bezpośrednia manipulacja rejestrem obsługa /REGISTER i /UNREGISTER  90% błędów na początku to problemy z rejestracją np. katalogi debug/release

13 COM – zarządzanie obiektem Zarządzanie pamięcią  czas życia - zliczanie referencji  zarządzanie kopiami danych przekazywanymi między obiektami Zunifikowany sposób tworzenia / likwidowania

14 Tworzenie obiektów 1. Indywidualna funkcja tworzaca obiekty 2. CoCreateObject() – wymaga dostarczenia IClassFactory

15 "Ręczne " tworzenie COM-a – InProcess DllGetClassObject(CLSID_Test, IID_IClassFactory, (void**)pClassFactory); pClassFactory->CreateInstance(NULL, IID_Test, (void**)pTest); pClassFactory->Release();

16 Klient COM if (! FAILED(CoInitialize(NULL))) { err = (CoCreateInstance(CLSID_TESTCLASS, NULL, CLSCTX_INPROC_SERVER, IID_TESTINTERFACE, (void **)&pInterface) ); //użycie COM-a pInterface->DoSmthg(5); //zwolnienie COM-a pInterface->Release(); CoUninitialise(); } CLSCTX_ALL CLSCTX_INPROC_SERVER CLSCTX_LOCAL_SERVER class ComClientClass {... virtual DoSmthg(int); } * pInterface;

17 Wsparcie dla COM Autorzy implementacji różnych języków definiją rozszerzenia pozwalające wołać COM-y. W C++ interfejs odpowiada wskaźnikowi do tablicy wskaźników do funkcji składowych interfejsu

18 Realizacja interfejsu w C++ class CBeeper: CUnknown { public: // wysokość dźwięku long m_lSound ; // wydanie dźwięku long GetSound (); void SetSound (long lSound); long Beep () ; } ptr = CoCreateInstance(....) ; (CBeeper)ptr->Beep(); interface IBeeper : IUnknown { long GetSound (); void SetSound (long lSound); long Beep () ; };

19 Realizacja interfejsu w C++ vs metody wirtualne

20 Skrypt IDL Język opisu interfejsów [uuid(108dbc1b-1ad2-4bda-b45a-e6b0f014c3a1),object] interface IMKInterface : IUnknown { import "unknwn.idl"; HRESULT GetSound([out]WORD *dw); HRESULT SetSound([in] WORD dw); HRESULT Beep (); } MIDL.EXE – kompilacja IDL do:  biblioteki typów  zrodla w c dla stub-a (dll) szeregującego

21 Biblioteka typów Może być linkowana jako zasób lub dostępna oddzielnie: HKEY_CLASSES_ROOT CLSID {a123x3y1-4ce6-4ce6-4ce6-2a212123223} = My Prog ProgID = Producent.Serwer.Wersja TypeLib = {a123x3y1-4ce6-4ce6-4ce6-a2121223} TypeLib {a123x3y1-4ce6-4ce6-4ce6-a2121223} = My Type Lib Dir = c:\tmp HelpDir = c:\tmp\Help 1.00 = Any.TLB 9 = English.TLB

22 IUnknown - podstawowy interfejs obiektu każdy obiekt COM odostępnia interfejs IUnknown każdy interfejs COM obejmuje (dziedziczy) IUnknown

23 Właściwości Interfejsów Statyczny (niezmienny w czasie) zestaw interfejsów Jednoznaczny i unikatowy IUnknown dla różnych obiektów Zada zwrotności: IA -> IA Zasada symetrii: IA -> IB -> IA Zasada przechodniości: IA -> IB -> IC i IA -> IC

24 IUnknown - funkcjonalność interface IUnknown { // zwiększa licznik odniesień ULONG AddRef () ; // zmniejsza licznik odniesień, // gdy licznik == 0 to zwalnia obiekt ULONG Release () ; // udostępnia interfejsy do obiektu HRESULT QueryInterface ( REFIID riid,// identyfikator interfejsu void** ppvObj) ;// wskaźnik do zwracanego interf. } ;

25 IUnknown – realizacja w C++ (MFC) class IUnknown { public: virtual HRESULT QueryInterface (REFIID, void**) ; virtual ULONG AddRef () ; virtual ULONG Release () ; } ; class IUnknown { public: STDMETHODIMP QueryInterface (REFIID, void**) ; STDMETHODIMP_(ULONG) AddRef () ; STDMETHODIMP_(ULONG) Release () ; } ; Makra MFC

26 Zliczanie odniesień Tworzenie kopii odniesienia do obiektu – AddRef Unieważnienie odniesienia do obiektu – Release W praktyce AddRef / Release  Zwrot referencji przez funkcję  Przekazanie odniesienia do oddzielnego wątku

27 Zarządzanie obiektami przez zliczanie odniesień class CXxxObject : public IUnknown { public: CXxxObject (…): m_cRef (0) {…} ; virtual HRESULT QueryInterface (REFIID, void**) ; virtual ULONG AddRef () ; virtual ULONG Release () ; … private: ULONG m_cRef ; // licznik odniesień … } ;

28 IUnknown::AddRef / Release ULONG CXxxObject::AddRef () { return ++m_cRef; // licznik odniesień } ULONG CXxxObject::Release () { if (0 != --m_cRef) // licznik odniesień return m_cRef ; delete this ;// usunięcie obiektu return 0 ; }

29 IUnknown::QueryInterface HRESULT CXxxObject::QueryInterface ( REFIID riid, void** ppvObj) { *ppvObj = NULL ; if ( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IMyInterface) ) // if (riid == IID_IUnknown || riid == IID_IMyInterface) *ppvObj = this ; if (NULL != *ppvObj) { ((IUnknown)*ppvObj)->AddRef (); //licznik odniesień return NOERROR ; } else return E_NOINTERFACE; }

30 IClassFactory - tworzenie obiektów interface IClassFactory : public IUnknown { // stworzenie obiektu HRESULT CreateInstance( IUnknown* pUnkOuter, // wskaźnik do obiektu nadrzęd. REFIID riid, // podstawowy interfejs obiektu void** ppvObj) ; // wskaźnik do zwracanego interf. // zablokowanie serwera w pamięci HRESULT LockServer( BOOL fLock ); } ;

31 Implementacja ClassFactory class CXxxObject ; // klasa tworzonych obiektów class CXxxClassFactory : public IClassFactory { public: // IUnknown STDMETHODIMP QueryInterface (REFIID, void**) ; STDMETHODIMP_(ULONG) AddRef () ; STDMETHODIMP_(ULONG) Release () ; // IClassFactory STDMETHODIMP CreateInstance ( IUnknown*, REFIID, void**) ; STDMETHODIMP LockServer (BOOL) ; private: … } ;

32 IClassFactory::CreateInstance STDMETHODIMP CXxxClassFactory::CreateInstance ( IUnknown* pUnkOuter, REFIID riid, void** ppvObj) { *ppvObj = NULL ; if (NULL != pUnkOuter)// obiekt nie wspiera agregacji return ResultFromScode(CLASS_E_NOAGGREGATION); // stworzenie obiektu CXxxObject pObj = new CXxxObject ; // udostepnienie żądanego łącza HRESULT hr = pObj->QueryInterface (riid, ppvObj) ; if (FAILED (hr)) delete pObj ; else *ppvObj = pObj ; return hr ; }

33 Serwer w procesie (in-process) biblioteka dynamiczna udostępniająca funkcje: STDAPI DllGetClassObject ( REFCLSID rclsid, // GUID klasy udostępnianych obiektów REFIID riid, // GUID łącza tworzącego obiekty // (zwykle IID_ClassFactory) void** ppv) ; // wskaźnik do zwracanego łącza STDAPI DllCanUnloadNow () ;

34 Funkcje serwera typu InProcess STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,void**ppv) { if (rclsid != CLSID_XXX) return ResultFromScode (E_FAIL) ; CXxxClassFactory* pObj = new CXxxClassFactory ; if (pObj == NULL) return ResultFromScode (E_OUTOFMEMORY); HRESULT hr = pObj->QueryInterface (riid, ppv) ; if (FAILED (hr)) delete pObj ; return hr; } STDAPI DllCanUnloadNow () { SCODE sc = (/*czy są obiekty? */…) ? S_FALSE : S_OK ; return ResultFromScode (sc); }

35 Klient COM Server COM CoCreateInstance CoGetClassObject ReadRegistry CoLoadLibrary(“test.dll”,TRUE) Hmodule = LoadLiibrary(test.dll) GetProcAdress(hModule, ”DllGetClassObject”) DllGetClassObject pFactory->CreateInstance pFactory->Release DllGetClassObject pFactory->AddRef pFactory->QueryInterface pFactory-> CreateInstance pObject->QueryInterface pObject->AddRef DllMain CLSID {123434-23213-2323-4234} InprocServer32 = “test.dll”

36 Serwer lokalny program wykonywalny (EXE) rejestrujący udostępniane obiekty: zagadnienia  utrzymanie programu w pamięci dopóki istnieją obiekty  pot. różny wygląd w zależności od typu pracy (/embeeded) STDAPI CoRegisterClassObject( REFCLSID rclsid,// GUID klasy obiektów IUnknown * pUnk,// Interfejs IUnknown // udostępnianego obiektu DWORD dwClsCtxt,// Rodzaj serwera DWORD flags,// Sposób nawiązywania połączenia DWORD** pdwReg// Wskaźnik do zarejestrowanej klasy );

37 Inicjalizacja i zakończenie serwera lokalnego // inicjalizacja if (FAILED (CoInitializeEx (NULL))) … // błąd inicjalizacji CXxxClassFactory* pClassFact = new CXxxClassFactory ; pClassFact->AddRef () ; DWORD dwReg ; if (FAILED (CoRegisterClassObject(CLSID_XXX, pClassFact,CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwReg)) ) … // błąd inicjalizacji // zakończenie CoRevokeClassObject (dwReg) ; pClassFact->Release () ; CoUninitializeEx () ;

38 Implementacja wielu interfejsów COM przez jedną klasę C++? Podział odpowiedzialności – różne klasy C++ Techniczny problem w przypadku realizacji interfejsów jako oddzielnych klas pot. problem z powoływaniem do życia i zarządzaniem wieloma POWIĄZANYMI obiektami Adres interfejsu vs. tożsamość obiektu możliwe rozwiązanie: klasy zagnieżdzone metody z IUnknown są delegowne do obiektu głównego MFC – BEGIN/END_INTERFACE_PART

39 COM - REUSABILITY

40 Wielokrotne wykorzystywanie (reusability) kodu C++  dziedziczenie wspólne pola danych dla klasy podstawowej i pochodnej wymaga bardzo dokładnego dokumentowania, zwykle przez udostępnianie kodu źródłowego COM  zawieranie obiektów  agregacja obiektów

41 Zawieranie obiektów modyfikacja metod obiektu obiekt zewnętrzny nie udostępnia łącza IUnknown obiektu wewnętrznego obiekt zewnętrzny udostępnia pośrednio wybrane łącza obiektu wewnętrznego

42 Zawieranie obiektów - zewnętrzny obiekt class CExtObject : IUnknown, IInterfaceW, IInterfaceZ { public: CExtObject (…): m_pInObj (NULL){ ::CoCreateInstance (CLSID_ExtObject, NULL, CLSCTX_ALL, IID_IUnknown, &m_pInObj) ; } ; ~CExtObject () { Release();delete m_pInObj;} ; … // metody łącz IInterfaceZ i IInterfaceW private: IUnknown* m_pInObj ; // obiekt wewnętrzny … } ;

43 Agregacja obiektów udostępnienie niezmienionych metod obiektu obiekt zewnętrzny udostępnia pośrednio łącze IUnknown obiektu wewnętrznego obiekt zewnętrzny udostępnia bezpośrednio pozostałe łącza obiektu wewnętrznego

44 Agregacja - wewnętrzny obiekt class CInObject : IUnknown, IInterfaceW { public: CInObject (IUnknown* pUnkOuter, …) ; virtual HRESULT QueryInterface (REFIID, void**) ; virtual ULONG AddRef () ; virtual ULONG Release () ; … private: ULONG m_cRef ; // licznik odniesień IUnknown *m_pUnkOuter ; // zewnętrzne IUnknown … } ;

45 Agregacja – zliczanie odniesień CInObject:: CInObject(IUnknown* pUnkOuter, …) m_cRef (0), m_pUnkOuter (pUnkOuter) { … } ULONG CInObject::AddRef (){ if (m_pUnkOuter) return m_pUnkOuter->AddRef () ; return ++m_cRef ; } ULONG CInObject::Release (){ if (m_pUnkOuter) return m_pUnkOuter->Release () ; if (0 != --m_cRef) return m_cRef ; delete this ; return 0 ; }

46 Agregacja - QueryInterface HRESULT CInObject::QueryInterface (REFIID riid, void** ppvObj) { *ppvObj = NULL ; if (m_pUnkOuter) return m_pUnkOuter->QueryInterface(riid, ppvObj); if (IsEqualIID (riid, IID_IUnknown) || IsEqualIID (riid, IID_IInterface1)) *ppvObj = this ; if (NULL != *ppvObj) { ((LPUNKNOWN)*ppvObj)->AddRef () ; return NOERROR ; } return ResultFromScode (E_NOINTERFACE) ; }

47 Agregacja – CreateInstance HRESULT CInClassFactory::CreateInstance ( IUnknown* pUnkOuter, REFIID riid, void** ppvObj) { *ppvObj = NULL ; if (pUnkOuter && riid != IID_IUnknown) return ResultFromScode (E_NOINTERFACE); CInObject pObj = new CInObject (pUnkOuter, …) ; HRESULT hr = pObj->QueryInterface (riid, ppvObj) ; if (FAILED (hr)) delete pObj ; else *ppvObj = pObj ; return hr ; }

48 Emulacja i wersjonowanie HKEY_CLASSES_ROOT MyFirm.MyProg = this is current version of component CLSID = {a123x3y1-4ce6-4ce6-4ce6-2a212123223} CurVer = {a123x3y1-4ce6-4ce6-4ce6-2a212123223} MyFirm.MyProg.1= this is version 1 of component CLSID = {x000x0y0-4ce6-4ce6-4ce6-2a212123223} MyFirm.MyProg.2 = this is version 2 of component CLSID = {a123x3y1-4ce6-4ce6-4ce6-2a212123223} TreatAs = {y00000-4ce6-4ce6-4ce6-2a212123223} AutoTreatAs = {y00000-4ce6-4ce6-4ce6-2a212123223} funkcje: CoTreateAsClass

49 ACTIVE X

50 ActiveX Kontrolki, Serwery Kontrolki ActiveX:  standard do rozszerzania zestawu pól dialogowych dostępnych w systemie Windows poprzednie standardy: Custom Controls, Visual Basic Controls OCX = ActiveX (OLE controls = ActiveX controls)  gotowe komponenty funkcjonalne do budowania programów Server ActiveX: program udostępniający IDispatch

51 Interfejs IDispatch interface IDispatch : IUnknown { HRESULT GetTypeInfoCount (…) ; HRESULT GetTypeInfo (…) ; HRESULT GetIDsOfNames (…) ; HRESULT Invoke (DISPID dispID, REFIID riid, LCID lcid, unsigned short wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, unsigned int* puArgErr) ; } ;

52 Obsługiwane typy danych IDL: boolean(bool), double, float, signed int(int/long), signed short(short), enum, BSTR, CY, DATE, IDispatch*, IUnknown*, SAFEARRAY, VARIANT

53 Klient automatyzacji - Visual Basic Dim ThisExcel As Excel.Application Dim ThisChart As Excel.Chart …. Dim TitleArray As Variant Dim DataArray As Variant TitleArray = Array("Dogs", "Cats", "Horses") DataArray = Array(34, 53, 12) Set ThisExcel = CreateObject("Excel.application") With ThisExcel.Workbooks.Add.Range("A1:C1").Value = TitleArray.Range("A2:C2").Value = DataArray.Range("A1:C2").Select Set ThisChart =.Charts.Add().Visible = True End With

54 Dedykowany klient automatyzacji MFC/.Net potrafią wygenerować klasę udostępniającą funkcjonalność obiektu ActiveX na postawie: biblioteki TLB (również np. wkompilowanej w dll) zawartości rejestru (ID.klasy)  klasa pośredniczy w wołaniu metod serwera  dostępie do pól udostepnianych przez serwer (Get/Set) CMyComClassDriver c; c.CreateDispatch(ComObjectCLSID); x = c.Calculate(15); c.ReleaseDispatch();

55 Klient automatyzacji - VC++ CLSID clsid; IDispatch* pIDispatch ; ::CLSIDFromProgID(T2OLE(_T("Excel.application")),&clsid); HRESULT hr = ::CoCreateInstance (clsid, NULL, CLSCTX_SERVER, IID_IDispatch, (void**) &pIDispatch); CApplication m_pThisExcel = new CApplication (pIDispatch) ; CChart*m_pThisChart = new CChart(CCharts(m_pThisExcel->Charts ()).Add ()); CRange( m_pThisExcel->Range("A1", "C1")).SetValue(TitleArray); CRange (m_pThisExcel->Range ("A1", "C2")).Select () ; m_pThisExcel->SetVisible (TRUE) ; m_pThisChart->SetRotation (iRotate) ;

56 IDispatch z perspektywy klienta Informacje o interfejsie ? IDispatch – samodokumentujacy się interfejs Biblioteka typów:  Pliki.TLB  Wbudowana w komponent (jako zasób) Sterowniki: VC++ - ClassWizard - dedykowana klasa (na podst. biblioteki typów) VB – import komponentu lub biblioteki

57 Właściwości interfejsu IDispatch Zalety:  Samodokumentowanie się interfejsów  Możliwość późnego wiązania Wady:  Duży narzut na pojedyncze wołanie Techniczna realizacje ActiveX:  Dwa zestawy interfejsów (dla COM/ActiveX)  Interfejsy dualne (IDL: dual, HRESULT)

58 IDispatchEx Zmienione zestawy parametrów Dynamiczna zmiana udostępnianej funkcjonalności interface IDispatchEx: IDispatch { GetDispID(...); GetNextDispID(...); InvokeEx(...); DeleteMemberByName(...); DeleteMemberByDispID(...); GetMemberProperties(...); GetMemberName(...); GetNameSpaceParent(...); };

59 COM VS.NET Com wiecznie żywy

60 Współpraca z COM Klient.Net Runtime Callable Wrapper Natywny COM Server IUnknown IDispatch IFoo RCW jest generowany przez runtime

61 Współpraca z COM Obiekt.Net klient COM IUnknown IDispatch IFoo Object name IFoo R egasm.exe pozwala wygenerować GUID i zaktualizować wpisy w rejestrze.

62 Klient Com w.NET Import i generacja wrapera Visual Studio Type Library Importer (Tlbimp.exe) System.Runtime.InteropServices.TypeLib Converter class “Ręcznie” napisana klasa Managed C++

63 Serwer Com w.NET using System.Runtime.InteropServices; using System.Reflection; [GuidAttribute("EA5A0174-D303-459a-8B9B-28F6674E9371"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IKlasaN { uint SetState(int state); uint GetState(out int state); } [ClassInterface(ClassInterfaceType.None), GuidAttribute("493DEA38-15EB-4acf-8196-042CF32A29F3"), ComVisible(true), ProgId(„comtestnet.klasa.1”)] public class KlasaN: IKlasaN {... } Rejestracja: regasm.exe


Pobierz ppt "Komponentowe systemy rozproszone COM i inni. Komunikacja/komponenty w WINDOWS w ujęciu historycznym 1. Schowek 2. DDE 3. 16-bitowe OLE 1.0 4. 16-bitowe."

Podobne prezentacje


Reklamy Google