ПредишенСледващото

Хак №11: GUID получите интерфейс на препратката на интерфейса

Наскоро, Ранди Магрудър ме попита в един много интересен проект върху който работи: Това, което се опитвам да направя: добавяне и премахване на поддържаните интерфейси в класа по време на изпълнение и да ги наричат. Аз вече направи достатъчно, за да мога да използва модела на модела OTAServices от Делфи за предаване на допълнителни интерфейси, да ги добавите към вътрешния списъка и заменя поведението на QueryInterface. призива да се върне на интерфейса от списъка, вместо стандартната таблица обект. Това звучи като на хладно (и сложно) проект! Той продължава: Но ако на обаждащия се знае само обект GUID интерфейс, който той се нуждае и иска да получи подходящ интерфейс и се обадете на метода в него наречен, какво мога да направя по въпроса? Аз използвам на удължения RTTI да IInvoker. Е, аз не съм сигурен как тя може да бъде решен. До колкото знам, не е просто проекция на обекта, който реализира интерфейса, от типа на интерфейса информация. Едно решение може да се състои в реализирането на интерфейси проекция GUID на типа информация. И пак ви се случи да знаете начин за извличане на интерфейса GUID в хода на времето. Тя трябва да е възможно, макар и малко по-сложно.

Може би си спомняте код. Написах да конвертирате позоваването на интерфейса на оръдия на обектите. Възможно е да смените този код в друг, който ще се върне отместването в обекта, който се намира на рекордно обект интерфейси интерфейс маса. Двойка това с покана за TObject.GetInterfaceTable PInterfaceTable. съдържащ запис TInterfaceEntry на интерфейса. Сравняване на изчислен отместването на полето IOffset. можем да намерим един мач и да разберете от IID полето GUID.

От System.pas. Но, разбира се, това ще работи само за интерфейсите, обявени в режим на проектиране.

За да постигнем целта си за получаване на справка GUID интерфейс, ние трябва да се върне към тази промяна, а не крайния резултат (референтен обект). Да променим функцията по-горе: Както можете да видите, това е почти един и същ код, както по-горе, но вместо да се завърне Integer TObject. Името на функцията малко "gikovato" - PIMT е съкращение от показалеца на масата на методи интерфейс. Тази специална "поле", генериран от компилатора, който се поставя в един обект, например, когато се декларира, че един клас реализира интерфейс. Функцията връща изместването на полето. Имайте предвид, че компилаторът използва командата Добави към изменения Self обстановка - но, всъщност, добавя отрицателен наклон. Ето защо кодът е на стойност от минус пред върнатата стойност.

Сега, ние можем да пренапишем оригиналната функция GetImplementingObject от гледна точка на тази нова подпрограми: Красива малка особеност - това е хубаво за нея, за да премахване на дублиращи код. Имайте предвид, че PAnsiChar - това е единственият - Тип данни, което позволява на аритметиката с указатели (в старата Delphi prim.per.); ползваме ги само, за да се улеснят изчисленията (prim.per упражняване -.? какво не е наред с PChar тип в този контекст).

Ние вече сме на една крачка от получаване GUID интерфейс (или IID - това е формално правилното име). Сега можем да се компенсира PIMT, но само по себе си не е много полезно. Какво го прави полезен - е фактът, че можем да го използваме, за да се сравни с компенсации съхраняват като част InterfaceEntry записи. генерирана от компилатора за всички интерфейси, изпълнявани от тях. Както бе посочено по-горе, можем да използваме класа TObject и неговото (клас) GetInterfaceTable функцията за получаване на указател към тази таблица. С това знание, ние можем да напише функция, която се опитва да намери запис InterfaceEntry. подходяща връзка интерфейс: На първо място, ние сме с помощта съчетания услуги горе, за да се получи препратка към даден обект и PIMT пристрастия. След това проверете класа и нейните предци в търсене InterfaceEntry. като същият офсет като поле PIMT. Когато го намерим, ние се върне указател към намери записа. Този пост съдържа PIMT офсетов и IID. Нека да напишете проста функция обвивка, която чете IID: Това е - това е много проста. Така че сега ние имаме всички функции и всички спомагателни код - сега ние само трябва да се провери, че тя работи. Тук ми е просто приложение за изпитване: Тази програма декларира интерфейс с метод Foo и клас, той изпълнява. Той създава инстанция на - това възлагане на еталонната интерфейс. За да започнете, ние тестваме функция GetImplementingObject и показване на името на класа интерфейс за прилагане. След това, което наричаме GetInterfaceIID три пъти и отпечатва полученото GUID. В първата покана, ние използваме съответния интерфейс директно - ако ни код е вярна, това би трябвало да работи. През второто повикване минаваме позоваването на интерфейс за IUnknown връзка. В зависимост от начина на компилатора изпълнява заданието на връзките между съвместими интерфейси, тя може да работи или да не работи. Нека да видим. И все пак за трети път, ние сме възлагане на препратка към нова инстанция IUnknown клас. В този случай, ние очакваме да получим (в смисъл на изхода на конзолата) GUID IUnknown.

Ако интерфейс IUnknown се определя чрез тъй. След това ние получаваме различни резултати: В този случай, ние получаваме следния извод: Имаме IID IUnknown. вместо IMyInterface. Причината е, че компилаторът генерира като -cast както следва: Този пример използва код предизвикателство System._IntfCast. за извършване на прехвърлянето и конверсия - и въпреки неговия код, който призовава QueryInterface. за извършване на преобразуването, ние заключаваме, че този разговор ще се върне различна референтна интерфейс (не забравяйте, на полето PIMT) - което TInterfacedObject добавя към IUnknown интерфейс (известен още като IInterface). Разбира се, този интерфейс е IID на себе си, и IID на оригинала, така че Ранди исках да се получи в своя въпрос, е загубено завинаги.

Дълъг низ в шестнадесетичен, която е представяне на IID, не е много "за четене от хора". Някои интерфейси (по-специално - COM интерфейси) и напишете ги IID "четящи" имена в системния регистър. Например, HKEY_LOCAL_MACHINE \ Software \ класове \ интерфейс \ = IUnknown. Можете да видите интерфейса за регистрация в регистъра за да се получи чете името на интерфейса за своята IID. Тази операция остава като упражнение читатели;)

Подкрепете проекта - споделете линка, благодаря!