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 #include "registryw9x.hxx"
29 
30 #include <windows.h>
31 #include <malloc.h>
32 #include "registryvalueimpl.hxx"
33 #include "registryexception.hxx"
34 #include "stringconverter.hxx"
35 
36 #include <assert.h>
37 
38 #ifdef _MSC_VER
39 #pragma warning(disable : 4786 4350)
40 #endif
41 
42 //---------------------------------------
43 //
44 //---------------------------------------
45 
46 const size_t MAX_TMP_BUFF_SIZE = 1024 * sizeof(wchar_t);
47 
48 
49 //############################################
50 // Creation
51 // only possible through WindowsRegistry class
52 //############################################
53 
54 
55 //-----------------------------------------------------
56 /** Create instance and open the specified Registry key
57 */
RegistryKeyImplWin9x(HKEY RootKey,const std::wstring & KeyName)58 RegistryKeyImplWin9x::RegistryKeyImplWin9x(HKEY RootKey, const std::wstring& KeyName) :
59 	RegistryKeyImpl(RootKey, KeyName)
60 {
61 }
62 
63 //-----------------------------------------------------
64 /** Create instance and open the specified Registry key
65 */
RegistryKeyImplWin9x(HKEY RootKey)66 RegistryKeyImplWin9x::RegistryKeyImplWin9x(HKEY RootKey) :
67 	RegistryKeyImpl(RootKey)
68 {
69 }
70 
71 //-----------------------------------------------------
72 /** Create an instances of the specified Registry key,
73 	the key is assumed to be already opened.
74 */
RegistryKeyImplWin9x(HKEY RootKey,HKEY SubKey,const std::wstring & KeyName,bool Writeable)75 RegistryKeyImplWin9x::RegistryKeyImplWin9x(HKEY RootKey, HKEY SubKey, const std::wstring& KeyName, bool Writeable) :
76 	RegistryKeyImpl(RootKey, SubKey, KeyName, Writeable)
77 {
78 }
79 
80 
81 //############################################
82 // Queries
83 //############################################
84 
85 
86 //-----------------------------------------------------
87 /** The number of sub values of the key at hand
88 
89 	@precond IsOpen = true
90 
91 	@throws
92 */
GetSubValueCount() const93 size_t RegistryKeyImplWin9x::GetSubValueCount() const
94 {
95 	assert(IsOpen());
96 
97 	DWORD nSubValues = 0;
98 
99 	LONG rc = RegQueryInfoKeyA(
100 		m_hSubKey,
101 		0, 0, 0, 0, 0, 0, &nSubValues, 0, 0, 0, 0);
102 
103 	if (ERROR_INVALID_HANDLE == rc)
104 		throw RegistryIOException(rc);
105 	else if (ERROR_SUCCESS != rc)
106 		throw RegistryException(rc);
107 
108 	return nSubValues;
109 }
110 
111 //-----------------------------------------------------
112 /** The number of sub-keys of the key at hand
113 
114 	@precond IsOpen = true
115 
116 	@throws
117 */
GetSubKeyCount() const118 size_t RegistryKeyImplWin9x::GetSubKeyCount() const
119 {
120 	assert(IsOpen());
121 
122 	DWORD nSubKeys = 0;
123 
124 	LONG rc = RegQueryInfoKeyA(
125 		m_hSubKey,
126 		0, 0, 0, &nSubKeys, 0, 0, 0, 0, 0, 0, 0);
127 
128 	if (ERROR_INVALID_HANDLE == rc)
129 		throw RegistryIOException(rc);
130 	else if (ERROR_SUCCESS != rc)
131 		throw RegistryException(rc);
132 
133 	return nSubKeys;
134 }
135 
136 //-----------------------------------------------------
137 /**
138 */
GetSubKeyNames() const139 StringListPtr RegistryKeyImplWin9x::GetSubKeyNames() const
140 {
141 	assert(IsOpen());
142 
143 	char        buff[1024];
144 	DWORD   buff_size = sizeof(buff);
145 	FILETIME ftime;
146 
147 	StringList* key_names = new StringList();
148 
149 	LONG rc = ERROR_SUCCESS;
150 
151 	for (DWORD i = 0; /* left empty */; i++)
152 	{
153 		rc = RegEnumKeyExA(
154 			m_hSubKey, i, buff, &buff_size,
155 			0, 0, 0, &ftime);
156 
157 		if (ERROR_SUCCESS != rc &&
158 			ERROR_MORE_DATA != rc)
159 			break;
160 
161 		buff_size = sizeof(buff);
162 
163 		key_names->push_back(AnsiToUnicodeString(buff));
164 	}
165 
166 	if (ERROR_INVALID_HANDLE == rc)
167 		throw RegistryIOException(rc);
168 	else if (ERROR_NO_MORE_ITEMS != rc && ERROR_SUCCESS != rc)
169 		throw RegistryException(rc);
170 
171 	return (StringListPtr) key_names;
172 }
173 
174 //-----------------------------------------------------
175 /**
176 */
GetSubValueNames() const177 StringListPtr RegistryKeyImplWin9x::GetSubValueNames() const
178 {
179 	assert(IsOpen());
180 
181 	char        buff[1024];
182 	DWORD   buff_size = sizeof(buff);
183 
184 	StringList* value_names = new StringList();
185 
186 	LONG rc = ERROR_SUCCESS;
187 
188 	for (DWORD i = 0; /* left empty */; i++)
189 	{
190         rc = RegEnumValueA(
191 			m_hSubKey, i, buff, &buff_size,
192 			0, 0, 0, 0);
193 
194 		if (ERROR_SUCCESS != rc &&
195 			ERROR_MORE_DATA != rc)
196 			break;
197 
198 		buff_size = sizeof(buff);
199 
200 		value_names->push_back(AnsiToUnicodeString(buff));
201 	}
202 
203 	if (ERROR_INVALID_HANDLE == rc)
204 		throw RegistryIOException(rc);
205 	else if (ERROR_NO_MORE_ITEMS != rc && ERROR_SUCCESS != rc)
206 		throw RegistryException(rc);
207 
208 	return (StringListPtr) value_names;
209 }
210 
211 //-----------------------------------------------------
212 /** Get the specified registry value
213 
214 	@precond IsOpen = true
215 */
GetValue(const std::wstring & Name) const216 RegistryValue RegistryKeyImplWin9x::GetValue(const std::wstring& Name) const
217 {
218 	assert(IsOpen());
219 
220 	DWORD Type;
221 	char  buff[MAX_TMP_BUFF_SIZE];
222 	DWORD size = sizeof(buff);
223 
224 	LONG rc = RegQueryValueExA(
225 		m_hSubKey,
226 		UnicodeToAnsiString(Name).c_str(),
227 		0,
228 		&Type,
229 		reinterpret_cast<LPBYTE>(buff),
230 		&size);
231 
232 	if (ERROR_FILE_NOT_FOUND == rc)
233 		throw RegistryValueNotFoundException(rc);
234 	else if (ERROR_ACCESS_DENIED == rc)
235 		throw RegistryAccessDeniedException(rc);
236 	else if (ERROR_SUCCESS != rc)
237 		throw RegistryException(rc);
238 
239 	RegistryValue regval;
240 
241 	if (REG_DWORD == Type)
242     {
243 		regval = RegistryValue(new RegistryValueImpl(Name, *(reinterpret_cast<int*>(buff))));
244     }
245 	else if (REG_SZ == Type || REG_EXPAND_SZ == Type || REG_MULTI_SZ == Type)
246     {
247         if (size > 0)
248             regval = RegistryValue(new RegistryValueImpl(Name, std::string(reinterpret_cast<char*>(buff))));
249         else
250             regval = RegistryValue(new RegistryValueImpl(Name, std::string()));
251     }
252 	else
253     {
254 		assert(false);
255     }
256 
257 	return regval;
258 }
259 
260 //-----------------------------------------------------
261 /** Get the specified registry value, return the given
262 	default value if value not found
263 
264 	@precond IsOpen = true
265 */
GetValue(const std::wstring & Name,const RegistryValue & Default) const266 RegistryValue RegistryKeyImplWin9x::GetValue(const std::wstring& Name, const RegistryValue& Default) const
267 {
268 	assert(IsOpen());
269 
270 	DWORD Type;
271 	char  buff[MAX_TMP_BUFF_SIZE];
272 	DWORD size = sizeof(buff);
273 
274 	LONG rc = RegQueryValueExA(
275 		m_hSubKey,
276 		UnicodeToAnsiString(Name).c_str(),
277 		0,
278 		&Type,
279 		reinterpret_cast<LPBYTE>(buff),
280 		&size);
281 
282 	if (ERROR_FILE_NOT_FOUND == rc)
283 	{
284         #if !defined(__MINGW32__) && (_MSC_VER < 1300)
285 		return Default;
286 		#else
287 		RegistryValue regval_ptr;
288 		regval_ptr = RegistryValue(new RegistryValueImpl(*Default));
289 		return regval_ptr;
290 		#endif
291 		}
292 
293 	if (ERROR_ACCESS_DENIED == rc)
294 		throw RegistryAccessDeniedException(rc);
295 	else if (ERROR_SUCCESS != rc)
296 		throw RegistryException(rc);
297 
298 	RegistryValue regval;
299 
300 	if (REG_DWORD == Type)
301 		regval = RegistryValue(new RegistryValueImpl(Name, *reinterpret_cast<int*>(buff)));
302 	else if (REG_SZ == Type || REG_EXPAND_SZ == Type || REG_MULTI_SZ == Type)
303 		regval = RegistryValue(new RegistryValueImpl(Name, std::string(reinterpret_cast<char*>(buff))));
304 	else
305 		assert(false);
306 
307 	return regval;
308 }
309 
310 
311 //############################################
312 // Commands
313 //############################################
314 
315 
316 //-----------------------------------------------------
317 /** Open the registry key, has no effect if
318 	the key is already open
319 
320 	@precond IsOpen = false
321 
322 	@throws RegistryKeyNotFoundException
323 			RegistryWriteAccessDenyException
324 			RegistryAccessDenyException
325 */
Open(bool Writeable)326 void RegistryKeyImplWin9x::Open(bool Writeable)
327 {
328 	assert(!IsOpen());
329 
330 	REGSAM regsam = KEY_READ;
331 
332 	if (Writeable)
333 		regsam |= KEY_WRITE;
334 
335 	LONG rc = RegOpenKeyExA(
336 		m_hRootKey,
337 		UnicodeToAnsiString(m_KeyName).c_str(),
338 		0,
339 		regsam,
340 		&m_hSubKey);
341 
342 	if (ERROR_FILE_NOT_FOUND == rc)
343 		throw RegistryKeyNotFoundException(rc);
344 	else if (ERROR_ACCESS_DENIED == rc)
345 		throw RegistryAccessDeniedException(rc);
346 	else if (ERROR_SUCCESS != rc)
347 		throw RegistryException(rc);
348 
349 	m_IsWriteable = Writeable;
350 
351 	assert(IsOpen());
352 }
353 
354 //-----------------------------------------------------
355 /** Open the specified sub-key of the registry key
356 	at hand
357 
358 	@precond IsOpen = true
359 			 HasSubKey(Name) = true
360 
361 	@throws RegistryIOException
362 			RegistryKeyNotFoundException
363 			RegistryAccessDeniedException
364 */
OpenSubKey(const std::wstring & Name,bool Writeable)365 RegistryKey RegistryKeyImplWin9x::OpenSubKey(const std::wstring& Name, bool Writeable)
366 {
367 	RegistryKey regkey(new RegistryKeyImplWin9x(m_hSubKey, Name));
368 	regkey->Open(Writeable);
369 	return regkey;
370 }
371 
372 //-----------------------------------------------------
373 /** Creates a new sub-key below the key at hand
374 
375 	@precond IsOpen = true
376 			 IsWriteable = true
377 
378 	@throws  RegistryIOException
379 			 RegistryWriteAccessDenyException
380 */
381 
CreateSubKey(const std::wstring & Name)382 RegistryKey RegistryKeyImplWin9x::CreateSubKey(const std::wstring& Name)
383 {
384 	assert(IsOpen());
385 	assert(IsWriteable());
386 
387 	HKEY hRoot = IsRootKey() ? m_hRootKey : m_hSubKey;
388 
389 	HKEY hKey;
390 
391 	LONG rc = RegCreateKeyExA(
392 		hRoot,
393 		UnicodeToAnsiString(Name).c_str(),
394 		0,
395 		0,
396 		REG_OPTION_NON_VOLATILE,
397 		KEY_READ | KEY_WRITE,
398 		0,
399 		&hKey,
400 		0);
401 
402 	if (ERROR_INVALID_HANDLE == rc)
403 		throw RegistryIOException(rc);
404 	else if (ERROR_ACCESS_DENIED == rc)
405 		throw RegistryAccessDeniedException(rc);
406 	else if (ERROR_SUCCESS != rc)
407 		throw RegistryException(rc);
408 
409 	return RegistryKey(new RegistryKeyImplWin9x(hRoot, hKey, Name));
410 }
411 
412 //-----------------------------------------------------
413 /** Deletes a sub-key below the key at hand, the
414 	key must not have sub-keys
415 
416 	@precond IsOpen = true
417 			 IsWriteable = true
418 
419 	@throws  RegistryIOException
420 			 RegistryWriteAccessDenyException
421 */
DeleteSubKey(const std::wstring & Name)422 void RegistryKeyImplWin9x::DeleteSubKey(const std::wstring& Name)
423 {
424 	assert(IsOpen());
425 	assert(IsWriteable());
426 	assert(HasSubKey(Name));
427 
428 	RegistryKey SubKey = OpenSubKey(Name);
429 
430 	size_t nSubKeyCount = SubKey->GetSubKeyCount();
431 
432 	assert(0 == nSubKeyCount);
433 
434 	if (nSubKeyCount)
435 		throw RegistryInvalidOperationException(ERROR_NOT_SUPPORTED);
436 
437 	LONG rc = RegDeleteKeyA(m_hSubKey, UnicodeToAnsiString(Name).c_str());
438 
439 	if (ERROR_INVALID_HANDLE == rc)
440 		throw RegistryIOException(rc);
441 	else if (ERROR_ACCESS_DENIED == rc)
442 		throw RegistryAccessDeniedException(rc);
443 	else if (ERROR_SUCCESS != rc)
444 		throw RegistryException(rc);
445 }
446 
447 //-----------------------------------------------------
448 /** Deletes a sub-key below the key at hand with all
449 	its sub-keys
450 
451 	@precond IsOpen = true
452 			 IsWriteable = true;
453 
454 	@throws  RegistryIOException
455 			 RegistryWriteAccessDenyException
456 */
DeleteSubKeyTree(const std::wstring & Name)457 void RegistryKeyImplWin9x::DeleteSubKeyTree(const std::wstring& Name)
458 {
459 	LONG rc = RegDeleteKeyA(m_hSubKey, UnicodeToAnsiString(Name).c_str());
460 
461 	if (ERROR_INVALID_HANDLE == rc)
462 		throw RegistryIOException(rc);
463 	else if (ERROR_ACCESS_DENIED == rc)
464 		throw RegistryAccessDeniedException(rc);
465 	else if (ERROR_SUCCESS != rc)
466 		throw RegistryException(rc);
467 }
468 
469 //-----------------------------------------------------
470 /** Delete the specified value
471 
472 		@precond IsOpen = true
473 				 IsWriteable = true
474 				 HasValue(Name) = true
475 
476 		@throws	RegistryIOException
477 				RegistryWriteAccessDeniedException
478 				RegistryValueNotFoundException
479 */
DeleteValue(const std::wstring & Name)480 void RegistryKeyImplWin9x::DeleteValue(const std::wstring& Name)
481 {
482 	assert(IsOpen());
483 	assert(HasValue(Name));
484 	assert(IsWriteable());
485 
486 	LONG rc = RegDeleteValueA(
487 		m_hSubKey,
488 		UnicodeToAnsiString(Name).c_str());
489 
490 	if (ERROR_INVALID_HANDLE == rc)
491 		throw RegistryIOException(rc);
492 	else if (ERROR_ACCESS_DENIED == rc)
493 		throw RegistryNoWriteAccessException(rc);
494 	else if (ERROR_FILE_NOT_FOUND == rc)
495 		throw RegistryValueNotFoundException(rc);
496 	else if (ERROR_SUCCESS != rc)
497 		throw RegistryException(rc);
498 }
499 
500 //-----------------------------------------------------
501 /** Set the specified registry value
502 
503 	@precond IsOpen = true
504 			 IsWriteable = true
505 
506 	@throws  RegistryIOException
507 			 RegistryWriteAccessDenyException
508 */
SetValue(const RegistryValue & Value)509 void RegistryKeyImplWin9x::SetValue(const RegistryValue& Value)
510 {
511 	assert(IsOpen());
512 	assert(IsWriteable());
513 
514 	LONG rc = ERROR_SUCCESS;
515 
516 	if (REG_SZ == Value->GetType())
517 	{
518 		std::string AnsiStr = Value->GetDataAsAnsiString();
519 
520 		rc = RegSetValueExA(
521 			m_hSubKey,
522 			UnicodeToAnsiString(Value->GetName()).c_str(),
523 			0,
524 			Value->GetType(),
525 			reinterpret_cast<const unsigned char*>(AnsiStr.c_str()),
526 			static_cast<DWORD>((AnsiStr.length() + 1)));
527 	}
528 	else
529 	{
530 		rc = RegSetValueExA(
531 			m_hSubKey,
532 			UnicodeToAnsiString(Value->GetName()).c_str(),
533 			0,
534 			Value->GetType(),
535 			reinterpret_cast<const unsigned char*>(Value->GetDataBuffer()),
536 			static_cast<DWORD>(Value->GetDataSize()));
537 	}
538 
539 	if (ERROR_INVALID_HANDLE == rc)
540 		throw RegistryIOException(rc);
541 	else if (ERROR_ACCESS_DENIED == rc)
542 		throw RegistryAccessDeniedException(rc);
543 	else if (ERROR_SUCCESS != rc)
544 		throw RegistryException(rc);
545 }
546 
547