9.2.2016 vjj 1 Component Object Model COM = SW stavebnice jazykově nezávislé objekty Win32 API extension
9.2.2016 vjj 2 Drag and Drop sada COM protokolů
9.2.2016 vjj 3 Drag-and-Drop Klient SYSTEM Server Okno DoDragDrop IDropSource IDropTarget IDataObject Dokument mujdatovyobjekt
9.2.2016 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);
9.2.2016 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,..
9.2.2016 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
9.2.2016 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 ; }
9.2.2016 vjj 8 DoDragDrop při pohybu kurzoru nad zaregistrovaným oknem IDropTarget -> DragOver když kurzor opouští zaregistrované okno IDropTarget -> DragLeave
9.2.2016 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 9.2.2016 vjj 10
9.2.2016 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
9.2.2016 vjj 12 XAML rectangle as a drag source <Rectangle Fill="Green" Stroke="Black" Height="200" Width="400" Margin="10" MouseMove="my_MouseMove" />
9.2.2016 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
9.2.2016 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
9.2.2016 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"
9.2.2016 vjj 16 drag target: AllowDrop property true:.net runtime zaregistruje (RegisterDragDrop) objekt 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
9.2.2016 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; }
9.2.2016 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; }
9.2.2016 vjj 19 Drag target: DragLeave private void my_dragleave( object sender, DragEventArgs e ) { Rectangle rctngl = sender as Rectangle; if( rctngl!= null ) { rctngl.fill = _previousfill; } }
9.2.2016 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 9.2.2016 vjj 21
9.2.2016 vjj 22 COM metody SetData GetFormats GetData GetDataPresent
9.2.2016 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
9.2.2016 vjj 24 stavebnicové soubory Compound Documents (složený, skládaný)
9.2.2016 vjj 25 NTFS - Stream C:\> ECHO "text" > SOUBOR.txt:myStream C:\> MORE < SOUBOR.TXT C:\> MORE < SOUBOR.TXT:myStream "text"
9.2.2016 vjj 26 NTFS - Stream C:\> COPY 500GB.mp4 > SOUBOR.txt:myStream
9.2.2016 vjj 27 stavebnicový soubor soubor na disku myfile.dat CreateStream Stream CreateStorage Storage Root Storage Stream CoCreateDocFile CreateStorage Storage Storage cizí objekt Stream Stream
9.2.2016 vjj 28 vytvoření objektu souboru CoCreateDocFile (, &prootstorage) ;
9.2.2016 vjj 29 základ vytvoření "podadresáře" na libovolné úrovni pstorage->createstorage (, &psubstorage) ; vytvoření datového "souboru" na libovolné úrovni pstorage->createstream (, &pnewsubstream) ;
9.2.2016 vjj 30 práce s "podadresářem" psubstorage->enumelements (... ) ; psubstorage->openstorage ("Name",, &pnewsubstream) ; psubstorage->openstream ("Name",, &pnewsubstream) ;
9.2.2016 vjj 31 práce s "podsouborem" psubstream->write (... ) ; psubstream->read (... ) ;
COM structured storage 9.2.2016 vjj 32
9.2.2016 vjj 33 Object in Structured Storage Klient Dokument Server pidataobject IDataObject Soubor IRootStorage IPersistStorage IStorage Object IStream
9.2.2016 vjj 34 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 ; 9.2.2016 vjj 35
9.2.2016 vjj 36 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 (... ) ;
9.2.2016 vjj 37 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 (... ) ;
9.2.2016 vjj 38.NET & Compound File http://openmcdf.sourceforge.net/
9.2.2016 vjj 39 konec (?) to byly jen dva jednoduché protokoly, COM jich má celkem dost
COM protokoly 9.2.2016 vjj 40
COM backgrounds 9.2.2016 vjj 41
9.2.2016 vjj 42 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
9.2.2016 vjj 43 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
9.2.2016 vjj 44 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
9.2.2016 vjj 45 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"
9.2.2016 vjj 46 UUID, GUID, CLSID, IID celý svět vs. celý vesmír
9.2.2016 vjj 47 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 ;
9.2.2016 vjj 48 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 ); 9.2.2016 vjj 49
GUIDgen.exe 9.2.2016 vjj 50
9.2.2016 vjj 51 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 9.2.2016 vjj 52
9.2.2016 vjj 53 struktura COM object DATA FUNCTIONS FUNCTIONS FUNCTIONS
interface 9.2.2016 vjj 54
9.2.2016 vjj 55 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
9.2.2016 vjj 56 struktura COM object FUNCTIONS FUNCTIONS FUNCTIONS DATA IUnknown IDataObject IDropSource e.g. text
9.2.2016 vjj 57 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); }
9.2.2016 vjj 58 konstruktor, AddRef mujobjekt::mujobjekt( void ) { m_cref = 0L; return; } STDMETHODIMP_(ULONG) mujobjekt::addref( ) { return ++m_cref; }
9.2.2016 vjj 59 Release STDMETHODIMP_(ULONG) mujobjekt::release( ) { if ( --m_cref == 0 ) { delete this ; g_cobj-- ; return 0 ; } return m_cref ; }
9.2.2016 vjj 60 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
9.2.2016 vjj 61 vytvoření instance COM objektu kompletní COM objekt = COM objekt + ClassFactory
9.2.2016 vjj 62 Vytvoření jediné instance CoCreateInstance ((REFCLSID) CLSID_objekt, (IUnknown*) punkouter, (DWORD) CLSCTX_typ_modulu, (REFIID) IID_rozhraní, (PPVOID) &pirozhraní) ;
9.2.2016 vjj 63 Vytvoření více instancí CoGetClassObject (CLSID_objekt, CLSCTX_typ_modulu, NULL, IID_ClassFactory, (PPVOID) &piclassfactory) ; piclassfactory->createinstance (...
9.2.2016 vjj 64 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)
9.2.2016 vjj 65 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 ; } 9.2.2016 vjj 66
9.2.2016 vjj 67 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í 9.2.2016 vjj 68
9.2.2016 vjj 69 data + methods COM object FUNCTIONS FUNCTIONS FUNCTIONS DATA IUnknown IDataObject IDropSource e.g. text C++ object C# object C
9.2.2016 vjj 70 data + methods COM object FUNCTIONS DATA IUnknown e.g. text C++ object COM object FUNCTIONS IDataObject C# object COM object FUNCTIONS IDropSource C
9.2.2016 vjj 71 jednoduchý objekt IUnknown QueryInterface AddRef Release InterfaceC InterfaceD
9.2.2016 vjj 72 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
9.2.2016 vjj 73 agregovatelný objekt Vnější C++ objekt : IUnknown QueryInterface AddRef Release Vnitřní C++ objekt : IUnknown QueryInterface AddRef Release InterfaceC InterfaceD
9.2.2016 vjj 74 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
9.2.2016 vjj 75 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?
9.2.2016 vjj 76 Remoting, Automation Remoting Programability Automation
9.2.2016 vjj 77 Remoting, Automation Remote Control Remoting Programability Automation
9.2.2016 vjj 78 Remoting, Automation Remote Control dálkové ovládání Remoting Programability Automation
9.2.2016 vjj 79 Remoting, Automation Remote Control dálkové ovládání Remoting používání dálkového ovládání Programability Automation
9.2.2016 vjj 80 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
9.2.2016 vjj 81 zpřístupnění objektu publikace informací o implementovaných metodách v implementovaných rozhraních IDispatch Type Library duální rozhraní
9.2.2016 vjj 82 IDispatch rozhraní umožňující dynamické zjišťování vlastností objektu cf..net Manifest & Reflection
9.2.2016 vjj 83 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
9.2.2016 vjj 84 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
9.2.2016 vjj 85 Type Library informace o implementovaných (nestandardních) metodách lze publikovat v Type Library cf..net Manifest & Reflection
9.2.2016 vjj 86 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 ; } } ;
9.2.2016 vjj 87 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