Az assembly-elv szinte a legnagyobb, ha nem a legnagyobb újítás a .NET rendszerben. Az assembly-k kulcsszerepet játszanak a .NET rendszerben történő programozásban. Ennek oka a funkcionalitásukban keresendő, melyek közül néhány a következő:
- Tartalmazzák a .NET futtatórendszer (CLR) által végrehajtandó kódot. Ez a Microsoft köztes nyelven írt kód (MSIL), mely egy hordozható, futtatandó fájlban található, nem fut, ha nem kapcsolódik egy assembly manifeszt-hez. Megjegyzendő, hogy minden assembly egy kezdőponttal rendelkezik (DllMain, WinMain, vagy Main).
- Az assembly egy olyan egység, melynek eléréséhez bizonyos jogok szükségesek, és annak futása is bizonyos jogokat követel meg a rendszerben. A rendszer biztonsága így jobban kézben tartható.
- A típusok tartalmazzák azt az információt is, hogy mely assembly-ben találhatóak. Ennek eredményeképpen a típusok önleíróak.
A forráskódok fordításakor generált assembly tehát sokkal több, mint egy puszta állomány, a .NET rendszer kifinomult logikai egysége. A cikkben bemutatandó programokkal analizálhatjuk is őket, hasznos információkat tudva meg egy-egy egységről.
Ildasm.exe alkalmazás
Az Ildasm.exe alkalmazás a Visual Studio.NET MSIL Disassembler programja, melynek inputja egy IL kódot hordozó assembly, és amely kihámozza ezt a kódot, majd tetszőleges formátumban megjeleníti.
A program alapértelmezésben a következő elérési útvonalon található: <winroot>:\\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin\ildasm.exe.
Vizsgáljuk meg, hogy milyen parancssori opciókat adhatunk meg akkor, ha a program parancssori változatát használjuk. A program hívásának szintaxisa a következő:
ildasm [opciók] [fájlnév] [opciók]
A következő opciók csak .DLL, .EXE, .OBJ és .LIB állományok esetén alkalmazhatóak.
| Opció |
Magyarázat |
| /output: filename |
A kimenet egy .IL kiterjesztésű fájlba menthető, nem egy dialógusablakban, vagy a konzol képernyőjén jelenik meg. |
| /text |
A kimenet a konzol ablakba kerül. |
| /? |
Help megjelenítése. |
Vannak csak .DLL és .EXE állományok esetén alkalmazható opciók is.
| Opció |
Magyarázat |
| /visibility: vis |
A kódból csak a megadott láthatóságú típus vagy tag kerül feldolgozásra. A megadható kulcsszavak közül néhány: PUB-public, PRI-private, ASM-assembly, stb. |
| /item: osztály [::metódus] |
Megadható, hogy csak a specifikált deklaráció visszafejtése történjen meg. Például a példánk ATLibrary.dll assembly-jéből az ATClass osztály GetSum metódusa a következőképpen fejthető vissza: ildasm.exe /item:ATClass:GetSum… |
A példánkban a következő parancssorral tudjuk az ATLibrary.dll-ben tárolt assembly-t visszafejteni, és generálni egy ATLibrary.il nevű állományt, benne az MSIL kóddal:
Ildasm.exe <útvonal>:\\ATLibrary.dll /output:ATLibrary.il
Ezt követően a generálódott állomány tetszőlegesen szerkeszthető manuálisan, majd visszaalakítható futtatható állománnyá.
A program nevét írva be a Command Prompt-ba, elindíthatjuk a grafikus felülettel rendelkező program-változatot. Itt vizuális elemek segítségével ismerhetjük meg a betöltött assembly meta-adatait, valamint a fájl szerkezetét.
A program View menüjében megadható, hogy milyen tulajdonságú részek jelenjenek meg a fastruktúrában, és melyek ne.
Egy tetszőleges elemre kattintva megjelenik annak IL kódja, vagyis az az utasítás sorozat, melyet a CLR végrehajt.
A File – Dump menüpontot választva megjelenik egy dialógusablak, melyben megadhatunk néhány paramétert a kód visszafejtéséhez. Az OK gombra kattintva az assembly mappájában megjelenik az assembly nevével megegyező nevű, de .IL kiterjesztésű állomány.
Ilasm.exe alkalmazás
A segédprogrammal a fenti módon generált .IL állományból létrehozhatunk egy futtatható állományt.
A program a következő mappából fut:
<winroot>:\\WINDOWS\Microsoft.NET\Framework\v1.0.3705\ilasm.exe.
A program szintaxisa a következő:
ilasm [opciók] állománynév [[opciók]állománynév...]
A program futtatásakor a következő opciók adhatók meg, finomítva a műveletet.
| Opciók |
Magyarázat |
| állománynév |
Az .IL állomány neve. |
| /clock |
A folyamat bizonyos részműveleteinek ideje mérhető ennek megadásával. |
| /debug |
A generálandó állomány tartalmaz DEBUG információkat is. |
| /exe |
EXE állomány generálódik. |
| /dll |
Dinamikus könyvtár generálódik. |
| /key: kulcs fájl |
Megadható egy kulcs-állomány, mellyel aláírhatjuk a generálandó assembly-t. Ekkor keletkezik egy ún. „Strong named” assembly. |
| /output: fájlnév |
Specifikálható a generált állomány neve. |
A fent generált ATLibrary.il állományból a következő parancssorral hozható létre egy assembly:
Ilasm.exe <útvonal>:\ATLibrary.il /dll
A visszafejtett assembly kódja tehát szabadon szerkeszthető, vagyis anélkül változtathatjuk meg egy modul működését, hogy újrafordítanánk a forrást, sőt arra nincs is szükségünk. Ennek eredményeképpen egy olyan gépen, ahol csak a .NET Framework fut, a rendszerben található assembly-k működése anélkül befolyásolható, hogy fel kellene telepítenünk a keretrendszert.
Példa alkalmazás
A mellékelt példában az ATLibrary projekt assembly-jét fogjuk visszafejteni, módosítani, majd módosítva meghívni.
A projekt ATClass osztályának kétparaméteres a konstruktora, vagyis példányosításkor megadható két szám, melyek az osztály két tagváltozójába kerülnek. Az osztály GetSum nyilvános metódusával a két szám összeadható, majd eredményük egy karakterláncban megkapható.
A hívó kliensben az osztályt példányosítjuk, majd meghívjuk a metódust, a felületen megadott két szám összeadásához. Ehhez az Összeadás gombot kell megnyomni.
ATLibrary.ATClass a = new ATLibrary.ATClass(Convert.ToInt32(textBox1.Text),Convert.ToInt32(textBox2.Text));
textBox3.Text = a.GetSum();
A hívó alkalmazás mappájában, a NewDll alkönyvtárban elhelyeztük a DLL visszafejtett IL kódját, melyben megváltoztattuk a metódus deklarációját, a public láthatóságot privat-ra változtattuk.
Az ilasm.exe programmal generáltunk egy új DLL-t, mely szintén a NewDll mappában található. A másik gombra kattintva ezt a DLL-t hívjuk, külső assembly-ként futtatva azt.
Első lépésként létrehozunk egy Assembly objektumot a fájlból.
Assembly a = Assembly.LoadFrom(Directory.GetParent(Directory.GetParent(Directory.GetParent(Application.StartupPath + "\\ATLibrary.dll").FullName).FullName).FullName + "\\NewDll\\ATLibrary.dll");
Kinyerjük belőle az osztály típusát:
Type t = a.GetType("ATLibrary.ATClass");
Létrehozzuk a két bemenő paramétert, és elhelyezzük őket egy objektum-tömbben.
int op1 = Convert.ToInt32(textBox1.Text);
int op2 = Convert.ToInt32(textBox2.Text);
object[] p = new object[2];
p[0] = op1;
p[1] = op2;
Példányosítjuk az osztályt.
object obj = Activator.CreateInstance(t,p);
Majd a típus ismeretében meghívjuk a megadott metódust, mely már privát.
textBox3.Text = t.InvokeMember("GetSum",BindingFlags.InvokeMethod,null,obj,null).ToString();
A futtatás kódját egy TRY-CATCH blokkba ágyaztuk, így a generálódó kivételt elkaphatjuk. Ez természetesen bekövetkezik, hiszen a kódban nem lehet meghívni egy nem nyilvános metódust.