15.11.2018 vjj 1 Component Object Model COM = SW stavebnice jazykově nezávislé objekty Win32 API extension
15.11.2018 vjj 2 Drag and Drop sada COM protokolů
15.11.2018 vjj 3 Drag-and-Drop Klient SYSTEM Server Okno DoDragDrop IDropSource IDropTarget IDataObject Dokument mujdatovyobjekt
15.11.2018 vjj 4 Drag-and-Drop target: pro okno které by mělo být schopno přijímat COM objekty prostřednictvím Drag-and-Drop RegisterDragDrop (hwindow, pidroptarget);
15.11.2018 vjj 5 Drag-and-Drop source: nejčastěji v reakci na specifickou činnost uživatele pro odstartování Drag-and-Drop, od té chvíle patří myš i klávesnice funkci DoDragDrop!!! case WM_LBUTTONDOWN : pidataobject = new mujdatovyobjekt(...) ; DoDragDrop (pidataobject, pidropsource,..
15.11.2018 vjj 6 Drag-and-Drop DoDragDrop - systémová knihovna OLE2 (naštěstí to nemusím programovat já!!!!!) zjistí, nad kterým oknem kurzor zrovna je case WM_MOUSEMOVE :... WindowFromPoint (... ) ;... podle svých tabulek zjistí, jestli má toto okno zaregistrovaný interface IDropTarget pokud ano, zahájí komunikaci s objekty IDropSource a IDropTarget
15.11.2018 vjj 7 vzhled kurzoru zobrazení správného informačního kurzoru např. pro okamžik, kdy kurzor přenášející COM objekt přijde nad zaregistrované okno: DoDragDrop zavolá: pidroptarget->dragenter( pidataobject, KeyState, point, peffect ) ; aplikace, které okno patří, se podívá na pidataobject a odpoví do peffect, co by byla ochotna s takovým objektem provést source aplikace rozhoduje o vzhledu kurzoru pro danou akci pidropsource->givefeedback( peffect ) ; GiveFeedback (... ) { return DRAGDROP_S_USEDEFAULTCURSORS ; }
15.11.2018 vjj 8 DoDragDrop při pohybu kurzoru nad zaregistrovaným oknem IDropTarget -> DragOver když kurzor opouští zaregistrované okno IDropTarget -> DragLeave
15.11.2018 vjj 9 při změně stavu klávesnice nebo tlačítek myši DoDragDrop se zeptá zdrojové aplikace, jak na to má reagovat IDropSource -> QueryContinueDrag odpověď S_OK znamená "nic se neděje", tj. že danou změnu stavu klávesnice nebo tlačítek myši má funkce DoDragDrop prostě ignorovat a v Drag-and-Drop se má pokračovat. pro zaregistrované okno to znamená jen obyčejný pohyb kurzoru na oknem: IDropTarget -> DragOver pokud je odpověď DRAGDROP_S_DROP uvědomí funkce DoDragDrop zaregistrované okno o tom, že na ně byl položen datový COM objekt IDropTarget -> Drop (pidataobject pokud je odpověď DRAGDROP_S_CANCEL uvědomí funkce DoDragDrop zaregistrované okno prostě jen o tom, že kurzor s COM objektem z něho zmizel IDropTarget -> DragLeave
.NET Drag-and-Drop 15.11.2018 vjj 10
15.11.2018 vjj 11.NET využívá COM implementaci Drag-and-Drop objekty, u kterých uživatel oprávněně očekává podporu Drag-and-Drop, např. TextBox, ji mají vesměs již standardně zabudovánu pro ostatní vizuální objekty, např. Rectangle, jsou k dispozici drag source: metoda DragDrop.DoDragDrop a události GiveFeedback, QueryContinueDrag drag target: vlastnost AllowDrop a události DragEnter, DragOver, DragLeave, Drop
15.11.2018 vjj 12 XAML rectangle as a drag source <Rectangle Fill="Green" Stroke="Black" Height="200" Width="400" Margin="10" MouseMove="my_MouseMove" />
15.11.2018 vjj 13 { } drag source: MouseMove private void my_mousemove( object sender, MouseEventArgs e) Rectangle rctngl = sender as Rectangle; if (rctngl!= null && { } e.leftbutton == MouseButtonState.Pressed) DragDrop.DoDragDrop( rctngl, // drag source object rctngl.fill.tostring(), // dragged data object DragDropEffects.Copy); // first value for GiveFeedback query // GiveFeedback; // QueryContinueDrag;
15.11.2018 vjj 14 defaults for drag source GiveFeedback event handler missing => default system feedback for user during entire drag-and-drop process QueryContinueDrag event handler missing => default reactions on key/button states during entire drag-and-drop process
15.11.2018 vjj 15 XAML rectangle as a drag target <Rectangle Fill="Green" Stroke="Black" Height="200" Width="400" Margin="10" /> AllowDrop ="True" DragEnter ="my_dragenter" DragOver ="my_dragover" DragLeave ="my_dragleave" Drop ="my_drop"
15.11.2018 vjj 16 drag target: AllowDrop property true:.net runtime zaregistruje (RegisterDragDrop) objekt (this) do seznamu objektů schopných reagovat na události vyvolávané funkcí DoDragDrop jako případný drag target.net runtime volá event handlery DragEnter, DragOver, DragLeave, Drop objektu ve své implementaci COM rozhraní IDropTarget
15.11.2018 vjj 17 Drag target: DragEnter private void my_dragenter( object sender, DragEventArgs e ) { Rectangle rctngl = sender as Rectangle; if ( rctngl!= null ) { // Save the current Fill brush so that you can revert back to this value in DragLeave. _previousfill = rctngl.fill; // If the DataObject contains string data, extract it. if( e.data.getdatapresent( DataFormats.StringFormat ) ) { string datastring = (string)e.data.getdata( DataFormats.StringFormat ); } } } // If the string can be converted into a Brush, convert it. BrushConverter converter = new BrushConverter( ); if( converter.isvalid( datastring ) ) { Brush newfill = (Brush)converter.ConvertFromString( datastring ); rctngl.fill = newfill; }
15.11.2018 vjj 18 Drag target: DragOver private void my_dragover( object sender, DragEventArgs e ) { e.effects = DragDropEffects.None; // If the DataObject contains string data, extract it. if( e.data.getdatapresent( DataFormats.StringFormat ) ) { string datastring = (string)e.data.getdata( DataFormats.StringFormat ); } } // If the string can be converted into a Brush, allow copying. BrushConverter converter = new BrushConverter(); if( converter.isvalid( datastring ) ) { e.effects = DragDropEffects.Copy DragDropEffects.Move; }
15.11.2018 vjj 19 Drag target: DragLeave private void my_dragleave( object sender, DragEventArgs e ) { Rectangle rctngl = sender as Rectangle; if( rctngl!= null ) { rctngl.fill = _previousfill; } }
15.11.2018 vjj 20 Drag target: Drop private void my_drop( object sender, DragEventArgs e ) { Rectangle rctngl = sender as Rectangle; if( rctngl!= null ) { // If the DataObject contains string data, extract it. if( e.data.getdatapresent( DataFormats.StringFormat ) ) { string datastring = (string)e.data.getdata( DataFormats.StringFormat ); } } } // If the string can be converted into a Brush, // convert it and apply it to the rectangle. BrushConverter converter = new BrushConverter( ); if( converter.isvalid( datastring ) ) { Brush newfill = (Brush)converter.ConvertFromString( datastring ); rctngl.fill = newfill; }
IDataObject 15.11.2018 vjj 21
15.11.2018 vjj 22 COM metody SetData GetFormats GetData GetDataPresent
15.11.2018 vjj 23 { }.NET implementace private void my_mousemove( object sender, MouseEventArgs e) Rectangle rctngl = sender as Rectangle; if (rctngl!= null && { } e.leftbutton == MouseButtonState.Pressed) DragDrop.DoDragDrop( rctngl, // drag source object rctngl.fill.tostring(), // dragged data object DragDropEffects.Copy); // first value for GiveFeedback query
15.11.2018 vjj 24 Compound Files složený, skládaný, stavebnicový, hierarchicky uspořádaný
15.11.2018 vjj 27 Compound Files File-system and platform independence. Because COM's Compound Files implementation runs on top of existing flat-file systems, compound files stored in the FAT file system, NTFS file system, or Macintosh file systems can be opened by applications using any one of the other file systems. Searchable. Because the separate objects in a compound file are saved in a standard format and can be accessed using standard COM interfaces and APIs, any browser utility using these interfaces and APIs can list the objects in the file, even though data within a given object may be in a proprietary format. Access to certain internal data. Because the Compound Files implementation provides standard ways of writing certain types of data summary information, for example applications can read this data using COM interfaces and APIs
15.11.2018 vjj 28 stavebnicový soubor soubor na disku myfile.dat CreateStream Stream CreateStorage Storage Root Storage Stream StgCreateDocfile CreateStorage Storage Storage cizí objekt Stream Stream
15.11.2018 vjj 29 vytvoření objektu souboru IStorage *prootstorage; StgCreateDocfile (filename,, &prootstorage) ; StgOpenStorage (filename,, &prootstorage) ;
15.11.2018 vjj 30 základ vytvoření "podadresáře" na libovolné úrovni pstorage->createstorage (, &psubstorage) ; vytvoření datového "souboru" na libovolné úrovni pstorage->createstream (, &pnewsubstream) ;
15.11.2018 vjj 31 práce s "podadresářem" psubstorage->enumelements (... ) ; psubstorage->openstorage ("Name",, &pnewsubstream) ; psubstorage->openstream ("Name",, &pnewsubstream) ;
15.11.2018 vjj 32 práce s "podsouborem" psubstream->write (... ) ; psubstream->read (... ) ;
15.11.2018 vjj 33.NET & Compound File http://openmcdf.sourceforge.net/
COM structured storage 15.11.2018 vjj 34
15.11.2018 vjj 35 Object in Structured Storage Klient Dokument Server pidataobject IDataObject Soubor IRootStorage IPersistStorage IStorage Object IStream
15.11.2018 vjj 36 PersistStorage klient: má ukazatel pidataobject na cizí datový objekt zeptá se ho, jestli se umí uložit do stavebnicového souboru pidataobject->queryinterface (IID_PersistStorage, &ppersiststorage) ; server implementace IDataObject: QueryInterface (... ) { ppersiststorage = this ; return S_OK ; }
InitNew klient: pstorage->createstorage (.., &psubstorage) ; ppersiststorage->initnew (&psubstorage) ; server - implementace IDataObject: InitNew (&psubstorage) { psubstorage->createstream (.., &pnewsubstream) ; } pnewsubstream->write (...... psubstorage->createstorage (.., &pnewsubstorage ) ;... return S_OK ; 15.11.2018 vjj 37
15.11.2018 vjj 38 klient: File Save ppersiststorage->save (&psubstream,...) ; server - implementace IPersistStorage:... Save (&psubstream,... ) { psubstream->write (... ) ; // psubstream->commit (... ) ; psubstream->release (... ) ; psubstorage->commit (... ) ; psubstorage->release (... ) ; return S_OK ; } klient: prootstorage->commit (... ) ;... ppersiststorage->savecompleted (... ) ;
15.11.2018 vjj 39 klient: File Close ppersiststorage->save (&psubstream,...) ; server - implementace IPersistStorage:... Save (&psubstream,... ) { psubstream->write (... ) ; // psubstream->commit (... ) ; psubstream->release (... ) ; psubstorage->commit (... ) ; psubstorage->release (... ) ; return S_OK ; } klient: prootstorage->commit (... ) ; prootstorage->release (... ) ;
15.11.2018 vjj 40 konec (?) to byly jen dva jednoduché protokoly, COM jich má celkem dost
COM protokoly 15.11.2018 vjj 41
COM backgrounds 15.11.2018 vjj 42
15.11.2018 vjj 43 rodokmen DDE OLE (Dynamic Data Exchange through GlobalAlloc) (Object Linking and Embedding) OLE (OLE 2) COM (Component Object Model) ActiveX DCOM (Distributed COM) COM+.NET
15.11.2018 vjj 44 literatura Kraig Brockschmidt: Inside OLE 2, Microsoft Press 1994, ISBN 1-55615-618-9 999 stran Guy Eddon, Henry Eddon: Inside Distributed COM Microsoft Press 1998, ISBN 1-57231-849-X
15.11.2018 vjj 45 COM objekt objekt = set of interfaces Interface - sada metod realizujících jednu stranu, nebo její autonomní část, jednoho COM protokolu vícenásobná dědičnost prvotní představa byla udělat něco, jako je v současnosti.net, ale kompletní informace o objektech nebyly zveřejňovány prostřednictvím manifestu v assembly, ale byly ukládány v Registry COM dll: Register Component by regsvr32.net dll: Register Assembly by gacutil
15.11.2018 vjj 46 mydllreg.reg volání Regsvr32 přímo do lokálního menu dll knihoven Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\.dll] @="dllfile" [HKEY_CLASSES_ROOT\dllfile\shell\ Register Component\command] @="regsvr32 \"%1\"" [HKEY_CLASSES_ROOT\dllfile\shell\ Unregister Component\command] @="regsvr32 \"%1\" /u"
15.11.2018 vjj 47 UUID, GUID, CLSID, IID celý svět vs. celý vesmír
15.11.2018 vjj 48 GUID objekty a rozhraní identifikovány ne jmény, ale pomocí 128-bitových konstant Globally Unique IDentifier formát podle standardu Open Software Foundation (OSF) {12345678-1234-1234-1234-567890ABCDEF} Microsoft: Universally Unique IDentifier typedef struct { DWORD Data1 ; WORD Data2 ; WORD Data3 ; BYTE Data4[8] ; } GUID ;
15.11.2018 vjj 49 Pojmenování GUID const IID IID_IMujPokus = { 0x12345678, 0x1234, 0x1234, {0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB}}; DEFINE_GUID (IID_IMujPokus, 0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB) ;
GUIDGEN.EXE GUI Generování (dříve i UUIDGEN.EXE - B/W prompt) GUID v potřebném formátu pro copy-and-paste C:\Program Files (x86)\microsoft Visual Studio 14.0\Common7\Tools // pgm - kompatibilní verze: RPC_STATUS RPC_ENTRY UuidCreateSequential ( UUID *Uuid ); // pgm - bezpečná verze (bez MAC) RPC_STATUS RPC_ENTRY UuidCreate ( UUID *Uuid ); UuidToString, UuidFromString GUID *pguid; HRESULT hr; hr = CoCreateGuid( &pguid ); 15.11.2018 vjj 50
GUIDgen.exe 15.11.2018 vjj 51
15.11.2018 vjj 52 je jich dost každý člověk na Zemi může vygenerovat cca 100 miliard hodnot každou vteřinu po dobu cca 10 až 20 miliard let (budoucnost sluneční soustavy se odhaduje na cca 4,5 miliardy let) 2 128 340. 10 36 12. 10 9 [lidí] * 100. 10 9 [hodnot/sec] * 31,5. 10 6 [sec/rok] * 9. 10 9 [roků]
struktura COM objektu 15.11.2018 vjj 53
15.11.2018 vjj 54 struktura COM object DATA FUNCTIONS FUNCTIONS FUNCTIONS
interface 15.11.2018 vjj 55
15.11.2018 vjj 56 Interface abstraktní třídy ("pure virtual" metody) předdefinované vs. vlastní (jen výjimečně) předdefinovaných je přes 60 IUnknown povinně implementované rozhraní všechna ostatních rozhraní jsou od něj odvozena
15.11.2018 vjj 57 struktura COM object FUNCTIONS FUNCTIONS FUNCTIONS DATA IUnknown IDataObject IDropSource e.g. text
15.11.2018 vjj 58 COM objekt class mujobjekt : public IRozhraniA, //metody A1, A2 public IRozhraniB //metody B1, B2 { private : DWORD m_cref ; public : MujObjekt( void ); ~MujObjekt( void ); // IUnknown STDMETHODIMP QueryInterface(REFIID,PPVOID); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IRozhraniA STDMETHODIMP A1(DWORD); STDMETHODIMP_(DWORD) A2(void); // IRozhraniB STDMETHODIMP B1(void); STDMETHODIMP_(DWORD) B2(DWORD); }
15.11.2018 vjj 59 konstruktor, AddRef mujobjekt::mujobjekt( void ) { m_cref = 0L; return; } STDMETHODIMP_(ULONG) mujobjekt::addref( ) { return ++m_cref; }
15.11.2018 vjj 60 Release STDMETHODIMP_(ULONG) mujobjekt::release( ) { if ( --m_cref == 0 ) { delete this ; g_cobj-- ; return 0 ; } return m_cref ; }
15.11.2018 vjj 61 QueryInterface STDMETHODIMP mujobjekt::queryinterface (REFIID parm1, PPVOID parm2) { } if (parm1 == IID_IUnknown) *parm2 = (PUNKNOWN) this ; else if (parm1 == IID_IRozhraniA) *parm2 = (PROZHRANIA) this ; else if (parm1 == IID_IRozhraniB) *parm2 = (PROZHRANIB) this ; else { *parm2 = NULL ; return E_NOINTERFACE ; } (*parm2)->addref() ; return S_OK ; // nebo S_FALSE
15.11.2018 vjj 62 vytvoření instance COM objektu kompletní COM objekt = COM objekt + ClassFactory
15.11.2018 vjj 63 Vytvoření jediné instance CoCreateInstance ((REFCLSID) CLSID_objekt, (IUnknown*) punkouter, (DWORD) CLSCTX_typ_modulu, (REFIID) IID_rozhraní, (PPVOID) &pirozhraní) ;
15.11.2018 vjj 64 Vytvoření více instancí CoGetClassObject (CLSID_objekt, CLSCTX_typ_modulu, NULL, IID_ClassFactory, (PPVOID) &piclassfactory) ; piclassfactory->createinstance (...
15.11.2018 vjj 65 DLL pro každou třídu implementovaných COM objektů musí implementovat a exportovat funkci DllGetClassObject ( REFCLSID x_rclsid, REFIID x_riid, PPVOID x_ppv) nevrací pointer na požadovaný objekt!!!!! vrací pointer na objekt ClassFactory - proč????? funkce DllGetClassObject nemůže zavolat přímo konstruktor objektu, protože nezná individuální kombinaci jeho parametrů místo toho tedy zavolá univerzální ClassFactory příslušnou k danému objektu ClassFactory zná všechny parametry konstruktoru (např. pro C++ objekt, který COM objekt implementuje)
15.11.2018 vjj 66 EXE musí pro každou implementovanou třídu objektů, zaregistrovat ClassFactory, tj. umožnit systému přístup ke ClassFactory pro objekt s požadovaným CLSID CoRegisterClassObject (CLSID_Obj, (PUNKNOWN) piclassfactory, CLSTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, & dwregco) ;
ClassFactory 1/2 STDMETHODIMP ClassFactoryProMujObjekt::CreateInstance( PUNKNOWN parm1, REFIID parm2, PPVOID parm3) { PMUJOBJEKT pobj ; HRESULT hr ; if (parm1!= NULL &&!IsEqualIID(parm2, IID_IUnknown)) { *parm3 = NULL ; return E_NOINTERFACE ; } 15.11.2018 vjj 67
15.11.2018 vjj 68 ClassFactory 2/2 pobj = new mujobjekt ( parm1 ) ; if (pobj == NULL) { *parm3 = NULL ; return E_OUTOFMEMORY ; } hr = pobj->queryinterface ( parm2, parm3 ) ; if ( FAILED(hr) ) delete pobj ; else g_cobj++ ; return hr ; }
skládání 15.11.2018 vjj 69
15.11.2018 vjj 70 data + methods COM object FUNCTIONS FUNCTIONS FUNCTIONS DATA IUnknown IDataObject IDropSource e.g. text C++ object C# object C
15.11.2018 vjj 71 data + methods COM object FUNCTIONS DATA IUnknown e.g. text C++ object COM object FUNCTIONS IDataObject C# object COM object FUNCTIONS IDropSource C
15.11.2018 vjj 72 jednoduchý objekt IUnknown QueryInterface AddRef Release InterfaceC InterfaceD
15.11.2018 vjj 73 skládání Řídící COM objekt : IUnknown QueryInterface AddRef Release Interface A Interface B Interface C Interface D Podřízený COM objekt : IUnknown QueryInterface AddRef Release InterfaceC InterfaceD
15.11.2018 vjj 74 agregovatelný objekt Vnější C++ objekt : IUnknown QueryInterface AddRef Release Vnitřní C++ objekt : IUnknown QueryInterface AddRef Release InterfaceC InterfaceD
15.11.2018 vjj 75 agregace Řídící COM objekt : Vnější C++ objekt : IUnknown QueryInterface AddRef Release Vnitřní C++ objekt : IUnknown QueryInterface AddRef Release InterfaceA InterfaceB Podřízený COM objekt : Vnější C++ objekt : IUnknown QueryInterface AddRef Release Vnitřní C++ objekt : IUnknown QueryInterface AddRef Release InterfaceC InterfaceD
15.11.2018 vjj 76 RPC jak využít objekt získaný prostřednictvím Drag-and-Drop? jak dokáže Visual Studio ukázat metody objektu z právě staženého DLL?
15.11.2018 vjj 77 Remoting, Automation Remoting Programability Automation
15.11.2018 vjj 78 Remoting, Automation Remote Control Remoting Programability Automation
15.11.2018 vjj 79 Remoting, Automation Remote Control dálkové ovládání Remoting Programability Automation
15.11.2018 vjj 80 Remoting, Automation Remote Control dálkové ovládání Remoting používání dálkového ovládání Programability Automation
15.11.2018 vjj 81 Remoting, Automation Remote Control dálkové ovládání Remoting používání dálkového ovládání Programability možnost naprogramovat dálkové ovládání, využití Remotingu v programu Automation dálkové ovládání programem
15.11.2018 vjj 82 zpřístupnění objektu publikace informací o implementovaných metodách v implementovaných rozhraních IDispatch Type Library duální rozhraní
15.11.2018 vjj 83 IDispatch rozhraní umožňující dynamické zjišťování vlastností objektu cf..net Manifest & Reflection
15.11.2018 vjj 84 Pure Automation: IDispatch Přístup ke všem (nestandardním) metodám (nestandardních) rozhraní objektu implementace IDispatch byla nutná pro zobrazení vlastností objektu např. ve Visual Studiu GetTypeInfoCount GetTypeInfo LoadRegTypeLib GetTypeInfoOfGuid GetIDsOfNames DispGetIDsOfNames Invoke
15.11.2018 vjj 85 Duální rozhraní duální rozhraní: IDispatch + Type Library dynamické zjišťování vlastností objektu: IDispatch statické zabudování využití objektu: slinkování s Type Library
15.11.2018 vjj 86 Type Library informace o implementovaných (nestandardních) metodách lze publikovat v Type Library cf..net Manifest & Reflection
15.11.2018 vjj 87 import "unknwn.idl" ; Type Library IDL Interface Description Language / soubor s popisem objektu [ object,uuid(11111111-1111-1111-1111-111111111111), oleautomation ] interface ImojeRozhrani : IUnknown { HRESULT mojemetoda ([in] int i, [out, retval] int* retval) ; } [ uuid(33333333-3333-3333-3333-333333333333), helpstring("type Library - muj pokus"), version(1.0) ] library mojekomponenta { importlib("stdole32.tlb") ; interface ImojeRozhrani ; [ uuid(22222222-2222-2222-2222-222222222222) ] coclass mujpokus { interface ImojeRozhrani ; } } ;
15.11.2018 vjj 88 Type Library překladač MIDL vygeneruje "Type Library". je nutné zaregistrovat "Type Library" a všechna rozhraní v Registry. HKEY_CLASSES_ROOT\TypeLib \{33333333-3333-3333-3333-333333333333} GUID version number path to the library flags path to the directory with the help files HKEY_CLASSES_ROOT\Interface \{11111111-1111-1111-1111-111111111111} Base Interface Num Methods ProxyStubClsid32 TypeLib