/******************************************************************************* * * (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) { StringCchPrintf(ValueName, ARRAYSIZE(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, ARRAYSIZE(ValueName)); // 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_FILE_NOT_FOUND && ValueName[0] == TEXT('\0')) { Type = REG_SZ; err = ERROR_SUCCESS; } if (err == ERROR_SUCCESS) { // 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; } if (!fError) { // 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, ARRAYSIZE(ValueName)); } 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)) { StringCchPrintf(DataText, ARRAYSIZE(DataText), s_StringDataFormatSpec, (LPTSTR) pValueData); if ((cbValueData/sizeof(TCHAR)) > MAXIMUM_STRINGDATATEXT + 1) // for null StringCchCat(DataText, ARRAYSIZE(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]; StringCchPrintf(TypeString, ARRAYSIZE(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); } }