Lezen van en schrijven naar het Windows Registry 1. Inleiding Ik ga uit van de veronderstelling dat je wel zo ongeveer weet wat het Registry is bij het windows besturingssysteem. Als je het niet weet, dan ga je je beter eerst informeren vooraleer je deze tutorial gebruikt. De code in deze tutorial kan (met goed gebruik) geen problemen opleveren met je Windows registry, maar fout gebruik kan wel degelijk leiden tot op zijn zachtst gezegd- ergerlijke problemen met Windows. Om zeker te zijn kan je eerst via regedit een backup van je register maken. 2. De nodige namespace en klassen Om te lezen van en te schrijven naar het registry hebben we de klassen Registry en RegistryKey nodig. Je vindt deze beide in de namespace Microsoft.Win32. using Microsoft.Win32; De klasse Registry De klasse Registry bevat een 7-tal statische objecten (ClassesRoot, CurrentConfig, CurrentUser, DynData, LocalMachine, PerformanceData, Users). Als je de registry editor opent (Start Æ Run Æ regedit), dan vind je 5 hoofdgroepen voor de registry sleutels terug: Ik gebruik Windows XP Pro, en vind slechts 5 overeenkomende sleutels terug. Reden hiervoor is, dat de sleutels HKEY_DYN_DATA en HKEY_PERFORMANCE_DATA enkel van toepassing zijn op Windows 95/98/Me, deze mogen volgens mij al plusminus als obsolete beschouwd worden (Alhoewel je er eventueel rekening mee kan houden in je software indien je er waarden uit nodig hebt, maar in deze tutorial gaan we geen rekening houden met Win95/98/Me. Wij gaan ervan uit dat.net software uitgevoerd wordt op Windows besturingssystemen vanaf Windows 2000).
De klasse Registry kan dus enkel statisch aangesproken worden, wat in feite logisch is, want één computer heeft normaal maar één lopend Windows besturingssysteem, en één Windows besturingssysteem heeft normaal maar één registry. Noot: Ik weet dat je met bepaalde software zoals VMware, twee Windows versies tegelijk kan runnen, maar dan loopt 1 van die Windows installs wel op een virtuele pc, die als aparte computer moet beschouwt worden. Het mag nu duidelijk zijn dat je via de klasse Registry alle sleutels in het Windows Register op een hiërarchische manier (net zoals in regedit) kan opvragen. De klasse RegisterKey Een instantie van de klasse RegistryKey stelt programmatorisch 1 specifieke sleutel voor. Dit kan een bestaande sleutel zijn, of je kan er een nieuwe sleutel mee definiëren om toe te voegen aan het register. Als je kijkt in de MSDN documentatie, dan merk je al vlug dat de de hoofdsleutels binnen de Registry klasse allemaal statisch gedefinieerde objecten van het type RegistryKey zijn (ClassesRoot, CurrentConfig, CurrentUser, LocalMachine en Users). Nu maak je waarschijnlijk ook meteen de link. Als je een RegistryKey object maakt, dan kan je die meteen doen wijzen naar één van deze 5 hoofdsleutels, bijvoorbeeld: RegistryKey key = Registry.CurrentUser; We gaan het dus in feite hoofdzakelijk hebben over RegistryKey objecten, de klasse Registry dient als programmatorische weergave van het Windows register. Is dit niet fantastisch van oompje Microsoft!? Een registersleutel kan zowel waarden (values) als onderliggende sleutels (subkeys) bevatten. Via de RegisteryKey klasse hebben we toegang tot een resem methoden en enkele properties van een registersleutel. Zo kan je bijvoorbeeld de naam opvragen van een sleutel, hoeveel onderliggende sleutels deze heeft, en hoeveel waarden er zijn opgeslagen binnen deze sleutel. Onderstaande code demonstreert dat: MessageBox.Show( Registry.CurrentUser.Name ); MessageBox.Show( Registry.CurrentUser.SubKeyCount.ToString() ); MessageBox.Show( Registry.CurrentUser.ValueCount.ToString() );
3. Een sleutel openen Om de waarden binnen een sleutel op te vragen (of eventueel zijn subsleutels op te vragen), moeten we de sleutel eerst openen. We gaan werken met een theoretische sleutel SOFTWARE\\BluePrint\\EDUKAClient\\1.0 binnen de CurrentUser hoofdsleutel. (We zijn een softwarebedrijfje BluePrint, dat instellingen omtrent zijn software EDUKAClient versie 1.0 kwijt wil in het register) Eén van de beschikbare methoden voor een instantie van de klasse RegistryKey is OpenSubKey, hiervan maken we gebruik om onze sleutel op te vragen. RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\BluePrint\\EDUKAClient\\1.0"); Ons object key zal nu een reference bevatten naar de sleutel 1.0. Na gebruik moet de sleutel terug afgesloten worden: key.close(); Als deze sleutel niet aanwezig is in het register, dan zal key gelijk zijn aan null. Dit vangen we natuurlijk best op, want anders krijgen we problemen. Neem als voorbeeld volgende methode: private bool CheckKeyInRegistry ( string sleutel ) { RegistryKey key = Registry.CurrentUser.OpenSubKey( sleutel ); if(key == null) return false; else { key.close(); return true; } } Met een dergelijke methode kunnen we controleren of de sleutel in het register aanwezig is. De methode geeft true terug als de sleutel bestaat, en false wanneer de sleutel niet gevonden is.
De methode OpenSubKey ( string name [, bool Writeable] ) stelt ons in staat rechtstreeks een sleutel te openen. De overloaded methode stelt ons in staat de sleutel als writeable te openen, wat inhoud dat je de waardes binnen de sleutel kan wijzigen. In onze CheckKeyInRegistry methode gebruikten we de constructor zonder op te geven dat we schrijftoegang willen, daar we geen schrijftoegang nodig hebben om te controleren of de sleutel aanwezig is. In ons geval zal de sleutel nog niet bestaan, dus gaan we nu eerst zien hoe we de sleutel kunnen toevoegen, en er enkele waarden in stoppen.
4. Een sleutel en enkele waarden voor deze sleutel toevoegen aan het register Een sleutel toevoegen aan het register gebeurt heel gelijkaardig aan het openen van een sleutel: RegistryKey key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\BluePrint\\EDUKAClient\\1.0"); We krijgen meteen een reference naar de nieuw toegevoegde sleutel via ons object key. Opgelet, ook hier kan het gebeuren dat er iets verkeerd loopt, en dat onze sleutel key null is. Dus gaan we ook hier moeten controleren of ons object correct geinstancieerd is. Om een waarde weg te schrijven in onze nieuwe sleutel kunnen we gebruik maken van ons RegistryKey object key, dit gebeurt via de methode SetValue( string name, object value). Noot: Je merkt dat je in feite een object met een naam ervoor toevoegt aan je sleutel. De waardes binnen een sleutel zijn dus niet gelimiteerd tot stringwaardes. Maar het is niet de bedoeling dat je grote objecten gaat wegschrijven in het register, daarvoor dient het register niet! We schrijven het path naar de database die door ons EDUKAClient programma gebruikt wordt naar onze sleutel: string DBPath = c:\program files\edukaclient\db\users.mdb ; RegistryKey key = Registry.CurrentUser.CreateSubKey("SOFTWARE\\BluePrint\\EDUKAClient\\1.0"); if(key!= null) { key.setvalue("databaselocation", DBPath); key.close(); } Noot: Een waarde binnen een sleutel wijzigen kan simpelweg ook gedaan worden via de methode SetValue. Je dient gewoon de SetValue uit te voeren met als naamparameter de naam van de reeds bestaande waarde.
5. Waarden lezen uit het register We gingen in hoofdstuk 3 al in op het openen van een sleutel om dan lees of updateacties erop uit te voeren. Nu gaan we zien hoe we de waardes binnen een sleutel opvragen. (Onze EDUKAClient applicatie moet natuurlijk de waardes kunnen opvragen, anders hebben die totaal geen nut) if(checkregistryentry("software\\blueprint\\edukaclient\\1.0")) { string DatabaseLocation = ; RegistryKey key = Registry.CurrentUser.OpenSubKey( "SOFTWARE\\BluePrint\\EDUKAClient\\1.0"); } DatabaseLocation = key.getvalue("databaselocation").tostring(); key.close(); Je ziet dat we meteen ook gebruik maken van ons hoger in dit document ontworpen methode CheckRegistry. Zo weten we dat de gewenste sleutel bestaat. Door de methode GetValue(string name) van een RegistryKey object aan te roepen kunnen we de opgeslagen waarde via zijn naam opvragen. Noot: Let erop dat GetValue de waarde zal teruggeven als object. Een applicatie die gebruik maakt van sleutels en waarden in het register weet normaal perfect welke gegevens er in de betreffende registersleutel aanwezig zijn. De applicatie zal in ons geval weten dat de waarde DatabaseLocation binnen het teruggegeven object een string bevat, en we die makkelijk opvragen door de methode ToString van object object. Bij het gebruik van andere waarden (niet string) zal de applicatie ook moeten weten welke type waarde er opgeslagen staat in het register, en zal de applicatie de waarde ook correct kunnen parsen (of converten ).
6. Een sleutel of waarde verwijderen Naast het openen of creëren van een sleutel of waarde is het natuurlijk ook mogelijk een sleutel, een sleuteltree of een waarde te verwijderen. De RegistryKey klasse bevat daarvoor volgende methoden: DeleteSubKey ( string subkey ) DeleteSubKeyTree ( string subkey ) DeleteValue ( string name ) Noot: Deze methoden bevatten ook enkele overloads, zie daarvoor in de MSDN bij de RegistryKey klasse. We gaan hier niet verder in op het verwijderen van een sleutel, daar dit meestal enkel gebruikt wordt door (des-)installatiesoftware. Bovenstaande methoden spreken zowat voor zich, en laten zich gelijkaardig als OpenSubKey en CreateSubKey gebruiken. 7. Enumereren van de aanwezig subsleutels en waardes binnen een sleutel Soms kan het interessant zijn om een lijst met subsleutels van een sleutel, of een lijst met waardes van een sleutel op te vragen. De methode GetSubKeyNames van de RegistryKey klasse geeft een string array terug met de namen van alle subsleutels van de opgegeven sleutel. De methode GetValueNames van de RegistryKey klasse geeft een string array terug met de namen van alle waarden die de opgegeven sleutel bevat. 8. Exception handling Via ons controleren als ons object key niet refereert naar null konden we in hoger beschreven code vrij zeker zijn dat we geen Exceptions zouden genereren met onze code. Dit betekent echter niet dat deze manier van werken fullproof is. Beter is het om try-catch-finally codeblocks toe te voegen aan de code. Zie bij de Registry en RegistryKey documentatie in de MSDN welke Exceptions er allemaal kunnen voorkomen door gebruik van deze 2 klassen en hun methoden.
Veel plezier. Kris.