Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/express/windowsRegistry.cxx

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

Generated on Fri May 2 00:38:51 2003 for Panda by doxygen1.3