Стандартні угоди в COM. Класифікація COM-серверів
Завантажити презентаціюПрезентація по слайдам:
Стандартні угоди в COM. Класифікація COM-серверів 2003 (Курс “Інформаційні технології”) Стандартні угоди в COM
Зміст Угода про підтримку вказівників на інтерфейси Угода про реалізацію викликів процедур (функцій) Угода про тип інтерфейсних методів Класифікація COM-серверів Маршалінг даних Стандартні угоди в COM
Угоди в COM Загалом, COM-технологія базується на використанні цілого ряду угод: від угод стосовно до двійкового коду (двійковий стандарт COM) до угод про стандартизацію інтерфейсів шляхом стандартизації їх функціональності (зокрема, стандартними в COM можна вважати інтерфейси IUnknown, IDispatch, ITypeInfo, ITypeLib, IMarshal, IFactory, IFactory2 тощо). Стандартні угоди в COM
Угода про підтримку вказівників на інтерфейси Механізм підтримки COM забезпечує встановлення зв’язку клієнта із сервером, як правило, шляхом отримування вказівника на інтерфейс. Зокрема, це стосується випадків використання функцій CreateComObject та CreateOleObject: function CreateOleObject(const ClassName:string):IDispatch; function CreateComObject(const ClassID:TGUID):IUnknown; За стандартом COM перші 4 байти внутрішнього представлення будь-якого інтерфейсу є вказівником на таблицю vtable, яка містить вказівники (теж 4-байтні) на функції (методи) інтерфейсу: Стандартні угоди в COM
Угода про реалізацію викликів процедур (функцій) Усі виклики інтерфейсних процедур чи функцій мають реалізовуватися в стилі Pascal. Суть угоди полягає в тому, що функція (процедура) сама має вибирати параметри зі стека перш, ніж повернути управління в місце виклику. У C/C++ традиційно діє угода, що за очищення стека, навпаки, відповідає функція, яка викликає, а не та, яку викликають (така угода спрощує реалізацію функцій зі змінною кількістю параметрів). Відповідно в С/С++ при описуванні інтерфейсних методів вимагається використовувати конструкцію _stdcall. Стандартні угоди в COM
Угода про тип інтерфейсних методів У COM за винятком дуже рідких випадків (а саме функцій AddRef та Release інтерфейсу IUnknown) функції повертають значення типу HRESULT. Дані типу HRESULT (від handle of result – дескриптор або описувач результату) є 32-розрядні дані. Старший біт HRESULT використовується для фіксації, чи успішно виконана функція: якщо старший біт значення HResult встановлений в 1, то виконання відбулося некоректно. Інші біти дозволяють у такому випадку визначити причину невдачі. Важливо відслідковувати успішність виконання не тільки COM API функцій, а й функцій інтерфейсів. Перевагою такого підходу є можливість перехопити не оброблювані виняткові ситуації до повернення управління у місце виклику: при виникненні не оброблюваної виняткової ситуації вона просто фіксується у результуючому значенні функції (типу HRESULT ). Така угода стосовно до Delphi втілена в угоду про виклики safecall: усі інтерфейсні методи повинні у програмі визначатися як safecall-методи (задаватись з описувачем safecall). Стандартні угоди в COM
Угода про тип інтерфейсних методів (приклад) Приклад (фрагмент з Pr_Dlg_TLB)такого опису: IConv_Dlg = interface(IDispatch) ['{EFAF2364-017A-11D8-A3E5-444553540000}'] function Conv(USD: Double): Double; safecall; end; Функція Conv за угодою про safecall-методи фактично буде компілятором розглядатись у відповідності з описом function Conv(USD: Double, out value Double): HRESULT; Більш того, фактично буде модифіковуватись і процедурний блок функції Conv шляхом створення зовнішньої оболонки try-except: try … Result:=S_OK; except Result:=E_UNEXPECTED; end Стандартні угоди в COM
Угода про тип інтерфейсних методів. Константи HRESULT У Delphi тип HResult визначається як Longint (у модулі Windows). Деякі константи типу HResult описуються в модулі Windows: const { HRESULT value definitions } { Success codes } S_OK = $00000000; NOERROR = 0; { Catastrophic failure } E_UNEXPECTED = $8000FFFF; (* непередбачуваний*) { Not implemented } E_NOTIMPL = $80004001; { No such interface supported } E_NOINTERFACE = $80004002; { Ran out of memory } E_OUTOFMEMORY = HRESULT($8007000E); Стандартні угоди в COM
Угода про тип інтерфейсних методів. Функції Succeeded та Failed Для відслідковування коректності виконання інтерфейсних методів у Delphi введено додаткові засоби. Зокрема, в модулі Windows визначено дві функції - Succeeded і Failed, що сприймають HResult як параметр і повертають значення типу BOOL, яке визначає, коректно завершилося виконання метода (із значенням S_OK) чи ні. function Failed(Status: HRESULT): BOOL; begin Result := Status and HRESULT($80000000) 0; end; Приклад: If Failed(MyCOMObject.Function1) then begin ShowMessage(‘Не можливо виконати Function1’); Exit end; If Failed(MyCOMObject.Function2) then begin ShowMessage(‘Не можливо виконати Function2’); Exit end. Стандартні угоди в COM
Угода про тип інтерфейсних методів. Процедура OleCheck Ще зручніше використовувати процедуру OleCheck (з модуля ComObj), яка “помилкові” значення HResult перетворює у виняткові ситуації. Синтаксис викликів методів із використанням OleCheck має вигляд: OleCheck(SomeFunctionThatReturnsHResult); і, наприклад, замість зазначеного вище фрагмента з перевірками If можна скористатися більш короткими операторами (з OleCheck): OleCheck(MyCOMObject.Function1); OleCheck(MyCOMObject.Function2). Стандартні угоди в COM
Класифікація COM-серверів та угоди про маршалінг даних COM забезпечує прозорість доступу та прозорість місцерозташування. Проте доступ до інтерфейсних методів та забезпечення їх виконання може вимагати різних засобів (механізмів) COM, залежно від того, де сервер розташований. Можливі варіанти відповідають наступній класифікації серверів: Внутрішній сервер (in-process server) Зовнішній або локальний сервер (out-of-process server або local server) Віддалений сервер (remote server) Стандартні угоди в COM
Внутрішній сервер Внутрішній сервер (in-process server) - це бібліотека (DLL), яка запускається в тому ж процесі, що і клієнт, а отже у цьому випадку використовується єдиний і для клієнта, і для сервера адресний простір. Таким чином, клієнт взаємодіє з in-process сервером, використовуючи прямі виклики до інтерфейсу COM. Стандартні угоди в COM
Зовнішній та віддалений сервери Зовнішній або локальний сервер (out-of-process server або local server) - це інший програмний додаток (EXE-модуль), який виконується в іншому процесі, але на тій же машині, що і клієнт. Пригадаємо, що кожний процес оперує “власною” віртуальною пам’яттю, має “власну” адресацію. Тому виклик в одному процесі процедури з іншого процесу вимагає, грубо кажучи, додаткових засобів, які власне і забезпечує механізм COM. Віддалений сервер (remote server) - це програмний додаток, що виконується на іншій машині в мережі. У цьому випадку використовується механізм distributed COM (розподілений COM, DCOM), щоб забезпечити клієнта доступом до інтерфейсів і можливістю взаємодіяти з сервером. Зовнішній і віддалений сервери відрізняються тим, що використовуються різні типи міжпроцесного зв'язку: використовується COM, щоб спілкуватись з локальним сервером і DCOM, щоб спілкуватись з віддаленою машиною. Стандартні угоди в COM
Використання повноважних представників (proxy) Коли серверний і клієнтські процеси є різними процесами (на одній або на різних машинах), загалом використовується proxy (повноважний представник), щоб забезпечити виклики інтерфейсних методів. Повноважний представник знаходиться в тому ж процесі, що і клієнт, і з точки зору клієнта, весь інтерфейс надається саме повноважним представником. Повноважний представник отримує виклик від клієнта і передає його далі - об'єкту сервера. Однією з найважливіших задач, що при цьому виконує proxy, є маршалінг даних. На сервері повноважний представник (але вже клієнта!) має назву stub (пень, заглушка). Він, зокрема, забезпечує демаршалінг отриманих від клієнта даних. (Результати запитів, навпаки, підлягають маршалінгу стабом на боці сервера і демаршалінгу, що здійснюється проксі на боці клієнта). Стандартні угоди в COM
Маршалінг даних Маршалінгом (marshaling) прийнято вважати процедуру перетворення даних (наприклад, клієнтського запиту) з метою їх подальшої передачі за межі процесу (наприклад, передачі зовнішньому чи віддаленому серверу). Традиційний підхід до проблеми маршалінга і загалом віддалених зв'язків ґрунтується на використанні: стандартизації інтерфейсних зв'язків - стандартизації мови визначення інтерфейсів (IDL); стандартизації даних транспортного рівня (транспортного протоколу); генерації (за IDL-описом інтерфейсів) кодів стабів клієнта і сервера для забезпечення перетворення даних (маршалінг і демаршалінг). (Бажано, щоб така генерація здійснювалась за IDL-описом автоматично). Стандартні угоди в COM
Remote Procedure Calls (RPC) RPC (початок 80-х, Sun Microsystems) - частина стандарту Середовища Розподілених Обчислень (Distributed Computing Environment - DCE), прообраз ОО проміжного шару (middleware): IDL (одна і та сама абревіатура в RPC, COM, CORBA!); UDP (User Datagram Protocol), TCP (Transmission Control Protocol); RPCGEN(Unix RPC) генерує обидва стаби (клієнтський та серверний). Microsoft : MS RPC, IDL (MIDL). Стандартні угоди в COM
Стандартний маршалер автоматизації У багатьох випадках при розробці серверів автоматизації можна не перейматися проблемами маршалінга, покладаючись на стандартний маршалер автоматизації та на майстрів, які враховують можливості стандартного маршалінга. Сумісними з автоматизацією є такі типи Delphi: Smallint, Integer, Single, Double, Currency, TDateTime, WideString, IDispatch, SCODE, WordBool, OleVariant, IUnknown, Byte. Для інших типів можна скористатись варіантами: реалізовувати для кожного такого типу інтерфейс IMarshal; вручну розробляти DLL з proxy/stub (у Delphi відсутні можливості автоматичної генерації proxy/stub); визначати тип в бібліотеці типів - зв’язуючій ланці між клієнтом і сервером; скористатись можливістю кодування до типу, який є сумісним з автоматизацією, та можливістю відповідного декодування. Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Типи Variant та OleVariant Змінні типів Variant та OleVariant дозволяють “зберігати” (“представляти”) значення різних типів, у тому числі не тільки елементарних, зокрема, масивів та посилань. Типи Variant та OleVariant відрізняються лише тим, що останній “підтримує” лише ті з типів, що є сумісними з автоматизацією. З типом Variant пов’язується тип запису з варіантами TVarData, поле VType якого визначає поточний тип даного, що зберігається у змінній типу Variant. Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Тип TVarData TVarData = packed record VType: Word; Reserved1, Reserved2, Reserved3: Word; case Integer of varSmallint: (VSmallint: Smallint); varInteger: (VInteger: Integer); varSingle: (VSingle: Single); varDouble: (VDouble: Double); varCurrency: (VCurrency: Currency); varDate: (VDate: Double); varOleStr: (VOleStr: PWideChar); varDispatch: (VDispatch: Pointer); varError: (VError: LongWord); varBoolean: (VBoolean: WordBool); varUnknown: (VUnknown: Pointer); varByte: (VByte: Byte); varString: (VString: Pointer); varAny: (VAny: Pointer); varArray: (VArray: PVarArray); varByRef: (VPointer: Pointer); end; Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Змінні типу Variant. Приклади var v1,v2 : variant; . . . v1 := 1.2; v1 :=‘string’; v1 :=‘222’; v2 := 111; ShowMessage(IntToString(v1+v2)); . . . Варіантні змінні стосовно операції присвоювання сумісні з елементарними типами даних Object Pascal (Integer, Real, String, Boolean). Усі потрібні перетворення Delphi виконує автоматично. Функція VarType повертає поточний тип даного: if VarType(v1)=$200C then {масив даних типу variant; «рекурсія»!} Record масив даних типу variant Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. “Маски” VarType const { Variant type codes (wtypes.h) } varEmpty = $0000; { vt_empty } varNull = $0001; { vt_null } varSmallint = $0002; { vt_i2 } varInteger = $0003; { vt_i4 } varSingle = $0004; { vt_r4 } varDouble = $0005; { vt_r8 } varCurrency = $0006; { vt_cy } varDate = $0007; { vt_date } varOleStr = $0008; { vt_bstr } varDispatch = $0009; { vt_dispatch } varError = $000A; { vt_error } varBoolean = $000B; { vt_bool } varVariant = $000C; { vt_variant } varUnknown = $000D; { vt_unknown } varByte = $0011; { vt_ui1 } varStrArg = $0048; { vt_clsid } varString = $0100; { Pascal string; not OLE compatible } varAny = $0101; varTypeMask = $0FFF; varArray = $2000; varByRef = $4000; Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Масиви даних типу Variant. Функції Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Приклад. Сервер SMarsh.dpr (фрагмент основного модуля Unit1) interface . . . procedure GetData(var v:OleVariant); implementation uses Variants; . . . procedure GetData; var s: string; begin { V:=VarArrayOf([’рядок1', 1.5e-5]);} V:=VarArrayCreate([0,1],varVariant); s:= ’рядок2'; V[0]:=s; V[1]:=2.5e-5; end; . . . SMarsh Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Приклад. Сервер SMarsh.dpr (модуль автоматизації) unit Unit2; interface uses ComObj, SMarsh_TLB, StdVcl; type TMarsh = class(TAutoObject, IMarsh) protected procedure GetData(out v: OleVariant); safecall; end; implementation uses ComServ, Unit1; procedure TMarsh.GetData(out v: OleVariant); begin Unit1.GetData(v); end; Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Приклад. Сервер SMarsh.dpr (інтерфейс модуля автоматизації) Стандартні угоди в COM
Маршалінг з використанням типу OleVariant. Приклад. Кліент CMarsh.dpr (фрагмент основного модуля) procedure TForm1.Button1Click(Sender: TObject); var i: integer; V: OleVariant; begin Serv.GetData(V); for i:= VarArrayLowBound(V,1) to VarArrayHighBound(V,1) do begin case VarType(V[i]) of . . . WordToHex(VarType(V[i]))+ V[i] . . . . . . WordToHex(VarType(V[i]))+ FloatToStr(V[i]). . . end end; CMarsh Стандартні угоди в COM
Схожі презентації
Категорії