I needed to update the registry on many devices in the field this week, so I wrote a little application to delete some registry keys and add some new keys and values. The requirements were simple; take a well defined set of registry keys and values and add them to the registry, takes some well defined registry keys and delete them and make it simple for the user.
I started by creating a few data structures that I could use to set up some static data to define the registry changes. RegDelete will define the registry keys to be deleted and RegAdd will define the registry keys and values to be added.   Both of these will be used as arrays of the structures, and both arrays will be processed in order. So that means the key to be added must come before the values to be added to that key.
RegAdd.Type will be used to store the registry value type like REG_DWORD and REG_SZ, but since this structure will also contain registry keys we need a type for that as well. Looking up the values used for REG_DWORD and REG_SZ in the header files reveals that zero is used for REG_NONE which I have no intention of supporting, so we will use zero to define the type for registry keys.
 
typedef struct{
                                HKEY hkey;
                                TCHAR *Name;
                } RegDelete;
 
typedef struct{
                                DWORD Type;
                                HKEY hkey;
                                TCHAR *Name;
                                TCHAR *StringValue;
                                DWORD DWORDValue;
                } RegAdd;
 
#define REGISTRY_KEY 0
 
So now that we have data types to use, it is time to define the data. The last entry will indicate that it is the end of the data. Since Name is used by both structures and is needed for each entry, NAME == NULL will be the end of data indicator and the rest of the data in that entry will just be ignored.
RegDelete RemoveKeys[] = {
                {HKEY_LOCAL_MACHINE, TEXT("System\\StorageManager\\Profiles\\HDProfile")},
                {HKEY_LOCAL_MACHINE, TEXT("System\\StorageManager\\Profiles\\HDProfile\\FATFS")},
                { INVALID_HANDLE_VALUE, NULL }
                };
 
RegAdd AddKeys[] = {
                { REGISTRY_KEY, HKEY_LOCAL_MACHINE, TEXT("Drivers\\PCCARD\\PCMCIA\\TEMPLATE\\PCMCIA"), NULL, 0 },
                                { REG_SZ, INVALID_HANDLE_VALUE, TEXT("Dll"), TEXT("pcmcia.dll"), 0 },
                                { REG_DWORD, INVALID_HANDLE_VALUE, TEXT("NoConfig"), NULL, 1 },
                                { REG_MULTI_SZ, INVALID_HANDLE_VALUE, TEXT("IClass"), TEXT("{6BEAB08A-8914-42fd-B33F-61968B9AAB32}=PCMCIA Card Services\0"), 0 },
                { REGISTRY_KEY, HKEY_LOCAL_MACHINE, TEXT("Loader"), NULL, 0 },
                                { REG_MULTI_SZ, INVALID_HANDLE_VALUE, TEXT("SystemPath"), TEXT("\\NOR Flash\\System\\\0\\Release\\\0"), 0 },
                { 0, INVALID_HANDLE_VALUE, NULL, NULL, 0 }
                };
The first function is DeleteRegKeys(). DeleteRegKeys() takes an array of RegDelete structures as its argument. It will iterate through the entries and delete them. Note that RegDeleteKey(), a Win32 API, will delete the key and all of its sub-keys. So, the example data will actually cause the failed message to be displayed because it tries to delete a sub-key after deleting the parent key.
 
void DeleteRegKeys( RegDelete RemoveKeys[] )
{
                DWORD Index = 0;
                for( Index = 0; ; Index++ )
                {
                                if( RemoveKeys[ Index ].Name == NULL )
                                                break;  
                                if( ERROR_SUCCESS != RegDeleteKey( RemoveKeys[ Index ].hkey, RemoveKeys[ Index ].Name ) )
                                                RETAILMSG( 1, (TEXT("Failed to delete key %s (%d)\r\n"), RemoveKeys[ Index ].Name, GetLastError() ));
                }
}
The next function, AddRegKeys(), will take care of adding the new keys and values. AddRegKeys() takes an array of RegAdd structures as its argument. It will iterate through the entries, create the registry keys and then add the values. The key is required to be defined in the data before the values. When a key is found in the data, the key will be created and the handle will be used to add values until the next key is found. When the next key is found, the existing key will be closed and the registry will be flushed.
AddRegKeys() handles REG_DWORD, REG_SZ and REG_MULTI_SZ. Other types can easily be added, but quite frankly I didn’t need any other types.
NOTE ON REG_MULTI_SZ: multi strings are defined in the registry as:
                <String><null>[<String><null>]…<null>
