1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 //---------------------------------------
25 //
26 //---------------------------------------
27
28 #ifdef _MSC_VER
29 #pragma warning(push, 1) /* disable warnings within system headers */
30 #endif
31 #include <windows.h>
32 #ifdef _MSC_VER
33 #pragma warning(pop)
34 #endif
35
36 #include <malloc.h>
37 #include "registrywnt.hxx"
38 #include "registryvalueimpl.hxx"
39 #include "registryexception.hxx"
40
41 #include <assert.h>
42
43 #ifdef _MSC_VER
44 #pragma warning(disable : 4786 4350)
45 #endif
46
47 //---------------------------------------
48 //
49 //---------------------------------------
50
51 const size_t MAX_TMP_BUFF_SIZE = 1024 * sizeof(wchar_t);
52
53
54 //############################################
55 // Creation
56 // only possible through WindowsRegistry class
57 //############################################
58
59
60 //-----------------------------------------------------
61 /** Create instance and open the specified Registry key
62 */
RegistryKeyImplWinNT(HKEY RootKey,const std::wstring & KeyName)63 RegistryKeyImplWinNT::RegistryKeyImplWinNT(HKEY RootKey, const std::wstring& KeyName) :
64 RegistryKeyImpl(RootKey, KeyName)
65 {
66 }
67
68 //-----------------------------------------------------
69 /** Create instance and open the specified Registry key
70 */
RegistryKeyImplWinNT(HKEY RootKey)71 RegistryKeyImplWinNT::RegistryKeyImplWinNT(HKEY RootKey) :
72 RegistryKeyImpl(RootKey)
73 {
74 }
75
76 //-----------------------------------------------------
77 /** Create an instances of the specified Registry key,
78 the key is assumed to be already opened.
79 */
RegistryKeyImplWinNT(HKEY RootKey,HKEY SubKey,const std::wstring & KeyName,bool Writeable)80 RegistryKeyImplWinNT::RegistryKeyImplWinNT(HKEY RootKey, HKEY SubKey, const std::wstring& KeyName, bool Writeable) :
81 RegistryKeyImpl(RootKey, SubKey, KeyName, Writeable)
82 {
83 }
84
85
86 //############################################
87 // Queries
88 //############################################
89
90
91 //-----------------------------------------------------
92 /** The number of sub values of the key at hand
93
94 @precond IsOpen = true
95
96 @throws
97 */
GetSubValueCount() const98 size_t RegistryKeyImplWinNT::GetSubValueCount() const
99 {
100 assert(IsOpen());
101
102 DWORD nSubValues = 0;
103
104 LONG rc = RegQueryInfoKeyW(
105 m_hSubKey,
106 0, 0, 0, 0, 0, 0, &nSubValues, 0, 0, 0, 0);
107
108 if (ERROR_INVALID_HANDLE == rc)
109 throw RegistryIOException(rc);
110 else if (ERROR_SUCCESS != rc)
111 throw RegistryException(rc);
112
113 return nSubValues;
114 }
115
116 //-----------------------------------------------------
117 /** The number of sub-keys of the key at hand
118
119 @precond IsOpen = true
120
121 @throws
122 */
GetSubKeyCount() const123 size_t RegistryKeyImplWinNT::GetSubKeyCount() const
124 {
125 assert(IsOpen());
126
127 DWORD nSubKeys = 0;
128
129 LONG rc = RegQueryInfoKeyA(
130 m_hSubKey,
131 0, 0, 0, &nSubKeys, 0, 0, 0, 0, 0, 0, 0);
132
133 if (ERROR_INVALID_HANDLE == rc)
134 throw RegistryIOException(rc);
135 else if (ERROR_SUCCESS != rc)
136 throw RegistryException(rc);
137
138 return nSubKeys;
139 }
140
141 //-----------------------------------------------------
142 /**
143 */
GetSubKeyNames() const144 StringListPtr RegistryKeyImplWinNT::GetSubKeyNames() const
145 {
146 assert(IsOpen());
147
148 wchar_t buff[1024];
149 DWORD buff_size = sizeof(buff);
150 FILETIME ftime;
151
152 StringList* key_names = new StringList();
153
154 LONG rc = ERROR_SUCCESS;
155
156 for (DWORD i = 0; /* left empty */; i++)
157 {
158 rc = RegEnumKeyExW(
159 m_hSubKey, i, buff, &buff_size,
160 0, 0, 0, &ftime);
161
162 if (ERROR_SUCCESS != rc &&
163 ERROR_MORE_DATA != rc)
164 break;
165
166 buff_size = sizeof(buff);
167
168 key_names->push_back(buff);
169 }
170
171 if (ERROR_INVALID_HANDLE == rc)
172 throw RegistryIOException(rc);
173 else if (ERROR_NO_MORE_ITEMS != rc && ERROR_SUCCESS != rc)
174 throw RegistryException(rc);
175
176 #if (_MSC_VER < 1300) && !defined(__MINGW32__)
177 return key_names;
178 #else
179 return (StringListPtr) key_names;
180 #endif
181 }
182
183 //-----------------------------------------------------
184 /**
185 */
GetSubValueNames() const186 StringListPtr RegistryKeyImplWinNT::GetSubValueNames() const
187 {
188 assert(IsOpen());
189
190 wchar_t buff[1024];
191 DWORD buff_size = sizeof(buff);
192
193 StringList* value_names = new StringList();
194
195 LONG rc = ERROR_SUCCESS;
196
197 for (DWORD i = 0; /* left empty */; i++)
198 {
199 rc = RegEnumValueW(
200 m_hSubKey, i, buff, &buff_size,
201 0, 0, 0, 0);
202
203 if (ERROR_SUCCESS != rc &&
204 ERROR_MORE_DATA != rc)
205 break;
206
207 buff_size = sizeof(buff);
208
209 value_names->push_back(buff);
210 }
211
212 if (ERROR_INVALID_HANDLE == rc)
213 throw RegistryIOException(rc);
214 else if (ERROR_NO_MORE_ITEMS != rc && ERROR_SUCCESS != rc)
215 throw RegistryException(rc);
216
217 #if (_MSC_VER < 1300) && !defined(__MINGW32__)
218 return value_names;
219 #else
220 return (StringListPtr) value_names;
221 #endif
222 }
223
224 //-----------------------------------------------------
225 /** Get the specified registry value
226
227 @precond IsOpen = true
228 */
GetValue(const std::wstring & Name) const229 RegistryValue RegistryKeyImplWinNT::GetValue(const std::wstring& Name) const
230 {
231 assert(IsOpen());
232
233 DWORD Type;
234 wchar_t buff[MAX_TMP_BUFF_SIZE];
235 DWORD size = sizeof(buff);
236
237 LONG rc = RegQueryValueExW(
238 m_hSubKey,
239 Name.c_str(),
240 0,
241 &Type,
242 reinterpret_cast<LPBYTE>(buff),
243 &size);
244
245 if (ERROR_FILE_NOT_FOUND == rc)
246 throw RegistryValueNotFoundException(rc);
247 else if (ERROR_ACCESS_DENIED == rc)
248 throw RegistryAccessDeniedException(rc);
249 else if (ERROR_SUCCESS != rc)
250 throw RegistryException(rc);
251
252 RegistryValue regval;
253
254 if (REG_DWORD == Type)
255 {
256 regval = RegistryValue(new RegistryValueImpl(Name, *(reinterpret_cast<int*>(buff))));
257 }
258 else if (REG_SZ == Type || REG_EXPAND_SZ == Type || REG_MULTI_SZ == Type)
259 {
260 if (size > 0)
261 regval = RegistryValue(new RegistryValueImpl(Name, std::wstring(reinterpret_cast<wchar_t*>(buff))));
262 else
263 regval = RegistryValue(new RegistryValueImpl(Name, std::wstring()));
264 }
265 else
266 {
267 assert(false);
268 }
269
270 return regval;
271 }
272
273 //-----------------------------------------------------
274 /** Get the specified registry value, return the given
275 default value if value not found
276
277 @precond IsOpen = true
278 */
GetValue(const std::wstring & Name,const RegistryValue & Default) const279 RegistryValue RegistryKeyImplWinNT::GetValue(const std::wstring& Name, const RegistryValue& Default) const
280 {
281 assert(IsOpen());
282
283 DWORD Type;
284 wchar_t buff[MAX_TMP_BUFF_SIZE];
285 DWORD size = sizeof(buff);
286
287 LONG rc = RegQueryValueExW(
288 m_hSubKey,
289 Name.c_str(),
290 0,
291 &Type,
292 reinterpret_cast<LPBYTE>(buff),
293 &size);
294
295 if (ERROR_FILE_NOT_FOUND == rc)
296 {
297 #if (_MSC_VER < 1300) && !defined(__MINGW32__)
298 return Default;
299 #else
300 RegistryValue regval_ptr;
301 regval_ptr = RegistryValue(new RegistryValueImpl(*Default));
302 return regval_ptr;
303 #endif
304 }
305
306 if (ERROR_ACCESS_DENIED == rc)
307 throw RegistryAccessDeniedException(rc);
308 else if (ERROR_SUCCESS != rc)
309 throw RegistryException(rc);
310
311 RegistryValue regval;
312
313 if (REG_DWORD == Type)
314 regval = RegistryValue(new RegistryValueImpl(Name, *reinterpret_cast<int*>(buff)));
315 else if (REG_SZ == Type || REG_EXPAND_SZ == Type || REG_MULTI_SZ == Type)
316 regval = RegistryValue(new RegistryValueImpl(Name, std::wstring(reinterpret_cast<wchar_t*>(buff))));
317 else
318 assert(false);
319
320 return regval;
321 }
322
323
324 //############################################
325 // Commands
326 //############################################
327
328
329 //-----------------------------------------------------
330 /** Open the registry key, has no effect if
331 the key is already open
332
333 @precond IsOpen = false
334
335 @throws RegistryKeyNotFoundException
336 RegistryWriteAccessDenyException
337 RegistryAccessDenyException
338 */
Open(bool Writeable)339 void RegistryKeyImplWinNT::Open(bool Writeable)
340 {
341 assert(!IsOpen());
342
343 REGSAM regsam = KEY_READ;
344
345 if (Writeable)
346 regsam |= KEY_WRITE;
347
348 LONG rc = RegOpenKeyExW(
349 m_hRootKey,
350 m_KeyName.c_str(),
351 0,
352 regsam,
353 &m_hSubKey);
354
355 if (ERROR_FILE_NOT_FOUND == rc)
356 throw RegistryKeyNotFoundException(rc);
357 else if (ERROR_ACCESS_DENIED == rc)
358 throw RegistryAccessDeniedException(rc);
359 else if (ERROR_SUCCESS != rc)
360 throw RegistryException(rc);
361
362 m_IsWriteable = Writeable;
363
364 assert(IsOpen());
365 }
366
367 //-----------------------------------------------------
368 /** Open the specified sub-key of the registry key
369 at hand
370
371 @precond IsOpen = true
372 HasSubKey(Name) = true
373
374 @throws RegistryIOException
375 RegistryKeyNotFoundException
376 RegistryAccessDeniedException
377 */
OpenSubKey(const std::wstring & Name,bool Writeable)378 RegistryKey RegistryKeyImplWinNT::OpenSubKey(const std::wstring& Name, bool Writeable)
379 {
380 RegistryKey regkey(new RegistryKeyImplWinNT(m_hSubKey, Name));
381 regkey->Open(Writeable);
382 return regkey;
383 }
384
385 //-----------------------------------------------------
386 /** Creates a new sub-key below the key at hand
387
388 @precond IsOpen = true
389 IsWriteable = true
390
391 @throws RegistryIOException
392 RegistryWriteAccessDenyException
393 */
394
CreateSubKey(const std::wstring & Name)395 RegistryKey RegistryKeyImplWinNT::CreateSubKey(const std::wstring& Name)
396 {
397 assert(IsOpen());
398 assert(IsWriteable());
399
400 HKEY hRoot = IsRootKey() ? m_hRootKey : m_hSubKey;
401
402 HKEY hKey;
403
404 LONG rc = RegCreateKeyExW(
405 hRoot,
406 Name.c_str(),
407 0,
408 0,
409 REG_OPTION_NON_VOLATILE,
410 KEY_READ | KEY_WRITE,
411 0,
412 &hKey,
413 0);
414
415 if (ERROR_INVALID_HANDLE == rc)
416 throw RegistryIOException(rc);
417 else if (ERROR_ACCESS_DENIED == rc)
418 throw RegistryAccessDeniedException(rc);
419 else if (ERROR_SUCCESS != rc)
420 throw RegistryException(rc);
421
422 return RegistryKey(new RegistryKeyImplWinNT(hRoot, hKey, Name));
423 }
424
425 //-----------------------------------------------------
426 /** Deletes a sub-key below the key at hand, the
427 key must not have sub-keys
428
429 @precond IsOpen = true
430 IsWriteable = true
431
432 @throws RegistryIOException
433 RegistryWriteAccessDenyException
434 */
DeleteSubKey(const std::wstring & Name)435 void RegistryKeyImplWinNT::DeleteSubKey(const std::wstring& Name)
436 {
437 assert(IsOpen());
438 assert(IsWriteable());
439 assert(HasSubKey(Name));
440
441 RegistryKey SubKey = OpenSubKey(Name);
442
443 size_t nSubKeyCount = SubKey->GetSubKeyCount();
444
445 assert(0 == nSubKeyCount);
446
447 if (nSubKeyCount)
448 throw RegistryInvalidOperationException(ERROR_NOT_SUPPORTED);
449
450 LONG rc = RegDeleteKeyW(m_hSubKey, Name.c_str());
451
452 if (ERROR_INVALID_HANDLE == rc)
453 throw RegistryIOException(rc);
454 else if (ERROR_ACCESS_DENIED == rc)
455 throw RegistryAccessDeniedException(rc);
456 else if (ERROR_SUCCESS != rc)
457 throw RegistryException(rc);
458 }
459
460 //-----------------------------------------------------
461 /** Deletes a sub-key below the key at hand with all
462 its sub-keys
463
464 @precond IsOpen = true
465 IsWriteable = true;
466
467 @throws RegistryIOException
468 RegistryWriteAccessDenyException
469 */
DeleteSubKeyTree(const std::wstring & Name)470 void RegistryKeyImplWinNT::DeleteSubKeyTree(const std::wstring& Name)
471 {
472 ImplDeleteSubKeyTree(m_hSubKey, Name);
473 }
474
475 //-----------------------------------------------------
476 /** Deletes a sub-key below the key at hand with all
477 its sub-keys
478
479 @precond IsOpen = true
480 IsWriteable = true;
481
482 @throws RegistryIOException
483 RegistryWriteAccessDenyException
484 */
ImplDeleteSubKeyTree(HKEY RootKey,const std::wstring & Name)485 LONG RegistryKeyImplWinNT::ImplDeleteSubKeyTree(HKEY RootKey, const std::wstring& Name)
486 {
487 assert(IsOpen());
488
489 HKEY hKey;
490
491 LONG rc = RegOpenKeyExW(
492 RootKey,
493 Name.c_str(),
494 0,
495 KEY_READ | DELETE,
496 &hKey);
497
498 if (ERROR_SUCCESS == rc)
499 {
500 wchar_t* lpSubKey;
501 DWORD nMaxSubKeyLen;
502
503 rc = RegQueryInfoKeyW(
504 hKey, 0, 0, 0, 0,
505 &nMaxSubKeyLen,
506 0, 0, 0, 0, 0, 0);
507
508 nMaxSubKeyLen++; // space for trailing '\0'
509
510 lpSubKey = reinterpret_cast<wchar_t*>(
511 _alloca(nMaxSubKeyLen*sizeof(wchar_t)));
512
513 while (ERROR_SUCCESS == rc)
514 {
515 DWORD nLen = nMaxSubKeyLen;
516
517 rc = RegEnumKeyExW(
518 hKey,
519 0, // always index zero
520 lpSubKey,
521 &nLen,
522 0, 0, 0, 0);
523
524 if (ERROR_NO_MORE_ITEMS == rc)
525 {
526 rc = RegDeleteKeyW(RootKey, Name.c_str());
527 break;
528 }
529 else if (rc == ERROR_SUCCESS)
530 {
531 rc = ImplDeleteSubKeyTree(hKey, lpSubKey);
532 }
533
534 } // while
535
536 RegCloseKey(hKey);
537
538 } // if
539
540 if (ERROR_INVALID_HANDLE == rc)
541 throw RegistryIOException(rc);
542 else if (ERROR_ACCESS_DENIED == rc)
543 throw RegistryAccessDeniedException(rc);
544 else if (ERROR_FILE_NOT_FOUND == rc)
545 throw RegistryKeyNotFoundException(rc);
546 else if (ERROR_SUCCESS != rc)
547 throw RegistryException(rc);
548
549 return rc;
550 }
551
552 //-----------------------------------------------------
553 /** Delete the specified value
554
555 @precond IsOpen = true
556 IsWriteable = true
557 HasValue(Name) = true
558
559 @throws RegistryIOException
560 RegistryWriteAccessDeniedException
561 RegistryValueNotFoundException
562 */
DeleteValue(const std::wstring & Name)563 void RegistryKeyImplWinNT::DeleteValue(const std::wstring& Name)
564 {
565 assert(IsOpen());
566 assert(HasValue(Name));
567 assert(IsWriteable());
568
569 LONG rc = RegDeleteValueW(
570 m_hSubKey,
571 Name.c_str());
572
573 if (ERROR_INVALID_HANDLE == rc)
574 throw RegistryIOException(rc);
575 else if (ERROR_ACCESS_DENIED == rc)
576 throw RegistryNoWriteAccessException(rc);
577 else if (ERROR_FILE_NOT_FOUND == rc)
578 throw RegistryValueNotFoundException(rc);
579 else if (ERROR_SUCCESS != rc)
580 throw RegistryException(rc);
581 }
582
583 //-----------------------------------------------------
584 /** Set the specified registry value
585
586 @precond IsOpen = true
587 IsWriteable = true
588
589 @throws RegistryIOException
590 RegistryWriteAccessDenyException
591 */
SetValue(const RegistryValue & Value)592 void RegistryKeyImplWinNT::SetValue(const RegistryValue& Value)
593 {
594 assert(IsOpen());
595 assert(IsWriteable());
596
597 LONG rc = RegSetValueExW(
598 m_hSubKey,
599 Value->GetName().c_str(),
600 0,
601 Value->GetType(),
602 reinterpret_cast<const unsigned char*>(Value->GetDataBuffer()),
603 static_cast<DWORD>(Value->GetDataSize()));
604
605 if (ERROR_INVALID_HANDLE == rc)
606 throw RegistryIOException(rc);
607 else if (ERROR_ACCESS_DENIED == rc)
608 throw RegistryAccessDeniedException(rc);
609 else if (ERROR_SUCCESS != rc)
610 throw RegistryException(rc);
611 }
612
613
614
615
616