WvStreams
|
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 void UniRegistryGen::setv(const UniConfPairList &pairs) 00206 { 00207 setv_naive(pairs); 00208 } 00209 00210 bool UniRegistryGen::exists(const UniConfKey &key) 00211 { 00212 return !get(key).isnull(); 00213 } 00214 00215 bool UniRegistryGen::haschildren(const UniConfKey &key) 00216 { 00217 UniRegistryGenIter iter(*this, key, m_hRoot); 00218 iter.rewind(); 00219 return iter.next(); 00220 } 00221 00222 00223 UniConfGen::Iter *UniRegistryGen::iterator(const UniConfKey &key) 00224 { 00225 return new UniRegistryGenIter(*this, key, m_hRoot); 00226 } 00227 00228 00229 UniRegistryGenIter::UniRegistryGenIter(UniRegistryGen &gen, 00230 const UniConfKey &key, HKEY base) 00231 : m_hKey(0), m_enumerating(KEYS), m_index(0), gen(gen), parent(key), 00232 m_dontClose(base) 00233 { 00234 bool isValue; 00235 HKEY hKey = follow_path(base, key, false, &isValue); 00236 00237 // fprintf(stderr, "(iter:%s:%d:%p)\n", 00238 // key.printable().cstr(), isValue, hKey); fflush(stderr); 00239 00240 if (isValue) 00241 { 00242 // a value doesn't have subkeys 00243 if (hKey != m_dontClose) RegCloseKey(hKey); 00244 m_enumerating = VALUES; 00245 } 00246 else 00247 m_hKey = hKey; 00248 } 00249 00250 00251 UniRegistryGenIter::~UniRegistryGenIter() 00252 { 00253 if (m_hKey && m_hKey != m_dontClose) 00254 RegCloseKey(m_hKey); 00255 } 00256 00257 00258 void UniRegistryGenIter::rewind() 00259 { 00260 current_key = "YOU HAVE TO REWIND, DUMMY!"; 00261 m_enumerating = KEYS; 00262 m_index = 0; 00263 } 00264 00265 00266 bool UniRegistryGenIter::next() 00267 { 00268 if (m_enumerating == KEYS) 00269 { 00270 LONG result = next_key(); 00271 if (result == ERROR_SUCCESS) 00272 return true; 00273 else if (result == ERROR_NO_MORE_ITEMS) 00274 { 00275 // done enumerating keys, now enumerate the values 00276 m_enumerating = VALUES; 00277 m_index = 0; 00278 } 00279 else 00280 { 00281 fprintf(stderr, "KEY_ENUM result: %ld\n", result); 00282 fflush(stderr); 00283 return false; // give up 00284 } 00285 } 00286 assert(m_enumerating == VALUES); 00287 LONG result = next_value(); 00288 if (result == ERROR_SUCCESS) 00289 return true; 00290 return false; 00291 } 00292 00293 UniConfKey UniRegistryGenIter::key() const 00294 { 00295 return current_key; 00296 } 00297 00298 00299 WvString UniRegistryGenIter::value() const 00300 { 00301 UniConfKey val(parent, current_key); 00302 return gen.get(val); 00303 } 00304 00305 00306 LONG UniRegistryGenIter::next_key() 00307 { 00308 if (!m_hKey) 00309 return ERROR_NO_MORE_ITEMS; 00310 00311 FILETIME dontcare; 00312 TCHAR data[1024]; 00313 DWORD size = sizeof(data) / sizeof(data[0]); 00314 LONG result = RegEnumKeyEx(m_hKey, m_index++, data, &size, 0, 0, 0, &dontcare); 00315 if (result == ERROR_SUCCESS) 00316 current_key = data; 00317 return result; 00318 } 00319 00320 00321 LONG UniRegistryGenIter::next_value() 00322 { 00323 if (!m_hKey) 00324 return ERROR_NO_MORE_ITEMS; 00325 00326 TCHAR data[1024] = ""; 00327 DWORD size = sizeof(data) / sizeof(data[0]); 00328 while (!*data) 00329 { 00330 LONG result = RegEnumValue(m_hKey, m_index++, data, &size, 0, 0, 0, 0); 00331 if (result != ERROR_SUCCESS) 00332 return result; 00333 } 00334 current_key = data; 00335 return ERROR_SUCCESS; 00336 } 00337 00338 00339 static IUniConfGen *creator(WvStringParm s, IObject*) 00340 { 00341 return new UniRegistryGen(s); 00342 } 00343 00344 #pragma warning(disable : 4073) 00345 #pragma init_seg(lib) 00346 WvMoniker<IUniConfGen> UniRegistryGenMoniker("registry", creator);