Example
                “data\0more data\0still more data\0\0”
Of course the you don’t need to actually put the last null character because the compile will do that for you.
 
void AddRegKeys( RegAdd AddKeys[] )
{
                DWORD Index = 0;
                DWORD Disposition ;
                UINT32 status;
                DWORD NumBytes = 0;
                HKEY regKey=NULL;
                BYTE *Data;
 
                for( Index = 0; ; Index++ )
                {
                                if( AddKeys[ Index ].Name == NULL )
                                                break;
 
                                if( AddKeys[ Index ].Type == REGISTRY_KEY )
                                {
                                                if( regKey != NULL )
                                                {
                                                                RegFlushKey( regKey );
                                                                RegCloseKey( regKey );
                                                }
                                                status = RegCreateKeyEx(AddKeys[ Index ].hkey,
                                                                AddKeys[ Index ].Name,
                                                                0,
                                                                0,
                                                                REG_OPTION_NON_VOLATILE,
                                                                0,
                                                                NULL,
                                                                &regKey,
                                                                &Disposition
                                                                );
                                                if( status != ERROR_SUCCESS )
                                                                RETAILMSG( 1, (TEXT("Error creating key %s (%d)\r\n"), AddKeys[ Index ].Name, GetLastError() ));
                                }
                                else
                                {
                                                if( AddKeys[ Index ].Type == REG_DWORD )
                                                {
                                                                NumBytes = sizeof(DWORD);
                                                                Data = (BYTE *)&AddKeys[ Index ].DWORDValue ;
                                                }
                                                else if( AddKeys[ Index ].Type == REG_SZ )
                                                {
                                                                NumBytes = ( wcslen( AddKeys[ Index ].StringValue ) + 1 ) * sizeof( TCHAR );
                                                                Data = (BYTE *)AddKeys[ Index ].StringValue ;
                                                }
                                                else if( AddKeys[ Index ].Type == REG_MULTI_SZ )
                                                {
                                                                BOOL Done = FALSE;
                                                                TCHAR *Str = AddKeys[ Index ].StringValue ;
                                                                NumBytes = 0;
                                                                while( !Done )
                                                                {
                                                                                if( *Str == '\0' )
                                                                                                Done = TRUE;
                                                                                NumBytes += wcslen( Str ) + 1;
                                                                                Str = &AddKeys[ Index ].StringValue[ NumBytes ];
                                                                }
                                                                NumBytes *= sizeof( TCHAR );
                                                                Data = (BYTE *)AddKeys[ Index ].StringValue ;
                                                }
 
                                                RegSetValueEx( regKey,
                                                                AddKeys[ Index ].Name,
                                                                0,
                                                                AddKeys[ Index ].Type,
                                                                Data,
                                                                NumBytes
                                                                );
                                }
                }
                if( regKey != NULL )
                {
                                RegFlushKey( regKey );
                                RegCloseKey( regKey );
                }
}
Finally, a WinMain to call the functions. Just in case there isn’t any data added to the registry this also flushes the registry when it is done.
int WINAPI WinMain( HINSTANCE hInstance,
                                                                                HINSTANCE hPrevInstance,
                                                                                LPTSTR    lpCmdLine,
                                                                                int       nCmdShow)
{
                DeleteRegKeys( RemoveKeys );
                AddRegKeys( AddKeys );
                RegFlushKey( HKEY_LOCAL_MACHINE );
}
 
You may also want to look at Summary of Registry Posts
Copyright © 2009 – Bruce Eitman
All Rights Reserved