Az új osztályon kívül több mindenre is szükségünk lesz. Ilyen például egy új attribútum osztály létrehozása, melyet majd a böngésző sávok létrehozásakor tudunk felhasználni úgy, hogy ezen keresztül adhatjuk meg annak nevét és súgószövegét.
Az új attribútum osztálynak csupán az lesz a feladata, hogy két szöveget tároljon, melyet a konstruktorán keresztül adunk meg.
Ennek az osztálynak a felhasználására, majd a sorozatunk következő részében láthatunk példát.
[AttributeUsage(AttributeTargets.Class)]
public class BandAttribute: System.Attribute
{
public string Name;
public string HelpText;
public BandAttribute(string name, string help)
{
Name = name;
HelpText = help;
}
}
Térjük most át a böngészősáv kontrol létrehozására. Ezt az osztályt a UserControl-ból származtatjuk, valamint itt fogjuk felhasználni azokat az interfészeket is, melyeket sorozatunk előző részében hoztunk létre az Interfaces.cs forráskódban.
public class BandControl: UserControl, IObjectWithSite, IDeskBand, IDockingWindow, IOleWindow, IInputObject
{
Kontrolunk több új property-t is tartalmaz: a Title property-ben adható meg a létrehozandó böngésző sáv címe.
public String Title
{
...
}
A MinSize property-ben azt adhatjuk meg, hogy mekkora az a minimális méret, melyre a felhasználó átméretezéskor lekicsinyítheti a böngészősávunkat. -1 esetén nem korlátozzuk ezt az értéket.
public Size MinSize
{
...
}
A MaxSize property-ben azt adhatjuk meg, hogy mekkora az a maximális méret, melyre a felhasználó átméretezéskor felnagyíthatja a böngészősávunkat. -1 esetén nem korlátozzuk ezt az értéket.
public Size MaxSize
{
...
}
Az IntegralSize property-ben megadott x és y irányú mértékben lehet majd növelni, csökkenteni a böngészősávunk méretét.
public Size IntegralSize
{
...
}
Az IDeskBand interfész GetBandInfo függvényének futásakor kell majd a fenti property-k értékét felhasználnunk és feltöltenünk a DESKBANDINFO struktúrát. Megadva böngészősávunk alapvető tulajdonságait.
public virtual void GetBandInfo(UInt32 dwBandID, UInt32 dwViewMode,ref DESKBANDINFO dbi)
{
dbi.wszTitle = this.Title;
dbi.ptActual.X = this.Size.Width;
dbi.ptActual.Y = this.Size.Height;
dbi.ptMaxSize.X = this.MaxSize.Width;
dbi.ptMaxSize.Y = this.MaxSize.Height;
dbi.ptMinSize.X = this.MinSize.Width;
dbi.ptMinSize.Y = this.MinSize.Height;
dbi.ptIntegral.X = this.IntegralSize.Width;
dbi.ptIntegral.Y = this.IntegralSize.Height;
A dwModeFlags mezőben adjuk meg azokat a konstans értékeket, melyek leírják, hogy a struktúra mely mezői tekintendők érvényes adatot tároló mezőnek.
dbi.dwModeFlags = DBIM.TITLE | DBIM.ACTUAL | DBIM.MAXSIZE | DBIM.MINSIZE | DBIM.INTEGRAL;
}
Az IDockingWindow interfész ShowDW függvényének futásakor kell gondoskodnunk a kontrolunk megjelenítéséről, eltüntetéséről. A paraméterként kapott fShow logikai érték alapján tudjuk meg, hogy melyik funkciót kell végrehajtanunk.
public virtual void ShowDW(bool fShow)
{
if (fShow)
{
Show();
}
else
{
Hide();
}
}
Az IDockingWindow interfész CloseDW függvényének futásakor szerzünk tudomást arról, hogy a kontrolunkra a továbbiakban már nincs szükség, így felszabadíthatjuk a lefoglalt erőforrásainkat.
public virtual void CloseDW(UInt32 dwReserved)
{
Dispose(true);
}
Az IOleWindow interfész GetWindow függvénye akkor kerül meghívásra, mikor a böngésző „kíváncsi” arra, hogy melyik ablak is lesz a felhasználandó böngészősáv. Ekkor a phwnd paraméterén keresztül adjuk meg a kontrolunk ablakazonosítóját.
public virtual void GetWindow(out System.IntPtr phwnd)
{
phwnd = Handle;
}
Az IObjectWithSite interfész SetSite függvény akkor kerül meghívásra, mikor a kontrolunk kapcsolata létrejött a böngészővel. Ekkor tudjuk meghatározni a böngésző adott példányát, melyet el kell tárolnunk ahhoz, hogy kontrolunk képes legyen kommunikálni a későbbiek folyamán az adott böngészővel.
public virtual void SetSite(Object pUnkSite)
{
Először is ellenőrizzük két változónkat, hogy kaptak-e már értéket egy korábbi hívás folyamán. Ha igen, akkor felszabadítjuk ezeket.
if (BandObjectSite != null)
{
Marshal.ReleaseComObject(BandObjectSite);
}
if (Explorer != null)
{
Marshal.ReleaseComObject(Explorer);
Explorer = null;
}
A böngészősávunkat tároló objektumot kapjuk meg IInputObjectSite interfész típusában a pUnkSite paraméterben. Ezt felhasználva tudjuk meghatározni a böngésző adott példányát.
BandObjectSite = (IInputObjectSite)pUnkSite;
if (BandObjectSite != null)
{
_IServiceProvider sp = BandObjectSite as _IServiceProvider;
...
try
{
Ennek meghatározásához az _IServiceProvider interfész QueryService függvényét hívjuk meg, melynek átadjuk a lekérdezendő alkalmazás GUID számát. Az eredményt a harmadik paraméterben átadott változóba kapjuk. Erre már csak rá kell definiálnunk az IWebBrowser típust, hogy rendelkezésünkre álljon a szükséges osztály, mely az adott böngésző alkalmazását fogja tartalmazni.
sp.QueryService(ref guid, ref riid, out w);
Explorer = (WebBrowserClass)Marshal.CreateWrapperOfType(w as IWebBrowser, typeof(WebBrowserClass));
}
...
}
}
Az IInputObject interfész UIActivateIO függvényére akkor lesz szükség, ha aktiválja a felhasználó a kontrolunkat. Ebben az esetben a fókuszt a saját kontrolunkra kell állítanunk.
public virtual void UIActivateIO(Int32 fActivate, ref MSG Msg)
{
if (fActivate != 0)
{
Control ctrl = GetNextControl(this, true);
if (ModifierKeys == Keys.Shift)
{
ctrl = GetNextControl(ctrl, false);
}
if (ctrl != null)
{
ctrl.Select();
}
this.Focus();
}
}
A fókusz birtoklásának lekérdezése a HasFocusIO függvényen keresztül történik.
public virtual Int32 HasFocusIO()
{
return this.ContainsFocus ? 0 : 1;
}
Speciális gyorsbillentyűk kezelését az IInputObject interfész TranslateAcceleratorIO függvényén keresztül tehetjük meg. Itt egy MSG struktúrában kapjuk meg a billentyűkezelés eseményének paramétereit. Ha a függvényen belül lekezeljük az eseményt, akkor a visszatérési értéknek nullát kell adnunk, különben nullától eltérő számot.
public virtual Int32 TranslateAcceleratorIO(ref MSG msg)
{
Például a billentyű lenyomást a WM_KEYDOWN esemény jelzi. A WM_KEYDOWN értéke 0x100.
if (msg.message == 0x100)
{
if (msg.wParam == (uint)Keys.Tab || msg.wParam == (uint)Keys.F6)
{
if (SelectNextControl(ActiveControl, ModifierKeys == Keys.Shift ? false : true, true, true, false))
{
return 0;
}
}
}
return 1;
}
A böngésző sáv helyes működésének érdekében az elkészült alkalmazásunkat regisztrálni is kell a Windows regisztrációs adatbázisban.
A regisztráció a következő módon zajlik:
- A HKEY_CLASSES_ROOT\CLSID\ kulcs alá egy új kulcsot kell létrehoznunk, mely tartalmazza az objektumunk GUID azonosítóját.
- Létre kell hoznunk az így létrejött kulcsa alá az Implemented Categories kulcsot.
- HKEY_CLASSES_ROOT\CLSID\saját guid\Implemented Categories kulcsa alá egy újabb kulcsot kell létrehoznunk, mely ismét egy GUID szám lesz, ami az alábbiak egyike lehet:
- {00021494-0000-0000-C000-000000000046} - abban az esetben, ha a böngészősávunkat vízszintes irányban szeretnénk megjeleníteni
- {00021493-0000-0000-C000-000000000046} - abban az esetben, ha a böngészősávunkat függőleges irányban szeretnénk megjeleníteni
Ahhoz, hogy ez a függvény az osztály regisztrációjakor automatikusan lefusson, a ComRegisterFunctionAttribute attribútumot kell megadnunk. A függvényen belül elvégezhetjük a szükséges regisztrációs tevékenységünket.
[ComRegisterFunctionAttribute]
public static void Register(Type t)
{
string guid = t.GUID.ToString("B");
RegistryKey rk1 = Registry.ClassesRoot.CreateSubKey(@"CLSID\"+guid);
...
RegistryKey rk2 = rk1.CreateSubKey("Implemented Categories");
rk2.CreateSubKey("{00021493-0000-0000-C000-000000000046}");
}
A regisztráció megszüntetésekor az általunk létrehozott bejegyzéseket is illik törölni a Windows regisztrációs adatbázisból, így ehhez is készítünk egy függvényt, melyet a ComUnregisterFunctionAttribute attribútummal jelölünk meg, így ez a függvényünk automatikusan lefut, amikor az objektumunk regisztrációja törlésre kerül.
Ez esetben nekünk sincs más dolgunk, mint a Windows regisztrációs adatbázisból törölni az imént létrehozott kulcsot, annak tartalmával együtt.
[ComUnregisterFunctionAttribute]
public static void Unregister(Type t)
{
string guid = t.GUID.ToString("B");
Registry.ClassesRoot.CreateSubKey(@"CLSID").DeleteSubKeyTree(guid);
}