1 ///////////////////////////////////////////////////////////////////////////////
3 // Module: WriteRegistry.cpp
5 // Desc: Functions to write a registry hive to a file.
7 // Copyright (c) 2003 Grant McDorman
8 // This file is licensed using a BSD-type license:
9 // This software is provided 'as-is', without any express or implied
10 // warranty. In no event will the authors be held liable for any damages
11 // arising from the use of this software.
13 // Permission is granted to anyone to use this software for any purpose,
14 // including commercial applications, and to alter it and redistribute it
15 // freely, subject to the following restrictions:
17 // 1. The origin of this software must not be misrepresented; you must not
18 // claim that you wrote the original software. If you use this software
19 // in a product, an acknowledgment in the product documentation would be
20 // appreciated but is not required.
21 // 2. Altered source versions must be plainly marked as such, and must not be
22 // misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source distribution.
25 ///////////////////////////////////////////////////////////////////////////////
28 #include <windows.h> // CreateFile, WriteFile, CloseHandle, DeleteFile, Reg* functions
29 #include <stdio.h> // _snprintf
31 #include "WriteRegistry.h"
33 static bool WriteRegValue(HANDLE hFile
, const char *key_path
, const char *name
, int name_len
, DWORD type
, const unsigned char *data
, DWORD data_len
);
34 static bool WriteValuesAndSubkeys(const char *key_path
, HKEY parent_key
, const char *subkey
, HANDLE hFile
);
35 static void WriteFileString(HANDLE hFile
, const char *string
);
37 bool WriteRegistryTreeToFile(const char *key
, const char *filename
)
39 const char *cp
= strchr(key
, '\\');
43 ptrdiff_t len
= cp
- key
;
46 #define IS_PATH(id, short_id) if (strncmp(key, #id, len) == 0 || strncmp(key, #short_id, len) == 0) hKey = id
47 IS_PATH(HKEY_CLASSES_ROOT
, HKCR
);
48 else IS_PATH(HKEY_CURRENT_USER
, HKCU
);
49 else IS_PATH(HKEY_LOCAL_MACHINE
, HKLM
);
50 else IS_PATH(HKEY_CURRENT_CONFIG
, HKCC
);
51 else IS_PATH(HKEY_USERS
, HKU
);
52 else IS_PATH(HKEY_PERFORMANCE_DATA
, HKPD
);
53 else IS_PATH(HKEY_DYN_DATA
, HKDD
);
57 return WriteRegistryTreeToFile(hKey
, cp
+ 1, filename
);
60 bool WriteRegistryTreeToFile(HKEY section
, const char *subkey
, const char *filename
)
63 HANDLE hFile
= ::CreateFile(
65 GENERIC_READ
| GENERIC_WRITE
,
66 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
69 FILE_ATTRIBUTE_NORMAL
,
71 if (INVALID_HANDLE_VALUE
!= hFile
) {
72 char * key_path
= "UNKNOWN";
73 #define SET_PATH(id) if (id == section) key_path = #id
74 SET_PATH(HKEY_CLASSES_ROOT
);
75 else SET_PATH(HKEY_CURRENT_USER
);
76 else SET_PATH(HKEY_LOCAL_MACHINE
);
77 else SET_PATH(HKEY_CURRENT_CONFIG
);
78 else SET_PATH(HKEY_USERS
);
79 else SET_PATH(HKEY_PERFORMANCE_DATA
);
80 else SET_PATH(HKEY_DYN_DATA
);
81 WriteFileString(hFile
, "REGEDIT4\r\n");
84 status
= WriteValuesAndSubkeys(key_path
, section
, subkey
, hFile
);
96 static bool WriteValuesAndSubkeys(const char *key_path
, HKEY parent_key
, const char *subkey
, HANDLE hFile
)
100 if (RegOpenKeyEx(parent_key
, subkey
, 0, KEY_READ
, &key
) != ERROR_SUCCESS
) {
101 OutputDebugString("RegOpenKeyEx failed, key:\n");
102 OutputDebugString(subkey
);
106 DWORD max_subkey_len
;
112 if (RegQueryInfoKey(key
,
116 &num_subkeys
, &max_subkey_len
,
118 &num_values
, &max_name_len
, &max_value_len
, NULL
, NULL
) != ERROR_SUCCESS
) {
119 OutputDebugString("RegQueryInfoKey failed, key:\n");
120 OutputDebugString(subkey
);
124 max_id_len
= (max_name_len
> max_subkey_len
) ? max_name_len
: max_subkey_len
;
125 char *this_path
= reinterpret_cast<char *>(alloca(strlen(key_path
) + strlen(subkey
) + 2));
126 // strcpy/strcat safe because of above alloca
127 strcpy(this_path
, key_path
);
128 strcat(this_path
, "\\");
129 strcat(this_path
, subkey
);
131 WriteFileString(hFile
, "\r\n[");
132 WriteFileString(hFile
, this_path
);
133 WriteFileString(hFile
, "]\r\n");
136 char *name
= reinterpret_cast<char *>(alloca(max_id_len
*2 + 2));
137 unsigned char *data
= reinterpret_cast<unsigned char *>(alloca(max_value_len
*2 + 2));
141 for (index
= 0; index
< num_values
&& status
; index
++) {
142 DWORD name_len
= max_id_len
+ 1;
143 DWORD value_len
= max_value_len
+ 1;
145 if (RegEnumValue(key
, index
, name
, &name_len
, NULL
, &type
, data
, &value_len
) == ERROR_SUCCESS
) {
146 status
= WriteRegValue(hFile
, this_path
, name
, name_len
, type
, data
, value_len
);
151 for (index
= 0; index
< num_subkeys
&& status
; index
++) {
152 DWORD name_len
= max_id_len
+ 1;
153 if (RegEnumKeyEx(key
, index
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
154 status
= WriteValuesAndSubkeys(this_path
, key
, name
, hFile
);
163 static bool WriteRegValue(HANDLE hFile
, const char * /*key_path*/, const char *name
, int /* name_len */, DWORD type
, const unsigned char *data
, DWORD data_len
)
165 WriteFileString(hFile
, "\"");
166 WriteFileString(hFile
, name
);
168 char string_type
[64];
171 case REG_DWORD
: // A 32-bit number.
172 strncpy(string_type
, "\"=dword:", sizeof string_type
);
175 case REG_SZ
: // A null terminated string.
176 strncpy(string_type
, "\"=\"", sizeof string_type
);
179 case REG_BINARY
: // Binary data in any form.
180 strncpy(string_type
, "\"=hex:", sizeof string_type
);
183 case REG_EXPAND_SZ
: // A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions. To expand the environment variable references, use the ExpandEnvironmentStrings function.
184 case REG_LINK
: // A Unicode symbolic link. Used internally; applications should not use this type.
185 case REG_MULTI_SZ
: // An array of null-terminated strings, terminated by two null characters.
186 case REG_NONE
: // No defined value type.
187 case REG_DWORD_BIG_ENDIAN
: // A 64-bit number in big-endian format.
188 case REG_RESOURCE_LIST
: // A device-driver resource list.
190 _snprintf(string_type
, sizeof string_type
, "\"=hex(%x):", type
);
194 WriteFileString(hFile
, string_type
);
196 if (type
== REG_SZ
|| type
== REG_EXPAND_SZ
) {
197 // escape special characters; length includes trailing NUL
199 // don't crash'n'burn if data_len is 0
200 for (i
= 0; i
< static_cast<int>(data_len
) - 1; i
++) {
201 if (data
[i
] == '\\' || data
[i
] == '"') {
202 WriteFileString(hFile
, "\\");
204 if (isprint(data
[i
])) {
206 if (!WriteFile(hFile
, &data
[i
], 1, &written
, NULL
) || written
!= 1) {
210 _snprintf(string_type
, sizeof string_type
, "\\%02x", data
[i
]);
211 WriteFileString(hFile
, string_type
);
214 WriteFileString(hFile
, "\"");
215 } else if (type
== REG_DWORD
) {
216 // write as hex, MSB first
218 for (i
= static_cast<int>(data_len
) - 1; i
>= 0; i
--) {
219 _snprintf(string_type
, sizeof string_type
, "%02x", data
[i
]);
220 WriteFileString(hFile
, string_type
);
223 // write as comma-separated hex values
225 for (i
= 0; i
< data_len
; i
++) {
226 _snprintf(string_type
, sizeof string_type
, "%s%02x", i
> 0 ? "," : "", data
[i
]);
227 WriteFileString(hFile
, string_type
);
228 if (i
> 0 && i
% 16 == 0) {
229 WriteFileString(hFile
, "\r\n");
233 WriteFileString(hFile
, "\r\n");
240 static void WriteFileString(HANDLE hFile
, const char *string
)
243 if (!WriteFile(hFile
, string
, strlen(string
), &written
, NULL
) || written
!= strlen(string
)) {
244 OutputDebugString("WriteFile failed\n");