Something went wrong. Try again.
Reactos
Something went wrong. Try again.
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644/* * regexpl - Console Registry Explorer * * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */
// RegistryTree.cpp: implementation of the CRegistryTree class.
#include "ph.h"#include "RegistryTree.h"#include "Pattern.h"#include "RegistryExplorer.h"
CRegistryTree::CRegistryTree(){ m_pszMachineName = NULL; VERIFY(SUCCEEDED(m_Root.m_Key.InitRoot())); m_Root.m_pUp = NULL; m_pCurrentKey = &m_Root; ASSERT(m_pCurrentKey->m_Key.IsRoot()); m_ErrorMsg[ERROR_MSG_BUFFER_SIZE] = 0;}
CRegistryTree::CRegistryTree(const CRegistryTree& Tree){ m_pszMachineName = NULL; VERIFY(SUCCEEDED(m_Root.m_Key.InitRoot())); m_Root.m_pUp = NULL; m_pCurrentKey = &m_Root; ASSERT(m_pCurrentKey->m_Key.IsRoot());
const TCHAR *pszPath = Tree.GetCurrentPath(); if ((pszPath[0] == _T('\\')) && (pszPath[1] == _T('\\'))) { // path has machine name pszPath += 2; while (*pszPath && (*pszPath != _T('\\'))) pszPath++;
ASSERT(*pszPath == _T('\\')); // if path begins with \\ it must be followed by machine name }
if (Tree.m_pszMachineName) SetMachineName(Tree.m_pszMachineName);
VERIFY(ChangeCurrentKey(pszPath));}
CRegistryTree::~CRegistryTree(){ if (m_pszMachineName) delete[] m_pszMachineName;
CNode *pNode; while(m_pCurrentKey->m_pUp) { pNode = m_pCurrentKey; m_pCurrentKey = m_pCurrentKey->m_pUp; delete pNode; }
// We are on root ASSERT(m_pCurrentKey->m_Key.IsRoot()); ASSERT(m_pCurrentKey == &m_Root);}
const TCHAR * CRegistryTree::GetCurrentPath() const{ return m_pCurrentKey->m_Key.GetKeyName();}
BOOL CRegistryTree::IsCurrentRoot(){ return m_pCurrentKey->m_Key.IsRoot();}
BOOL CRegistryTree::ChangeCurrentKey(const TCHAR *pszRelativePath){ if (*pszRelativePath == _T('\\')) GotoRoot(); // This is full absolute path.
// split path to key names. const TCHAR *pszSeps = _T("\\");
// Make buffer and copy relative path into it. TCHAR *pszBuffer = new (std::nothrow) TCHAR[_tcslen(pszRelativePath)+1]; if (!pszBuffer) { SetError(ERROR_OUTOFMEMORY); return FALSE; }
_tcscpy(pszBuffer,pszRelativePath);
// We accept names in form "\"blablabla\\blab labla\"\\" size_t size = _tcslen(pszBuffer); if (size) { if (pszBuffer[size-1] == _T('\\')) pszBuffer[--size] = 0;
TCHAR *psz; if (*pszBuffer == _T('\"') && (psz = _tcschr(pszBuffer+1,_T('\"'))) && size_t(psz-pszBuffer) == size-1) { size--; pszBuffer[size] = 0;
pszBuffer++; } }
const TCHAR *pszNewKey = _tcstok(pszBuffer,pszSeps);
if ((!pszNewKey)&&((*pszRelativePath != _T('\\'))||(*(pszRelativePath+1) != 0))) { SetError(_T("Invalid key name")); goto Abort; };
// change keys while (pszNewKey) { if (!InternalChangeCurrentKey(pszNewKey,KEY_READ)) goto Abort; // InternalChangeCurrentKey sets last error description
// Get next key name pszNewKey = _tcstok(NULL,pszSeps); }
return TRUE;
Abort: delete[] pszBuffer; return FALSE;}
const TCHAR * CRegistryTree::GetLastErrorDescription(){ return m_ErrorMsg;}
void CRegistryTree::GotoRoot(){ // Delete current tree CNode *pNode; while(m_pCurrentKey->m_pUp) { pNode = m_pCurrentKey; m_pCurrentKey = m_pCurrentKey->m_pUp; delete pNode; }
// We are on root ASSERT(m_pCurrentKey->m_Key.IsRoot()); ASSERT(m_pCurrentKey == &m_Root);}
BOOL CRegistryTree::SetMachineName(LPCTSTR pszMachineName){ GotoRoot();
// If we are going to local machine... if (pszMachineName == NULL) { // Delete previous machine name buffer if allocated. if (m_pszMachineName) delete[] m_pszMachineName;
m_pszMachineName = NULL; m_Root.m_Key.InitRoot(); return TRUE; }
// Skip leading backslashes if any. while ((*pszMachineName)&&(*pszMachineName == _T('\\'))) pszMachineName++;
ASSERT(*pszMachineName); // No machine name.
TCHAR *pszNewMachineName = new (std::nothrow) TCHAR[_tcslen(pszMachineName)+3]; // two leading backslashes + terminating null
if (!pszNewMachineName) { SetError(ERROR_OUTOFMEMORY); return FALSE; }
// Delete previous machine name buffer if allocated. if (m_pszMachineName) delete[] m_pszMachineName;
m_pszMachineName = pszNewMachineName;
_tcscpy(m_pszMachineName,_T("\\\\")); // leading backslashes _tcscpy(m_pszMachineName+2,pszMachineName); // machine name itself _tcsupr(m_pszMachineName+2); // upercase it
VERIFY(SUCCEEDED(m_Root.m_Key.InitRoot(m_pszMachineName))); return TRUE;}
BOOL CRegistryTree::NewKey(const TCHAR *pszKeyName, const TCHAR *pszPath, BOOL blnVolatile){ if (!m_pCurrentKey) { SetErrorCommandNAOnRoot(_T("Creating new key ")); return FALSE; }
CRegistryTree Tree(*this); if (!Tree.ChangeCurrentKey(pszPath)) { SetError(Tree.GetLastErrorDescription()); return FALSE; }
BOOL blnOpened; HKEY hKey;
LONG nError = Tree.m_pCurrentKey->m_Key.CreateSubkey(KEY_READ, pszKeyName, hKey, &blnOpened, blnVolatile); if (nError == ERROR_SUCCESS) { LONG nError = RegCloseKey(hKey); ASSERT(nError == ERROR_SUCCESS); }
if ((nError == ERROR_SUCCESS) && blnOpened) { SetError(_T("A key \"%s\" already exists."),pszKeyName); return FALSE; }
if (nError != ERROR_SUCCESS) { SetError(_T("Cannot create key : %s%s\nError %d (%s)\n"), GetCurrentPath(),pszKeyName,nError,GetErrorDescription(nError));
return FALSE; }
return TRUE;}
BOOL CRegistryTree::DeleteSubkeys(const TCHAR *pszKeyPattern, const TCHAR *pszPath, BOOL blnRecursive){ CRegistryKey Key; if (!GetKey(pszPath,KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS|DELETE,Key)) return FALSE;
return DeleteSubkeys(Key, pszKeyPattern, blnRecursive);}
BOOL CRegistryTree::DeleteSubkeys(CRegistryKey& rKey, const TCHAR *pszKeyPattern, BOOL blnRecursive){ LONG nError;
// enumerate subkeys DWORD dwMaxSubkeyNameLength; nError = rKey.GetSubkeyNameMaxLength(dwMaxSubkeyNameLength); if (nError != ERROR_SUCCESS) { SetError(_T("Cannot delete subkeys(s) of key %s.\nRequesting info about key failed.\nError %d (%s)\n"), rKey.GetKeyName(),nError,GetErrorDescription(nError)); return FALSE; }
TCHAR *pszSubkeyName = new (std::nothrow) TCHAR [dwMaxSubkeyNameLength]; rKey.InitSubkeyEnumeration(pszSubkeyName, dwMaxSubkeyNameLength); BOOL blnKeyDeleted = FALSE; while ((nError = rKey.GetNextSubkeyName()) == ERROR_SUCCESS) { if (PatternMatch(pszKeyPattern,pszSubkeyName)) { if (blnRecursive) { // deltion is recursive, delete subkey subkeys CRegistryKey Subkey; // open subkey nError = rKey.OpenSubkey(DELETE,pszSubkeyName,Subkey); // delete subkey subkeys if (DeleteSubkeys(Subkey, PATTERN_MATCH_ALL, TRUE)) { AddErrorDescription(_T("Cannot delete subkey(s) of key %s. Subkey deletion failed.\n"),Subkey.GetKeyName()); return FALSE; } }
nError = rKey.DeleteSubkey(pszSubkeyName); if (nError != ERROR_SUCCESS) { SetError(_T("Cannot delete the %s subkey of key %s.\nError %d (%s)\n"), pszSubkeyName,rKey.GetKeyName(),nError,GetErrorDescription(nError));
return FALSE; } blnKeyDeleted = TRUE; rKey.InitSubkeyEnumeration(pszSubkeyName, dwMaxSubkeyNameLength); // reset iteration } }
ASSERT(nError != ERROR_SUCCESS); if (nError != ERROR_NO_MORE_ITEMS) { SetError(_T("Cannot delete subkeys(s) of key %s.\nSubkey enumeration failed.\nError %d (%s)\n"), rKey.GetKeyName(),nError,GetErrorDescription(nError)); return FALSE; }
if (!blnKeyDeleted) SetError(_T("The key %s has no subkeys that match %s pattern.\n"),rKey.GetKeyName(),pszKeyPattern);
return blnKeyDeleted;}
const TCHAR * CRegistryTree::GetErrorDescription(LONG nError){ switch(nError) { case ERROR_ACCESS_DENIED: return _T("Access denied"); case ERROR_FILE_NOT_FOUND: return _T("The system cannot find the key specified"); case ERROR_INTERNAL_ERROR: return _T("Internal error"); case ERROR_OUTOFMEMORY: return _T("Out of memory"); default: return _T("Unknown error"); }}
void CRegistryTree::SetError(LONG nError){ SetError(_T("Error %u (%s)"),nError,GetErrorDescription(nError));}
void CRegistryTree::SetError(const TCHAR *pszFormat, ...){ va_list args; va_start(args,pszFormat); if (_vsntprintf(m_ErrorMsg,ERROR_MSG_BUFFER_SIZE,pszFormat,args) < 0) m_ErrorMsg[ERROR_MSG_BUFFER_SIZE] = 0; va_end(args);}
void CRegistryTree::SetInternalError(){ SetError(_T("Internal Error"));}
void CRegistryTree::AddErrorDescription(const TCHAR *pszFormat, ...){ size_t size = _tcslen(m_ErrorMsg); if (size < ERROR_MSG_BUFFER_SIZE) { TCHAR *pszAdd = m_ErrorMsg+size; va_list args; va_start(args,pszFormat); size = ERROR_MSG_BUFFER_SIZE-size; if (_vsntprintf(pszAdd,size,pszFormat,args) < 0) m_ErrorMsg[size] = 0; va_end(args); }}
void CRegistryTree::SetErrorCommandNAOnRoot(const TCHAR *pszCommand){ ASSERT(pszCommand); if (pszCommand) SetError(_T("%s") COMMAND_NA_ON_ROOT,pszCommand); else SetInternalError();}
BOOL CRegistryTree::InternalChangeCurrentKey(const TCHAR *pszSubkeyName, REGSAM DesiredAccess){ size_t size = _tcslen(pszSubkeyName); TCHAR *pszSubkeyNameBuffer = new (std::nothrow) TCHAR[size+3]; if (!pszSubkeyNameBuffer) { SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"), GetCurrentPath(),pszSubkeyName,ERROR_OUTOFMEMORY,GetErrorDescription(ERROR_OUTOFMEMORY)); }
_tcscpy(pszSubkeyNameBuffer,pszSubkeyName); if (size && (pszSubkeyName[0] == _T('\"')) && (pszSubkeyName[size-1] == _T('\"'))) { pszSubkeyNameBuffer[size-1] = 0; pszSubkeyName = pszSubkeyNameBuffer+1; }
if (_tcscmp(pszSubkeyName,_T(".")) == 0) { delete[] pszSubkeyNameBuffer; return TRUE; }
if (_tcscmp(pszSubkeyName,_T("..")) == 0) { // Up level abstraction if (m_pCurrentKey->m_Key.IsRoot()) { // We are on root ASSERT(m_pCurrentKey->m_pUp == NULL); SetError(_T("Cannot open key. The root is not child.\n")); delete[] pszSubkeyNameBuffer; return FALSE; }
ASSERT(m_pCurrentKey->m_pUp); if (!m_pCurrentKey->m_pUp) { SetInternalError(); delete[] pszSubkeyNameBuffer; return FALSE; } CNode *pNode = m_pCurrentKey; m_pCurrentKey = m_pCurrentKey->m_pUp; delete pNode; delete[] pszSubkeyNameBuffer; return TRUE; }
CNode *pNewKey = new CNode; if (!pNewKey) { SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"), GetCurrentPath(),pszSubkeyName,ERROR_OUTOFMEMORY,GetErrorDescription(ERROR_OUTOFMEMORY)); delete[] pszSubkeyNameBuffer; return FALSE; }
if (!InternalGetSubkey(pszSubkeyName,DesiredAccess,pNewKey->m_Key)) { delete pNewKey; delete[] pszSubkeyNameBuffer; return FALSE; } pNewKey->m_pUp = m_pCurrentKey; m_pCurrentKey = pNewKey;
delete[] pszSubkeyNameBuffer; return TRUE;}
BOOL CRegistryTree::InternalGetSubkey(const TCHAR *pszSubkeyName, REGSAM DesiredAccess, CRegistryKey& rKey){ LONG nError; HKEY hNewKey = NULL; TCHAR *pszSubkeyNameCaseUpdated = NULL;
nError = m_pCurrentKey->m_Key.OpenSubkey(DesiredAccess,pszSubkeyName,hNewKey);
if (nError != ERROR_SUCCESS) { SetError(_T("Cannot open key : %s%s\nError %u (%s)\n"), GetCurrentPath(),pszSubkeyName,nError,GetErrorDescription(nError));
return FALSE; }
// enum subkeys to find the subkey and get its name in stored case. DWORD dwMaxSubkeyNameLength; nError = m_pCurrentKey->m_Key.GetSubkeyNameMaxLength(dwMaxSubkeyNameLength); if (nError != ERROR_SUCCESS) goto SkipCaseUpdate;
pszSubkeyNameCaseUpdated = new (std::nothrow) TCHAR [dwMaxSubkeyNameLength]; m_pCurrentKey->m_Key.InitSubkeyEnumeration(pszSubkeyNameCaseUpdated, dwMaxSubkeyNameLength); while ((nError = m_pCurrentKey->m_Key.GetNextSubkeyName()) == ERROR_SUCCESS) if (_tcsicmp(pszSubkeyNameCaseUpdated, pszSubkeyName) == 0) break;
if (nError != ERROR_SUCCESS) { delete[] pszSubkeyNameCaseUpdated; pszSubkeyNameCaseUpdated = NULL; }
SkipCaseUpdate:
HRESULT hr; ASSERT(hNewKey); if (pszSubkeyNameCaseUpdated) { hr = rKey.Init(hNewKey,GetCurrentPath(),pszSubkeyNameCaseUpdated,DesiredAccess); if (FAILED(hr)) { if (hr == (HRESULT)E_OUTOFMEMORY) SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"), GetCurrentPath(),pszSubkeyName,ERROR_OUTOFMEMORY,GetErrorDescription(ERROR_OUTOFMEMORY)); else SetError(_T("Cannot open key : %s%s\nUnknown error\n"), GetCurrentPath(), pszSubkeyName);
goto Abort; }
delete[] pszSubkeyNameCaseUpdated; } else { hr = rKey.Init(hNewKey,GetCurrentPath(),pszSubkeyName,DesiredAccess); if (FAILED(hr)) { if (hr == (HRESULT)E_OUTOFMEMORY) SetError(_T("Cannot open key : %s%s\nError %d (%s)\n"), GetCurrentPath(),pszSubkeyName,ERROR_OUTOFMEMORY,GetErrorDescription(ERROR_OUTOFMEMORY)); else SetError(_T("Cannot open key : %s%s\nUnknown error \n"), GetCurrentPath(), pszSubkeyName);
goto Abort; } }
return TRUE;Abort: if (pszSubkeyNameCaseUpdated) delete[] pszSubkeyNameCaseUpdated;
if (hNewKey) { LONG nError = RegCloseKey(hNewKey); ASSERT(nError == ERROR_SUCCESS); }
return FALSE;}
BOOL CRegistryTree::GetKey(const TCHAR *pszRelativePath, REGSAM DesiredAccess, CRegistryKey& rKey){ CRegistryTree Tree(*this);
if (!Tree.ChangeCurrentKey(pszRelativePath)) { SetError(Tree.GetLastErrorDescription()); return FALSE; }
if (Tree.m_pCurrentKey->m_Key.IsRoot()) { HRESULT hr = rKey.InitRoot(m_pszMachineName); if (FAILED(hr)) { if (hr == (HRESULT)E_OUTOFMEMORY) SetError(_T("\nError %d (%s)\n"), ERROR_OUTOFMEMORY,GetErrorDescription(ERROR_OUTOFMEMORY)); else SetInternalError(); return FALSE; }
return TRUE; }
// open key with desired access
// may be call to DuplicateHandle() is better. // registry key handles returned by the RegConnectRegistry function cannot be used in a call to DuplicateHandle.
// Get short key name now... const TCHAR *pszKeyName = Tree.m_pCurrentKey->m_Key.GetKeyName(); if (pszKeyName == NULL) { SetInternalError(); return FALSE; }
size_t size = _tcslen(pszKeyName); ASSERT(size); if (!size) { SetInternalError(); return FALSE; }
const TCHAR *pszShortKeyName_ = pszKeyName + size-1; pszShortKeyName_--; // skip ending backslash size = 0; while (pszShortKeyName_ >= pszKeyName) { if (*pszShortKeyName_ == _T('\\')) break; pszShortKeyName_--; size++; }
if (!size || (*pszShortKeyName_ != _T('\\'))) { ASSERT(FALSE); SetInternalError(); return FALSE; }
TCHAR *pszShortKeyName = new (std::nothrow) TCHAR [size+1]; if (!pszShortKeyName) { SetError(ERROR_OUTOFMEMORY); return FALSE; }
memcpy(pszShortKeyName,pszShortKeyName_+1,size*sizeof(TCHAR)); pszShortKeyName[size] = 0;
// change to parent key if (!Tree.InternalChangeCurrentKey(_T(".."),READ_CONTROL)) { delete[] pszShortKeyName; ASSERT(FALSE); SetInternalError(); return FALSE; }
// change back to target key if (!Tree.InternalGetSubkey(pszShortKeyName,DesiredAccess,rKey)) { delete[] pszShortKeyName; SetError(Tree.GetLastErrorDescription()); return FALSE; }
delete[] pszShortKeyName; return TRUE;}