ReactOS  0.4.14-dev-552-g2fad488
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 {
33  m_Root.m_pUp = NULL;
37 }
38 
40 {
43  m_Root.m_pUp = NULL;
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 {
65  if (m_pszMachineName)
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 {
83  return m_pCurrentKey->m_Key.GetKeyName();
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 
146 Abort:
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.
180  if (m_pszMachineName)
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.
203  if (m_pszMachineName)
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 
216 BOOL 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 
262 BOOL CRegistryTree::DeleteSubkeys(const TCHAR *pszKeyPattern, const TCHAR *pszPath, BOOL blnRecursive)
263 {
266  return FALSE;
267 
268  return DeleteSubkeys(Key, pszKeyPattern, blnRecursive);
269 }
270 
271 BOOL 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
298  if (DeleteSubkeys(Subkey, PATTERN_MATCH_ALL, TRUE))
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  {
336  case ERROR_ACCESS_DENIED:
337  return _T("Access denied");
339  return _T("The system cannot find the key specified");
341  return _T("Internal error");
342  case ERROR_OUTOFMEMORY:
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 
354 void CRegistryTree::SetError(const TCHAR *pszFormat, ...)
355 {
356  va_list args;
357  va_start(args,pszFormat);
360  va_end(args);
361 }
362 
364 {
365  SetError(_T("Internal Error"));
366 }
367 
368 void CRegistryTree::AddErrorDescription(const TCHAR *pszFormat, ...)
369 {
370  size_t size = _tcslen(m_ErrorMsg);
372  {
373  TCHAR *pszAdd = m_ErrorMsg+size;
374  va_list args;
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
418  if (m_pCurrentKey->m_Key.IsRoot())
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 
497 SkipCaseUpdate:
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"),
527  GetCurrentPath(),
528  pszSubkeyName);
529 
530  goto Abort;
531  }
532  }
533 
534  return TRUE;
535 Abort:
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 
HRESULT Init(HKEY hKey, const TCHAR *pszPath, const TCHAR *pszKeyName, REGSAM CurrentAccess)
Definition: RegistryKey.cpp:91
CNode * m_pCurrentKey
Definition: RegistryTree.h:110
#define TRUE
Definition: types.h:120
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
BOOL SetMachineName(LPCTSTR pszMachineName)
IN PLARGE_INTEGER IN PLARGE_INTEGER PEPROCESS ULONG Key
Definition: fatprocs.h:2697
class CRegistryTree::CNode m_Root
#define ERROR_SUCCESS
Definition: deptool.c:10
HRESULT hr
Definition: shlfolder.c:183
#define ERROR_INTERNAL_ERROR
Definition: winerror.h:840
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
#define _tcsicmp
Definition: xmlstorage.h:205
#define KEY_READ
Definition: nt_native.h:1023
int _tcscmp(const _TCHAR *s1, const _TCHAR *s2)
Definition: tcscmp.h:8
const TCHAR * GetCurrentPath() const
const TCHAR * GetKeyName()
_TCHAR * _tcscpy(_TCHAR *to, const _TCHAR *from)
Definition: tcscpy.h:8
HRESULT InitRoot(const TCHAR *pszMachineName=NULL)
Definition: RegistryKey.cpp:52
LONG GetSubkeyNameMaxLength(DWORD &rdwMaxSubkeyNameLength)
Definition: match.c:390
void SetError(LONG nError)
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
LONG OpenSubkey(REGSAM samDesired, const TCHAR *pszSubkeyName, HKEY &rhKey)
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define va_end(ap)
Definition: acmsvcex.h:90
#define ERROR_ACCESS_DENIED
Definition: compat.h:87
BOOL ChangeCurrentKey(const TCHAR *pchRelativePath)
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL GetKey(const TCHAR *pchRelativePath, REGSAM DesiredAccess, CRegistryKey &rKey)
long LONG
Definition: pedump.c:60
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
smooth NULL
Definition: ftsmooth.c:416
char * va_list
Definition: acmsvcex.h:78
BOOL InternalGetSubkey(const TCHAR *pszSubkeyName, REGSAM DesiredAccess, CRegistryKey &rKey)
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
BOOL IsCurrentRoot()
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
GLsizeiptr size
Definition: glext.h:5919
LONG DeleteSubkey(const TCHAR *pszPatternSubkeyName)
LPTSTR m_pszMachineName
Definition: RegistryTree.h:112
LONG HRESULT
Definition: typedefs.h:77
#define VERIFY(e)
Definition: ph.h:34
unsigned long DWORD
Definition: ntddk_ex.h:95
#define _vsntprintf
Definition: xmlstorage.h:203
CRegistryTree Tree
#define READ_CONTROL
Definition: nt_native.h:58
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
LONG GetNextSubkeyName(DWORD *pdwActualSize=NULL)
BOOL PatternMatch(const TCHAR *pszPattern, const TCHAR *pszTry)
Definition: Pattern.cpp:28
void SetInternalError()
const TCHAR * GetLastErrorDescription()
LONG CreateSubkey(REGSAM samDesired, const TCHAR *pszKeyName, HKEY &rhKey, BOOL *pblnOpened=NULL, BOOL blnVolatile=FALSE)
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define _tcsupr
Definition: tchar.h:1467
BOOL InternalChangeCurrentKey(const TCHAR *pszSubkeyName, REGSAM DesiredAccess)
void SetErrorCommandNAOnRoot(const TCHAR *pszCommand)
void AddErrorDescription(const TCHAR *pszFormat,...)
const TCHAR * GetErrorDescription(LONG nError)
#define COMMAND_NA_ON_ROOT
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define PATTERN_MATCH_ALL
Definition: Pattern.h:7
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK DesiredAccess
Definition: create.c:4157
#define ERROR_MSG_BUFFER_SIZE
Definition: RegistryTree.h:12
ACCESS_MASK REGSAM
Definition: winreg.h:69
BOOL NewKey(const TCHAR *pszKeyName, const TCHAR *pszPath, BOOL blnVolatile=FALSE)
#define va_start(ap, A)
Definition: acmsvcex.h:91
#define _tcstok
Definition: tchar.h:1416
void InitSubkeyEnumeration(TCHAR *pchSubkeyNameBuffer, DWORD dwBufferSize)
BOOL DeleteSubkeys(const TCHAR *pszKeyPattern, const TCHAR *pszPath, BOOL blnRecursive=FALSE)
TCHAR m_ErrorMsg[ERROR_MSG_BUFFER_SIZE+1]
Definition: RegistryTree.h:111
virtual ~CRegistryTree()
CRegistryKey m_Key
Definition: RegistryTree.h:107
#define args
Definition: format.c:66
#define SUCCEEDED(hr)
Definition: intsafe.h:57
#define DELETE
Definition: nt_native.h:57
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define KEY_ENUMERATE_SUB_KEYS
Definition: nt_native.h:1019