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 
174 void UniRegistryGen::set(const UniConfKey &key, WvStringParm value)
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);
WvString::edit
char * edit()
make the string editable, and return a non-const (char*)
Definition: wvstring.h:397
UniRegistryGen::setv
virtual void setv(const UniConfPairList &pairs)
Stores multiple key-value pairs into the registry.
Definition: uniregistrygen.cc:205
UniRegistryGenIter::rewind
virtual void rewind()
Rewinds the iterator.
Definition: uniregistrygen.cc:258
UniRegistryGenIter::key
virtual UniConfKey key() const
Returns the current key.
Definition: uniregistrygen.cc:293
UniConfKey::printable
WvString printable() const
Returns the canonical string representation of the path.
Definition: uniconfkey.cc:212
UniRegistryGen::haschildren
virtual bool haschildren(const UniConfKey &key)
Returns true if a key has children.
Definition: uniregistrygen.cc:215
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
UniRegistryGen::exists
virtual bool exists(const UniConfKey &key)
Without fetching its value, returns true if a key exists.
Definition: uniregistrygen.cc:210
IUniConfGen
An abstract data container that backs a UniConf tree.
Definition: uniconfgen.h:39
UniRegistryGenIter::~UniRegistryGenIter
virtual ~UniRegistryGenIter()
Destroys the iterator.
Definition: uniregistrygen.cc:251
WvFastString::isnull
bool isnull() const
returns true if this string is null
Definition: wvstring.h:290
UniRegistryGen::get
virtual WvString get(const UniConfKey &key)
Fetches a string value for a key from the registry.
Definition: uniregistrygen.cc:123
WvFastString::cstr
const char * cstr() const
return a (const char *) for this string.
Definition: wvstring.h:267
UniRegistryGenIter
Definition: uniregistrygen.h:47
UniConfKey
Represents a UniConf key which is a path in a hierarchy structured much like the traditional Unix fil...
Definition: uniconfkey.h:38
WvMoniker
A type-safe version of WvMonikerBase that lets you provide create functions for object types other th...
Definition: wvmoniker.h:61
UniConfGen::delta
void delta(const UniConfKey &key, WvStringParm value)
Call this when a key's value or children have possibly changed.
Definition: uniconfgen.cc:77
IObject
Definition: IObject.h:65
UniConfKey::first
UniConfKey first(int n=1) const
Returns the path formed by the n first segments of this path.
Definition: uniconfkey.h:314
UniRegistryGen::isok
virtual bool isok()
Determines if the generator is usable and working properly.
Definition: uniregistrygen.cc:118
UniConfKey::range
UniConfKey range(int i, int j) const
Returns a range of segments.
Definition: uniconfkey.cc:200
UniRegistryGen::iterator
virtual Iter * iterator(const UniConfKey &key)
Returns an iterator over the children of the specified key.
Definition: uniregistrygen.cc:223
UniRegistryGenIter::value
virtual WvString value() const
Returns the value of the current key.
Definition: uniregistrygen.cc:299
UniRegistryGenIter::next
virtual bool next()
Seeks to the next element in the sequence.
Definition: uniregistrygen.cc:266
UniRegistryGen::set
virtual void set(const UniConfKey &key, WvStringParm value)
Stores a string value for a key into the registry.
Definition: uniregistrygen.cc:174
UniConfKey::segment
UniConfKey segment(int n) const
Returns the specified segment of the path.
Definition: uniconfkey.h:297
UniRegistryGen
A generator that exposes the windows registry.
Definition: uniregistrygen.h:24
UniConfKey::last
UniConfKey last(int n=1) const
Returns the path formed by the n last segments of this path.
Definition: uniconfkey.h:324
UniConfKey::numsegments
int numsegments() const
Returns the number of segments in this path.
Definition: uniconfkey.h:287
UniConfGen::Iter
An abstract iterator over keys and values in a generator.
Definition: uniconfgen.h:323