Panda3D
|
00001 // Filename: windowsRegistry.cxx 00002 // Created by: drose (06Aug01) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "windowsRegistry.h" 00016 #include "config_express.h" 00017 #include "textEncoder.h" 00018 00019 #if defined(WIN32_VC) 00020 #define WIN32_LEAN_AND_MEAN 00021 #include <windows.h> 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: WindowsRegistry::set_string_value 00025 // Access: Published, Static 00026 // Description: Sets the registry key to the indicated value as a 00027 // string. The supplied string value is automatically 00028 // converted from whatever encoding is set by 00029 // TextEncoder::set_default_encoding() and written as a 00030 // Unicode string. The registry key must already exist 00031 // prior to calling this function. 00032 //////////////////////////////////////////////////////////////////// 00033 bool WindowsRegistry:: 00034 set_string_value(const string &key, const string &name, const string &value, 00035 WindowsRegistry::RegLevel rl) 00036 { 00037 TextEncoder encoder; 00038 wstring wvalue = encoder.decode_text(value); 00039 00040 bool okflag = true; 00041 00042 // Now convert the string to Windows' idea of the correct wide-char 00043 // encoding, so we can store it in the registry. This might well be 00044 // the same string we just decoded from, but it might not. 00045 00046 // Windows likes to have a null character trailing the string (even 00047 // though we also pass a length). 00048 wvalue += (wchar_t)0; 00049 int mb_result_len = 00050 WideCharToMultiByte(CP_ACP, 0, 00051 wvalue.data(), wvalue.length(), 00052 NULL, 0, 00053 NULL, NULL); 00054 if (mb_result_len == 0) { 00055 express_cat.error() 00056 << "Unable to convert '" << value 00057 << "' from Unicode to MultiByte form.\n"; 00058 return false; 00059 } 00060 00061 char *mb_result = (char *)alloca(mb_result_len); 00062 WideCharToMultiByte(CP_ACP, 0, 00063 wvalue.data(), wvalue.length(), 00064 mb_result, mb_result_len, 00065 NULL, NULL); 00066 00067 if (express_cat.is_debug()) { 00068 express_cat.debug() 00069 << "Converted '" << value << "' to '" << mb_result 00070 << "' for storing in registry.\n"; 00071 } 00072 00073 return do_set(key, name, REG_SZ, mb_result, mb_result_len, rl); 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: WindowsRegistry::set_int_value 00078 // Access: Published, Static 00079 // Description: Sets the registry key to the indicated value as an 00080 // integer. The registry key must already exist prior 00081 // to calling this function. 00082 //////////////////////////////////////////////////////////////////// 00083 bool WindowsRegistry:: 00084 set_int_value(const string &key, const string &name, int value, 00085 WindowsRegistry::RegLevel rl) 00086 { 00087 DWORD dw = value; 00088 return do_set(key, name, REG_DWORD, &dw, sizeof(dw), rl); 00089 } 00090 00091 //////////////////////////////////////////////////////////////////// 00092 // Function: WindowsRegistry::get_key_type 00093 // Access: Published, Static 00094 // Description: Returns the type of the indicated key, or T_none if 00095 // the key is not known or is some unsupported type. 00096 //////////////////////////////////////////////////////////////////// 00097 WindowsRegistry::Type WindowsRegistry:: 00098 get_key_type(const string &key, const string &name, 00099 WindowsRegistry::RegLevel rl) 00100 { 00101 int data_type; 00102 string data; 00103 if (!do_get(key, name, data_type, data, rl)) { 00104 return T_none; 00105 } 00106 00107 switch (data_type) { 00108 case REG_SZ: 00109 return T_string; 00110 00111 case REG_DWORD: 00112 return T_int; 00113 00114 default: 00115 return T_none; 00116 } 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: WindowsRegistry::get_string_value 00121 // Access: Published, Static 00122 // Description: Returns the value associated with the indicated 00123 // registry key, assuming it is a string value. The 00124 // string value is automatically encoded using 00125 // TextEncoder::get_default_encoding(). If the key is 00126 // not defined or is not a string type value, 00127 // default_value is returned instead. 00128 //////////////////////////////////////////////////////////////////// 00129 string WindowsRegistry:: 00130 get_string_value(const string &key, const string &name, 00131 const string &default_value, 00132 WindowsRegistry::RegLevel rl) 00133 { 00134 int data_type; 00135 string data; 00136 if (!do_get(key, name, data_type, data, rl)) { 00137 return default_value; 00138 } 00139 00140 if (data_type != REG_SZ) { 00141 express_cat.warning() 00142 << "Registry key " << key << " does not contain a string value.\n"; 00143 return default_value; 00144 } 00145 00146 // Now we have to decode the MultiByte string to Unicode, and re-encode 00147 // it according to our own encoding. 00148 00149 if (data.empty()) { 00150 return data; 00151 } 00152 00153 int wide_result_len = 00154 MultiByteToWideChar(CP_ACP, 0, 00155 data.data(), data.length(), 00156 NULL, 0); 00157 if (wide_result_len == 0) { 00158 express_cat.error() 00159 << "Unable to convert '" << data 00160 << "' from MultiByte to Unicode form.\n"; 00161 return data; 00162 } 00163 00164 wchar_t *wide_result = (wchar_t *)alloca(wide_result_len * sizeof(wchar_t)); 00165 MultiByteToWideChar(CP_ACP, 0, 00166 data.data(), data.length(), 00167 wide_result, wide_result_len); 00168 00169 wstring wdata(wide_result, wide_result_len); 00170 00171 TextEncoder encoder; 00172 string result = encoder.encode_wtext(wdata); 00173 00174 if (express_cat.is_debug()) { 00175 express_cat.debug() 00176 << "Converted '" << data << "' from registry to '" << result << "'\n"; 00177 } 00178 00179 return result; 00180 } 00181 00182 //////////////////////////////////////////////////////////////////// 00183 // Function: WindowsRegistry::get_int_value 00184 // Access: Published, Static 00185 // Description: Returns the value associated with the indicated 00186 // registry key, assuming it is an integer value. If 00187 // the key is not defined or is not an integer type 00188 // value, default_value is returned instead. 00189 //////////////////////////////////////////////////////////////////// 00190 int WindowsRegistry:: 00191 get_int_value(const string &key, const string &name, int default_value, 00192 WindowsRegistry::RegLevel rl) 00193 { 00194 int data_type; 00195 string data; 00196 if (!do_get(key, name, data_type, data, rl)) { 00197 return default_value; 00198 } 00199 00200 if (data_type != REG_DWORD) { 00201 express_cat.warning() 00202 << "Registry key " << key << " does not contain an integer value.\n"; 00203 return default_value; 00204 } 00205 00206 // Now we have a DWORD encoded in a string. 00207 nassertr(data.length() == sizeof(DWORD), default_value); 00208 DWORD dw = *(DWORD *)data.data(); 00209 return dw; 00210 } 00211 00212 //////////////////////////////////////////////////////////////////// 00213 // Function: WindowsRegistry::do_set 00214 // Access: Private, Static 00215 // Description: The internal function to actually make all of the 00216 // appropriate windows calls to set the registry value. 00217 //////////////////////////////////////////////////////////////////// 00218 bool WindowsRegistry:: 00219 do_set(const string &key, const string &name, 00220 int data_type, const void *data, int data_length, 00221 const WindowsRegistry::RegLevel rl) 00222 { 00223 HKEY hkey, regkey = HKEY_LOCAL_MACHINE; 00224 LONG error; 00225 00226 if (rl == rl_user) // switch to user local settings 00227 regkey = HKEY_CURRENT_USER; 00228 00229 error = 00230 RegOpenKeyEx(regkey, key.c_str(), 0, KEY_SET_VALUE, &hkey); 00231 if (error != ERROR_SUCCESS) { 00232 express_cat.error() 00233 << "Unable to open registry key " << key 00234 << ": " << format_message(error) << "\n"; 00235 return false; 00236 } 00237 00238 bool okflag = true; 00239 00240 error = 00241 RegSetValueEx(hkey, name.c_str(), 0, data_type, 00242 (CONST BYTE *)data, data_length); 00243 if (error != ERROR_SUCCESS) { 00244 express_cat.error() 00245 << "Unable to set registry key " << key << " name " << name 00246 << ": " << format_message(error) << "\n"; 00247 okflag = false; 00248 } 00249 00250 error = RegCloseKey(hkey); 00251 if (error != ERROR_SUCCESS) { 00252 express_cat.warning() 00253 << "Unable to close opened registry key " << key 00254 << ": " << format_message(error) << "\n"; 00255 } 00256 00257 return okflag; 00258 } 00259 00260 //////////////////////////////////////////////////////////////////// 00261 // Function: WindowsRegistry::do_get 00262 // Access: Private, Static 00263 // Description: The internal function to actually make all of the 00264 // appropriate windows calls to retrieve the registry 00265 // value. 00266 //////////////////////////////////////////////////////////////////// 00267 bool WindowsRegistry:: 00268 do_get(const string &key, const string &name, int &data_type, string &data, 00269 const WindowsRegistry::RegLevel rl) 00270 { 00271 HKEY hkey, regkey = HKEY_LOCAL_MACHINE; 00272 LONG error; 00273 00274 if (rl == rl_user) // switch to user local settings 00275 regkey = HKEY_CURRENT_USER; 00276 00277 error = 00278 RegOpenKeyEx(regkey, key.c_str(), 0, KEY_QUERY_VALUE, &hkey); 00279 if (error != ERROR_SUCCESS) { 00280 express_cat.debug() 00281 << "Unable to open registry key " << key 00282 << ": " << format_message(error) << "\n"; 00283 return false; 00284 } 00285 00286 bool okflag = true; 00287 00288 // We start with a 1K buffer; presumably that will be big enough 00289 // most of the time. 00290 static const size_t init_buffer_size = 1024; 00291 char init_buffer[init_buffer_size]; 00292 DWORD buffer_size = init_buffer_size; 00293 DWORD dw_data_type; 00294 00295 error = 00296 RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type, 00297 (BYTE *)init_buffer, &buffer_size); 00298 if (error == ERROR_SUCCESS) { 00299 data_type = dw_data_type; 00300 if (data_type == REG_SZ || 00301 data_type == REG_MULTI_SZ || 00302 data_type == REG_EXPAND_SZ) { 00303 // Eliminate the trailing null character for non-zero lengths. 00304 if (buffer_size > 0) // if zero, leave it 00305 buffer_size--; 00306 } 00307 data = string(init_buffer, buffer_size); 00308 00309 } else if (error == ERROR_MORE_DATA) { 00310 // Huh, 1K wasn't big enough. Ok, get a bigger buffer. 00311 00312 // If we were querying HKEY_PERFORMANCE_DATA, we'd have to keep 00313 // guessing bigger and bigger until we got it. Since we're 00314 // querying static data for now, we can just use the size Windows 00315 // tells us. 00316 char *new_buffer = (char *)PANDA_MALLOC_ARRAY(buffer_size); 00317 error = 00318 RegQueryValueEx(hkey, name.c_str(), 0, &dw_data_type, 00319 (BYTE *)new_buffer, &buffer_size); 00320 if (error == ERROR_SUCCESS) { 00321 data_type = dw_data_type; 00322 if (data_type == REG_SZ || 00323 data_type == REG_MULTI_SZ || 00324 data_type == REG_EXPAND_SZ) { 00325 // Eliminate the trailing null character for non-zero lengths. 00326 if (buffer_size > 0) // if zero, leave it 00327 buffer_size--; 00328 } 00329 data = string(new_buffer, buffer_size); 00330 } 00331 PANDA_FREE_ARRAY(new_buffer); 00332 } 00333 00334 if (error != ERROR_SUCCESS) { 00335 express_cat.debug() 00336 << "Unable to get registry value " << name 00337 << ": " << format_message(error) << "\n"; 00338 okflag = false; 00339 } 00340 00341 error = RegCloseKey(hkey); 00342 if (error != ERROR_SUCCESS) { 00343 express_cat.warning() 00344 << "Unable to close opened registry key " << key 00345 << ": " << format_message(error) << "\n"; 00346 } 00347 00348 if (okflag) { 00349 if (data_type == REG_EXPAND_SZ) { 00350 // Expand the string. 00351 DWORD destSize=ExpandEnvironmentStrings(data.c_str(), 0, 0); 00352 char *dest = (char *)PANDA_MALLOC_ARRAY(destSize); 00353 ExpandEnvironmentStrings(data.c_str(), dest, destSize); 00354 data = dest; 00355 PANDA_FREE_ARRAY(dest); 00356 data_type = REG_SZ; 00357 } 00358 } 00359 00360 return okflag; 00361 } 00362 00363 //////////////////////////////////////////////////////////////////// 00364 // Function: WindowsRegistry::format_message 00365 // Access: Private, Static 00366 // Description: Returns the Windows error message associated with the 00367 // given error code. 00368 //////////////////////////////////////////////////////////////////// 00369 string WindowsRegistry:: 00370 format_message(int error_code) { 00371 PVOID buffer; 00372 DWORD length = 00373 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 00374 NULL, error_code, 0, (LPTSTR)&buffer, 0, NULL); 00375 if (length == 0) { 00376 return "Unknown error message"; 00377 } 00378 00379 const char *text = (const char *)buffer; 00380 00381 // Strip off \n's and \r's trailing the string. 00382 while (length > 0 && 00383 (text[length - 1] == '\r' || text[length - 1] == '\n')) { 00384 length--; 00385 } 00386 00387 string result((const char *)text, length); 00388 LocalFree(buffer); 00389 return result; 00390 } 00391 00392 #endif 00393 00394 00395