fel
le

Az Assembly (DLL)

Amikor egy nagyobb programot készítünk, gyakori, hogy nem minden részét egyedül készítjük. Felhasználhatjuk saját cégünknél dolgozó más programozók munkáját, saját korábbi projectjeink kódjait, de akár más, külső cégek programozóinak kódjait is.

Amikor Windows programot írunk, akkor például erősen támaszkodunk a Microsoft programozóinak munkájára - hiszen a programunk ablakos felületével kapcsolatos kódokat nem mi írjuk, hanem hivatkozunk a Windows mint operációs rendszer kódrészeire.

Az egyik legjobb módszer más programozók kódjainak felhasználására a DLL-ek használata.

A DLL-ek (Dynamic Link Library) olyan file-ok, melyek lefordított kódot tartalmaznak. Az egyik leglényegesebb különbség az EXE (Executable) és a DLL között, hogy ez utóbbi önállóan nem futtatható file, ugyanis jellemzően nem tartalmaz Main() függvényt.

Win16 és Win32 DLL

A DLL technológia már igen régen használatban van a Windows operációs rendszereken. A Windows 3.1-es verziójával már rengeteg .dll file települt fel a gépünkre. Az újabb verziójú, 32 bites Windows-okkal érkező .dll-ek is igen hasonló belső szerkezettel, és felhasználási területtel rendelkeznek.

Ezen .dll file-ok belsejében függvények találhatóak, melyeket bármilyen más program elvileg használhat a saját kódjának kiegészítéseképpen. Vagyis a program írása során is ezen függvényekre hivatkozik, melyek már meg vannak írva, le vannak tesztelve. Egy ilyen .exe file e miatt egyrészt kisebb méretű lesz (kódhossz-csökkentés), de futásához szükséges (értelemszerűen), hogy a célgépen is ott legyen a hivatkozott .dll file.

Egy apró problém van ezekkel a .dll file-okkal: tartalmuk nem önleíró! Vagyis legfeljebb az deríthető fel egy "ismeretlen" dll file esetén, hogy milyen "nevű" függvények találhatóak benne. De sem a függvények paramétereiről, sem a visszatérési érték típusáról, sem magáról a függvény által elvégzett feladatról nem tartalmaz információt (ez utóbbira a függvény nevéből lehet esetleg következtetni). A fentieken túl azt sem lehet tudni, hogy a függvény milyen módon jelzi a hibás működést, milyen hibakódokat adhat vissza, és melyiknek mi a jelentése, stb.

Természetesen amennyiben nem csak maga a .dll file, hanem annak dokumentációja is rendelkezésre áll (esetleg kis példaprogramokkal megtámogatva), úgy a helyzet egészen más: akkor a .dll file-t könnyedén be tudjuk illeszteni a saját programunkba.

Problémák: a fentieken túl állandó problémát jelentett, hogy a Win32 DLL-ek esetén ismerni kellett azt is, hogy az adott DLL mely programozási nyelven készült. Ugyanis a különböző nyelvek eltérő módon vagy bithosszon ábrázolták a különböző egyszerű adattípusokat (integer, double), de legfőképpen különböztek a string-ek ábrázolásában. Összetett adattípusokkal (vektor, rekord) még több problémára lehetett számítani. Ezért jellemző volt, hogy egy adott DLL-t csak ugyanazon a programozási nyelven készülő projectben lehetett problémamentesen felhasználni.

.NET DLL

A helyzet sokat változott a .NET esetében. Az itteni .dll-ek csak funkcióban hasonlítanak a fentiekben ismertetett Win32 (natív) dll-ekre. A .NET DLL-jei ...

  • nem függvényeket, hanem osztályokat, általánosabban típusokat tartalmaznak. Ezen osztályok metódusokat, mezőket, property-ket tartalmaznak. A saját kódunkban a DLL-ben lévő osztályszintű metódusokat közvetlenül hívhatjuk meg. De van lehetőség az osztályok példányosítására, így a példányszintű metódusokat is használhatjuk. De arra is van mód, hogy saját kódunkban egy, a DLL-ben definiált osztályból gyermekosztályt készítsünk.
  • önleíróak: vagyis egy ilyen DLL-ben lévő névterek, osztályok, azokban lévő mezők, metódusok nevei, típusai, esetleg paraméterei könnyedén felderíthetőek.
  • a DLL-ek is .NET-ben kerültek leprogramozásra, vagyis egyrészt szintén managelt kódnak minősülnek (pl. a Garbage Collector felügyelet alá esnek), másrészt teljesen lényegtelen, milyen alapnyelven készültek, mivel biztosan meg kell feleljenek az Common Language Specification-nak (CLS). Ennek megfelelően tetszőleges más .NET-es nyelven készülő projektben is gond nélkül beilleszthetőek.

