================== Dealing with Keys ================== Here, we are going to learn how to deal with registry keys by using "ring_wincreg" extension capabilities through RCRegistry class library. .. index:: pair: Dealing with Keys; Create Key Create Key ============= We can create a new key by using the same functions for opening keys because these functions can create a key if it is not existed and then open it. (:ref:`Open-Keys`) .. index:: pair: Dealing with Keys; Key Existence Key Existence ============== We can check whether a specific key existed before we open it by using **KeyExists()** function. This function accepts two parameters(HKEY ROOT, "SubKey\Path"). See the next example: .. code-block:: none Load "wincreg.ring" New RCRegistry { If KeyExists(HKEY_CURRENT_USER, "Software\MyApp") = True See "MyApp key is existed inside Software key" Else See "MyApp does not exist in Software key" Ok } .. index:: pair: Dealing with Keys; Open Key .. _Open-Keys: Open Key ========= We can open a registry key using more than one function and option. .. index:: pair: Open Key; OpenKey() Function OpenKey() Function ------------------- This function is the primary open key function in the RCRegistry class that could be used to open keys. This function accepts parameters as a list so we should pass one list parameter that contains other parameters. The number of parameters allowed are 2-4. These parameters are: 1. The HKEY root indexes: of the windows registry which could either be: * HKEY_CLASSES_ROOT * HKEY_CURRENT_USER * HKEY_LOCAL_MACHINE * HKEY_USERS * HKEY_CURRENT_CONFIG .. note:: ROOT HKEY indexes are numbers for each HKEY root, this index has been defined depending on the root organization in Windows Registry Editor but it starts with one. The complete list of HKEY roots indexes is: * HKEY_CLASSES_ROOT = 1 * HKCR = 1 * HKEY_CURRENT_USER = 2 * HKCU = 2 * HKEY_LOCAL_MACHINE = 3 * HKLM = 3 * HKEY_USERS = 4 * HKU = 4 * HKEY_CURRENT_CONFIG = 5 * HKCC = 5 Note that each HKEY root has been shorten for easier call. 2. The sub key path: which is the key that we want to open under the specified root. It is a complete path to the required key under the specified root. 3. Flags: which are numerical values represent specific behaviour that should extension assume. These flags allow more control over extension behaviour. They could be one or more of the follow: * CREG_CREATE = 1 : this flag will make the function to create the key if its not exist. (This flag used by default if no flags have been set) * CREG_READONLY = 0 : this flag opens the key if it is existed but will not create it if it is not. It cannot be used with CREG_CREATE flag at the same time. * CREG_AUTOOPEN = 2 : this flag activates the auto open mechanism of this extension, which helps faster performance by automatic close and then open the key whenever it is needed. This is useful in case of repeatedly calling key open and close functions. * CREG_NOCACHE = 4 : deactivate the caching mechanism of the CRegistry Class. ( Activated by default ) .. note:: Till now, the first three flags are only effective in the process of opening and closing the key, and the last one is effective in dealing with entries and values. To know how to use flags in more details go to (:ref:`SetAndGetFlags`) section. 4. The option to access Wow64 tree: which could be true for access or false for opposite. It has been set "False" by default. .. hint:: Wow64 tree is an automatically created tree of keys inside windows registry for 32 bit programs that run on an 64 bit windows. So opening/creating "Software\\MyApp" under the HKEY_LOCAL_MACHINE root will not open/create it as expected but it will be opened/created as "Software\\Wow6432Node\\MyApp". `(Registry Redirection) <https://msdn.microsoft.com/en-us/library/windows/desktop/ms724072(v=vs.85).aspx>`_ Till now any windows application created by Ring Programming Language is considered to be 32 bit application because Ring is built as 32 bit program. Now lets have some examples for how to use **OpenKey()** function. Example 1 .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software", CREG_READONLY]) If Reg.SubKeyExists("Microsoft") See "Microsoft key is already present in the Software key" Ok Reg.CloseKey() This example opens "Software" key in the "HKEY_CURRENT_USER" HKEY root for reading only which means it will not auto create sub key if its not existed. Then it checks for "Microsoft" sub key whether it exists under "Software" key or not. Example 2 .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_LOCAL_MACHINE, "Software", CREG_READONLY, True]) If Reg.SubKeyExists("Microsoft") See "Microsoft key is already created in the Wow64 tree" Ok Reg.CloseKey() This example does the same task that the previous example do. The main difference is that it opens the key in the Wow64 tree not the regular tree due to adding the forth parameter with "True" value. .. note:: This example may show access denied error (if Registry Virtualization has been disabled by manifest file). You can get around it by running Ring as Administrator. You can use `"Ring_WINAPI" <https://github.com/MajdiSobain/ring_winapi>`_ extension to help elevating Ring. .. note:: In case you want to reach Wow64 tree without changing flags you can open the key first by calling **OpenKey()** function with two parameters then use **Access64Tree()** function (:ref:`Access64Tree`) to access Wow64 tree. .. index:: pair: Open Key; OpenKey2() Function OpenKey2() Function -------------------- This function is an overriding copy of the previous **OpenKey()** . But it accepts just two non list parameters, these are: 1. HKEY root. 2. Sub key to be opened. Example .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey2(HKCU, "Software\MyApp") Reg["version"].SetValue("4.4") See "MyApp version is : " + Reg["version"].GetValue() Reg.CloseKey() .. index:: pair: Open Key; OpenKey3() Function OpenKey3() Function -------------------- This function is an overriding copy of OpenKey() function. But it accepts just three non list parameters, these are: 1. HKEY root. 2. Sub key to be opened. 3. Flags Example .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey3(HKCU, "Software\MyApp", CREG_CREATE) Reg["version"].SetValue("4.4") See "MyApp version is : " + Reg["version"].GetValue() Reg.CloseKey() .. index:: pair: Open Key; OpenKey4() Function OpenKey4() Function -------------------- This function is another overriding copy of OpenKey() function. But it accepts all four non list parameters, which are: 1. HKEY root. 2. Sub key to be opened. 3. Flags. 4. Wow64 tree access. Example .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey4(HKEY_LOCAL_MACHINE, "Software\MyApp", CREG_CREATE, True) Reg["version"].SetValue("4.4") See "MyApp version is : " + Reg["version"].GetValue() Reg.CloseKey() After opening the key it will be saved in an attribute as a pointer in RCRegistry object named **(Key)**, So that it could be used by other functions easily. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software,MyApp"]) See "This is the information of Key handle pointer of this RCRegistry Object" + NL See Reg.Key Reg.CloseKey() .. index:: pair: Dealing with Keys; Access HKEY Root Access HKEY Root ================= We can access/open any HKEY Root by passing empty string as sub key path as follow: .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry { OpenKey([HKCU, ""]) } See "The sub keys contained in HKEY_CURRENT_USER are : " + NL See Reg.GetSubKeys() Reg.CloseKey() .. index:: pair: Dealing with Keys; Close Key Close Key ============ We can close any opened key by using **CloseKey()** function. It is recommended to close any key you opened to prevent any conflicts when the key is needed to be opened again. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) See "MyApp key is Opened" + NL Reg.CloseKey() See "MyApp key is closed" .. index:: pair: Dealing with Keys; Set and Get Flags .. _SetAndGetFlags: Set and Get Flags ================== We can Set or Get flags any time in the code using special functions. This may be useful if we opened a key without specifying enough flags that we want. This can be done using **SetFlags()** and **GetFlags()** functions as follow: .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) See "The flags that has been already set are : " + Reg.GetFlags() + NL # Reg.GetFlags() will return 1 because CREG_CREATE flag has been set by default Reg.SetFlags(Reg.GetFlags() | CREG_AUTOOPEN) See "The flags after addition of CREG_AUTOOPEN are : " + Reg.GetFlags() + NL Reg.SetFlags(Reg.GetFlags() & ~CREG_AUTOOPEN) See "The flags after subtraction of CREG_AUTOOPEN are : " + Reg.GetFlags() Reg.CloseKey() It is a must to know that setting new flags will omit any previously set flags. You can set multiple flags using bitwise operators as following (check previous example): - OR "|" operator : will sum any flags. You can use "+" operator to do the same task. - AND plus COMPLEMENT " & ~ " operators : will cause subtraction of any previously set flag. These operators reduce the possibility of creating unexpected flags than using "-" operator that may lead to unexpected behaviour if subtracted flags are not set initially. The most important thing is that subtracting using bitwise operators should be segmented if you want to remove more than one flag as follow: .. code-block:: none SetFlags( GetFlags() & ~CREG_AUTOOPEN ) SetFlags( GetFlags() & ~CREG_CREATE ) OR .. code-block:: none SetFlags( (GetFlags() & ~CREG_AUTOOPEN) & ~CREG_CREATE ) .. note:: Setting multiple flags inappropriately may lead to unexpected behaviour. **CREG_CREATE** and **CREG_READONLY** flags **are not allowed** to be used together in the same flag setting context to avoid unexpected behaviour. The accepted ways to use them are: * (CREG_CREATE) : This flag, alone or with other flags, will allow creating new keys. * (CREG_READONLY) : This flag, alone or with other flags, will not permit creating keys if they are not existed. * (GetFlags() & ~CREG_CREATE) : This expression will switch from **CREG_CREATE** situation into **CREG_READONLY** one in a key previously set to allow creating new keys. Providing that GetFlags() function returns multiple flags containing **CREG_CREATE** flag. * (GetFlags() | CREG_CREATE) : this expression will switch from **CREG_READONLY** situation into **CREG_CREATE** one in a key previously set to prevent creating new keys. Providing that GetFlags() function returns multiple flags containing **CREG_READONLY** flag. The last two conditions help reset flags in case that there are already used multiple flags, but if you want to set flags completely from scratch use the previous two individual flags. **CREG_CREATE** flag is used by default when calling OpenKey() function without setting flags. But if you set **CREG_AUTOOPEN** and\\or **CREG_NOCACHE** flags alone without setting any one of the previous two flags (**CREG_CREATE** or **CREG_READONLY**), the extension will use **CREG_READONLY** by default. As we highlighted before in (:ref:`Open-Keys`) section, using **CREG_AUTOOPEN** flag will help opening and closing the key automatically whenever it is needed, unless the key is manually closed or deleted. Now we will have a quick example showing the benefit of this: .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry { OpenKey([HKCU, "Software\MyApp", CREG_CREATE | CREG_AUTOOPEN]) } # After opening the key it will be closed automatically Reg["version"].SetValue("5.5") # Here the key will be opened, setting the value, and then closed automatically See "The version of my app is : " + Reg["version"].GetValue() # Here the key will be opened again, retrieving the value, and then closed automatically **CREG_NOCACHE** flag may rarely be used if you want to relieve some load from RAM if the application is suspected to run on old computers, because this extension load all entries of the opened key by default for better responsiveness and performance. .. index:: pair: Dealing with Keys; Accessing 64 Bit Tree (Registry Redirection) .. _Access64Tree: Accessing Wow64 Tree (Registry Redirection) ============================================= We can change the setting that let us access the 64 bit applications registry tree any time if we miss to set it during key opening. This could be done by using **Access64Tree()** function as follow: .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_LOCAL_MACHINE, "Software\MyApp"]) Reg.Access64Tree(False) Reg["new value"].SetValue("1") Reg.Access64Tree(False) IF Reg["new value"].Exists() See "new value does exist" + NL Else See "new value does not exist" + NL Ok Reg.Access64Tree(True) IF Reg["new value"].Exists() See "new value does exist" + NL Else See "new value does not exist" + NL Ok Reg.CloseKey() .. note:: This example may show access denied error. You can get around it by running Ring as Administrator. You can use `"Ring_WINAPI" <https://github.com/MajdiSobain/ring_winapi>`_ extension to help elevating Ring. .. index:: pair: Dealing with Keys; Registry Virtualization Check Registry Virtualization Check ============================== We can attempt to check whether the opened key is under virtualization effect or not using **IsVirtualized()** and **IsVirtualized2()** functions. **Registry Virtualization** is an internal mechanism of Windows that helps keeping the sensitive registry keys and windows files away from being touched by the applications that have been developed to reach them in the previous copies of windows. So that to reach such sensitive keys and files you have to disable virtualization either by running your application/program as an administrator or use manifest files. Now check whether the currently opened key has been virtualized or not we can use these two functions. .. index:: pair: Registry Virtualization Check; IsVirtualized() Function IsVirtualized() Function ------------------------- This function checks virtualization of the opened key and return True/False. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_LOCAL_MACHINE, "Software\MyApp"]) If Reg.IsVirtualized() See "This key is virtualized" Else See "This key is not virtualized" Ok Reg.CloseKey() .. index:: pair: Registry Virtualization Check; IsVirtualized2() Function IsVirtualized2() Function -------------------------- This function checks virtualization of the opened key and return: 1. Number ( 1 ) if it is virtualized. 2. Number ( 0 ) if it is not virtualized. 3. Number ( -1 ) if the function is not certain about virtualization of the specified key. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_LOCAL_MACHINE, "Software\MyApp"]) Switch Reg.IsVirtualized2() On 1 See "This key is virtualized" On 0 See "This key is not virtualized" On -1 See "The function is not able to check virtualization of this key" Off Reg.CloseKey() .. index:: pair: Dealing with Keys; Refresh Caching Refresh Caching ================ If we found that some unknown or unexpected behaviours of "ring_wincreg" extension regarding retrieving entries or some values we can refresh the internal catching mechanism by using **Refresh()** function. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) See "Refreshing wincreg" + NL Reg.Refresh() See "Ring_WinCReg extension has been refreshed" Reg.CloseKey() .. note:: This function may not be used during all of your work as there is a good internal management mechanism in "ring_wincreg" extension. .. index:: pair: Dealing with Keys; Sub Keys Existence Sub Keys Existence =================== We can check for any sub key that we may think it could be existed within the opened key by **SubKeyExists()** function. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) If Reg.SubKeyExists("Options") See "Options sub key already existed" Else See "Options sub key does not exist" Ok Reg.CloseKey() .. index:: pair: Dealing with Keys; Sub Keys Count Sub Keys Count =============== We can get the total number of sub keys that are contained within any opened key by using **SubKeysCount()** function as follow: .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) See "The total number of sub keys contained in this key are : " + Reg.SubKeysCount() Reg.CloseKey() .. index:: pair: Dealing with Keys; Sub Key by Index Sub Key by Index ================= We can get any sub key present in the opened key by its index using **GetSubKeyAt()** function. .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) See "The first sub key in this key is : " + Reg.GetSubKeyAt(1) Reg.CloseKey() .. index:: pair: Dealing with Keys; Get All Sub Keys Get All Sub Keys ================= We can get the list of all sub keys in the opened key as a list by using **GetSubKeys()** function as follow: .. code-block:: none Load "wincreg.ring" New RCRegistry { OpenKey([HKEY_CURRENT_USER, "Software\MyApp"]) See "The list of Keys in MyApp key are : " + NL aList = GetSubKeys() See aList CloseKey() } .. index:: pair: Dealing with Keys; Delete Key Delete Key ============= We can delete any key by using **DeleteKey()** and **DeleteKey2()** functions. .. index:: pair: Delete Key; DeleteKey() Function DeleteKey() Function --------------------- This function can delete any opened key as follow: .. code-block:: none Load "wincreg.ring" Reg = New RCRegistry Reg.OpenKey([HKEY_CURRENT_USER, "Software\MyTempApp"]) See "MyTempApp key is Created and Opened" + NL Reg.DeleteKey() See "MyTempApp key is deleted now" .. index:: pair: Delete Key; DeleteKey2() Function DeleteKey2() Function ---------------------- This function can delete any key that is not already opened. This function accepts two parameters (HKEY ROOT, "SubKey\Path") as follow: .. code-block:: none Load "wincreg.ring" New RCRegistry { OpenKey([HKEY_CURRENT_USER, "Software\MyTempApp"]) See "MyTempApp has been created" + NL CloseKey() } New RCRegistry { DeleteKey2(HKEY_CURRENT_USER, "Software\MyTempApp") See "MyTempApp key is deleted without opening" }