windows-nt/Source/XPSP1/NT/base/fs/utils/regedit/regvalue.c

1445 lines
40 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1993-1994
*
* TITLE: REGVALUE.C
*
* VERSION: 4.01
*
* AUTHOR: Tracy Sharpe
*
* DATE: 05 Mar 1994
*
* ValueListWnd ListView routines for the Registry Editor.
*
*******************************************************************************/
#include "pch.h"
#include "regedit.h"
#include "regvalue.h"
#include "regstred.h"
#include "regbined.h"
#include "regdwded.h"
#include "regresid.h"
extern void DisplayResourceData(HWND hWnd, DWORD dwType, LPEDITVALUEPARAM lpEditValueParam);
extern void DisplayBinaryData(HWND hWnd, LPEDITVALUEPARAM lpEditValueParam, DWORD dwValueType);
#define MAX_VALUENAME_TEMPLATE_ID 100
// Maximum number of bytes that will be shown in the ListView. If the user
// wants to see more, then they can use the edit dialogs.
#define SIZE_DATATEXT 196
// Allow room in a SIZE_DATATEXT buffer for one null and possibly
// the ellipsis.
#define MAXIMUM_STRINGDATATEXT 192
const TCHAR s_StringDataFormatSpec[] = TEXT("%.192s");
// Allow room for multiple three character pairs, one null, and possibly the
// ellipsis.
#define MAXIMUM_BINARYDATABYTES 64
const TCHAR s_BinaryDataFormatSpec[] = TEXT("%02x ");
const TCHAR s_Ellipsis[] = TEXT("...");
const LPCTSTR s_TypeNames[] = { TEXT("REG_NONE"),
TEXT("REG_SZ"),
TEXT("REG_EXPAND_SZ"),
TEXT("REG_BINARY"),
TEXT("REG_DWORD"),
TEXT("REG_DWORD_BIG_ENDIAN"),
TEXT("REG_LINK"),
TEXT("REG_MULTI_SZ"),
TEXT("REG_RESOURCE_LIST"),
TEXT("REG_FULL_RESOURCE_DESCRIPTOR"),
TEXT("REG_RESOURCE_REQUIREMENTS_LIST"),
TEXT("REG_QWORD")
};
#define MAX_KNOWN_TYPE REG_QWORD
VOID
PASCAL
RegEdit_OnValueListDelete(
HWND hWnd
);
VOID
PASCAL
RegEdit_OnValueListRename(
HWND hWnd
);
VOID
PASCAL
ValueList_EditLabel(
HWND hValueListWnd,
int ListIndex
);
/*******************************************************************************
*
* RegEdit_OnNewValue
*
* DESCRIPTION:
*
* PARAMETERS:
* hWnd, handle of RegEdit window.
*
*******************************************************************************/
VOID
PASCAL
RegEdit_OnNewValue(
HWND hWnd,
DWORD Type
)
{
UINT NewValueNameID;
TCHAR ValueName[MAXVALUENAME_LENGTH];
DWORD Ignore;
DWORD cbValueData;
LV_ITEM LVItem;
int ListIndex;
UINT ErrorStringID;
BYTE abValueDataBuffer[4]; // DWORD is largest init. value
if (g_RegEditData.hCurrentSelectionKey == NULL)
return;
//
// Loop through the registry trying to find a valid temporary name until
// the user renames the key.
//
NewValueNameID = 1;
while (NewValueNameID < MAX_VALUENAME_TEMPLATE_ID) {
wsprintf(ValueName, g_RegEditData.pNewValueTemplate, NewValueNameID);
if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName,
NULL, &Ignore, NULL, &Ignore) != ERROR_SUCCESS) {
//
// For strings, we need to have at least one byte to represent the
// null. For binary data, it's okay to have zero-length data.
//
switch (Type) {
case REG_SZ:
case REG_EXPAND_SZ:
((PTSTR) abValueDataBuffer)[0] = 0;
cbValueData = sizeof(TCHAR);
break;
case REG_DWORD:
((LPDWORD) abValueDataBuffer)[0] = 0;
cbValueData = sizeof(DWORD);
break;
case REG_BINARY:
cbValueData = 0;
break;
case REG_MULTI_SZ:
((PTSTR) abValueDataBuffer)[0] = 0;
cbValueData = sizeof(TCHAR);
break;
}
if (RegSetValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, 0,
Type, abValueDataBuffer, cbValueData) == ERROR_SUCCESS)
break;
else {
ErrorStringID = IDS_NEWVALUECANNOTCREATE;
goto error_ShowDialog;
}
}
NewValueNameID++;
}
if (NewValueNameID == MAX_VALUENAME_TEMPLATE_ID) {
ErrorStringID = IDS_NEWVALUENOUNIQUE;
goto error_ShowDialog;
}
LVItem.mask = LVIF_TEXT | LVIF_IMAGE;
LVItem.pszText = ValueName;
LVItem.iItem = ListView_GetItemCount(g_RegEditData.hValueListWnd);
LVItem.iSubItem = 0;
LVItem.iImage = IsRegStringType(Type) ? IMAGEINDEX(IDI_STRING) :
IMAGEINDEX(IDI_BINARY);
if ((ListIndex = ListView_InsertItem(g_RegEditData.hValueListWnd,
&LVItem)) != -1) {
ValueList_SetItemDataText(g_RegEditData.hValueListWnd, ListIndex,
abValueDataBuffer, cbValueData, Type);
ValueList_EditLabel(g_RegEditData.hValueListWnd, ListIndex);
}
return;
error_ShowDialog:
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
MAKEINTRESOURCE(IDS_NEWVALUEERRORTITLE), MB_ICONERROR | MB_OK);
}
/*******************************************************************************
*
* RegEdit_OnValueListBeginLabelEdit
*
* DESCRIPTION:
*
* PARAMETERS:
* hWnd, handle of RegEdit window.
* lpLVDispInfo,
*
*******************************************************************************/
BOOL
PASCAL
RegEdit_OnValueListBeginLabelEdit(
HWND hWnd,
LV_DISPINFO FAR* lpLVDispInfo
)
{
//
// B#7933: We don't want the user to hurt themselves by making it too easy
// to rename keys and values. Only allow renames via the menus.
//
//
// We don't get any information on the source of this editing action, so
// we must maintain a flag that tells us whether or not this is "good".
//
if (!g_RegEditData.fAllowLabelEdits)
return TRUE;
//
// All other labels are fair game. We need to disable our keyboard
// accelerators so that the edit control can "see" them.
//
g_fDisableAccelerators = TRUE;
return FALSE;
}
/*******************************************************************************
*
* RegEdit_OnValueListEndLabelEdit
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
BOOL
PASCAL
RegEdit_OnValueListEndLabelEdit(
HWND hWnd,
LV_DISPINFO FAR* lpLVDispInfo
)
{
BOOL fSuccess = TRUE;
HWND hValueListWnd;
DWORD cbValueData;
DWORD Ignore;
DWORD Type;
TCHAR ValueName[MAXVALUENAME_LENGTH];
UINT ErrorStringID;
PBYTE pbValueData;
//
// We can reenable our keyboard accelerators now that the edit control no
// longer needs to "see" them.
//
g_fDisableAccelerators = FALSE;
hValueListWnd = g_RegEditData.hValueListWnd;
//
// Check to see if the user cancelled the edit. If so, we don't care so
// just return.
//
if (lpLVDispInfo-> item.pszText != NULL)
{
ListView_GetItemText(hValueListWnd, lpLVDispInfo-> item.iItem, 0,
ValueName, sizeof(ValueName)/sizeof(TCHAR));
// Check to see if the new value name is empty
if (lpLVDispInfo->item.pszText[0] == 0)
{
ErrorStringID = IDS_RENAMEVALEMPTY;
fSuccess = FALSE;
}
// Check to see if the new name already exists
else if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, lpLVDispInfo->
item.pszText, NULL, &Ignore, NULL, &Ignore) != ERROR_FILE_NOT_FOUND)
{
ErrorStringID = IDS_RENAMEVALEXISTS;
fSuccess = FALSE;
}
// Set new name
if (fSuccess)
{
fSuccess = FALSE;
// Query for data size
RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName,
NULL, &Type, NULL, &cbValueData);
// Allocate storage space
pbValueData = LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type));
if (pbValueData)
{
ErrorStringID = IDS_RENAMEVALOTHERERROR;
if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, NULL,
&Type, pbValueData, &cbValueData) == ERROR_SUCCESS)
{
if (RegSetValueEx(g_RegEditData.hCurrentSelectionKey,
lpLVDispInfo->item.pszText, 0, Type, pbValueData, cbValueData) ==
ERROR_SUCCESS)
{
if (RegDeleteValue(g_RegEditData.hCurrentSelectionKey, ValueName) ==
ERROR_SUCCESS)
{
fSuccess = TRUE;
}
}
}
LocalFree(pbValueData);
}
else
{
ErrorStringID = IDS_EDITVALNOMEMORY;
}
}
if (!fSuccess)
{
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
MAKEINTRESOURCE(IDS_RENAMEVALERRORTITLE), MB_ICONERROR | MB_OK,
(LPTSTR) ValueName);
}
}
return fSuccess;
}
/*******************************************************************************
*
* RegEdit_OnValueListCommand
*
* DESCRIPTION:
* Handles the selection of a menu item by the user intended for the
* ValueList child window.
*
* PARAMETERS:
* hWnd, handle of RegEdit window.
* MenuCommand, identifier of menu command.
*
*******************************************************************************/
VOID
PASCAL
RegEdit_OnValueListCommand(
HWND hWnd,
int MenuCommand
)
{
//
// Check to see if this menu command should be handled by the main window's
// command handler.
//
if (MenuCommand >= ID_FIRSTMAINMENUITEM && MenuCommand <=
ID_LASTMAINMENUITEM)
RegEdit_OnCommand(hWnd, MenuCommand, NULL, 0);
else {
switch (MenuCommand) {
case ID_CONTEXTMENU:
RegEdit_OnValueListContextMenu(hWnd, TRUE);
break;
case ID_MODIFY:
RegEdit_OnValueListModify(hWnd, FALSE);
break;
case ID_DELETE:
RegEdit_OnValueListDelete(hWnd);
break;
case ID_RENAME:
RegEdit_OnValueListRename(hWnd);
break;
case ID_MODIFYBINARY:
RegEdit_OnValueListModify(hWnd, TRUE);
break;
}
}
}
/*******************************************************************************
*
* RegEdit_OnValueListContextMenu
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
VOID
PASCAL
RegEdit_OnValueListContextMenu(
HWND hWnd,
BOOL fByAccelerator
)
{
HWND hValueListWnd;
DWORD MessagePos;
POINT MessagePoint;
LV_HITTESTINFO LVHitTestInfo;
int ListIndex;
UINT MenuID;
HMENU hContextMenu;
HMENU hContextPopupMenu;
int MenuCommand;
hValueListWnd = g_RegEditData.hValueListWnd;
//
// If fByAcclerator is TRUE, then the user hit Shift-F10 to bring up the
// context menu. Following the Cabinet's convention, this menu is
// placed at (0,0) of the ListView client area.
//
if (fByAccelerator) {
MessagePoint.x = 0;
MessagePoint.y = 0;
ClientToScreen(hValueListWnd, &MessagePoint);
ListIndex = ListView_GetNextItem(hValueListWnd, -1, LVNI_SELECTED);
}
else {
MessagePos = GetMessagePos();
MessagePoint.x = GET_X_LPARAM(MessagePos);
MessagePoint.y = GET_Y_LPARAM(MessagePos);
LVHitTestInfo.pt = MessagePoint;
ScreenToClient(hValueListWnd, &LVHitTestInfo.pt);
ListIndex = ListView_HitTest(hValueListWnd, &LVHitTestInfo);
}
MenuID = (ListIndex != -1) ? IDM_VALUE_CONTEXT :
IDM_VALUELIST_NOITEM_CONTEXT;
if ((hContextMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(MenuID))) == NULL)
return;
hContextPopupMenu = GetSubMenu(hContextMenu, 0);
if (ListIndex != -1) {
RegEdit_SetValueListEditMenuItems(hContextMenu, ListIndex);
SetMenuDefaultItem(hContextPopupMenu, ID_MODIFY, MF_BYCOMMAND);
}
// FEATURE: Fix constant
else
RegEdit_SetNewObjectEditMenuItems(GetSubMenu(hContextPopupMenu, 0));
MenuCommand = TrackPopupMenuEx(hContextPopupMenu, TPM_RETURNCMD |
TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_TOPALIGN, MessagePoint.x,
MessagePoint.y, hWnd, NULL);
DestroyMenu(hContextMenu);
RegEdit_OnValueListCommand(hWnd, MenuCommand);
}
/*******************************************************************************
*
* RegEdit_SetValueListEditMenuItems
*
* DESCRIPTION:
* Shared routine between the main menu and the context menu to setup the
* edit menu items.
*
* PARAMETERS:
* hPopupMenu, handle of popup menu to modify.
*
*******************************************************************************/
VOID
PASCAL
RegEdit_SetValueListEditMenuItems(
HMENU hPopupMenu,
int SelectedListIndex
)
{
UINT SelectedCount;
UINT EnableFlags;
SelectedCount = ListView_GetSelectedCount(g_RegEditData.hValueListWnd);
//
// The edit option is only enabled when a single item is selected. Note
// that this item is not in the main menu, but this should work fine.
//
if (SelectedCount == 1)
EnableFlags = MF_ENABLED | MF_BYCOMMAND;
else
EnableFlags = MF_GRAYED | MF_BYCOMMAND;
EnableMenuItem(hPopupMenu, ID_MODIFY, EnableFlags);
//
// The rename option is also only enabled when a single item is selected
// and that item cannot be the default item. EnableFlags is already
// disabled if the SelectedCount is not one from above.
//
if (SelectedListIndex == 0)
EnableFlags = MF_GRAYED | MF_BYCOMMAND;
EnableMenuItem(hPopupMenu, ID_RENAME, EnableFlags);
//
// The delete option is only enabled when multiple items are selected.
//
if (SelectedCount > 0)
EnableFlags = MF_ENABLED | MF_BYCOMMAND;
else
EnableFlags = MF_GRAYED | MF_BYCOMMAND;
EnableMenuItem(hPopupMenu, ID_DELETE, EnableFlags);
}
/*******************************************************************************
*
* RegEdit_OnValueListModify
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
VOID
PASCAL
RegEdit_OnValueListModify(HWND hWnd, BOOL fEditBinary)
{
// Verify that we only have one item selected
// Don't beep for a double-clicking on the background.
UINT SelectedCount = ListView_GetSelectedCount(g_RegEditData.hValueListWnd);
if (SelectedCount > 0)
{
if (SelectedCount != 1)
{
MessageBeep(0);
}
else
{
RegEdit_EditCurrentValueListItem(hWnd, fEditBinary);
}
}
}
VOID PASCAL RegEdit_EditCurrentValueListItem(HWND hWnd, BOOL fEditBinary)
{
DWORD Type;
UINT ErrorStringID;
BOOL fError = FALSE;
EDITVALUEPARAM EditValueParam;
TCHAR ValueName[MAXVALUENAME_LENGTH];
int ListIndex = ListView_GetNextItem(g_RegEditData.hValueListWnd, -1, LVNI_SELECTED);
LONG err;
// VALUE NAME
ListView_GetItemText(g_RegEditData.hValueListWnd, ListIndex, 0, ValueName, ARRAYSIZE(ValueName));
// This is the "(Default)" value. It either does not exist in the registry because
// it's value is not set, or it exists in the registry as '\0' when its value is set
if (ListIndex == 0)
{
ValueName[0] = TEXT('\0');
}
EditValueParam.pValueName = ValueName;
// VALUE DATA
// Query for size and type
// Note that for the DefaultValue, the value may not actually exist yet. In that case we
// will get back ERROR_FILE_NOT_FOUND as the error code.
err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, NULL, &Type, NULL, &EditValueParam.cbValueData);
if (err == ERROR_SUCCESS || (err == ERROR_FILE_NOT_FOUND && ValueName[0] == TEXT('\0')))
{
// Allocate storage space
EditValueParam.pValueData = LocalAlloc(LPTR, EditValueParam.cbValueData+ExtraAllocLen(Type));
if (EditValueParam.pValueData)
{
UINT TemplateID = IDD_EDITBINARYVALUE;
DLGPROC lpDlgProc = EditBinaryValueDlgProc;
BOOL fResourceType = FALSE;
// Initialize with registry value
err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, NULL, &Type, EditValueParam.pValueData, &EditValueParam.cbValueData);
// Allow the special behavior for a key's Default Value.
if (err == ERROR_FILE_NOT_FOUND && ValueName[0] == TEXT('\0')) {
Type = REG_SZ;
*((TCHAR*)EditValueParam.pValueData) = TEXT('\0');
err = ERROR_SUCCESS;
}
if (err == ERROR_SUCCESS)
{
if (!fEditBinary)
{
switch (Type)
{
case REG_SZ:
case REG_EXPAND_SZ:
TemplateID = IDD_EDITSTRINGVALUE;
lpDlgProc = EditStringValueDlgProc;
break;
case REG_MULTI_SZ:
if(ValueList_MultiStringToString(&EditValueParam))
{
TemplateID = IDD_EDITMULTISZVALUE;
lpDlgProc = EditStringValueDlgProc;
}
break;
case REG_RESOURCE_LIST:
case REG_FULL_RESOURCE_DESCRIPTOR:
case REG_RESOURCE_REQUIREMENTS_LIST:
fResourceType = TRUE;
break;
case REG_DWORD_BIG_ENDIAN:
if (EditValueParam.cbValueData == sizeof(DWORD))
{
*((DWORD*)EditValueParam.pValueData) = ValueList_SwitchEndian(*((DWORD*)EditValueParam.pValueData));
TemplateID = IDD_EDITDWORDVALUE;
lpDlgProc = EditDwordValueDlgProc;
}
break;
case REG_DWORD:
if (EditValueParam.cbValueData == sizeof(DWORD))
{
TemplateID = IDD_EDITDWORDVALUE;
lpDlgProc = EditDwordValueDlgProc;
}
break;
}
}
if (fResourceType)
{
// only display, no editing
DisplayResourceData(hWnd, Type, &EditValueParam);
}
else if (DialogBoxParam(g_hInstance, MAKEINTRESOURCE(TemplateID),
hWnd, lpDlgProc, (LPARAM) &EditValueParam) == IDOK)
{
if ((Type == REG_MULTI_SZ) && (!fEditBinary))
{
ValueList_StringToMultiString(&EditValueParam);
ValueList_RemoveEmptyStrings(hWnd, &EditValueParam);
}
if ((Type == REG_DWORD_BIG_ENDIAN) && (!fEditBinary) && EditValueParam.cbValueData == sizeof(DWORD))
{
*((DWORD*)EditValueParam.pValueData) = ValueList_SwitchEndian(*((DWORD*)EditValueParam.pValueData));
}
// set the registry value
if (RegSetValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, 0,
Type, EditValueParam.pValueData, EditValueParam.cbValueData) !=
ERROR_SUCCESS)
{
ErrorStringID = IDS_EDITVALCANNOTWRITE;
fError = TRUE;
}
// set the display value
ValueList_SetItemDataText(g_RegEditData.hValueListWnd, ListIndex,
EditValueParam.pValueData, EditValueParam.cbValueData, Type);
}
}
else
{
ErrorStringID = IDS_EDITVALCANNOTREAD;
fError = TRUE;
}
LocalFree(EditValueParam.pValueData);
}
else
{
ErrorStringID = IDS_EDITVALNOMEMORY;
fError = TRUE;
}
}
else
{
ErrorStringID = IDS_EDITVALCANNOTREAD;
fError = TRUE;
}
if (fError)
{
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
MAKEINTRESOURCE(IDS_EDITVALERRORTITLE), MB_ICONERROR | MB_OK,
(LPTSTR) ValueName);
}
}
/*******************************************************************************
*
* RegEdit_OnValueListDelete
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
VOID
PASCAL
RegEdit_OnValueListDelete(
HWND hWnd
)
{
HWND hValueListWnd;
UINT ConfirmTextStringID;
BOOL fErrorDeleting;
int ListStartIndex;
int ListIndex;
TCHAR ValueName[MAXVALUENAME_LENGTH];
hValueListWnd = g_RegEditData.hValueListWnd;
ConfirmTextStringID = (ListView_GetSelectedCount(hValueListWnd) == 1) ?
IDS_CONFIRMDELVALTEXT : IDS_CONFIRMDELVALMULTITEXT;
if (InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ConfirmTextStringID),
MAKEINTRESOURCE(IDS_CONFIRMDELVALTITLE), MB_ICONWARNING | MB_YESNO) !=
IDYES)
return;
SetWindowRedraw(hValueListWnd, FALSE);
fErrorDeleting = FALSE;
ListStartIndex = -1;
while ((ListIndex = ListView_GetNextItem(hValueListWnd, ListStartIndex,
LVNI_SELECTED)) != -1) {
if (ListIndex != 0) {
ListView_GetItemText(hValueListWnd, ListIndex, 0, ValueName,
sizeof(ValueName)/sizeof(TCHAR));
}
else
ValueName[0] = 0;
if (RegDeleteValue(g_RegEditData.hCurrentSelectionKey, ValueName) ==
ERROR_SUCCESS) {
if (ListIndex != 0)
ListView_DeleteItem(hValueListWnd, ListIndex);
else {
ValueList_SetItemDataText(hValueListWnd, 0, NULL, 0, REG_SZ);
ListStartIndex = 0;
}
}
else {
fErrorDeleting = TRUE;
ListStartIndex = ListIndex;
}
}
SetWindowRedraw(hValueListWnd, TRUE);
if (fErrorDeleting)
InternalMessageBox(g_hInstance, hWnd,
MAKEINTRESOURCE(IDS_DELETEVALDELETEFAILED),
MAKEINTRESOURCE(IDS_DELETEVALERRORTITLE), MB_ICONERROR | MB_OK);
}
/*******************************************************************************
*
* RegEdit_OnValueListRename
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
VOID
PASCAL
RegEdit_OnValueListRename(
HWND hWnd
)
{
HWND hValueListWnd;
int ListIndex;
hValueListWnd = g_RegEditData.hValueListWnd;
if (ListView_GetSelectedCount(hValueListWnd) == 1 && (ListIndex =
ListView_GetNextItem(hValueListWnd, -1, LVNI_SELECTED)) != 0)
ValueList_EditLabel(g_RegEditData.hValueListWnd, ListIndex);
}
/*******************************************************************************
*
* RegEdit_OnValueListRefresh
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
LONG
PASCAL
RegEdit_OnValueListRefresh(HWND hWnd)
{
UINT ErrorStringID;
BOOL fError = FALSE;
BOOL fInsertedDefaultValue;
HWND hValueListWnd = g_RegEditData.hValueListWnd;
LONG result = ERROR_SUCCESS;
RegEdit_SetWaitCursor(TRUE);
SetWindowRedraw(hValueListWnd, FALSE);
ListView_DeleteAllItems(hValueListWnd);
if (g_RegEditData.hCurrentSelectionKey != NULL)
{
LV_ITEM LVItem;
LONG PrevStyle;
DWORD EnumIndex;
TCHAR achValueName[MAXVALUENAME_LENGTH];
LVItem.mask = LVIF_TEXT | LVIF_IMAGE;
LVItem.pszText = achValueName;
LVItem.iSubItem = 0;
PrevStyle = SetWindowLong(hValueListWnd, GWL_STYLE,
GetWindowLong(hValueListWnd, GWL_STYLE) | LVS_SORTASCENDING);
EnumIndex = 0;
fInsertedDefaultValue = FALSE;
while (TRUE)
{
DWORD Type;
DWORD cbValueData = 0;
int ListIndex;
PBYTE pbValueData;
DWORD cchValueName = ARRAYSIZE(achValueName);
// VALUE DATA
// Query for data size
result = RegEnumValue(g_RegEditData.hCurrentSelectionKey, EnumIndex++,
achValueName, &cchValueName, NULL, &Type, NULL,
&cbValueData);
if (result != ERROR_SUCCESS)
{
break;
}
// allocate memory for data
pbValueData = LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type));
if (pbValueData)
{
if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, achValueName,
NULL, &Type, pbValueData, &cbValueData) != ERROR_SUCCESS)
{
ErrorStringID = IDS_REFRESHCANNOTREAD;
fError = TRUE;
}
else
{
if (cchValueName == 0)
{
fInsertedDefaultValue = TRUE;
}
LVItem.iImage = IsRegStringType(Type) ? IMAGEINDEX(IDI_STRING) :
IMAGEINDEX(IDI_BINARY);
ListIndex = ListView_InsertItem(hValueListWnd, &LVItem);
ValueList_SetItemDataText(hValueListWnd, ListIndex,
pbValueData, cbValueData, Type);
}
LocalFree(pbValueData);
}
else
{
fError = TRUE;
ErrorStringID = IDS_REFRESHNOMEMORY;
}
if (fError)
{
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
MAKEINTRESOURCE(IDS_REFRESHERRORTITLE), MB_ICONERROR | MB_OK,
(LPTSTR) achValueName);
fError = FALSE;
}
}
SetWindowLong(hValueListWnd, GWL_STYLE, PrevStyle);
LVItem.iItem = 0;
LVItem.pszText = g_RegEditData.pDefaultValue;
LVItem.iImage = IMAGEINDEX(IDI_STRING);
if (fInsertedDefaultValue)
{
LVItem.mask = LVIF_TEXT;
ListView_SetItem(hValueListWnd, &LVItem);
}
else
{
ListView_InsertItem(hValueListWnd, &LVItem);
ValueList_SetItemDataText(hValueListWnd, 0, NULL, 0, REG_SZ);
}
ListView_SetItemState(hValueListWnd, 0, LVIS_FOCUSED, LVIS_FOCUSED);
}
SetWindowRedraw(hValueListWnd, TRUE);
RegEdit_SetWaitCursor(FALSE);
return result;
}
/*******************************************************************************
*
* ValueList_SetItemDataText
*
* DESCRIPTION:
*
* PARAMETERS:
* hValueListWnd, handle of ValueList window.
* ListIndex, index into ValueList window.
* pValueData, pointer to buffer containing data.
* cbValueData, size of the above buffer.
* Type, type of data this buffer contains (REG_* definition).
*
*******************************************************************************/
VOID
PASCAL
ValueList_SetItemDataText(
HWND hValueListWnd,
int ListIndex,
PBYTE pValueData,
DWORD cbValueData,
DWORD Type
)
{
BOOL fMustDeleteString;
TCHAR DataText[SIZE_DATATEXT];
int BytesToWrite;
PTSTR pString;
fMustDeleteString = FALSE;
//
// When pValueData is NULL, then that's a special indicator to us that this
// is the default value and it's value is undefined.
//
if (pValueData == NULL)
pString = g_RegEditData.pValueNotSet;
else if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ)) {
wsprintf(DataText, s_StringDataFormatSpec, (LPTSTR) pValueData);
if ((cbValueData/sizeof(TCHAR)) > MAXIMUM_STRINGDATATEXT + 1) // for null
lstrcat(DataText, s_Ellipsis);
pString = DataText;
}
else if (Type == REG_DWORD || Type == REG_DWORD_BIG_ENDIAN) {
// FEATURE: Check for invalid cbValueData!
if (cbValueData == sizeof(DWORD))
{
DWORD dw = *((DWORD*)pValueData);
if (Type == REG_DWORD_BIG_ENDIAN)
{
dw = ValueList_SwitchEndian(dw);
}
pString = LoadDynamicString(IDS_DWORDDATAFORMATSPEC, dw);
}
else
{
pString = LoadDynamicString(IDS_INVALIDDWORDDATA);
}
fMustDeleteString = TRUE;
}
else if (Type == REG_MULTI_SZ) {
int CharsAvailableInBuffer;
int ComponentLength;
PTCHAR Start;
ZeroMemory(DataText,sizeof(DataText));
CharsAvailableInBuffer = MAXIMUM_STRINGDATATEXT+1;
Start = DataText;
for(pString=(PTSTR)pValueData; *pString; pString+=ComponentLength+1) {
ComponentLength = lstrlen(pString);
//
// Quirky behavior of lstrcpyn is exactly what we need here.
//
if(CharsAvailableInBuffer > 0) {
lstrcpyn(Start,pString,CharsAvailableInBuffer);
Start += ComponentLength;
}
CharsAvailableInBuffer -= ComponentLength;
if(CharsAvailableInBuffer > 0) {
lstrcpyn(Start,TEXT(" "),CharsAvailableInBuffer);
Start += 1;
}
CharsAvailableInBuffer -= 1;
}
if(CharsAvailableInBuffer < 0) {
lstrcpy(DataText+MAXIMUM_STRINGDATATEXT,s_Ellipsis);
}
pString = DataText;
}
else {
if (cbValueData == 0)
pString = g_RegEditData.pEmptyBinary;
else {
BytesToWrite = min(cbValueData, MAXIMUM_BINARYDATABYTES);
pString = DataText;
while (BytesToWrite--)
pString += wsprintf(pString, s_BinaryDataFormatSpec,
(BYTE) *pValueData++);
*(--pString) = 0;
if (cbValueData > MAXIMUM_BINARYDATABYTES)
lstrcpy(pString, s_Ellipsis);
pString = DataText;
}
}
if(Type <= MAX_KNOWN_TYPE) {
ListView_SetItemText(hValueListWnd, ListIndex, 1, (LPTSTR)s_TypeNames[Type]);
} else {
TCHAR TypeString[24];
wsprintf(TypeString,TEXT("0x%x"),Type);
ListView_SetItemText(hValueListWnd, ListIndex, 1, TypeString);
}
ListView_SetItemText(hValueListWnd, ListIndex, 2, pString);
if (fMustDeleteString)
DeleteDynamicString(pString);
}
/*******************************************************************************
*
* ValueList_EditLabel
*
* DESCRIPTION:
*
* PARAMETERS:
* hValueListWnd, handle of ValueList window.
* ListIndex, index of item to edit.
*
*******************************************************************************/
VOID
PASCAL
ValueList_EditLabel(
HWND hValueListWnd,
int ListIndex
)
{
g_RegEditData.fAllowLabelEdits = TRUE;
//
// We have to set the focus to the ListView or else ListView_EditLabel will
// return FALSE. While we're at it, clear the selected state of all the
// items to eliminate some flicker when we move the focus back to this
// pane.
//
if (hValueListWnd != g_RegEditData.hFocusWnd) {
ListView_SetItemState(hValueListWnd, -1, 0, LVIS_SELECTED |
LVIS_FOCUSED);
SetFocus(hValueListWnd);
}
ListView_EditLabel(hValueListWnd, ListIndex);
g_RegEditData.fAllowLabelEdits = FALSE;
}
//------------------------------------------------------------------------------
// ValueList_MultiStringToString
//
// DESCRIPTION: Replaces NULL with '\r\n' to convert a Multi-String to a String
//
// PARAMETERS: EditValueParam - the edit value information
//------------------------------------------------------------------------------
BOOL PASCAL ValueList_MultiStringToString(LPEDITVALUEPARAM pEditValueParam)
{
BOOL fSuccess = TRUE;
int iStrLen = pEditValueParam->cbValueData / sizeof(TCHAR);
if (iStrLen > 1)
{
int i;
int cNullsToReplace = 0;
PTSTR pszTemp = NULL;
PTSTR psz = (TCHAR*)pEditValueParam->pValueData;
// Determine new size
for (i = iStrLen - 2; i >=0; i--)
{
if (psz[i] == TEXT('\0'))
{
cNullsToReplace++;
}
}
// the new string is always atleast as big as the old str, so we can convert back
pszTemp = LocalAlloc(LPTR, pEditValueParam->cbValueData + cNullsToReplace * sizeof(TCHAR));
if (pszTemp)
{
int iCurrentChar = 0;
int iLastNull = iStrLen - 1;
// change NULL to '\r\n'
for(i = 0; i < iLastNull; i++)
{
if (psz[i] == TEXT('\0'))
{
pszTemp[iCurrentChar++] = TEXT('\r');
pszTemp[iCurrentChar] = TEXT('\n');
}
else
{
pszTemp[iCurrentChar] = psz[i];
}
iCurrentChar++;
}
pszTemp[iCurrentChar++] = TEXT('\0');
pEditValueParam->pValueData = (PBYTE)pszTemp;
pEditValueParam->cbValueData = iCurrentChar * sizeof(psz[0]);
LocalFree(psz);
}
else
{
fSuccess = FALSE;
}
}
return fSuccess;
}
//------------------------------------------------------------------------------
// ValueList_StringToMultiString
//
// DESCRIPTION: Replaces '\r\n' with NULL
//
// PARAMETERS: EditValueParam - the edit value information
//------------------------------------------------------------------------------
VOID PASCAL ValueList_StringToMultiString(LPEDITVALUEPARAM pEditValueParam)
{
PTSTR psz = (TCHAR*)pEditValueParam->pValueData;
int iStrLen = pEditValueParam->cbValueData / sizeof(TCHAR);
if (iStrLen > 1)
{
int i = 0;
int iCurrentChar = 0;
// remove a return at the end of the string
// because another string does not follow it.
if (iStrLen >= 3)
{
if (psz[iStrLen - 3] == TEXT('\r'))
{
psz[iStrLen - 3] = TEXT('\0');
iStrLen -= 2;
}
}
for (i = 0; i < iStrLen; i++)
{
if (psz[i] == '\r')
{
psz[iCurrentChar++] = TEXT('\0');
i++; // jump past the '\n'
}
else
{
psz[iCurrentChar++] = psz[i];
}
}
// Null terminate multi-string
psz[iCurrentChar++] = TEXT('\0');
pEditValueParam->cbValueData = iCurrentChar * sizeof(psz[0]);
}
}
//------------------------------------------------------------------------------
// ValueList_RemoveEmptyStrings
//
// DESCRIPTION: Removes empty strings from multi-strings
//
// PARAMETERS: EditValueParam - the edit value information
//------------------------------------------------------------------------------
VOID PASCAL ValueList_RemoveEmptyStrings(HWND hWnd, LPEDITVALUEPARAM pEditValueParam)
{
PTSTR psz = (TCHAR*)pEditValueParam->pValueData;
int iStrLen = pEditValueParam->cbValueData / sizeof(TCHAR);
if (iStrLen > 1)
{
int i = 0;
int cNullStrings = 0;
int iCurrentChar = 0;
int iLastChar = pEditValueParam->cbValueData / sizeof(psz[0]) - 1;
for (i = 0; i < iLastChar; i++)
{
if (((psz[i] != TEXT('\0')) || (psz[i+1] != TEXT('\0'))) &&
((psz[i] != TEXT('\0')) || (i != 0)))
{
psz[iCurrentChar++] = psz[i];
}
}
psz[iCurrentChar++] = TEXT('\0');
if (iCurrentChar > 1)
{
cNullStrings = iLastChar - iCurrentChar;
// Null terminate multi-string
psz[iCurrentChar++] = TEXT('\0');
// warn user of empty strings
if (cNullStrings)
{
UINT ErrorStringID
= (cNullStrings == 1) ? IDS_EDITMULTSZEMPTYSTR : IDS_EDITMULTSZEMPTYSTRS;
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
MAKEINTRESOURCE(IDS_EDITWARNINGTITLE), MB_ICONERROR | MB_OK, NULL);
}
}
pEditValueParam->cbValueData = (iCurrentChar * sizeof(psz[0]));
}
}
//------------------------------------------------------------------------------
// ValueList_SwitchEndian
//
// DESCRIPTION: Switched a DWORD between little and big endian.
//
// PARAMETERS: dwSrc - the source DWORD to switch around
//------------------------------------------------------------------------------
DWORD PASCAL ValueList_SwitchEndian(DWORD dwSrc)
{
DWORD dwDest = 0;
BYTE * pbSrc = (BYTE *)&dwSrc;
BYTE * pbDest = (BYTE *)&dwDest;
int i;
for(i = 0; i < 4; i++)
{
pbDest[i] = pbSrc[3-i];
}
return dwDest;
}
VOID RegEdit_DisplayBinaryData(HWND hWnd)
{
DWORD Type;
UINT ErrorStringID;
BOOL fError = FALSE;
EDITVALUEPARAM EditValueParam;
TCHAR achValueName[MAXVALUENAME_LENGTH];
int ListIndex = ListView_GetNextItem(g_RegEditData.hValueListWnd, -1, LVNI_SELECTED);
LONG err;
ListView_GetItemText(g_RegEditData.hValueListWnd, ListIndex, 0, achValueName, ARRAYSIZE(achValueName));
if (ListIndex == 0)
{
// This is the "(Default)" value. It either does not exist in the registry because
// it's value is not set, or it exists in the registry as '\0' when its value is set
achValueName[0] = TEXT('\0');
}
EditValueParam.pValueName = achValueName;
// get size and type
err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, achValueName, NULL, &Type, NULL, &EditValueParam.cbValueData);
if (err == ERROR_SUCCESS || (err == ERROR_FILE_NOT_FOUND && achValueName[0] == TEXT('\0'))) {
// Allocate storage space
EditValueParam.pValueData = LocalAlloc(LPTR, EditValueParam.cbValueData+ExtraAllocLen(Type));
if (EditValueParam.pValueData)
{
err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, achValueName, NULL, &Type, EditValueParam.pValueData, &EditValueParam.cbValueData);
// Allow the special behavior for a key's Default Value.
if (err == ERROR_FILE_NOT_FOUND && achValueName[0] == TEXT('\0')) {
Type = REG_SZ;
*((TCHAR*)EditValueParam.pValueData) = TEXT('\0');
err = ERROR_SUCCESS;
}
if (err == ERROR_SUCCESS) {
DisplayBinaryData(hWnd, &EditValueParam, Type);
} else {
ErrorStringID = IDS_EDITVALCANNOTREAD;
fError = TRUE;
}
LocalFree(EditValueParam.pValueData);
}
else
{
ErrorStringID = IDS_EDITVALNOMEMORY;
fError = TRUE;
}
}
else
{
ErrorStringID = IDS_EDITVALCANNOTREAD;
fError = TRUE;
}
if (fError)
{
InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
MAKEINTRESOURCE(IDS_EDITVALERRORTITLE), MB_ICONERROR | MB_OK,
(LPTSTR) achValueName);
}
}