A .NET-es DLL-eket ennek megfelelően már nem is dll-eknek hívják, hanem szerelvényeknek (assembly) megkülönböztetésül a hagyományos (natív) Win32-es DLL-ekkel szemben. Ugyanakkor a lefordított file-ok kiterjesztése továbbra is .dll.

.NET DLL készítése

Amikor DLL-t készítünk, a project típusát Class Library-t kell választani a project típusaként:

1. ábra: A DLL project tipus

A Visual Studio által felajánlott kód nem tartalmaz Main() függvényt, mivel ilyet a DLL jellemzően nem tartalmaz. Lehetőségünk van a szokásos módon kódolni, valamely névtérben osztályokat készíteni, azokba a szokásos módon metódusokat, property-ket, mezőket, konstruktorokat készíteni.

2. ábra: A DLL forráskódja

Javasolt a kódba dokumentációt is beszúrni. A dokumentációs megjegyzések nem // perjel, hanem /// perjelek mögé vanak rejtve. Amikor valamely mező, metódus, property elé ilyen három perjelet írunk, a Visual Studio automatikusan <summary>, és hasonló elemeket jelenít meg. Ez XML stílusú kommentezés. A fenti példában látható, hogy lehetővé válik a metódus feladatának leírása (<summary> és </summary> között), a metódus paramétereinek jelentésének leírása (<param name="a"> és </param> között), valamint a metódus visszatérési értékének leírására (<returns> és </returns> között).

Ha ily módon felkommentezzük a DLL kódját, akkor ezen dokumentáció nem a lefordított DLL kódjába kerül be, hanem külön dokumentációs file-ba. Ennek nevét és helyét, a project beállításoknál lehet megadni (jobb egérgombos lebegőmenü):

3. ábra: DLL project beállitások

Ki kell pipálni a BUILD beállításoknál az XML Documentation file lehetőséget, és ha szükséges, módosítani a felajánlott mentési könyvtárat és filenevet:

4. ábra: XML dokumentáció generálása

A megadott XML file-ba kerülnek a forráskódból kiemelt dokumentációs kommentek. Ez a DLL-t felhasználó programozó számára igen hasznos lesz később.

.NET DLL belsejében a public class

Amikor DLL-t készítünk, osztálygyűjteményt készítünk. A DLL-ek osztályokból állnak. Ezek közül van olyan osztály, amelyet külső felhasználásra szánunk (ők alkotják a DLL lényegét), de lehetnek olyan osztályok is, amelyek mintegy segédosztályként szolgálnak, és nem kívánjuk őket a DLL-t felhasználó programozó számára elérhetőnek deklarálni.

A DLL-ből a külvilág (felhasználó kód) felé publikus osztályokat meg kell jelölni a public jelzővel. Amelyek segédosztályként szolgálnak, azokat pedig nem kell ezzel megjelölni (az alapértelmezett módosító itt is a private). Az ilyen osztályokat a DLL-t felhasználó kód nem "látja", és nem tudja felhasználni semmilyen formában. Természetesen minden DLL-ben legalább egy publikus osztálynak lennie kell, hiszen ennek hiányában a DLL tartalma a külvilág szempontjából "üres" lenne.

public class FontosOsztaly
{
  ...
}

class segedOsztaly
{
  ...
}
 

Amennyiben publikus osztályt készítünk, néhány szabályt figyelembe kell venni:

  • a publikus osztály ősosztályának is publikusnak kell lennie! Erre akkor kell különösen ügyelni, ha az ősosztály is ugyanebben a DLL-ben található
  • a publikus osztály publikus részeinek típusai is publikusak kell legyenek. Pl. a függvények visszatérési érték-típusa, paramétereinek típusai, property-k típusai, stb.

.NET DLL belsejében internal védelmi szint

