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