#include "stdafx.h"
#include "registryxmllib.h"
long Helper_OpenKey(CString &szMainKey, CString &szPath, HKEY *pKey)
{
if (pKey==NULL) return 1; // generic error
*pKey = NULL;
// open the key now
long hr;
if (szMainKey.CompareNoCase("HKEY_CLASSES_ROOT")==0)
{
hr = ::RegOpenKey(HKEY_CLASSES_ROOT, szPath, pKey);
}
else if (szMainKey.CompareNoCase("HKEY_CURRENT_USER")==0)
{
hr = ::RegOpenKey(HKEY_CURRENT_USER, szPath, pKey);
}
else if (szMainKey.CompareNoCase("HKEY_LOCAL_MACHINE")==0)
{
hr = ::RegOpenKey(HKEY_LOCAL_MACHINE, szPath, pKey);
}
else if (szMainKey.CompareNoCase("HKEY_USERS")==0)
{
hr = ::RegOpenKey(HKEY_USERS, szPath, pKey);
}
else if (szMainKey.CompareNoCase("HKEY_CURRENT_CONFIG")==0)
{
hr = ::RegOpenKey(HKEY_CURRENT_CONFIG, szPath, pKey);
}
else
return 1; // break here
return hr;
}
void AddChildren(CTreeCtrl &tree, HTREEITEM hItem, CString &szPath)
{
// build path from item name
//
if (hItem==NULL || tree.GetParentItem(hItem)==NULL) return;
if (szPath.IsEmpty()) return;
CString szMainKeyname = szPath;
int nSlash = szPath.Find(_T("\\") );
if (nSlash>-1)
{
szMainKeyname = szPath.Left( nSlash );
szPath = szPath.Right( szPath.GetLength()-(nSlash+1));
}
else
szPath.Empty();
// open the key now
HKEY hKey;
long hr;
hr = Helper_OpenKey(szMainKeyname, szPath, &hKey);
if (hr==ERROR_SUCCESS) // it's ok
{
AddChildRegistryKeys(tree, hItem, hKey);
::RegCloseKey(hKey);
}
}
void AddChildRegistryKeys(CTreeCtrl &tree, HTREEITEM hParent, HKEY hKey)
{
DWORD cSubKeys; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i;
DWORD retCode;
// Get the class name and the value count.
retCode = ::RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // length of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
if (retCode!=ERROR_SUCCESS) return;
// Enumerate the child keys, until RegEnumKeyEx fails.
CHAR *achKey = new CHAR[cbMaxSubKey+1];
if (!achKey) return;
for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
{
DWORD achKeyMaxLength = cbMaxSubKey + 1;
retCode = ::RegEnumKeyEx(hKey,
i,
achKey,
&achKeyMaxLength,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS && achKey && achKeyMaxLength>0)
{
achKey[achKeyMaxLength]=0; // force EOL
HTREEITEM hNewItem =
tree.InsertItem(achKey, ILI_FOLDER, ILI_FOLDERS, hParent, TVI_LAST);
// now try to guess if this item has children ?
// - if yes, ten add a fake item, just to make sure it is expandable
// - if no, ok good bye!
if (hNewItem)
{
HKEY hSubkey;
if (::RegOpenKey(hKey, achKey, &hSubkey)==ERROR_SUCCESS)
{
DWORD cChildSubKeys = 0;
if (::RegQueryInfoKey(hSubkey, // key handle
NULL, // buffer for class name
NULL, // length of class string
NULL, // reserved
&cChildSubKeys, // number of subkeys
NULL, // longest subkey size
NULL, // longest class string
NULL, // number of values for this key
NULL, // longest value name
NULL, // longest value data
NULL, // security descriptor
NULL)==ERROR_SUCCESS ) // last write time
{
if (cChildSubKeys>0)
tree.InsertItem(FAKEDITEM, ILI_DEFAULT, ILI_DEFAULT, hNewItem, TVI_LAST);
}
::RegCloseKey(hSubkey);
}
}
}
}
delete [] achKey;
}
void AddRegistryValues(HKEY hKey, CPtrArray &arrValues)
{
DWORD cSubKeys; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues = 0; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD j;
DWORD retValue;
// Get the class name and the value count.
retValue = ::RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // length of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
// Enumerate the child keys, until RegEnumKeyEx fails.
CHAR *achValueName = new CHAR[cchMaxValue+1];
if (!achValueName) return;
CHAR *achValueData = new CHAR[cbMaxValueData+1];
if (!achValueData)
{
delete [] achValueName;
return;
}
CString szDefaultName = IDS_DEFAULTVALUENAME; // (Default)
CString szDefaultValue = IDS_DEFAULTVALUEVALUE; // (value not set)
// Enumerate the key values.
if (cValues && cValues!=-1 && retValue==ERROR_SUCCESS)
{
for (j = 0, retValue = ERROR_SUCCESS; j < cValues; j++)
{
DWORD cchValueName = cchMaxValue + 1;
DWORD cchValueData = cbMaxValueData + 1;
DWORD dwType;
achValueName[0] = _T('\0');
achValueData[0] = _T('\0');
retValue = ::RegEnumValue(hKey, j, achValueName,
&cchValueName,
NULL,
&dwType,
(LPBYTE) achValueData,
&cchValueData);
if (retValue == ERROR_SUCCESS)
{
KeyValue *p = new KeyValue();
if (!p) continue; //
CStringArray a;
if (cchValueName==0 && strlen(achValueName)==0)
{
if (cchValueData==0 && strlen(achValueData)==0)
p->SetKeyValue( szDefaultName,
szDefaultValue,
dwType);
else
p->SetKeyValue( szDefaultName,
CString (achValueData),
dwType);
}
else
{
p->SetKeyValue( CString(achValueName),
ConvertToString(dwType,achValueData,cchValueData),
dwType );
}
arrValues.Add( p );
}
}
} // end if (cValues && cValues!=-1)
// now sort all this
//
int nNbItems = arrValues.GetSize();
BOOL bSorted = FALSE;
while (!bSorted)
{
bSorted = TRUE;
if (nNbItems<=1) break; // no need to sort trivial arrays
int i=0;
while ( bSorted && i<(nNbItems-1) )
{
KeyValue *pCur = (KeyValue*) arrValues.GetAt(i);
KeyValue *pNext = (KeyValue*) arrValues.GetAt(i+1);
if (pCur && pNext)
{
if (pCur->GetName().CompareNoCase(szDefaultName)==0)
{
i++;
continue;
}
if (pCur->GetName().CompareNoCase( pNext->GetName() ) >0 )
{
bSorted = FALSE;
arrValues.SetAt(i, pNext); // swap values
arrValues.SetAt(i+1, pCur);
}
}
i++;
} // first-pass
} // second-pass
// make sure we have at least a default value to play with
BOOL bFound = FALSE;
int i = 0;
while (!bFound && i<nNbItems)
{
KeyValue *p = (KeyValue*) arrValues.GetAt(i++);
if (p)
{
bFound = ( p->GetName().Compare(szDefaultName)==0 );
}
}
if (!bFound)
{
// this is a fake add, just to visually match what's shown in regedit.exe
KeyValue *p = new KeyValue();
if (p)
{
p->SetKeyValue( szDefaultName,
szDefaultValue,
REG_SZ);
arrValues.InsertAt(0, p);
}
}
delete [] achValueData;
delete [] achValueName;
}
CString ConvertToString(DWORD dwType, LPTSTR szRawBuffer, DWORD nLen)
{
CString s;
// conversion from number to string
if ( (dwType>=REG_BINARY && dwType<=REG_DWORD_BIG_ENDIAN) ||
dwType==11 ||
dwType==REG_RESOURCE_LIST ||
dwType==REG_RESOURCE_REQUIREMENTS_LIST)
{
switch (dwType)
{
case REG_BINARY :
case REG_RESOURCE_LIST :
case REG_RESOURCE_REQUIREMENTS_LIST :
{
CString sByte;
for (int i=0; i<(long)nLen; i++)
{
byte c = szRawBuffer[i];
sByte.Format(_T("%02x"), c);
if (!s.IsEmpty()) s += _T(" ");
s += sByte;
}
}
break;
case REG_DWORD : // == REG_DWORD_LITTLE_ENDIAN
{
byte a = szRawBuffer[3];
byte b = szRawBuffer[2];
byte c = szRawBuffer[1];
byte d = szRawBuffer[0];
s.Format(_T("0x%02x%02x%02x%02x"), a, b, c, d);
DWORD n = (a<<24) | (b<<16) | (c<<8) | d;
CString sDword;
sDword.Format(_T(" (%d)"), n);
s += sDword;
}
break;
case REG_DWORD_BIG_ENDIAN :
{
byte a = szRawBuffer[0];
byte b = szRawBuffer[1];
byte c = szRawBuffer[2];
byte d = szRawBuffer[3];
s.Format(_T("0x%02x%02x%02x%02x"), a, b, c, d);
DWORD n = (a<<24) | (b<<16) | (c<<8) | d;
CString sDword;
sDword.Format(_T(" (%d)"), n);
s += sDword;
}
break;
case 11 : // QWORD, QWORD_LITTLE_ENDIAN (64-bit integer)
{
byte a = szRawBuffer[7];
byte b = szRawBuffer[6];
byte c = szRawBuffer[5];
byte d = szRawBuffer[4];
byte e = szRawBuffer[3];
byte f = szRawBuffer[2];
byte g = szRawBuffer[1];
byte h = szRawBuffer[0];
s.Format(_T("0x%02x%02x%02x%02x%02x%02x%02x%02x"), a, b, c, d, e, f, g, h);
}
break;
}
}
else
{
if (dwType==REG_LINK)
{
// convert the Unicode string to local charset string
char *temps = new char[nLen+1];
int nActualLength = ::WideCharToMultiByte(CP_ACP,
0,
(wchar_t *)szRawBuffer,
-1,
temps,
nLen,
NULL,
NULL);
temps[nActualLength]= _T('\0'); // EOL
s = temps;
delete [] temps;
}
else if (dwType==REG_MULTI_SZ)
{
// a MULTI_SZ value is a set of strings separated by a 0 char, and
// finishes with a double 0
for (int i=0; i<long(nLen-2); i++) // nLen-1 instead of nLen, because we don't care the second 0 of the double 0
{
if (szRawBuffer[i]==0)
s += _T("\r\n");
else
s += szRawBuffer[i];
}
}
else
{
s = szRawBuffer;
}
}
return s;
}
// this function is the dual of ConvertToString
void ConvertFromString(CString &szValue, DWORD dwType, LPSTR *szRawBuffer, DWORD *nLen)
{
if (szRawBuffer==NULL || nLen==NULL) return;
*szRawBuffer = NULL; // defensive programming
*nLen = 0;
// real conversion starts here
if (dwType==REG_SZ || dwType==REG_EXPAND_SZ)
{
long n = szValue.GetLength()+1;
char *buffer = new char[n];
if (buffer)
{
*nLen = n;
strncpy(buffer, szValue.GetBuffer(0), n-1);
buffer[n-1]=0; // EOL
*szRawBuffer = buffer;
}
}
else if (dwType==REG_BINARY || dwType==REG_RESOURCE_LIST || dwType==REG_RESOURCE_REQUIREMENTS_LIST)
{
if (szValue.GetLength()==0) // stupid case handling
{
char *buffer = new char[1];
if (buffer)
{
buffer[0]=0;
*nLen = 1;
*szRawBuffer = buffer;
}
}
else
{
long n = ( szValue.GetLength()+1 ) / 3;
char *buffer = new char[n];
if (buffer)
{
*nLen = n;
long ncur = 0;
for (long i=0; i<n; i++)
{
buffer[i] = ConvertToDecimal( szValue.GetAt(ncur), szValue.GetAt(ncur+1) );
ncur += 3;
}
*szRawBuffer = buffer;
}
}
}
else if (dwType==REG_DWORD)
{
if (szValue.GetLength()==0) // stupid case handling
{
char *buffer = new char[4];
if (buffer)
{
buffer[0]=0;buffer[1]=0;buffer[2]=0;buffer[3]=0;
*nLen = 4;
*szRawBuffer = buffer;
}
}
else
{
long n = 4;
char *buffer = new char[n];
if (buffer)
{
*nLen = n;
long ncur = 2; // starts of offset 2 since we have 0x
for (long i=0; i<n; i++)
{
buffer[n-1-i] = ConvertToDecimal( szValue.GetAt(ncur), szValue.GetAt(ncur+1) );
ncur += 2;
}
*szRawBuffer = buffer;
}
}
}
else if (dwType==11)
{
if (szValue.GetLength()==0) // stupid case handling
{
char *buffer = new char[8];
if (buffer)
{
buffer[0]=0;buffer[1]=0;buffer[2]=0;buffer[3]=0;
buffer[4]=0;buffer[5]=0;buffer[6]=0;buffer[7]=0;
*nLen = 8;
*szRawBuffer = buffer;
}
}
else
{
long n = 8;
char *buffer = new char[n];
if (buffer)
{
*nLen = n;
long ncur = 2; // starts of offset 2 since we have 0x
for (long i=0; i<n; i++)
{
buffer[n-1-i] = ConvertToDecimal( szValue.GetAt(ncur), szValue.GetAt(ncur+1) );
ncur += 2;
}
*szRawBuffer = buffer;
}
}
}
else if (dwType==REG_LINK)
{
char *buffer = new char[ (szValue.GetLength()+1)*2 ];
if (buffer)
{
// local charset to widechar
//
int nActualWideLength = ::MultiByteToWideChar(CP_ACP,
0,
szValue.GetBuffer(0),
szValue.GetLength(),
(wchar_t*) buffer,
szValue.GetLength());
buffer[2*nActualWideLength] = 0; // EOL (two bytes)
buffer[2*nActualWideLength+1] = 0;
*nLen = nActualWideLength;
*szRawBuffer = buffer;
}
}
else if (dwType==REG_MULTI_SZ)
{
// szValue : the MULTI_SZ value is strings separated by \r\n (0x0A0x0D)
// buffer : a MULTI_SZ value is a set of strings separated by a 0 char, and
// finishes with a double 0
// szValue has a greater length than buffer since \r\n is 2 chars, while a 0-EOL is only one
// buf buffer has also a trailing EOL
char *buffer = new char[ szValue.GetLength()+2 ];
if (buffer)
{
long n = 0;
long nszvaluelen = szValue.GetLength();
for (long i=0; i<nszvaluelen; i++)
{
char c = szValue.GetAt(i);
if (c!='\r' && c!='\n')
{
buffer[n++] = c;
}
else if (c=='\n')
{
buffer[n++] = 0;
}
}
buffer[n++] = 0;
buffer[n++] = 0;
if (nszvaluelen==0) n=1;
*nLen = n;
*szRawBuffer = buffer;
}
}
}
char ConvertToDecimal(char c1, char c2)
{
char n1, n2;
if (c1>='0' && c1<='9')
n1 = c1-'0';
else if (c1>='A' && c1<='F')
n1 = c1-'A'+10;
else if (c1>='a' && c1<='f')
n1 = c1-'a'+10;
if (c2>='0' && c2<='9')
n2 = c2-'0';
else if (c2>='A' && c2<='F')
n2 = c2-'A'+10;
else if (c2>='a' && c2<='f')
n2 = c2-'a'+10;
return n1*16+n2;
}
CString StringFromValueType(DWORD nType)
{
CString s;
switch (nType) // see winnt.h
{
case REG_BINARY: s = "REG_BINARY"; break;
case REG_DWORD : s = "REG_DWORD"; break;
case REG_DWORD_BIG_ENDIAN : s = "REG_DWORD"; break;
case REG_EXPAND_SZ : s = "REG_EXPAND_SZ"; break;
case REG_LINK : s = "REG_SZ"; break;
case REG_MULTI_SZ : s = "REG_MULTI_SZ"; break;
case REG_NONE : s = "REG_SZ"; break;
case 11 : s = "REG_QWORD"; break; // QWORD (64-bit integer)
case REG_RESOURCE_LIST : s = "REG_RESOURCE_LIST"; break;
case REG_RESOURCE_REQUIREMENTS_LIST : s = "REG_RESOURCE_REQUIREMENTS_LIST"; break;
case REG_SZ : s = "REG_SZ"; break;
}
return s;
}
// this function is the dual of StringFromValueType
DWORD TypeFromString(CString &szValueType)
{
DWORD nType = REG_SZ; // default type
if (szValueType.CompareNoCase("REG_BINARY")==0)
nType = REG_BINARY;
else if (szValueType.CompareNoCase("REG_DWORD")==0)
nType = REG_DWORD;
else if (szValueType.CompareNoCase("REG_SZ")==0)
nType = REG_SZ;
else if (szValueType.CompareNoCase("REG_EXPAND_SZ")==0)
nType = REG_EXPAND_SZ;
else if (szValueType.CompareNoCase("REG_MULTI_SZ")==0)
nType = REG_MULTI_SZ;
else if (szValueType.CompareNoCase("REG_QWORD")==0)
nType = 11; // QWORD (64-bit integer)
else if (szValueType.CompareNoCase("REG_RESOURCE_LIST")==0)
nType = REG_RESOURCE_LIST;
else if (szValueType.CompareNoCase("REG_RESOURCE_REQUIREMENTS_LIST")==0)
nType = REG_RESOURCE_REQUIREMENTS_LIST;
return nType;
}
BOOL SaveAsXml( XmlWriter &w, BOOL bFakedXml, CString &szInPath)
{
CString szPath = szInPath;
if (szPath.IsEmpty()) return FALSE;
CString szMainKeyname = szPath;
int nSlash = szPath.Find(_T("\\") );
if (nSlash>-1)
{
szMainKeyname = szPath.Left( nSlash );
szPath = szPath.Right( szPath.GetLength()-(nSlash+1));
}
else
szPath.Empty();
// open the key now
HKEY hKey;
long hr = Helper_OpenKey(szMainKeyname, szPath, &hKey);
if (hr==ERROR_SUCCESS) // it's ok
{
// write the main key here
//
CStringArray arKeyPath;
int nIndexSlash = 0, i;
CString szTmpPath = szInPath;
do
{
nIndexSlash = szTmpPath.Find("\\", 0);
if (nIndexSlash>-1)
{
arKeyPath.Add( szTmpPath.Left(nIndexSlash++) );
szTmpPath = szTmpPath.Right( szTmpPath.GetLength()-nIndexSlash );
}
else
arKeyPath.Add( szTmpPath );
}
while ( nIndexSlash>-1);
int nSize = arKeyPath.GetSize();
BOOL bResult;
if (!bFakedXml)
{
for (i=0; i<nSize; i++)
{
XmlElement wkey( CString(XML_KEY) );
GetEscapedXmlString( arKeyPath.GetAt(i) );
wkey.AddAttrib( GetEscapedXmlString( CString(XML_NAME) ),
GetEscapedXmlString( arKeyPath.GetAt(i) ) );
wkey.Write(w,1);
}
bResult = SaveAsXml(w, bFakedXml, CString(""), hKey);
for (i=0; i<nSize; i++)
{
XmlElement wkey( CString(XML_KEY) );
wkey.WriteClosingTag(w,-1);
}
}
else
{
nSize--;
for (i=0; i<nSize; i++)
{
XmlElement wkey( arKeyPath.GetAt(i) );
wkey.Write(w,1);
}
bResult = SaveAsXml(w, bFakedXml, arKeyPath.GetAt(nSize), hKey);
for (i=0; i<nSize; i++)
{
XmlElement wkey( arKeyPath.GetAt(nSize-1-i) );
wkey.WriteClosingTag(w,-1);
}
}
::RegCloseKey(hKey);
return bResult;
}
return FALSE;
}
long g_nSaveCounter = 0;
BOOL SaveAsXml( XmlWriter &w, BOOL bFakedXml, CString szKeyname, HKEY hKey)
{
// write key name
//
DWORD cSubKeys; // number of subkeys
DWORD cbMaxSubKey; // longest subkey size
DWORD cchMaxClass; // longest class string
DWORD cValues; // number of values for key
DWORD cchMaxValue; // longest value name
DWORD cbMaxValueData; // longest value data
DWORD cbSecurityDescriptor; // size of security descriptor
FILETIME ftLastWriteTime; // last write time
DWORD i;
DWORD retCode;
// Get the class name and the value count.
retCode = ::RegQueryInfoKey(hKey, // key handle
NULL, // buffer for class name
NULL, // length of class string
NULL, // reserved
&cSubKeys, // number of subkeys
&cbMaxSubKey, // longest subkey size
&cchMaxClass, // longest class string
&cValues, // number of values for this key
&cchMaxValue, // longest value name
&cbMaxValueData, // longest value data
&cbSecurityDescriptor, // security descriptor
&ftLastWriteTime); // last write time
if (retCode!=ERROR_SUCCESS) return FALSE;
// Enumerate the child keys, until RegEnumKeyEx fails.
CHAR *achKey = new CHAR[cbMaxSubKey+1];
if (!achKey) return FALSE;
XmlElement wkey( CString(XML_KEY) );
if (!szKeyname.IsEmpty())
{
if (!bFakedXml) // standard xml
{
wkey.AddAttrib( GetEscapedXmlString( CString(XML_NAME) ),
GetEscapedXmlString( szKeyname ) );
if (cSubKeys>0 || cValues>0)
wkey.Write(w,1);
else
wkey.WriteEmpty(w,1);
}
else // faked xml
{
wkey.SetName( GetEscapedXmlString( szKeyname ) );
}
}
// each 50 values, we pump a window message, to check out whether the user hit ESCAPE
if ( (g_nSaveCounter++ % 50)==0 )
{
MSG msg ;
if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
if (msg.message==WM_KEYDOWN && msg.wParam==VK_ESCAPE) // abort if the user presses the ESC key
return FALSE;
}
}
// save values
//
CPtrArray arrValues;
AddRegistryValues(hKey, arrValues);
int nbItems = arrValues.GetSize();
for (int j=0; j<nbItems; j++)
{
KeyValue *p = (KeyValue*) arrValues.GetAt(j);
if (!p) continue;
if (p->GetName().Compare(IDS_DEFAULTVALUENAME) || p->GetValue().Compare(IDS_DEFAULTVALUEVALUE) )
{
DWORD dwType = p->GetType();
int nValueIcon = ILI_STRING;
if ( (dwType>=REG_BINARY && dwType<=REG_DWORD_BIG_ENDIAN) || dwType==11)
nValueIcon = ILI_BINARY;
if (!bFakedXml) // standard xml
{
XmlElement wvalue( CString(XML_VALUE) );
wvalue.AddAttrib( CString(XML_NAME), GetEscapedXmlString( p->GetName() ) );
wvalue.AddAttrib( CString(XML_VALUE2), GetEscapedXmlString( p->GetValue() ) );
if (dwType!=REG_SZ && dwType!=REG_NONE)
{
wvalue.AddAttrib( CString(XML_TYPE), GetEscapedXmlString( StringFromValueType(dwType) ) );
}
wvalue.WriteEmpty(w, 1);
}
else // faked xml
{
wkey.AddAttrib( GetEscapedXmlString( p->GetName() ), GetEscapedXmlString( p->GetValue() ) );
}
}
delete p; // destroy the now useless temp struct
}
if (!szKeyname.IsEmpty())
{
if (bFakedXml)
{
if (cSubKeys>0)
wkey.Write(w,1);
else
wkey.WriteEmpty(w,1);
}
}
for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
{
DWORD achKeyMaxLength = cbMaxSubKey + 1;
retCode = ::RegEnumKeyEx(hKey,
i,
achKey,
&achKeyMaxLength,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS && achKey && achKeyMaxLength>0)
{
achKey[achKeyMaxLength]=0; // force EOL
// open sub keys
//
HKEY hSubkey;
if (::RegOpenKey(hKey, achKey, &hSubkey)==ERROR_SUCCESS)
{
if (!SaveAsXml(w, bFakedXml, CString(achKey), hSubkey))
return FALSE; //
::RegCloseKey(hSubkey);
}
}
} // end for
if (!szKeyname.IsEmpty())
{
if (!bFakedXml)
{
if (cSubKeys>0 || cValues>0)
wkey.WriteClosingTag(w,-1);
}
else
{
// with faked xml, we only need to actually close the tag when there
// are keys under it, otherwise, we did a WriteEmpty above.
if (cSubKeys>0)
wkey.WriteClosingTag(w,-1);
}
}
delete [] achKey;
return TRUE;
}
BOOL LoadAsXml( XmlReader &r, CString &szFilename)
{
BOOL bReturn = TRUE;
r.ShowMsgBoxOnError();
r.Open( szFilename );
CPtrArray arrInternalKeyLoads;
CString szValueName, szValueValue, szValueType;
while ( r.ReadString() && bReturn )
{
switch ( r.GetNodeType() )
{
case NODETYPE_BEGINELEMENT:
{
CString szElement;
r.GetNodeName(szElement);
szElement = GetUnescapedXmlString(szElement);
}
break;
case NODETYPE_ENDELEMENT:
{
CString szElement;
r.GetNodeName(szElement);
szElement = GetUnescapedXmlString(szElement);
// close the latest key now
if ( szElement.CompareNoCase(XML_KEY)==0 && arrInternalKeyLoads.GetSize()>0 )
{
// retrieve latest key
InternalKeyLoad *p = (InternalKeyLoad*) arrInternalKeyLoads.GetAt( arrInternalKeyLoads.GetSize()-1 );
if (p)
{
LoadAsXml_CloseKey( p->hKey );
arrInternalKeyLoads.RemoveAt( arrInternalKeyLoads.GetSize()-1 );
delete p;
}
}
else if ( szElement.CompareNoCase(XML_VALUE)==0 && arrInternalKeyLoads.GetSize()>0 ) // <v .../>
{
// now set/create the value
InternalKeyLoad *p = (InternalKeyLoad*) arrInternalKeyLoads.GetAt( arrInternalKeyLoads.GetSize()-1 );
if (p)
LoadAsXml_SetValue( p->hKey, szValueName, szValueValue, szValueType);
szValueName.Empty();
szValueValue.Empty();
szValueType.Empty();
}
}
break;
case NODETYPE_ATTRIB:
{
CString szName, szValue;
r.GetAttrib(szName, szValue);
szName = GetUnescapedXmlString(szName);
szValue = GetUnescapedXmlString(szValue);
CString szCurrentElement;
r.GetNodeName(szCurrentElement);
// <k name="..."> ?
if (szName.CompareNoCase(XML_NAME)==0 && szCurrentElement.CompareNoCase(XML_KEY)==0)
{
InternalKeyLoad *p = new InternalKeyLoad();
if (p)
{
p->szKeyname = szValue;
arrInternalKeyLoads.Add( p );
// open the key, and store the handle
p->hKey = LoadAsXml_OpenKey( arrInternalKeyLoads );
if (p->hKey==NULL)
bReturn = FALSE; // abort the process
} // end if (p)
}
else if (szCurrentElement.CompareNoCase(XML_VALUE)==0) // <v name="..." value="..." type="..." />
{
if (szName.CompareNoCase(XML_NAME)==0) // name="..."
{
szValueName = szValue;
szValueValue.Empty();
szValueType.Empty();
}
else if (szName.CompareNoCase(XML_VALUE2)==0) // value="..."
{
szValueValue = szValue;
szValueType.Empty();
}
else if (szName.CompareNoCase(XML_TYPE)==0) // type="..."
{
szValueType = szValue;
}
}
}
break;
// other nodetypes : we don't care
}
} // end read lines one by one
long nSize = arrInternalKeyLoads.GetSize();
for (long i=0;i< nSize; i++)
delete arrInternalKeyLoads.GetAt( i );
r.Close();
return bReturn;
}
HKEY LoadAsXml_OpenKey(CPtrArray &arrInternalKeyLoads)
{
HKEY hKey = NULL;
long hr;
if (arrInternalKeyLoads.GetSize()==0) return NULL; // come on!
// build the real path from the array of keynames
// open the key now
CString szMainKeyname, szPath;
long nSize = arrInternalKeyLoads.GetSize();
for (long i=0; i<nSize; i++)
{
InternalKeyLoad *p = (InternalKeyLoad*) arrInternalKeyLoads.GetAt(i);
if (p)
{
if (i==0)
{
szMainKeyname = p->szKeyname;
}
else
{
if (!szPath.IsEmpty())
szPath += "\\";
szPath += p->szKeyname;
}
}
} // end for
hr = Helper_OpenKey(szMainKeyname, szPath, &hKey);
// open the registry key now
if (hr==ERROR_SUCCESS) // it's ok
return hKey;
// key does not exist, so let's create it !
if (szMainKeyname.CompareNoCase("HKEY_CLASSES_ROOT")==0)
{
hr = ::RegCreateKey(HKEY_CLASSES_ROOT, szPath, &hKey);
}
else if (szMainKeyname.CompareNoCase("HKEY_CURRENT_USER")==0)
{
hr = ::RegCreateKey(HKEY_CURRENT_USER, szPath, &hKey);
}
else if (szMainKeyname.CompareNoCase("HKEY_LOCAL_MACHINE")==0)
{
hr = ::RegCreateKey(HKEY_LOCAL_MACHINE, szPath, &hKey);
}
else if (szMainKeyname.CompareNoCase("HKEY_USERS")==0)
{
hr = ::RegCreateKey(HKEY_USERS, szPath, &hKey);
}
else if (szMainKeyname.CompareNoCase("HKEY_CURRENT_CONFIG")==0)
{
hr = ::RegCreateKey(HKEY_CURRENT_CONFIG, szPath, &hKey);
}
else
return NULL; // break here
if (hr==ERROR_SUCCESS) // it's ok
return hKey;
//
SetCursor(LoadCursor (NULL, IDC_ARROW)); // back to normal cursor
CString s;
s.Format("couldn't create key %s\\%s", szMainKeyname.GetBuffer(0), szPath.GetBuffer(0) );
AfxMessageBox(s);
return NULL;
}
void LoadAsXml_CloseKey(HKEY hKey)
{
if (hKey) ::RegCloseKey(hKey);
}
void LoadAsXml_SetValue(HKEY hKey, CString &szName, CString &szValue, CString &szType)
{
if (hKey==NULL) return;
// handle the (Default) value
LPCTSTR pName = szName.CompareNoCase(IDS_DEFAULTVALUENAME)==0 ? NULL : szName.GetBuffer(0);
DWORD nType = TypeFromString(szType);
LPSTR buffer = NULL;
DWORD nLen = 0;
ConvertFromString(szValue, nType, &buffer, &nLen);
if (buffer && nLen>0)
{
long hr = ::RegSetValueEx(
hKey, // handle to key
pName, // value name
0, // reserved
nType, // value type
(CONST BYTE *) buffer, //szValue.GetBuffer(0), // value data
(DWORD) nLen //szValue.GetLength() // size of value data
);
delete [] (char*)buffer;
if (hr==ERROR_SUCCESS) // it's ok
return;
}
//
SetCursor(LoadCursor (NULL, IDC_ARROW)); // back to normal cursor
CString s;
s.Format("couldn't set value %s", szName.GetBuffer(0) );
AfxMessageBox(s);
}
CString GetEscapedXmlString(CString szInput)
{
CString s;
if (szInput.GetLength()==0) return s;
long nLength = szInput.GetLength();
for (long i=0; i<nLength; i++)
{
char c = szInput.GetAt(i);
if (c=='&')
s += "&";
else if (c=='"')
s += """;
else if (c=='<')
s += "<";
else
s += c;
}
return UTF8Conversion(s);
}
CString UTF8Conversion(CString &s)
{
wchar_t *pWideString = new wchar_t[s.GetLength()+1];
if (!pWideString) return s;
// local charset to widechar
//
int nActualWideLength = ::MultiByteToWideChar(CP_ACP,
0,
s.GetBuffer(0),
s.GetLength(),
pWideString,
s.GetLength());
pWideString[nActualWideLength] = 0;
// widechar to UTF8
//
char *temps = new char[2*nActualWideLength+5]; // 2*x+5 (why not?)
if (!temps)
{
delete [] pWideString;
return s;
}
int nActualLength = ::WideCharToMultiByte(CP_UTF8,
0,
pWideString,
-1,
temps,
2*nActualWideLength+5,
NULL,
NULL);
CString st = temps;
delete [] temps;
delete [] pWideString;
return st;
}
CString GetUnescapedXmlString(CString szInput) // Xml escape chars (" ==> ", < ==> <, & ==> &);
{
CString s;
if (szInput.GetLength()==0) return s;
s = FromUTF8Conversion(szInput);
int nLt;
while ( (nLt=s.Find("<",0))>-1 )
s = s.Left(nLt) + "<" + s.Right( s.GetLength()-(nLt+strlen("<")) );
int nQuot;
while ( (nQuot=s.Find(""",0))>-1 )
s = s.Left(nQuot) + "\"" + s.Right( s.GetLength()-(nQuot+strlen(""")) );
int nAmp;
while ( (nAmp=s.Find("&",0))>-1 )
s = s.Left(nAmp) + "&" + s.Right( s.GetLength()-(nAmp+strlen("&")) );
return s;
}
CString FromUTF8Conversion(CString &s) // UTF8 ==> local charset
{
wchar_t *pWideString = new wchar_t[s.GetLength()+1];
if (!pWideString) return s;
// UTF8 to widechar
//
int nActualWideLength = ::MultiByteToWideChar(CP_UTF8,
0,
s.GetBuffer(0),
s.GetLength(),
pWideString,
s.GetLength());
pWideString[nActualWideLength] = 0;
// widechar to local charset
//
char *temps = new char[nActualWideLength+1];
if (!temps)
{
delete [] pWideString;
return s;
}
int nActualLength = ::WideCharToMultiByte(CP_ACP,
0,
pWideString,
-1,
temps,
nActualWideLength+1,
NULL,
NULL);
CString st = temps;
delete [] temps;
delete [] pWideString;
return st;
}