Nemcsak az osztályok készítésénél kell figyelni a védelmi szintekre, az osztály belsejében lévő elemekre (property, metódus, mező, stb.) is van kiegészítő szabály. A fenti elemekre egy internal (belső) kiegészítő védelmi szint módosító csatolható. Az internal elemek a DLL belsejére nézve public-ként viselkednek, de a DLL-en kívüli kódra nincs hatással.

Ennek megfelelően az alábbi kombinációk képezhetőek védelmi szintre:

  • private, protected, public: ezek a szokásos viselkedésüek, egyaránt vonatkoznak a DLL-en belülre és kívülre, egyformán értendők mindkét terület felé
  • internal private: ez azt jelöli, hogy ez az elem a DLL belsejében public-ként viselkedik, a DLL-n kivülre azonban nem terjed a határköre, így nem elérhető
  • internal protected: az azt jelöli, hogy az elem a DLL belsejében public, kifelé protected.

Vegyük észre, hogy internal public nincs, mivel ez azt jelentené, hogy a DLL belsejében, és kifelé is public-ként kell az elemnek viselkednie, de ezt a viselkedést az egyszerű public is tudja produkálni, az internal nélkül is.

.NET DLL felhasználása

Amikor valamely projectünkbe egy .NET DLL-t (és nem Win32 DLL-t!!!) kívánunk felhasználni, első lépésként hozzá kell azt adni a projectünkhöz. Ezt megtehetjük a Solution Explorer-en, a References részen. Jobb egérgombbal felbukkanó lebegőmenüben az Add reference menüpontot kell választani:

5. ábra: DLL hozzáadása a referencia listához

Ennek hatására egy párbeszédablak bukkan elő, amelyben kiválaszthatjuk a projektünkhöz hozzáadható DLL-t. Ennek több módja is van, attól függően, milyen jellegű DLL-t kívánunk hozzáadni:

6. ábra: Rendszer DLL hozzáadása a listáról

Az első fülön kapjuk meg a.NET rendszerrel szállított DLL-eket. Ezek között szerepelnek a Base Class Library-t alkotó DLL-ek is. Ezek nevei jellemzően System.*.DLL. Mellettük mindig szerepel a DLL verziószáma is.

A COM fülön szerepelnek a .NET elődjének is tekinthető COM (Component Object Model) technológiát használó DLL-ek, amelyek fel vannak telepítve és be vannak regisztrálva a számítógépünkön. Ezek használata .NET-ben lehetséges, de több probléma is van velük kapcsolatosan, az egyik legfontosabb, hogy ha programunkat másik számítógépen is futtatni szeretnénk, nem garantált, hogy azon is fel lesz majd installálva ez a DLL.

A Project fülön a saját solution-ben szereplő Class Library jellegű projectjeink szerepelnek. Innen könnyedén hozzá tudunk adni saját DLL-t.

A Browse fülön a szokásos tallózási lehetőséggel megkereshetünk a háttértárolóról bármely DLL-t, és hozzáadhatjuk azt a projecthez.

A sikeres hozzáadást követően a DLL rákerül a References listára, amelyet kinyitva tájékozódhatunk arról, a futtatható file-unk milyen külső DLL-ektől függ. Amennyiben jobb egérgombbal rákattintunk egy ilyen DLL-re a listán, a lebegőmenüben kiválaszthatjuk a View in Object Browser lehetőséget:

7. ábra: Object Browser indítása

Az Object Browser egy objektum-tallózó. Felnyitja a megadott DLL-t, így lehetőségünk van megtekinteni, milyen névterekből áll, melyik névtérben milyen objektum-osztályok találhatóak, azok milyen részekből (mezők, metódusok, property-k) áll. Egy metódusra kattintva kiíródik annak paraméterezése, és visszatérési értékének típusa is:

8. ábra: Object Browser képernyője

Mint látszik, amennyiben a DLL-ket készítettünk dokumentációs XML file-t is, úgy annak tartalma automatikusan feldolgozásra kerül. De nem csak itt lehetünk ennek tanújele, hanem a kód írásakor az editor ablakban is:

9. ábra: A XML dokumentáció műkodés közben

Amennyiben egy DLL-hez utólag kapcsoljuk be az XML dokumentációs file készítését, elképzelhető, hogy azon projektekben, amelyekben ezt a DLL-t előtte adtuk hozzá - el kell távolítani a DLL file-t a referencia-listáról, és újból hozzáadni, hogy a Visual Studio is érzékelje ezt a változást.

Hernyák Zoltán
2013-03-17 19:56:05