uniregistrygen.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2004 Net Integration Technologies, Inc.
00004  * 
00005  * A generator that exposes the windows registry.
00006  */
00007 #include "uniregistrygen.h"
00008 #include "wvmoniker.h"
00009 #include "wvlinkerhack.h"
00010 
00011 WV_LINK(UniRegistryGen);
00012 
00013 
00014 // returns a handle to the key specified by key, or, if key specifies a value,
00015 // a handle to the key containing that value (and setting isValue = true)
00016 static HKEY follow_path(HKEY from, const UniConfKey &key,
00017                         bool create, bool *isValue)
00018 {
00019     const REGSAM samDesired = KEY_READ | KEY_WRITE;
00020     LONG result;
00021     HKEY hLastKey = from; // DuplicateHandle() does not work with regkeys
00022     int n = key.numsegments();
00023 
00024     if (isValue) *isValue = false;
00025 
00026     for (int i=0;i<n;i++)
00027     {
00028         WvString subkey = key.segment(i).printable();
00029         HKEY hNextKey;
00030         
00031         if (create)
00032         {
00033             result = RegCreateKeyEx(hLastKey, subkey, 0, NULL, 0, samDesired, 
00034                 NULL, &hNextKey, NULL);
00035         }
00036         else
00037         {
00038             result = RegOpenKeyEx(hLastKey, subkey, 0, samDesired, &hNextKey);
00039         }
00040 
00041         if ((result == ERROR_FILE_NOT_FOUND) && (i == n-1))
00042         {
00043             WvString xsub(subkey=="." ? WvString::null : subkey);
00044             
00045             // maybe the last segment is a value name
00046             if (RegQueryValueEx(hLastKey, xsub, 0, NULL, NULL, NULL) == ERROR_SUCCESS)
00047             {
00048                 // ... it is a value
00049                 if (isValue) *isValue = true;
00050                 break;
00051             }
00052         }
00053         if (result != ERROR_SUCCESS)
00054         {
00055             return 0;
00056         }
00057         
00058         
00059         if (i > 0)
00060         {
00061             RegCloseKey(hLastKey);
00062         }
00063         hLastKey = hNextKey;
00064     }
00065 
00066     return hLastKey;
00067 }
00068 
00069 
00070 UniRegistryGen::UniRegistryGen(WvString _moniker) :
00071     m_log(_moniker), m_hRoot(0)
00072 {
00073     UniConfKey key = _moniker;
00074     WvString hive = key.first().printable();
00075     if (strcmp("HKEY_CLASSES_ROOT", hive) == 0)
00076     {
00077         m_hRoot = HKEY_CLASSES_ROOT;
00078     } 
00079     else if (strcmp("HKEY_CURRENT_USER", hive) == 0)
00080     {
00081         m_hRoot = HKEY_CURRENT_USER;
00082     }
00083     else if (strcmp("HKEY_LOCAL_MACHINE", hive) == 0)
00084     {
00085         m_hRoot = HKEY_LOCAL_MACHINE;
00086     }
00087     else if (strcmp("HKEY_USERS", hive) == 0)
00088     {
00089         m_hRoot = HKEY_USERS;
00090     }
00091 
00092     m_hRoot = follow_path(m_hRoot, key.range(1, key.numsegments()), true, NULL);
00093 
00094 #if 0
00095     // FIXME: Notifications don't work for external registry changes.
00096     //
00097     hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
00098     RegNotifyChangeKeyValue(
00099         m_hRoot,
00100         TRUE,
00101         REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
00102         REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY,
00103         hEvent,
00104         TRUE
00105     );
00106 #endif
00107 }
00108 
00109 UniRegistryGen::~UniRegistryGen()
00110 {
00111     if (m_hRoot)
00112     {
00113         RegCloseKey(m_hRoot);
00114         m_hRoot = 0;
00115     }
00116 }
00117 
00118 bool UniRegistryGen::isok()
00119 {
00120     return m_hRoot != 0;
00121 }
00122 
00123 WvString UniRegistryGen::get(const UniConfKey &key)
00124 {
00125     WvString retval = WvString::null;
00126     bool isvalue;
00127     HKEY hKey = follow_path(m_hRoot, key, false, &isvalue);
00128 
00129     WvString value;
00130     if (isvalue)
00131     {
00132         // the path ends up at a value so fetch that
00133         value = key.last();
00134         if (value == ".") value = WvString::null;
00135     }
00136     else
00137     {
00138         // the key isn't a value, fetch its default value instead
00139         value = WvString::null;
00140     }
00141     
00142     DWORD type;
00143     TCHAR data[1024];
00144     DWORD size = sizeof(data) / sizeof(data[0]);
00145     LONG result = RegQueryValueEx(
00146         hKey, 
00147         value.cstr(), 
00148         0, 
00149         &type, 
00150         (BYTE *) data, 
00151         &size
00152     );
00153 
00154     if (result == ERROR_SUCCESS)
00155     {
00156         switch (type)
00157         {
00158         case REG_DWORD:
00159             retval.setsize(11);
00160             itoa(*((int *) data), retval.edit(), 10);
00161             break;
00162         case REG_SZ:
00163             retval = data;
00164             break;
00165         default:
00166             break;
00167         };
00168     }
00169 
00170     if (hKey != m_hRoot) RegCloseKey(hKey);
00171     return retval;
00172 }
00173 
00174 void UniRegistryGen::set(const UniConfKey &key, WvStringParm value)
00175 {
00176     LONG result;
00177     HKEY hKey = follow_path(m_hRoot, key.first( key.numsegments()-1 ), true, NULL);
00178     if (hKey)
00179     {
00180         if (value.isnull())
00181         {
00182             result = RegDeleteValue(hKey, key.last().printable());
00183         }
00184         else
00185         {
00186             WvString last = key.last();
00187             if (last == ".") last = WvString::null;
00188             result = RegSetValueEx(
00189                 hKey,
00190                 last,
00191                 0,
00192                 REG_SZ,
00193                 (BYTE *) value.cstr(),
00194                 strlen(value)+1
00195             );
00196         }
00197         if (result == ERROR_SUCCESS)
00198         {
00199             delta(key, value);
00200         }
00201     }
00202     if (hKey != m_hRoot) RegCloseKey(hKey);
00203 }
00204 
00205 bool UniRegistryGen::exists(const UniConfKey &key)
00206 {
00207     return get(key) == WvString::null;
00208 }
00209 
00210 bool UniRegistryGen::haschildren(const UniConfKey &key)
00211 {
00212     UniRegistryGenIter iter(*this, key, m_hRoot);
00213     iter.rewind();
00214     return iter.next();
00215 }
00216 
00217 
00218 UniConfGen::Iter *UniRegistryGen::iterator(const UniConfKey &key)
00219 {
00220     return new UniRegistryGenIter(*this, key, m_hRoot);
00221 }
00222 
00223 
00224 UniRegistryGenIter::UniRegistryGenIter(UniRegistryGen &gen,
00225                                        const UniConfKey &key, HKEY base)
00226     : m_hKey(0), m_enumerating(KEYS), m_index(0), gen(gen), parent(key),
00227       m_dontClose(base)
00228 {
00229     bool isValue;
00230     HKEY hKey = follow_path(base, key, false, &isValue);
00231     
00232     // fprintf(stderr, "(iter:%s:%d:%p)\n",
00233     //      key.printable().cstr(), isValue, hKey); fflush(stderr);
00234             
00235     if (isValue)
00236     {
00237         // a value doesn't have subkeys
00238         if (hKey != m_dontClose) RegCloseKey(hKey);
00239         m_enumerating = VALUES;
00240     }
00241     else
00242         m_hKey = hKey;
00243 }
00244 
00245 
00246 UniRegistryGenIter::~UniRegistryGenIter()
00247 {
00248     if (m_hKey && m_hKey != m_dontClose)
00249         RegCloseKey(m_hKey);
00250 }
00251 
00252 
00253 void UniRegistryGenIter::rewind()
00254 {
00255     current_key = "YOU HAVE TO REWIND, DUMMY!";
00256     m_enumerating = KEYS;
00257     m_index = 0;
00258 }
00259 
00260 
00261 bool UniRegistryGenIter::next()
00262 {
00263     if (m_enumerating == KEYS)
00264     {
00265         LONG result = next_key();
00266         if (result == ERROR_SUCCESS)
00267             return true;
00268         else if (result == ERROR_NO_MORE_ITEMS)
00269         {
00270             // done enumerating keys, now enumerate the values
00271             m_enumerating = VALUES;
00272             m_index = 0;
00273         }
00274         else
00275         {
00276             fprintf(stderr, "KEY_ENUM result: %d\n", result);
00277             fflush(stderr);
00278             return false; // give up
00279         }
00280     }
00281     assert(m_enumerating == VALUES);
00282     LONG result = next_value();
00283     if (result == ERROR_SUCCESS)
00284         return true;
00285     return false;
00286 }
00287 
00288 UniConfKey UniRegistryGenIter::key() const
00289 {
00290     return current_key;
00291 }
00292 
00293 
00294 WvString UniRegistryGenIter::value() const
00295 {
00296     UniConfKey val(parent, current_key);
00297     return gen.get(val);
00298 }
00299 
00300 
00301 LONG UniRegistryGenIter::next_key()
00302 {
00303     if (!m_hKey)
00304         return ERROR_NO_MORE_ITEMS;
00305     
00306     FILETIME dontcare;
00307     TCHAR data[1024];
00308     DWORD size = sizeof(data) / sizeof(data[0]);
00309     LONG result = RegEnumKeyEx(m_hKey, m_index++, data, &size, 0, 0, 0, &dontcare);
00310     if (result == ERROR_SUCCESS)
00311         current_key = data;
00312     return result;
00313 }
00314 
00315 
00316 LONG UniRegistryGenIter::next_value()
00317 {
00318     if (!m_hKey)
00319         return ERROR_NO_MORE_ITEMS;
00320     
00321     TCHAR data[1024] = "";
00322     DWORD size = sizeof(data) / sizeof(data[0]);
00323     while (!*data)
00324     {
00325         LONG result = RegEnumValue(m_hKey, m_index++, data, &size, 0, 0, 0, 0);
00326         if (result != ERROR_SUCCESS)
00327             return result;
00328     }
00329     current_key = data;
00330     return ERROR_SUCCESS;
00331 }
00332 
00333 
00334 static IUniConfGen *creator(WvStringParm s, IObject *, void *)
00335 {
00336     return new UniRegistryGen(s);
00337 }
00338 
00339 #pragma warning(disable : 4073)
00340 #pragma init_seg(lib)
00341 WvMoniker<IUniConfGen> UniRegistryGenMoniker("registry", creator);

Generated on Wed Jul 12 17:53:20 2006 for WvStreams by  doxygen 1.4.7