CrashServer: ship new library in installer
[TortoiseGit.git] / src / crashrpt / WriteRegistry.cpp
blobb719c11df70a782512706b29a75632d1cc8c1f92
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // Module: WriteRegistry.cpp
4 //
5 // Desc: Functions to write a registry hive to a file.
6 //
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 ///////////////////////////////////////////////////////////////////////////////
26 #include <StdAfx.h>
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, '\\');
40 if (cp == NULL) {
41 return false;
43 ptrdiff_t len = cp - key;
44 HKEY hKey = 0;
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);
54 else {
55 return false;
57 return WriteRegistryTreeToFile(hKey, cp + 1, filename);
60 bool WriteRegistryTreeToFile(HKEY section, const char *subkey, const char *filename)
62 bool status = false;
63 HANDLE hFile = ::CreateFile(
64 filename,
65 GENERIC_READ | GENERIC_WRITE,
66 FILE_SHARE_READ | FILE_SHARE_WRITE,
67 NULL,
68 CREATE_ALWAYS,
69 FILE_ATTRIBUTE_NORMAL,
70 0);
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");
82 #undef SET_PATH
83 try {
84 status = WriteValuesAndSubkeys(key_path, section, subkey, hFile);
85 } catch (...) {
86 status = false;
88 CloseHandle(hFile);
89 if (!status) {
90 DeleteFile(filename);
93 return status;
96 static bool WriteValuesAndSubkeys(const char *key_path, HKEY parent_key, const char *subkey, HANDLE hFile)
98 HKEY key;
100 if (RegOpenKeyEx(parent_key, subkey, 0, KEY_READ, &key) != ERROR_SUCCESS) {
101 OutputDebugString("RegOpenKeyEx failed, key:\n");
102 OutputDebugString(subkey);
103 return false;
105 DWORD num_subkeys;
106 DWORD max_subkey_len;
107 DWORD num_values;
108 DWORD max_name_len;
109 DWORD max_value_len;
110 DWORD max_id_len;
112 if (RegQueryInfoKey(key,
113 NULL, // class
114 NULL, // num_class
115 NULL, // reserved
116 &num_subkeys, &max_subkey_len,
117 NULL, // MaxClassLen
118 &num_values, &max_name_len, &max_value_len, NULL, NULL) != ERROR_SUCCESS) {
119 OutputDebugString("RegQueryInfoKey failed, key:\n");
120 OutputDebugString(subkey);
121 return false;
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");
135 // enumerate values
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));
138 DWORD index;
139 bool status = true;
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;
144 DWORD type;
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);
150 // enumerate subkeys
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);
158 RegCloseKey(key);
160 return status;
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];
170 switch(type) {
171 case REG_DWORD: // A 32-bit number.
172 strncpy(string_type, "\"=dword:", sizeof string_type);
173 break;
175 case REG_SZ: // A null terminated string.
176 strncpy(string_type, "\"=\"", sizeof string_type);
177 break;
179 case REG_BINARY: // Binary data in any form.
180 strncpy(string_type, "\"=hex:", sizeof string_type);
181 break;
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.
189 default:
190 _snprintf(string_type, sizeof string_type, "\"=hex(%x):", type);
191 break;
194 WriteFileString(hFile, string_type);
196 if (type == REG_SZ || type == REG_EXPAND_SZ) {
197 // escape special characters; length includes trailing NUL
198 int i;
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])) {
205 DWORD written;
206 if (!WriteFile(hFile, &data[i], 1, &written, NULL) || written != 1) {
207 return false;
209 } else {
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
217 int i;
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);
222 } else {
223 // write as comma-separated hex values
224 DWORD i;
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");
235 return true;
240 static void WriteFileString(HANDLE hFile, const char *string)
242 DWORD written;
243 if (!WriteFile(hFile, string, strlen(string), &written, NULL) || written != strlen(string)) {
244 OutputDebugString("WriteFile failed\n");
245 throw false;