Blog gunsmoker-a (átutalás) egy hack - 11 fogadni guid felület a felület referencia

Haq №11: GUID kap felületet a felület referencia

Nemrégiben Randy Magruder megkért egy nagyon érdekes projekt ő dolgozik: Azt akarom csinálni: add, és távolítsa el a támogatott interfészek az osztály futási időben, és hívja őket. Már tett eleget, így tudtam használni a modellt OTAServices modell Delphi továbbítására vonatkozó további kapcsolódási pontok, add hozzá a belső listán, és helyébe a viselkedését QueryInterface. A hívás, hogy visszatérjen a felületet a listából, hanem a szabványos objektum asztalra. Úgy hangzik, mint egy hűvös (és bonyolult) projekt! Majd így folytatja: De ha a hívó fél tudja, csak objektum GUID felület, amire szüksége van, és azt akarja, hogy egy megfelelő felületet, és hívja a módszer hívják, mit tehetek ellene? Én a kiterjesztett RTTI a IInvoker. Nos, nem vagyok benne biztos, hogy meg lehet oldani. AFAIK, nincs egyszerű vetülete az objektum, amely megvalósítja az interfészt, hogy milyen típusú interfész információk. Az egyik megoldás eshet a megvalósítása a vetítési GUID interfészek az információ típusát. És ismét, akkor megtörténhet, hogy tudja a módját, hogy bontsa ki a felület GUID a futásidejű. Lehetővé kell tenni, bár egy kicsit bonyolult.

Talán emlékeznek kódot. Írtam átalakítani a felület hivatkozás egy tárgy munkagépek. Lehetőség van megváltoztatni ezt a kódot egy másik, amely visszatér az eltolás az objektum található, amely a felületen asztal rekord objektum interfészek. Pár ezt a felhívást TObject.GetInterfaceTable PInterfaceTable. tartalmazó felvétel TInterfaceEntry a felület. Összehasonlítjuk a kiszámított eltolás a mező IOffset. találunk egy mérkőzés, és megtudja a területen GUID IID.

Tól System.pas. De persze, ez csak akkor működik a felületek bejelentett a tervező módban.

Ahhoz, hogy elérjük célunkat egyre GUID interfész referencia, vissza kell térnünk ehhez a változáshoz, hanem a kész eredményt (objektum hivatkozás). Változtassuk meg a funkció felett: Mint látható, szinte ugyanazt a kódot, mint fent, de ahelyett, hogy visszatért Egész TObject. függvény nevét egy kicsit „gikovato” - PIMT a rövidítése a mutatót az asztalra interfész módszereket. Ez a speciális „mező” a fordító által generált, amely bekerül egy objektum például, ha kijelentjük, hogy egy osztály megvalósítja egy interfész. A függvény visszaküldi az eltolás a területen. Megjegyezzük, hogy a fordító használja az ADD parancs módosításai Self nyomás -, de valójában, hozzáad egy negatív torzítást. Ezért a kódot érdemes mínusz előtt a visszatérési érték.

Most már átírni az eredeti GetImplementingObject funkció szempontjából az új alprogramok: szép kis funkció - ez volt kedves tőle, hogy távolítsa el ismétlődő kódot. Vegye figyelembe, hogy PAnsiChar - ez az egyetlen (a régi Delphi - prim.per.) Az adatok típusa, amely lehetővé teszi a mutató aritmetika; csak arra használjuk, hogy egyszerűsítse a számítási (prim.per gyakorlat -. hogy mi a baj a típus PChar ebben az összefüggésben?).

Mi már egy lépés választja el attól, hogy GUID interfész (vagy IID - azaz formálisan helyes neve). Most már tudjuk, hogy az eltolás PIMT, de önmagában ez nem túl hasznos. Mi teszi, hogy hasznos - az a tény, hogy tudjuk használni, hogy hasonlítsuk össze tárolt korrekciók részeként InterfaceEntry rekordokat. a fordító által generált összes csatoló végre őket. Amint azt fentebb megállapítottuk, tudjuk használni a TObject osztály és annak (osztály) GetInterfaceTable funkciót, hogy megkapjuk egy mutatót a táblához. Ezzel a tudással tudunk írni egy függvényt, amely megpróbálja megtalálni egy bejegyzést InterfaceEntry. a megfelelő interfész jelzet: Először is, mi a szolgáltatás használata rutinok előállítása céljából a fentiekben hivatkozás egy tárgy és PIMT torzítás. Akkor megyünk át az osztály, és a szülő a keresési InterfaceEntry. amely ugyanolyan offset a PIMT területen. Ha találunk egy mérkőzés, visszatérünk egy mutatót a megtalált rekordot. Ez a bejegyzés tartalmazza PIMT ofszet és IID. Írjunk egy egyszerű wrapper függvényt, amely beolvassa a IID: Ez - ez nagyon egyszerű. Tehát most már az összes funkciót és az összes kiegészítő kódot - csak azt kell tesztelni, hogy működik. Itt van az én egyszerű teszt alkalmazás: Ez a program kijelenti közvetítői eljárás Foo és az osztály, hogy végrehajtja. Ez létrehoz egy példányt - kiosztva az interfész referencia. Kezdeni, teszteljük GetImplementingObject funkciót, és megjeleníti a nevét a végrehajtási osztály felületen. Akkor hívjuk GetInterfaceIID háromszor és kiírja az GUID. Az első hívás, használjuk a megfelelő interfész közvetlenül - ha a kód helyes, ezt kell dolgozni. A második hívás átadjuk a felület utalás IUnknown link. Attól függően, hogy a fordító hajtja végre a megbízást közötti kapcsolatok kompatibilis interfészeket, akkor működik, vagy nem működik. Lássuk. És még egy harmadik alkalommal, mi hozzárendel egy hivatkozás egy új példányát az osztálynak IUnknown. Ebben az esetben, azt várjuk, hogy megkapja (abban az értelemben, a kimenet a konzolra) GUID IUnknown.

Ha a IUnknown felületen keresztül kerül kiosztásra, mint. akkor azt kapjuk, különböző eredményeket: Ebben az esetben, megkapjuk a következő következtetést: Kaptunk IID IUnknown. ehelyett IMyInterface. Ennek az az oka, hogy a fordító generál a -cast a következő: Ez a kiviteli használ kód kérése System._IntfCast. elvégzi a megbízás és a konverziós - és annak ellenére, hogy kód, amely felhívja QueryInterface. az átalakításhoz, arra a következtetésre jutunk, hogy ez a hívás visszatér egy másik felület referencia (ne felejtsük, a mező PIMT) - amely TInterfacedObject adunk IUnknown felület (aka IInterface). Persze, ez a felület az IID a saját, valamint a IID az eredeti, úgyhogy Randy akart bejutni a kérdést, örökre elveszett.

Hosszú karakterláncot hex, ami a képviselete a IID nem nagyon „emberi szemmel olvasható”. Néhány interfészek (különösen - COM-interfészek), és azt írja IID „emberi szemmel olvasható” nevek a rendszerleíró adatbázisban. Például HKEY_LOCAL_MACHINE \ SOFTWARE \ Classes \ Interface \ = IUnknown. Megnézheti a regisztrációs felületen a registry-ben, így olvasható a felület nevét annak IID. Ezt a műveletet még az edzés olvasók;)