ReactOS 0.4.15-dev-7788-g1ad9096
RegistryTree.cpp
Go to the documentation of this file.
1/*
2 * regexpl - Console Registry Explorer
3 *
4 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22// RegistryTree.cpp: implementation of the CRegistryTree class.
23
24#include "ph.h"
25#include "RegistryTree.h"
26#include "Pattern.h"
27#include "RegistryExplorer.h"
28
30{
37}
38
40{
46
47 const TCHAR *pszPath = Tree.GetCurrentPath();
48 if ((pszPath[0] == _T('\\')) && (pszPath[1] == _T('\\')))
49 { // path has machine name
50 pszPath += 2;
51 while (*pszPath && (*pszPath != _T('\\')))
52 pszPath++;
53
54 ASSERT(*pszPath == _T('\\')); // if path begins with \\ it must be followed by machine name
55 }
56
59
60 VERIFY(ChangeCurrentKey(pszPath));
61}
62
64{
66 delete[] m_pszMachineName;
67
68 CNode *pNode;
69 while(m_pCurrentKey->m_pUp)
70 {
71 pNode = m_pCurrentKey;
73 delete pNode;
74 }
75
76 // We are on root
79}
80
82{
84}
85
87{
88 return m_pCurrentKey->m_Key.IsRoot();
89}
90
92{
93 if (*pszRelativePath == _T('\\'))
94 GotoRoot(); // This is full absolute path.
95
96 // split path to key names.
97 const TCHAR *pszSeps = _T("\\");
98
99 // Make buffer and copy relative path into it.
100 TCHAR *pszBuffer = new (std::nothrow) TCHAR[_tcslen(pszRelativePath)+1];
101 if (!pszBuffer)
102 {
104 return FALSE;
105 }
106
107 _tcscpy(pszBuffer,pszRelativePath);
108
109 // We accept names in form "\"blablabla\\blab labla\"\\"
110 size_t size = _tcslen(pszBuffer);
111 if (size)
112 {
113 if (pszBuffer[size-1] == _T('\\'))
114 pszBuffer[--size] = 0;
115
116 TCHAR *psz;
117 if (*pszBuffer == _T('\"') && (psz = _tcschr(pszBuffer+1,_T('\"'))) && size_t(psz-pszBuffer) == size-1)
118 {
119 size--;
120 pszBuffer[size] = 0;
121
122 pszBuffer++;
123 }
124 }
125
126 const TCHAR *pszNewKey = _tcstok(pszBuffer,pszSeps);
127
128 if ((!pszNewKey)&&((*pszRelativePath != _T('\\'))||(*(pszRelativePath+1) != 0)))
129 {
130 SetError(_T("Invalid key name"));
131 goto Abort;
132 };
133
134 // change keys
135 while (pszNewKey)
136 {
137 if (!InternalChangeCurrentKey(pszNewKey,KEY_READ))
138 goto Abort; // InternalChangeCurrentKey sets last error description
139
140 // Get next key name
141 pszNewKey = _tcstok(NULL,pszSeps);
142 }
143
144 return TRUE;
145
146Abort:
147 delete[] pszBuffer;
148 return FALSE;
149}
150
152{
153 return m_ErrorMsg;
154}
155
157{
158 // Delete current tree
159 CNode *pNode;
160 while(m_pCurrentKey->m_pUp)
161 {
162 pNode = m_pCurrentKey;
164 delete pNode;
165 }
166
167 // We are on root
170}
171
173{
174 GotoRoot();
175
176 // If we are going to local machine...
177 if (pszMachineName == NULL)
178 {
179 // Delete previous machine name buffer if allocated.
181 delete[] m_pszMachineName;
182
185 return TRUE;
186 }
187
188 // Skip leading backslashes if any.
189 while ((*pszMachineName)&&(*pszMachineName == _T('\\')))
190 pszMachineName++;
191
192 ASSERT(*pszMachineName); // No machine name.
193
194 TCHAR *pszNewMachineName = new (std::nothrow) TCHAR[_tcslen(pszMachineName)+3]; // two leading backslashes + terminating null
195
196 if (!pszNewMachineName)
197 {
199 return FALSE;
200 }
201
202 // Delete previous machine name buffer if allocated.
204 delete[] m_pszMachineName;
205
206 m_pszMachineName = pszNewMachineName;
207
208 _tcscpy(m_pszMachineName,_T("\\\\")); // leading backslashes
209 _tcscpy(m_pszMachineName+2,pszMachineName); // machine name itself
210 _tcsupr(m_pszMachineName+2); // upercase it
211
213 return TRUE;
214}
215
216BOOL CRegistryTree::NewKey(const TCHAR *pszKeyName, const TCHAR *pszPath, BOOL blnVolatile)
217{
218 if (!m_pCurrentKey)
219 {
220 SetErrorCommandNAOnRoot(_T("Creating new key "));
221 return FALSE;
222 }
223
224 CRegistryTree Tree(*this);
225 if (!Tree.ChangeCurrentKey(pszPath))
226 {
228 return FALSE;
229 }
230
231 BOOL blnOpened;
232 HKEY hKey;
233
235 pszKeyName,
236 hKey,
237 &blnOpened,
238 blnVolatile);
239 if (nError == ERROR_SUCCESS)
240 {
241 LONG nError = RegCloseKey(hKey);
242 ASSERT(nError == ERROR_SUCCESS);
243 }
244
245 if ((nError == ERROR_SUCCESS) && blnOpened)
246 {
247 SetError(_T("A key \"%s\" already exists."),pszKeyName);
248 return FALSE;
249 }
250
251 if (nError != ERROR_SUCCESS)
252 {
253 SetError(_T("Cannot create key : %s%s\nError %d (%s)\n"),
254 GetCurrentPath(),pszKeyName,nError,GetErrorDescription(nError));
255
256 return FALSE;
257 }
258
259 return TRUE;
260}
261
262BOOL CRegistryTree::DeleteSubkeys(const TCHAR *pszKeyPattern, const TCHAR *pszPath, BOOL blnRecursive)
263{
266 return FALSE;
267
268 return DeleteSubkeys(Key, pszKeyPattern, blnRecursive);
269}
270
271BOOL CRegistryTree::DeleteSubkeys(CRegistryKey& rKey, const TCHAR *pszKeyPattern, BOOL blnRecursive)
272{
273 LONG nError;
274
275 // enumerate subkeys
276 DWORD dwMaxSubkeyNameLength;
277 nError = rKey.GetSubkeyNameMaxLength(dwMaxSubkeyNameLength);
278 if (nError != ERROR_SUCCESS)
279 {
280 SetError(_T("Cannot delete subkeys(s) of key %s.\nRequesting info about key failed.\nError %d (%s)\n"),
281 rKey.GetKeyName(),nError,GetErrorDescription(nError));
282 return FALSE;
283 }
284
285 TCHAR *pszSubkeyName = new (std::nothrow) TCHAR [dwMaxSubkeyNameLength];
286 rKey.InitSubkeyEnumeration(pszSubkeyName, dwMaxSubkeyNameLength);
287 BOOL blnKeyDeleted = FALSE;
288 while ((nError = rKey.GetNextSubkeyName()) == ERROR_SUCCESS)
289 {
290 if (PatternMatch(pszKeyPattern,pszSubkeyName))
291 {
292 if (blnRecursive)
293 { // deltion is recursive, delete subkey subkeys
294 CRegistryKey Subkey;
295 // open subkey
296 nError = rKey.OpenSubkey(DELETE,pszSubkeyName,Subkey);
297 // delete subkey subkeys
299 {
300 AddErrorDescription(_T("Cannot delete subkey(s) of key %s. Subkey deletion failed.\n"),Subkey.GetKeyName());
301 return FALSE;
302 }
303 }
304
305 nError = rKey.DeleteSubkey(pszSubkeyName);
306 if (nError != ERROR_SUCCESS)
307 {
308 SetError(_T("Cannot delete the %s subkey of key %s.\nError %d (%s)\n"),
309 pszSubkeyName,rKey.GetKeyName(),nError,GetErrorDescription(nError));
310
311 return FALSE;
312 }
313 blnKeyDeleted = TRUE;
314 rKey.InitSubkeyEnumeration(pszSubkeyName, dwMaxSubkeyNameLength); // reset iteration
315 }
316 }
317
318 ASSERT(nError != ERROR_SUCCESS);
319 if (nError != ERROR_NO_MORE_ITEMS)
320 {
321 SetError(_T("Cannot delete subkeys(s) of key %s.\nSubkey enumeration failed.\nError %d (%s)\n"),
322 rKey.GetKeyName(),nError,GetErrorDescription(nError));
323 return FALSE;
324 }
325
326 if (!blnKeyDeleted)
327 SetError(_T("The key %s has no subkeys that match %s pattern.\n"),rKey.GetKeyName(),pszKeyPattern);
328
329 return blnKeyDeleted;
330}
331
333{
334 switch(nError)
335 {
337 return _T("Access denied");
339 return _T("The system cannot find the key specified");
341 return _T("Internal error");
343 return _T("Out of memory");
344 default:
345 return _T("Unknown error");
346 }
347}
348
350{
351 SetError(_T("Error %u (%s)"),nError,GetErrorDescription(nError));
352}
353
354void CRegistryTree::SetError(const TCHAR *pszFormat, ...)
355{
357 va_start(args,pszFormat);
360 va_end(args);
361}
362
364{
365 SetError(_T("Internal Error"));
366}
367
368void CRegistryTree::AddErrorDescription(const TCHAR *pszFormat, ...)
369{
370 size_t size = _tcslen(m_ErrorMsg);
372 {
373 TCHAR *pszAdd = m_ErrorMsg+size;
375 va_start(args,pszFormat);
377 if (_vsntprintf(pszAdd,size,pszFormat,args) < 0)
378 m_ErrorMsg[size] = 0;
379 va_end(args);
380 }
381}
382
384{
385 ASSERT(pszCommand);
386 if (pszCommand)
387 SetError(_T("%s") COMMAND_NA_ON_ROOT,pszCommand);
388 else
390}
391
393{
394 size_t size = _tcslen(pszSubkeyName);
395 TCHAR *pszSubkeyNameBuffer = new (std::nothrow) TCHAR[size+3];
396 if (!pszSubkeyNameBuffer)
397 {
398 SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"),
400 }
401
402 _tcscpy(pszSubkeyNameBuffer,pszSubkeyName);
403 if (size && (pszSubkeyName[0] == _T('\"')) && (pszSubkeyName[size-1] == _T('\"')))
404 {
405 pszSubkeyNameBuffer[size-1] = 0;
406 pszSubkeyName = pszSubkeyNameBuffer+1;
407 }
408
409 if (_tcscmp(pszSubkeyName,_T(".")) == 0)
410 {
411 delete[] pszSubkeyNameBuffer;
412 return TRUE;
413 }
414
415 if (_tcscmp(pszSubkeyName,_T("..")) == 0)
416 {
417 // Up level abstraction
419 {
420 // We are on root
422 SetError(_T("Cannot open key. The root is not child.\n"));
423 delete[] pszSubkeyNameBuffer;
424 return FALSE;
425 }
426
428 if (!m_pCurrentKey->m_pUp)
429 {
431 delete[] pszSubkeyNameBuffer;
432 return FALSE;
433 }
434 CNode *pNode = m_pCurrentKey;
436 delete pNode;
437 delete[] pszSubkeyNameBuffer;
438 return TRUE;
439 }
440
441 CNode *pNewKey = new CNode;
442 if (!pNewKey)
443 {
444 SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"),
446 delete[] pszSubkeyNameBuffer;
447 return FALSE;
448 }
449
450 if (!InternalGetSubkey(pszSubkeyName,DesiredAccess,pNewKey->m_Key))
451 {
452 delete pNewKey;
453 delete[] pszSubkeyNameBuffer;
454 return FALSE;
455 }
456 pNewKey->m_pUp = m_pCurrentKey;
457 m_pCurrentKey = pNewKey;
458
459 delete[] pszSubkeyNameBuffer;
460 return TRUE;
461}
462
464{
465 LONG nError;
466 HKEY hNewKey = NULL;
467 TCHAR *pszSubkeyNameCaseUpdated = NULL;
468
469 nError = m_pCurrentKey->m_Key.OpenSubkey(DesiredAccess,pszSubkeyName,hNewKey);
470
471 if (nError != ERROR_SUCCESS)
472 {
473 SetError(_T("Cannot open key : %s%s\nError %u (%s)\n"),
474 GetCurrentPath(),pszSubkeyName,nError,GetErrorDescription(nError));
475
476 return FALSE;
477 }
478
479 // enum subkeys to find the subkey and get its name in stored case.
480 DWORD dwMaxSubkeyNameLength;
481 nError = m_pCurrentKey->m_Key.GetSubkeyNameMaxLength(dwMaxSubkeyNameLength);
482 if (nError != ERROR_SUCCESS)
483 goto SkipCaseUpdate;
484
485 pszSubkeyNameCaseUpdated = new (std::nothrow) TCHAR [dwMaxSubkeyNameLength];
486 m_pCurrentKey->m_Key.InitSubkeyEnumeration(pszSubkeyNameCaseUpdated, dwMaxSubkeyNameLength);
487 while ((nError = m_pCurrentKey->m_Key.GetNextSubkeyName()) == ERROR_SUCCESS)
488 if (_tcsicmp(pszSubkeyNameCaseUpdated, pszSubkeyName) == 0)
489 break;
490
491 if (nError != ERROR_SUCCESS)
492 {
493 delete[] pszSubkeyNameCaseUpdated;
494 pszSubkeyNameCaseUpdated = NULL;
495 }
496
497SkipCaseUpdate:
498
499 HRESULT hr;
500 ASSERT(hNewKey);
501 if (pszSubkeyNameCaseUpdated)
502 {
503 hr = rKey.Init(hNewKey,GetCurrentPath(),pszSubkeyNameCaseUpdated,DesiredAccess);
504 if (FAILED(hr))
505 {
506 if (hr == (HRESULT)E_OUTOFMEMORY)
507 SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"),
509 else
510 SetError(_T("Cannot open key : %s%s\nUnknown error\n"), GetCurrentPath(), pszSubkeyName);
511
512 goto Abort;
513 }
514
515 delete[] pszSubkeyNameCaseUpdated;
516 }
517 else
518 {
519 hr = rKey.Init(hNewKey,GetCurrentPath(),pszSubkeyName,DesiredAccess);
520 if (FAILED(hr))
521 {
522 if (hr == (HRESULT)E_OUTOFMEMORY)
523 SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"),
525 else
526 SetError(_T("Cannot open key : %s%s\nUnknown error \n"),
528 pszSubkeyName);
529
530 goto Abort;
531 }
532 }
533
534 return TRUE;
535Abort:
536 if (pszSubkeyNameCaseUpdated)
537 delete[] pszSubkeyNameCaseUpdated;
538
539 if (hNewKey)
540 {
541 LONG nError = RegCloseKey(hNewKey);
542 ASSERT(nError == ERROR_SUCCESS);
543 }
544
545 return FALSE;
546}
547
549{
550 CRegistryTree Tree(*this);
551
552 if (!Tree.ChangeCurrentKey(pszRelativePath))
553 {
555 return FALSE;
556 }
557
559 {
561 if (FAILED(hr))
562 {
563 if (hr == (HRESULT)E_OUTOFMEMORY)
564 SetError(_T("\nError %d (%s)\n"),
566 else
568 return FALSE;
569 }
570
571 return TRUE;
572 }
573
574 // open key with desired access
575
576 // may be call to DuplicateHandle() is better.
577 // registry key handles returned by the RegConnectRegistry function cannot be used in a call to DuplicateHandle.
578
579 // Get short key name now...
580 const TCHAR *pszKeyName = Tree.m_pCurrentKey->m_Key.GetKeyName();
581 if (pszKeyName == NULL)
582 {
584 return FALSE;
585 }
586
587 size_t size = _tcslen(pszKeyName);
588 ASSERT(size);
589 if (!size)
590 {
592 return FALSE;
593 }
594
595 const TCHAR *pszShortKeyName_ = pszKeyName + size-1;
596 pszShortKeyName_--; // skip ending backslash
597 size = 0;
598 while (pszShortKeyName_ >= pszKeyName)
599 {
600 if (*pszShortKeyName_ == _T('\\'))
601 break;
602 pszShortKeyName_--;
603 size++;
604 }
605
606 if (!size || (*pszShortKeyName_ != _T('\\')))
607 {
608 ASSERT(FALSE);
610 return FALSE;
611 }
612
613 TCHAR *pszShortKeyName = new (std::nothrow) TCHAR [size+1];
614 if (!pszShortKeyName)
615 {
617 return FALSE;
618 }
619
620 memcpy(pszShortKeyName,pszShortKeyName_+1,size*sizeof(TCHAR));
621 pszShortKeyName[size] = 0;
622
623 // change to parent key
625 {
626 delete[] pszShortKeyName;
627 ASSERT(FALSE);
629 return FALSE;
630 }
631
632 // change back to target key
633 if (!Tree.InternalGetSubkey(pszShortKeyName,DesiredAccess,rKey))
634 {
635 delete[] pszShortKeyName;
637 return FALSE;
638 }
639
640 delete[] pszShortKeyName;
641 return TRUE;
642}
643
CRegistryTree Tree
BOOL PatternMatch(const TCHAR *pszPattern, const TCHAR *pszTry)
Definition: Pattern.cpp:28
#define PATTERN_MATCH_ALL
Definition: Pattern.h:7
#define COMMAND_NA_ON_ROOT
#define ERROR_MSG_BUFFER_SIZE
Definition: RegistryTree.h:12
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define RegCloseKey(hKey)
Definition: registry.h:49
LONG GetSubkeyNameMaxLength(DWORD &rdwMaxSubkeyNameLength)
const TCHAR * GetKeyName()
LONG OpenSubkey(REGSAM samDesired, const TCHAR *pszSubkeyName, HKEY &rhKey)
LONG GetNextSubkeyName(DWORD *pdwActualSize=NULL)
LONG DeleteSubkey(const TCHAR *pszPatternSubkeyName)
HRESULT Init(HKEY hKey, const TCHAR *pszPath, const TCHAR *pszKeyName, REGSAM CurrentAccess)
Definition: RegistryKey.cpp:91
LONG CreateSubkey(REGSAM samDesired, const TCHAR *pszKeyName, HKEY &rhKey, BOOL *pblnOpened=NULL, BOOL blnVolatile=FALSE)
HRESULT InitRoot(const TCHAR *pszMachineName=NULL)
Definition: RegistryKey.cpp:52
void InitSubkeyEnumeration(TCHAR *pchSubkeyNameBuffer, DWORD dwBufferSize)
CRegistryKey m_Key
Definition: RegistryTree.h:107
virtual ~CRegistryTree()
const TCHAR * GetErrorDescription(LONG nError)
BOOL InternalChangeCurrentKey(const TCHAR *pszSubkeyName, REGSAM DesiredAccess)
BOOL NewKey(const TCHAR *pszKeyName, const TCHAR *pszPath, BOOL blnVolatile=FALSE)
void SetError(LONG nError)
void AddErrorDescription(const TCHAR *pszFormat,...)
BOOL GetKey(const TCHAR *pchRelativePath, REGSAM DesiredAccess, CRegistryKey &rKey)
CNode * m_pCurrentKey
Definition: RegistryTree.h:110
void SetErrorCommandNAOnRoot(const TCHAR *pszCommand)
BOOL SetMachineName(LPCTSTR pszMachineName)
BOOL InternalGetSubkey(const TCHAR *pszSubkeyName, REGSAM DesiredAccess, CRegistryKey &rKey)
const TCHAR * GetCurrentPath() const
BOOL IsCurrentRoot()
class CRegistryTree::CNode m_Root
void SetInternalError()
LPTSTR m_pszMachineName
Definition: RegistryTree.h:112
const TCHAR * GetLastErrorDescription()
BOOL ChangeCurrentKey(const TCHAR *pchRelativePath)
BOOL DeleteSubkeys(const TCHAR *pszKeyPattern, const TCHAR *pszPath, BOOL blnRecursive=FALSE)
TCHAR m_ErrorMsg[ERROR_MSG_BUFFER_SIZE+1]
Definition: RegistryTree.h:111
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
#define ERROR_ACCESS_DENIED
Definition: compat.h:97
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
GLsizeiptr size
Definition: glext.h:5919
#define _tcscmp
Definition: tchar.h:1424
#define _tcscpy
Definition: tchar.h:623
#define _tcstok
Definition: tchar.h:1416
#define _tcsupr
Definition: tchar.h:1467
#define _tcschr
Definition: tchar.h:1406
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define ASSERT(a)
Definition: mode.c:44
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
#define KEY_READ
Definition: nt_native.h:1023
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define KEY_ENUMERATE_SUB_KEYS
Definition: nt_native.h:1019
#define DELETE
Definition: nt_native.h:57
#define READ_CONTROL
Definition: nt_native.h:58
long LONG
Definition: pedump.c:60
#define args
Definition: format.c:66
HRESULT hr
Definition: shlfolder.c:183
Definition: match.c:390
#define VERIFY(e)
Definition: ph.h:34
#define _T(x)
Definition: vfdio.h:22
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2658
#define ERROR_INTERNAL_ERROR
Definition: winerror.h:840
ACCESS_MASK REGSAM
Definition: winreg.h:69
char TCHAR
Definition: xmlstorage.h:189
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
#define _vsntprintf
Definition: xmlstorage.h:203
#define _tcslen
Definition: xmlstorage.h:198
#define _tcsicmp
Definition: xmlstorage.h:205