Panda3D
Loading...
Searching...
No Matches
windowsRegistry.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file windowsRegistry.cxx
10 * @author drose
11 * @date 2001-08-06
12 */
13
14#include "windowsRegistry.h"
15#include "config_express.h"
16#include "textEncoder.h"
17
18#if defined(WIN32_VC)
19#ifndef WIN32_LEAN_AND_MEAN
20#define WIN32_LEAN_AND_MEAN 1
21#endif
22#include <windows.h>
23
24using std::string;
25
26/**
27 * Sets the registry key to the indicated value as a string. The supplied
28 * string value is automatically converted from whatever encoding is set by
29 * TextEncoder::set_default_encoding() and written as a Unicode string. The
30 * registry key must already exist prior to calling this function.
31 */
32bool WindowsRegistry::
33set_string_value(const string &key, const string &name, const string &value,
34 WindowsRegistry::RegLevel rl)
35{
36 TextEncoder encoder;
37 std::wstring wvalue = encoder.decode_text(value);
38
39 // Now convert the string to Windows' idea of the correct wide-char
40 // encoding, so we can store it in the registry. This might well be the
41 // same string we just decoded from, but it might not.
42
43 // Windows likes to have a null character trailing the string (even though
44 // we also pass a length).
45 wvalue += (wchar_t)0;
46 int mb_result_len =
47 WideCharToMultiByte(CP_ACP, 0,
48 wvalue.data(), wvalue.length(),
49 nullptr, 0,
50 nullptr, nullptr);
51 if (mb_result_len == 0) {
52 express_cat.error()
53 << "Unable to convert '" << value
54 << "' from Unicode to MultiByte form.\n";
55 return false;
56 }
57
58 char *mb_result = (char *)alloca(mb_result_len);
59 WideCharToMultiByte(CP_ACP, 0,
60 wvalue.data(), wvalue.length(),
61 mb_result, mb_result_len,
62 nullptr, nullptr);
63
64 if (express_cat.is_debug()) {
65 express_cat.debug()
66 << "Converted '" << value << "' to '" << mb_result
67 << "' for storing in registry.\n";
68 }
69
70 return do_set(key, name, REG_SZ, mb_result, mb_result_len, rl);
71}
72
73/**
74 * Sets the registry key to the indicated value as an integer. The registry
75 * key must already exist prior to calling this function.
76 */
77bool WindowsRegistry::
78set_int_value(const string &key, const string &name, int value,
79 WindowsRegistry::RegLevel rl)
80{
81 DWORD dw = value;
82 return do_set(key, name, REG_DWORD, &dw, sizeof(dw), rl);
83}
84
85/**
86 * Returns the type of the indicated key, or T_none if the key is not known or
87 * is some unsupported type.
88 */
89WindowsRegistry::Type WindowsRegistry::
90get_key_type(const string &key, const string &name,
91 WindowsRegistry::RegLevel rl)
92{
93 int data_type;
94 string data;
95 if (!do_get(key, name, data_type, data, rl)) {
96 return T_none;
97 }
98
99 switch (data_type) {
100 case REG_SZ:
101 return T_string;
102
103 case REG_DWORD:
104 return T_int;
105
106 default:
107 return T_none;
108 }
109}
110
111/**
112 * Returns the value associated with the indicated registry key, assuming it
113 * is a string value. The string value is automatically encoded using
114 * TextEncoder::get_default_encoding(). If the key is not defined or is not a
115 * string type value, default_value is returned instead.
116 */
117string WindowsRegistry::
118get_string_value(const string &key, const string &name,
119 const string &default_value,
120 WindowsRegistry::RegLevel rl)
121{
122 int data_type;
123 string data;
124 if (!do_get(key, name, data_type, data, rl)) {
125 return default_value;
126 }
127
128 if (data_type != REG_SZ) {
129 express_cat.warning()
130 << "Registry key " << key << " does not contain a string value.\n";
131 return default_value;
132 }
133
134 // Now we have to decode the MultiByte string to Unicode, and re-encode it
135 // according to our own encoding.
136
137 if (data.empty()) {
138 return data;
139 }
140
141 int wide_result_len =
142 MultiByteToWideChar(CP_ACP, 0,
143 data.data(), data.length(),
144 nullptr, 0);
145 if (wide_result_len == 0) {
146 express_cat.error()
147 << "Unable to convert '" << data
148 << "' from MultiByte to Unicode form.\n";
149 return data;
150 }
151
152 wchar_t *wide_result = (wchar_t *)alloca(wide_result_len * sizeof(wchar_t));
153 MultiByteToWideChar(CP_ACP, 0,
154 data.data(), data.length(),
155 wide_result, wide_result_len);
156
157 std::wstring wdata(wide_result, wide_result_len);
158
159 TextEncoder encoder;
160 string result = encoder.encode_wtext(wdata);
161
162 if (express_cat.is_debug()) {
163 express_cat.debug()
164 << "Converted '" << data << "' from registry to '" << result << "'\n";
165 }
166
167 return result;
168}
169
170/**
171 * Returns the value associated with the indicated registry key, assuming it
172 * is an integer value. If the key is not defined or is not an integer type
173 * value, default_value is returned instead.
174 */
175int WindowsRegistry::
176get_int_value(const string &key, const string &name, int default_value,
177 WindowsRegistry::RegLevel rl)
178{
179 int data_type;
180 string data;
181 if (!do_get(key, name, data_type, data, rl)) {
182 return default_value;
183 }
184
185 if (data_type != REG_DWORD) {
186 express_cat.warning()
187 << "Registry key " << key << " does not contain an integer value.\n";
188 return default_value;
189 }
190
191 // Now we have a DWORD encoded in a string.
192 nassertr(data.length() == sizeof(DWORD), default_value);
193 DWORD dw = *(DWORD *)data.data();
194 return dw;
195}
196
197/**
198 * The internal function to actually make all of the appropriate windows calls
199 * to set the registry value.
200 */
201bool WindowsRegistry::
202do_set(const string &key, const string &name,
203 int data_type, const void *data, int data_length,
204 const WindowsRegistry::RegLevel rl)
205{
206 HKEY hkey, regkey = HKEY_LOCAL_MACHINE;
207 LONG error;
208
209 if (rl == rl_user) // switch to user local settings
210 regkey = HKEY_CURRENT_USER;
211
212 error =
213 RegOpenKeyEx(regkey, key.c_str(), 0, KEY_SET_VALUE, &hkey);
214 if (error != ERROR_SUCCESS) {
215 express_cat.error()
216 << "Unable to open registry key " << key
217 << ": " << format_message(error) << "\n";
218 return false;
219 }
220
221 bool okflag = true;
222
223 error =
224 RegSetValueEx(hkey, name.c_str(), 0, data_type,
225 (CONST BYTE *)data, data_length);
226 if (error != ERROR_SUCCESS) {
227 express_cat.error()
228 << "Unable to set registry key " << key << " name " << name
229 << ": " << format_message(error) << "\n";
230 okflag = false;
231 }
232
233 error = RegCloseKey(hkey);
234 if (error != ERROR_SUCCESS) {
235 express_cat.warning()
236 << "Unable to close opened registry key " << key
237 << ": " << format_message(error) << "\n";
238 }
239
240 return okflag;
241}
242
243/**
244 * The internal function to actually make all of the appropriate windows calls
245 * to retrieve the registry value.
246 */
247bool WindowsRegistry::
248do_get(const string &key, const string &name, int &data_type, string &data,
249 const WindowsRegistry::RegLevel rl)
250{
251 HKEY hkey, regkey = HKEY_LOCAL_MACHINE;
252 LONG error;
253
254 if (rl == rl_user) // switch to user local settings
255 regkey = HKEY_CURRENT_USER;
256
257 error =
258 RegOpenKeyEx(regkey, key.c_str(), 0, KEY_QUERY_VALUE, &hkey);
259 if (error != ERROR_SUCCESS) {
260 express_cat.debug()
261 << "Unable to open registry key " << key
262 << ": " << format_message(error) << "\n";
263 return false;
264 }
265
266 bool okflag = true;
267
268 // We start with a 1K buffer; presumably that will be big enough most of the
269 // time.
270 static const size_t init_buffer_size = 1024;
271 char init_buffer[init_buffer_size];
272 DWORD buffer_size = init_buffer_size;
273 DWORD dw_data_type;
274
275 error =
276 RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type,
277 (BYTE *)init_buffer, &buffer_size);
278 if (error == ERROR_SUCCESS) {
279 data_type = dw_data_type;
280 if (data_type == REG_SZ ||
281 data_type == REG_MULTI_SZ ||
282 data_type == REG_EXPAND_SZ) {
283 // Eliminate the trailing null character for non-zero lengths.
284 if (buffer_size > 0) // if zero, leave it
285 buffer_size--;
286 }
287 data = string(init_buffer, buffer_size);
288
289 } else if (error == ERROR_MORE_DATA) {
290 // Huh, 1K wasn't big enough. Ok, get a bigger buffer.
291
292 // If we were querying HKEY_PERFORMANCE_DATA, we'd have to keep guessing
293 // bigger and bigger until we got it. Since we're querying static data
294 // for now, we can just use the size Windows tells us.
295 char *new_buffer = (char *)PANDA_MALLOC_ARRAY(buffer_size);
296 error =
297 RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type,
298 (BYTE *)new_buffer, &buffer_size);
299 if (error == ERROR_SUCCESS) {
300 data_type = dw_data_type;
301 if (data_type == REG_SZ ||
302 data_type == REG_MULTI_SZ ||
303 data_type == REG_EXPAND_SZ) {
304 // Eliminate the trailing null character for non-zero lengths.
305 if (buffer_size > 0) // if zero, leave it
306 buffer_size--;
307 }
308 data = string(new_buffer, buffer_size);
309 }
310 PANDA_FREE_ARRAY(new_buffer);
311 }
312
313 if (error != ERROR_SUCCESS) {
314 express_cat.debug()
315 << "Unable to get registry value " << name
316 << ": " << format_message(error) << "\n";
317 okflag = false;
318 }
319
320 error = RegCloseKey(hkey);
321 if (error != ERROR_SUCCESS) {
322 express_cat.warning()
323 << "Unable to close opened registry key " << key
324 << ": " << format_message(error) << "\n";
325 }
326
327 if (okflag) {
328 if (data_type == REG_EXPAND_SZ) {
329 // Expand the string.
330 DWORD destSize=ExpandEnvironmentStrings(data.c_str(), 0, 0);
331 char *dest = (char *)PANDA_MALLOC_ARRAY(destSize);
332 ExpandEnvironmentStrings(data.c_str(), dest, destSize);
333 data = dest;
334 PANDA_FREE_ARRAY(dest);
335 data_type = REG_SZ;
336 }
337 }
338
339 return okflag;
340}
341
342/**
343 * Returns the Windows error message associated with the given error code.
344 */
345string WindowsRegistry::
346format_message(int error_code) {
347 PVOID buffer;
348 DWORD length =
349 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
350 nullptr, error_code, 0, (LPTSTR)&buffer, 0, nullptr);
351 if (length == 0) {
352 return "Unknown error message";
353 }
354
355 const char *text = (const char *)buffer;
356
357 // Strip off \n's and \r's trailing the string.
358 while (length > 0 &&
359 (text[length - 1] == '\r' || text[length - 1] == '\n')) {
360 length--;
361 }
362
363 string result((const char *)text, length);
364 LocalFree(buffer);
365 return result;
366}
367
368#endif
This class can be used to convert text between multiple representations, e.g.
Definition textEncoder.h:33
std::wstring decode_text(const std::string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system.
std::string encode_wtext(const std::wstring &wtext) const
Encodes a wide-text string into a single-char string, according to the current encoding.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.