Microsoft & .NET.NETManipulating Registry Elements in WinCE

Manipulating Registry Elements in WinCE

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

In this last lesson on using the CE Registry, we are going to learn techniques for manipulating individual elements. You’ll see how to read or delete a single key, and how to delete a key value.

Reading A Single Named Value

If you know a value is present and you know its name, reading a single value allows you to be a little more precise in Registry accesses. Referring to the RegDemo example, you can see how we do this in the WndProc() message switch, in response to the IDM_READ_ONE_VAL message.

The first step is to open its parent key with at least KEY_QUERY_VALUE access.

case IDM_READ_ONE_VAL:
 // open the keys to gain 
 // access to the values
 rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                 TEXT ("Softwaren2"), 
                 0,
                 KEY_QUERY_VALUE, 
                 &hKeyN2);

Before we actually read the value’s data, we can query the key to see how much data it has. Here’s how to do this.

//How much data do we have
dwDSize = 1; // pass non null to get array size
dwValType = REG_DWORD;
rc = RegQueryValueEx (hKeyN2, 
                      TEXT ("OneDWORD"),
                      NULL, &dwValType,
                      NULL, &dwDSize);

The parameters to RegQueryValueEx(), in the order shown, are the handle to the parent key, the value name as a Unicode string, a NULL place holder, the address of a DWORD that will receive the registry data type of this value, a pointer to the buffer to receive the value data, and the address of a DWORD that will receive the size in bytes of the value’s data. Notice that in this call, we set the pointer to the data buffer to NULL. This causes the function to return the size of the value’s data, without returning the data itself. This allows you to allocate a buffer for the exact size of the data rather than reserving space for the largest possible amount of data.

//allocate space
pbData = (PBYTE)LocalAlloc(LPTR,dwDSize);
if(!pbData )
{
    MessageBox (NULL, TEXT("LocalAlloc Failed"),
        TEXT("Fail and Bail!"), MB_OK);
    return FALSE;
}
//Get the key value
rc = RegQueryValueEx (hKeyN2, TEXT ("OneDWORD"),
                                    NULL, &dwValType,
                                    pbData, &dwDSize);

The next time we call RegQueryValueEx(), we pass the pointer to the newly allocated data buffer and retrieve the value data.

if(rc == ERROR_SUCCESS )
{
    wsprintf( wszMessage, 
              TEXT("%s: %x"),
              TEXT("OneDWORD"), *(int*)pbData );
    MessageBox (NULL, 
                wszMessage,
                TEXT("Value Retrieved"), MB_OK);
    return FALSE;
}

Notice once more that when we copy the returned value data out of the buffer, we first cast the address of the data to an integer pointer, and then dereference. Finally, we close the key:

RegCloseKey( hKeyN2 );
break;

Deleting Values

Deleting a registry entry is fairly straightforward. In RegDemo, we do this in the WndProc() message switch in response to the IDM_DELETE_VALUES message.

First, open the key that owns the value. In this case, we open with KEY_ALL_ACCESS permission to ensure that we can delete it.

//open key to gain access to values
rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                   TEXT ("Softwaren2"), 0,
                   KEY_ALL_ACCESS, &hKeyN2);
  if(rc != ERROR_SUCCESS )
      { return FALSE; }

To delete a specific value, you must know its name.

//delete named value
rc =  RegDeleteValue( hKeyN2, TEXT("OneDWORD") );

The parameters, in the order shown, are the handle to the parent key, and the name of the value as a Unicode string. Skipping over the message box code, the last step is to close the key that owned the value.

RegCloseKey( hKeyN2 );
return FALSE;

Deleting Keys

Deleting keys is like pruning a tree: Everything further out the branch is lopped off when you nip the key. This is a powerful way of cleaning a Registry tree, but has to be used with caution and respect. We do this in the WndProc() message switch in response to the IDM_DELETE_KEY message.

case IDM_DELETE_KEY:
  //wipe reg keys and their values
  rc = RegDeleteKey( HKEY_LOCAL_MACHINE, 
                     TEXT ("Softwaren2"));
    break;

Notice that we don’t open the key. Keys may not be deleted unless they are closed. The parameters to RegDeleteKey(), in the order shown, are the handle to the parent key and the name of the key to delete as a Unicode string. In this case, the key “n2”, all its values, and all of its subkeys are being deleted. This is convenient because we don’t have to open any keys before we deleten2, but a safe approach might be something like this:

//a safe approach to deleting keys
  //open key to gain access to values
  rc = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
                     TEXT ("Software "), 0,
                     KEY_ALL_ACCESS, &hKeySoftware);

  //delete access to n2, but not to software
  rc = RegDeleteKey(hKeySoftware, TEXT ("n2"));

  //close this key
    RegCloseKey(hKeySoftware);

This approach requires a couple of extra steps, but has this advantage: You can’t accidentally delete a parent key because it is open. The safest strategy when deleting keys is to carefully limit the scope of possible deletions.

Wrapping Up

If you are porting Registry code from Win32 applications, chances are you’ll be making some fairly significant (though not terribly complicated) changes to the Desktop code. Here are some tips on how to approach the job:

Registry Porting Checklist

  • Keep Registry tree structures as “flat” as possible.
  • Wherever possible, aggregate multiple named key values into a single block of bytes. Have the application retrieve the entire block and parse individual values.
  • All CE key and value names are Unicode strings.
  • Double check all size parameters passed to Registry functions. String buffer sizes are the Unicode character capacity of the buffer, including the terminal NULL. Data buffer sizes are in bytes.
  • When retrieving values, pay careful attention to casting the address of the data buffer. Cast the address of the buffer to a pointer to the registry data type, and then dereference: ( * (int *)pDataBuffer, *(TCHAR *)pDataBuffer, etc.).
  • Close keys as soon as possible.
  • When opening keys, use the least expansive access permissions necessary.
  • When deleting keys, limit the scope of potential deletions by opening the key immediately above the highest node you are deleting.

Looking Ahead

As the lessons progress, we seem to be winding our way to the very heart of CE. In the next set of lessons, Threads and Power Management, we arrive there. Everything we strive to achieve as CE software developers comes down to one simple fact of life: power conservation. Fortunately, CE devices are inherently intelligent in this respect. The more we know, however, the more efficiently we can use the resources at our disposal.

We also explore threading. On the surface, it may seem that threading and power management have little in common. In theory, this is so. However, in practice, the nature of typical Win32 threaded applications raises serious power consumption issues for CE developers. Onward.

About the Author

Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, entry time data validation.

In addition to writing for Developer.com, she has written several books, including Making Win 32 Applications Mobile.

# # #

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories