WvStreams
uniregistrygen.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2004 Net Integration Technologies, Inc.
4 *
5 * A generator that exposes the windows registry.
6 */
7#include "uniregistrygen.h"
8#include "wvmoniker.h"
9#include "wvlinkerhack.h"
10
11WV_LINK(UniRegistryGen);
12
13
14// returns a handle to the key specified by key, or, if key specifies a value,
15// a handle to the key containing that value (and setting isValue = true)
16static HKEY follow_path(HKEY from, const UniConfKey &key,
17 bool create, bool *isValue)
18{
19 const REGSAM samDesired = KEY_READ | KEY_WRITE;
20 LONG result;
21 HKEY hLastKey = from; // DuplicateHandle() does not work with regkeys
22 int n = key.numsegments();
23
24 if (isValue) *isValue = false;
25
26 for (int i=0;i<n;i++)
27 {
28 WvString subkey = key.segment(i).printable();
29 HKEY hNextKey;
30
31 if (create)
32 {
33 result = RegCreateKeyEx(hLastKey, subkey, 0, NULL, 0, samDesired,
34 NULL, &hNextKey, NULL);
35 }
36 else
37 {
38 result = RegOpenKeyEx(hLastKey, subkey, 0, samDesired, &hNextKey);
39 }
40
41 if ((result == ERROR_FILE_NOT_FOUND) && (i == n-1))
42 {
43 WvString xsub(subkey=="." ? WvString::null : subkey);
44
45 // maybe the last segment is a value name
46 if (RegQueryValueEx(hLastKey, xsub, 0, NULL, NULL, NULL) == ERROR_SUCCESS)
47 {
48 // ... it is a value
49 if (isValue) *isValue = true;
50 break;
51 }
52 }
53 if (result != ERROR_SUCCESS)
54 {
55 return 0;
56 }
57
58
59 if (i > 0)
60 {
61 RegCloseKey(hLastKey);
62 }
63 hLastKey = hNextKey;
64 }
65
66 return hLastKey;
67}
68
69
70UniRegistryGen::UniRegistryGen(WvString _moniker) :
71 m_log(_moniker), m_hRoot(0)
72{
73 UniConfKey key = _moniker;
74 WvString hive = key.first().printable();
75 if (strcmp("HKEY_CLASSES_ROOT", hive) == 0)
76 {
77 m_hRoot = HKEY_CLASSES_ROOT;
78 }
79 else if (strcmp("HKEY_CURRENT_USER", hive) == 0)
80 {
81 m_hRoot = HKEY_CURRENT_USER;
82 }
83 else if (strcmp("HKEY_LOCAL_MACHINE", hive) == 0)
84 {
85 m_hRoot = HKEY_LOCAL_MACHINE;
86 }
87 else if (strcmp("HKEY_USERS", hive) == 0)
88 {
89 m_hRoot = HKEY_USERS;
90 }
91
92 m_hRoot = follow_path(m_hRoot, key.range(1, key.numsegments()), true, NULL);
93
94#if 0
95 // FIXME: Notifications don't work for external registry changes.
96 //
97 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
98 RegNotifyChangeKeyValue(
99 m_hRoot,
100 TRUE,
101 REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES |
102 REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_SECURITY,
103 hEvent,
104 TRUE
105 );
106#endif
107}
108
109UniRegistryGen::~UniRegistryGen()
110{
111 if (m_hRoot)
112 {
113 RegCloseKey(m_hRoot);
114 m_hRoot = 0;
115 }
116}
117
119{
120 return m_hRoot != 0;
121}
122
124{
125 WvString retval = WvString::null;
126 bool isvalue;
127 HKEY hKey = follow_path(m_hRoot, key, false, &isvalue);
128
129 WvString value;
130 if (isvalue)
131 {
132 // the path ends up at a value so fetch that
133 value = key.last();
134 if (value == ".") value = WvString::null;
135 }
136 else
137 {
138 // the key isn't a value, fetch its default value instead
139 value = WvString::null;
140 }
141
142 DWORD type;
143 TCHAR data[1024];
144 DWORD size = sizeof(data) / sizeof(data[0]);
145 LONG result = RegQueryValueEx(
146 hKey,
147 value.cstr(),
148 0,
149 &type,
150 (BYTE *) data,
151 &size
152 );
153
154 if (result == ERROR_SUCCESS)
155 {
156 switch (type)
157 {
158 case REG_DWORD:
159 retval.setsize(11);
160 itoa(*((int *) data), retval.edit(), 10);
161 break;
162 case REG_SZ:
163 retval = data;
164 break;
165 default:
166 break;
167 };
168 }
169
170 if (hKey != m_hRoot) RegCloseKey(hKey);
171 return retval;
172}
173
175{
176 LONG result;
177 HKEY hKey = follow_path(m_hRoot, key.first( key.numsegments()-1 ), true, NULL);
178 if (hKey)
179 {
180 if (value.isnull())
181 {
182 result = RegDeleteValue(hKey, key.last().printable());
183 }
184 else
185 {
186 WvString last = key.last();
187 if (last == ".") last = WvString::null;
188 result = RegSetValueEx(
189 hKey,
190 last,
191 0,
192 REG_SZ,
193 (BYTE *) value.cstr(),
194 strlen(value)+1
195 );
196 }
197 if (result == ERROR_SUCCESS)
198 {
199 delta(key, value);
200 }
201 }
202 if (hKey != m_hRoot) RegCloseKey(hKey);
203}
204
205void UniRegistryGen::setv(const UniConfPairList &pairs)
206{
207 setv_naive(pairs);
208}
209
211{
212 return !get(key).isnull();
213}
214
216{
217 UniRegistryGenIter iter(*this, key, m_hRoot);
218 iter.rewind();
219 return iter.next();
220}
221
222
224{
225 return new UniRegistryGenIter(*this, key, m_hRoot);
226}
227
228
229UniRegistryGenIter::UniRegistryGenIter(UniRegistryGen &gen,
230 const UniConfKey &key, HKEY base)
231 : m_hKey(0), m_enumerating(KEYS), m_index(0), gen(gen), parent(key),
232 m_dontClose(base)
233{
234 bool isValue;
235 HKEY hKey = follow_path(base, key, false, &isValue);
236
237 // fprintf(stderr, "(iter:%s:%d:%p)\n",
238 // key.printable().cstr(), isValue, hKey); fflush(stderr);
239
240 if (isValue)
241 {
242 // a value doesn't have subkeys
243 if (hKey != m_dontClose) RegCloseKey(hKey);
244 m_enumerating = VALUES;
245 }
246 else
247 m_hKey = hKey;
248}
249
250
252{
253 if (m_hKey && m_hKey != m_dontClose)
254 RegCloseKey(m_hKey);
255}
256
257
259{
260 current_key = "YOU HAVE TO REWIND, DUMMY!";
261 m_enumerating = KEYS;
262 m_index = 0;
263}
264
265
267{
268 if (m_enumerating == KEYS)
269 {
270 LONG result = next_key();
271 if (result == ERROR_SUCCESS)
272 return true;
273 else if (result == ERROR_NO_MORE_ITEMS)
274 {
275 // done enumerating keys, now enumerate the values
276 m_enumerating = VALUES;
277 m_index = 0;
278 }
279 else
280 {
281 fprintf(stderr, "KEY_ENUM result: %ld\n", result);
282 fflush(stderr);
283 return false; // give up
284 }
285 }
286 assert(m_enumerating == VALUES);
287 LONG result = next_value();
288 if (result == ERROR_SUCCESS)
289 return true;
290 return false;
291}
292
294{
295 return current_key;
296}
297
298
300{
301 UniConfKey val(parent, current_key);
302 return gen.get(val);
303}
304
305
306LONG UniRegistryGenIter::next_key()
307{
308 if (!m_hKey)
309 return ERROR_NO_MORE_ITEMS;
310
311 FILETIME dontcare;
312 TCHAR data[1024];
313 DWORD size = sizeof(data) / sizeof(data[0]);
314 LONG result = RegEnumKeyEx(m_hKey, m_index++, data, &size, 0, 0, 0, &dontcare);
315 if (result == ERROR_SUCCESS)
316 current_key = data;
317 return result;
318}
319
320
321LONG UniRegistryGenIter::next_value()
322{
323 if (!m_hKey)
324 return ERROR_NO_MORE_ITEMS;
325
326 TCHAR data[1024] = "";
327 DWORD size = sizeof(data) / sizeof(data[0]);
328 while (!*data)
329 {
330 LONG result = RegEnumValue(m_hKey, m_index++, data, &size, 0, 0, 0, 0);
331 if (result != ERROR_SUCCESS)
332 return result;
333 }
334 current_key = data;
335 return ERROR_SUCCESS;
336}
337
338
339static IUniConfGen *creator(WvStringParm s, IObject*)
340{
341 return new UniRegistryGen(s);
342}
343
344#pragma warning(disable : 4073)
345#pragma init_seg(lib)
346WvMoniker<IUniConfGen> UniRegistryGenMoniker("registry", creator);
The basic interface which is included by all other XPLC interfaces and objects.
Definition: IObject.h:65
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:40
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:324
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:39
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
UniConfKey range(int i, int j) const
Returns a range of segments.
Definition: uniconfkey.cc:200
int numsegments() const
Returns the number of segments in this path.
Definition: uniconfkey.h:287
UniConfKey segment(int n) const
Returns the specified segment of the path.
Definition: uniconfkey.h:297
UniConfKey first(int n=1) const
Returns the path formed by the n first segments of this path.
Definition: uniconfkey.h:314
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
virtual UniConfKey key() const
Returns the current key.
virtual ~UniRegistryGenIter()
Destroys the iterator.
virtual bool next()
Seeks to the next element in the sequence.
virtual void rewind()
Rewinds the iterator.
virtual WvString value() const
Returns the value of the current key.
A generator that exposes the windows registry.
virtual bool exists(const UniConfKey &key)
Without fetching its value, returns true if a key exists.
virtual bool haschildren(const UniConfKey &key)
Returns true if a key has children.
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
virtual bool isok()
Determines if the generator is usable and working properly.
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:62
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330
char * edit()
make the string editable, and return a non-const (char*)
Definition: wvstring.h:397