windows-nt/Source/XPSP1/NT/base/mvdm/wow16/regedit/virt.c
2020-09-26 16:20:57 +08:00

520 lines
13 KiB
C

#include <windows.h>
#include "SDKRegEd.h"
#ifndef DBCS
#define AnsiNext(x) ((x)+1)
#endif
HANDLE hPars = NULL;
WORD maxKeys = 0;
BOOL bChangesMade = FALSE;
static HWND hWndVals, hWndDels;
char szListbox[] = "listbox";
extern HANDLE hInstance;
extern HWND hWndIds, hWndMain;
extern char szNull[];
extern VOID NEAR PASCAL MySetSel(HWND hWndList, int index);
static int NEAR PASCAL AddKeyToList(PSTR szPath, int index, int nLevel)
{
PSTR szLast, pNext;
DWORD dwResult;
int nResult = -IDS_OUTOFMEMORY;
WORD *pPars;
int i, nKeys, nParent, nLevels;
/* Create the list of parents if necessary */
if(!hPars) {
if(!(hPars=LocalAlloc(LMEM_MOVEABLE, 8*sizeof(WORD))))
goto Error1;
else
maxKeys = 8;
}
/* Get the current number of keys, and check index
* index == -1 means to add to the end of the list
*/
if((nKeys=(WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L)) == LB_ERR)
nKeys = 0;
if(index == 0xffff)
index = nKeys;
else if(index > nKeys)
goto Error1;
if(!(pPars=(WORD *)LocalLock(hPars)))
goto Error1;
szLast = szPath;
if(*szPath == '\\') {
/* This is a full path name, which will be inserted the first
* place it can be. The level and index are ignored: they will
* need to be determined
* if this is the root, set the variables and jump to the adding part
* otherwise, find the existing parent and the new tail
*/
if(!*(szPath+1)) {
/* If the root exists, just return its index
*/
if((nResult=FindKey(szPath)) >= 0)
goto Error2;
nParent = -1;
nLevels = 0;
pNext = szPath + 1;
goto AddNewKey;
} else {
++szLast;
if((nParent=FindLastExistingKey(0, szLast)) < 0)
goto Error2;
index = nParent + 1;
}
} else {
/* Not an absolute path
* nLevel == -1 means the preceding index is the parent, so nLevel is ignored
* otherwise, find the ancestor of the preceding key with a lower
* level than nLevel, and that is the parent
* Finally, check for existing keys, and adjust nParent and index if necessary
*/
if(nLevel == -1) {
nParent = index - 1;
} else {
for(i=index-1; i>=0; i=pPars[i], --nLevel)
/* do nothing */ ;
if(nLevel > 0)
goto Error2;
for(i=index-1; nLevel<0; i=pPars[i], ++nLevel)
/* do nothing */ ;
nParent = i;
}
if(index < nKeys) {
if((nParent=FindLastExistingKey(nParent, szLast)) < 0)
goto Error2;
else if(nParent >= index)
index = nParent + 1;
}
}
/* At this point, index should be set to the intended index,
* nParent should be set to the parent of the new key,
* and szLast is the path for the new key (which may have subkeys)
*/
for(nLevels=0; pNext=OFFSET(MyStrTok(szLast, '\\'));
++nLevels, szLast=pNext) {
AddNewKey:
if (pNext-szLast > MAX_KEY_LENGTH) {
nResult = -IDS_BADKEY;
goto CleanUp;
}
/* Make sure we have room for the new parents */
if(nKeys+nLevels+1 > (int)maxKeys) {
HANDLE hTemp;
LocalUnlock(hPars);
if(!(hTemp=LocalReAlloc(hPars,(maxKeys+8)*sizeof(WORD),LMEM_MOVEABLE)))
goto Error1;
hPars = hTemp;
if(!(pPars=(WORD *)LocalLock(hPars)))
goto Error1;
maxKeys += 8;
}
if((dwResult=SendMessage(hWndIds, LB_INSERTSTRING, index+nLevels,
(DWORD)((LPSTR)szLast)))==LB_ERR)
break;
if((dwResult=SendMessage(hWndVals, LB_INSERTSTRING, index+nLevels,
(DWORD)((LPSTR)szNull)))==LB_ERR) {
SendMessage(hWndIds, LB_DELETESTRING, index+nLevels, 0L);
break;
}
SendMessage(hWndVals, LB_SETITEMDATA, index+nLevels, 1L);
}
/* If the new key already exists, return it */
if(!nLevels)
nResult = nParent;
else if(dwResult != LB_ERR)
nResult = LOWORD(dwResult);
CleanUp:
/* update the parent list */
for(--nKeys; nKeys>=index; --nKeys) {
if(pPars[nKeys] >= (WORD)index)
pPars[nKeys+nLevels] = pPars[nKeys] + nLevels;
else
pPars[nKeys+nLevels] = pPars[nKeys];
}
for(--nLevels; nLevels>=0; --nLevels)
pPars[index+nLevels] = nParent+nLevels;
Error2:
LocalUnlock(hPars);
Error1:
return(nResult);
}
static WORD NEAR PASCAL ListRegs(HWND hWnd, HKEY hKey, int wLevel)
{
HANDLE hTail;
PSTR pTail;
int i;
HKEY hSubKey;
WORD wErrMsg = NULL;
for(i=0; !wErrMsg; ++i) {
if(MyEnumKey(hKey, i, &hTail) != ERROR_SUCCESS)
break;
pTail = LocalLock(hTail);
if((int)(wErrMsg=-AddKeyToList(pTail, -1, wLevel))>0 ||
(wErrMsg=GetErrMsg((WORD)RegOpenKey(hKey, pTail, &hSubKey))))
goto Error1;
wErrMsg = ListRegs(hWnd, hSubKey, wLevel+1);
RegCloseKey(hSubKey);
Error1:
LocalUnlock(hTail);
LocalFree(hTail);
}
return(wErrMsg);
}
WORD NEAR PASCAL MyResetIdList(HWND hDlg)
{
HKEY hKey;
int i, nNum;
WORD wErrMsg = IDS_OUTOFMEMORY;
if((!hWndVals && !(hWndVals=GetDlgItem(hDlg, ID_VALLIST))) ||
(!hWndDels && !(hWndDels=GetDlgItem(hDlg, ID_DELLIST))))
goto Error1;
bChangesMade = FALSE;
SendMessage(hWndIds, LB_RESETCONTENT, 0, 0L);
SendMessage(hWndVals, LB_RESETCONTENT, 0, 0L);
SendMessage(hWndDels, LB_RESETCONTENT, 0, 0L);
if((int)(wErrMsg=-AddKeyToList("\\", 0, 0)) <= 0) {
if(!(wErrMsg=GetErrMsg((WORD)RegCreateKey(HKEY_CLASSES_ROOT,
NULL, &hKey)))) {
wErrMsg = ListRegs(hWndIds, hKey, 1);
RegCloseKey(hKey);
nNum = (int)SendMessage(hWndVals, LB_GETCOUNT, 0, 0L);
for(i=0; i<nNum; ++i)
SendMessage(hWndVals, LB_SETITEMDATA, i, 0L);
}
MySetSel(hWndIds, 0);
}
Error1:
return(wErrMsg);
}
WORD NEAR PASCAL MySaveChanges(void)
{
HKEY hKeyTemp;
HANDLE hPath, hVal;
WORD wNum, wErrMsg;
DWORD dwTemp;
int i;
if(wErrMsg=GetErrMsg((WORD)RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKeyTemp)))
goto Error1;
wNum = (WORD)SendMessage(hWndDels, LB_GETCOUNT, 0, 0L);
for(i=0; !wErrMsg && (WORD)i<wNum; ++i) {
wErrMsg = IDS_OUTOFMEMORY;
if(!(hPath=GetListboxString(hWndDels, i)))
break;
dwTemp = RegDeleteKey(HKEY_CLASSES_ROOT, LocalLock(hPath)+1);
wErrMsg = dwTemp==ERROR_BADKEY ? NULL : GetErrMsg((WORD)dwTemp);
LocalUnlock(hPath);
LocalFree(hPath);
}
wNum = GetErrMsg((WORD)RegCloseKey(hKeyTemp));
if(wErrMsg || (wErrMsg=wNum) ||
(wErrMsg=GetErrMsg((WORD)RegCreateKey(HKEY_CLASSES_ROOT, NULL,
&hKeyTemp))))
goto Error1;
wNum = (WORD)SendMessage(hWndVals, LB_GETCOUNT, 0, 0L);
for(i=wNum-1; !wErrMsg && i>=0; --i) {
if(!SendMessage(hWndVals, LB_GETITEMDATA, i, 0L))
continue;
wErrMsg = IDS_OUTOFMEMORY;
if(!(hPath=MyGetPath(i)))
break;
if(!(hVal=GetListboxString(hWndVals, i)))
goto Error2;
wErrMsg = GetErrMsg((WORD)RegSetValue(HKEY_CLASSES_ROOT,
LocalLock(hPath)+1, REG_SZ, LocalLock(hVal), 0L));
LocalUnlock(hVal);
LocalUnlock(hPath);
LocalFree(hVal);
Error2:
LocalFree(hPath);
}
wNum = GetErrMsg((WORD)RegCloseKey(hKeyTemp));
Error1:
return(wErrMsg ? wErrMsg : wNum);
}
WORD NEAR PASCAL MyDeleteKey(int nId)
{
HANDLE hPath;
WORD *pPars;
int nKeys, i, j;
WORD wErrMsg = IDS_OUTOFMEMORY;
/* Get the path and try to delete it */
if(!(hPath=MyGetPath(nId)))
goto Error1;
if(SendMessage(hWndDels, LB_ADDSTRING, 0, (DWORD)((LPSTR)LocalLock(hPath)))
== LB_ERR)
goto Error2;
pPars = (WORD *)LocalLock(hPars);
nKeys = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L);
/* Find the first key that does not have nId in its parent chain */
for(i=nId+1; i<nKeys; ++i) {
for(j=pPars[i]; j>=0 && j!=nId; j=pPars[j])
/* do nothing */ ;
if(j != nId)
break;
}
/* Do not delete the root from the list */
if(!nId)
++nId;
/* Delete the string from the listbox */
for(j=nId; j<i; ++j) {
SendMessage(hWndIds, LB_DELETESTRING, nId, 0L);
SendMessage(hWndVals, LB_DELETESTRING, nId, 0L);
}
/* Update the parent list */
i -= nId;
nKeys -= i;
for(j=nId; j<nKeys; ++j) {
if(pPars[j+i] >= (WORD)nId)
pPars[j] = pPars[j+i] - i;
else
pPars[j] = pPars[j+i];
}
bChangesMade = TRUE;
wErrMsg = NULL;
LocalUnlock(hPars);
Error2:
LocalUnlock(hPath);
LocalFree(hPath);
Error1:
return(wErrMsg);
}
unsigned long NEAR PASCAL MyGetValue(int nId, HANDLE *hValue)
{
unsigned long result;
HANDLE hPath;
if(SendMessage(hWndVals, LB_GETITEMDATA, nId, 0L)) {
if(!(*hValue=GetListboxString(hWndVals, nId)))
return(ERROR_OUTOFMEMORY);
result = ERROR_SUCCESS;
} else {
if(!(hPath=MyGetPath(nId)))
return(ERROR_OUTOFMEMORY);
result = MyQueryValue(HKEY_CLASSES_ROOT, LocalLock(hPath)+1, hValue);
LocalUnlock(hPath);
LocalFree(hPath);
}
return(result);
}
/* Strip off leading and trailing spaces, and return
* -1 if there are any invalid characters, otherwise the address
* of the first non-blank.
*/
PSTR NEAR PASCAL VerifyKey(PSTR lpK)
{
PSTR lpT;
char cLast = '\0';
/* skip some spaces, just to be wierd
*/
while (*lpK == ' ')
lpK++;
/* Special case the string "\"
*/
if (*(unsigned int *)lpK == (unsigned int)'\\')
return(lpK);
/* Note that no extended characters are allowed, so no DBCS
* characters are allowed in a key
*/
for (lpT=lpK; ; ++lpT)
{
switch (*lpT)
{
case '\0':
/* We do not allow a \ as the last char
*/
return(cLast=='\\' ? (PSTR)-1 : lpK);
case '\\':
/* We do not allow two \'s in a row
*/
if (cLast == '\\')
return((PSTR)-1);
break;
default:
/* If we get a control or extended character, return -1.
*/
if ((char)(*lpT) <= ' ')
return((PSTR)-1);
break;
}
cLast = *lpT;
}
}
unsigned long NEAR PASCAL SDKSetValue(HKEY hKey, PSTR pSubKey, PSTR pVal)
{
WORD wNewKey;
if (hKey == HKEY_CLASSES_ROOT)
hKey = 0L;
else
hKey = -(long)hKey;
if ((pSubKey=VerifyKey(pSubKey)) == (PSTR)-1)
return(ERROR_BADKEY);
if((int)(wNewKey=(WORD)AddKeyToList(pSubKey, (WORD)hKey+1, -1))>=0 &&
SendMessage(hWndVals, LB_INSERTSTRING, wNewKey, (LONG)(LPSTR)pVal)
!=LB_ERR) {
SendMessage(hWndVals, LB_DELETESTRING, wNewKey+1, 0L);
SendMessage(hWndVals, LB_SETITEMDATA, wNewKey, 1L);
MySetSel(hWndIds, wNewKey);
bChangesMade = TRUE;
return(ERROR_SUCCESS);
}
return(ERROR_OUTOFMEMORY);
}
int NEAR PASCAL DoCopyKey(int nId, PSTR pPath)
{
WORD *pPars;
int nParent, result, i, j, nKeys, nNewKey;
pPars = (WORD *)LocalLock(hPars);
/* Cannot copy the whole tree */
result = -IDS_NOSUBKEY;
if(!nId)
goto Error1;
/* Find the longest path that currently exists
* return an error if that is the whole string
* or a subkey of the key to be copied
*/
if(*pPath == '\\') {
++pPath;
if((result=nParent=FindLastExistingKey(0, pPath)) < 0)
goto Error1;
} else {
if((result=nParent=FindLastExistingKey(pPars[nId], pPath)) < 0)
goto Error1;
}
result = -IDS_NOSUBKEY;
for(i=nParent; i>=0; i=pPars[i])
if(i == nId)
goto Error1;
result = -IDS_ALREADYEXIST;
if(!*pPath)
goto Error1;
/* Find the first key that does not have nId in its parent chain */
nKeys = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L);
for(i=nId+1; i<nKeys; ++i) {
for(j=pPars[i]; j>=0 && j!=nId; j=pPars[j])
/* do nothing */ ;
if(j != nId)
break;
}
/* Add the new keys
* hPars should be unlocked in case it needs to grow
*/
LocalUnlock(hPars);
pPars = NULL;
if(SDKSetValue(-nParent, pPath, szNull) != ERROR_SUCCESS)
goto Error1;
nNewKey = (int)SendMessage(hWndIds, LB_GETCURSEL, 0, 0L);
for(--i, result=nId; i>=nId && result==nId; --i) {
HANDLE hPart, hValue;
PSTR pPart;
if(nNewKey <= nId) {
int nDiff;
/* Need to update i and nId if keys were added before them */
nDiff = (WORD)SendMessage(hWndIds, LB_GETCOUNT, 0, 0L) - nKeys;
nKeys += nDiff;
i += nDiff;
nId += nDiff;
}
result = -IDS_OUTOFMEMORY;
if(!(hPart=MyGetPartialPath(i, nId)))
goto Error2;
pPart = LocalLock(hPart);
if(MyGetValue(i, &hValue) != ERROR_SUCCESS)
goto Error3;
if(SDKSetValue(-nNewKey, pPart, LocalLock(hValue)) != ERROR_SUCCESS)
goto Error4;
result = nId;
Error4:
LocalUnlock(hValue);
LocalFree(hValue);
Error3:
LocalUnlock(hPart);
LocalFree(hPart);
Error2:
;
}
Error1:
if(pPars)
LocalUnlock(hPars);
return(result);
}