Inserting Registry Keys in a List Control

This month, we are continuing our examination of remote manipulation of CE devices. We’ll be dissecting the code that implements the “Walk Registry Tree” page of the tabbed dialog created by the RapiDemo example program. The ability to remotely manipulate Registry entries is a powerful tool for managing and maintaining remote or embedded applications. In our example, we’ll limit ourselves to reading the keys. When you become adept with the basics of this operation, you may graduate to creating, writing, and deleting Registry elements using RAPI APIs.

How Key Values Are Inserted in the List Control

Registry key values are limited to a specific set of data types. For this reason, accessing the key values is a two-step process. First, we find the values by enumerating them, and then we format the raw value data to make it useful for our particular purpose. You’ve seen the first step in previous examples. In the InterpretKeyValue() member shown below, we handle the second step. The parameters to InterpretKeyValue(), in the order shown, are a WCHAR string containing the value’s name, the address of the data buffer, the size of the data, and the Registry data type.

Just a couple of points before we push on with the job of inserting values in the listbox. First, Registry values can be unnamed, so it’s possible to have data, but not have a value name. Second, we copied a maximum of 1024 bytes of data per value, but this is an artificial limit. The value could actually have more data than that. If you call CeRegEnumValue() with the data buffer address and size set to NULL, the function returns the actual size of the data, and you can allocate a buffer accordingly.

void CWalkReg::InterpretKeyValue(  wchar_t* pwszValueName,
                                   PBYTE pbValueData,
                                   DWORD dwValueDataSize,
                                   DWORD dwRegDataType)
{
   char  szMBCSData[1024];
   int i, iLoopLimit ;

   //insert the name of the value
   memset(szMBCSData, 0x0, sizeof(szMBCSData));
   wcstombs(&szMBCSData[0], pwszValueName, sizeof(szMBCSData));
   m_RegList.InsertString( -1, szMBCSData );

The code immediately above inserts the name of the value, and then we use a switch to appropriately handle the value data. Notice that all string data passed back from the CE registry is Unicode, and so must be translated to multibyte character format before it can be inserted in the listbox control.

   memset(szMBCSData, 0x0, sizeof(szMBCSData));
   switch (dwRegDataType)
   {
   case REG_MULTI_SZ:
   case REG_EXPAND_SZ:
   case REG_SZ:
      wcstombs(&szMBCSData[0], (WCHAR*)pbValueData,
               sizeof(szMBCSData));
      break;

   case REG_DWORD:
      sprintf (&szMBCSData[0],"%x ", *(DWORD *)pbValueData);
      break;

   case REG_BINARY:
      szMBCSData[0] = '\0';
      iLoopLimit = ( (int)dwValueDataSize < sizeof(szMBCSData) - 1)?
                          dwValueDataSize : sizeof(szMBCSData) - 1;

      for ( i = 0; i < iLoopLimit; i++)
      {
         //len = lstrlen ((LPTSTR)szData[0]);
         sprintf (&szMBCSData[i], "%02X ", pbValueData[i]);
         // if (len > dim(szData) - 6)
         //    break;
      }
      break;

   default:
      sprintf (>szMBCSData[0],"Unknown type: %x", dwRegDataType);
   }

   m_RegList.InsertString( -1, szMBCSData );
   m_RegList.InsertString( -1, " " );

   return;
}

Below is a complete list of Registry data types and their constants. Notice that the BINARY type provides a flexible format that allows you to store anything that doesn’t conveniently fit into one of the other types. It can be a useful strategy to use the REG_BINARY type to organize and store app-specific hierarchical data. Keeping the CE Registry tree as “flat” as possible yields big performance benefits.

Table 1: CE Registry Data Types and Their Uses

Registry Data Type Name Meaning
REG_BINARY Byte stream; good for application defined/interpreted complex types.
REG_DWORD A 32-bit number.
REG_DWORD_LITTLE_ENDIAN A 32-bit number in little-endian format. Windows CE is designed to run on little-endian computer architectures. Some UNIX systems are big endian.
REG_DWORD_BIG_ENDIAN A 32-bit number in big-endian format.
REG_EXPAND_SZ A null-terminated string that contains unexpanded references to environment variables (for example, “%PATH%”).
REG_MULTI_SZ An array of null-terminated strings, terminated by two null characters.
REG_NONE No defined value type.
REG_RESOURCE_LIST A device driver resource list.
REG_SZ A null-terminated string. It will be a Unicode or ANSI string, depending on whether you use the Unicode or ANSI functions.

Figure 1: The Walk Registry Tree Page of The RapiDemo App

In the next installment, we are going to use a classic programming technique to find and navigate the entire membership of the Registry tree. We’ll preview that technique here so we can go straight to work on the code that implements it in the next lesson.

Getting Ready to Walk The Registry Tree

To correctly initialize the tree view control, we have to walk all the way to the end of each of the branches of the Registry tree. Because we don’t know the exact depth of the Registry hierarchy, and because it isn’t likely to be symmetrical, we use recursion to find all the nodes in the tree. Recursion, in a nutshell, is when a function calls itself until some condition is met.

Recursion can be an indispensable tool for traversing hierarchical data, but it has risks. A runaway recursion will overflow the stack, and probably cause an unrecoverable failure (a.k.a. crash). Also, deep recursion is likely to cause the stack to be reallocated, which at least will slow your code down and at worst will expose other silent code defects. Use recursion if it makes sense, but don’t overuse it. Here are a few tips on using recursion:

  • Try to minimize the size of parameter lists for recursive functions.
  • Try to minimize the size of local data in a recursive function.
  • Don’t use recursion unless it is clearly required by the problem you are trying to solve.
  • Don’t use recursion unless you can reasonably estimate the depth of the recursion.

Looking Ahead

In the next installment, we’ll examine the code that recursively walks the Registry tree, finding and returning key values.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read