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 
11 WV_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)
16 static 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 
70 UniRegistryGen::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 
109 UniRegistryGen::~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 
205 void 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 
229 UniRegistryGenIter::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 
306 LONG 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 
321 LONG 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 
339 static IUniConfGen *creator(WvStringParm s, IObject*)
340 {
341  return new UniRegistryGen(s);
342 }
343 
344 #pragma warning(disable : 4073)
345 #pragma init_seg(lib)
346 WvMoniker<IUniConfGen> UniRegistryGenMoniker("registry", creator);
virtual bool haschildren(const UniConfKey &key)
Returns true if a key has children.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:93
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
The basic interface which is included by all other XPLC interfaces and objects.
Definition: IObject.h:65
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key&#39;s value or children have possibly changed.
Definition: uniconfgen.cc:77
UniConfKey first(int n=1) const
Returns the path formed by the n first segments of this path.
Definition: uniconfkey.h:314
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:39
UniConfKey segment(int n) const
Returns the specified segment of the path.
Definition: uniconfkey.h:297
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:323
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
UniConfKey range(int i, int j) const
Returns a range of segments.
Definition: uniconfkey.cc:200
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
virtual UniConfKey key() const
Returns the current key.
A generator that exposes the windows registry.
virtual void rewind()
Rewinds the iterator.
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:61
int numsegments() const
Returns the number of segments in this path.
Definition: uniconfkey.h:287
char * edit()
make the string editable, and return a non-const (char*)
Definition: wvstring.h:397
virtual bool next()
Seeks to the next element in the sequence.
virtual ~UniRegistryGenIter()
Destroys the iterator.
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
virtual bool exists(const UniConfKey &key)
Without fetching its value, returns true if a key exists.
virtual bool isok()
Determines if the generator is usable and working properly.
virtual WvString value() const
Returns the value of the current key.
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329