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