xref: /AOO41X/main/setup_native/source/win32/customactions/reg4msdoc/registrywnt.cxx (revision 32b1fd08cf0851da51c0ed68f50bc63c4ee660e0)
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