Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1444 lines
40 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1993-1994
  4. *
  5. * TITLE: REGVALUE.C
  6. *
  7. * VERSION: 4.01
  8. *
  9. * AUTHOR: Tracy Sharpe
  10. *
  11. * DATE: 05 Mar 1994
  12. *
  13. * ValueListWnd ListView routines for the Registry Editor.
  14. *
  15. *******************************************************************************/
  16. #include "pch.h"
  17. #include "regedit.h"
  18. #include "regvalue.h"
  19. #include "regstred.h"
  20. #include "regbined.h"
  21. #include "regdwded.h"
  22. #include "regresid.h"
  23. extern void DisplayResourceData(HWND hWnd, DWORD dwType, LPEDITVALUEPARAM lpEditValueParam);
  24. extern void DisplayBinaryData(HWND hWnd, LPEDITVALUEPARAM lpEditValueParam, DWORD dwValueType);
  25. #define MAX_VALUENAME_TEMPLATE_ID 100
  26. // Maximum number of bytes that will be shown in the ListView. If the user
  27. // wants to see more, then they can use the edit dialogs.
  28. #define SIZE_DATATEXT 196
  29. // Allow room in a SIZE_DATATEXT buffer for one null and possibly
  30. // the ellipsis.
  31. #define MAXIMUM_STRINGDATATEXT 192
  32. const TCHAR s_StringDataFormatSpec[] = TEXT("%.192s");
  33. // Allow room for multiple three character pairs, one null, and possibly the
  34. // ellipsis.
  35. #define MAXIMUM_BINARYDATABYTES 64
  36. const TCHAR s_BinaryDataFormatSpec[] = TEXT("%02x ");
  37. const TCHAR s_Ellipsis[] = TEXT("...");
  38. const LPCTSTR s_TypeNames[] = { TEXT("REG_NONE"),
  39. TEXT("REG_SZ"),
  40. TEXT("REG_EXPAND_SZ"),
  41. TEXT("REG_BINARY"),
  42. TEXT("REG_DWORD"),
  43. TEXT("REG_DWORD_BIG_ENDIAN"),
  44. TEXT("REG_LINK"),
  45. TEXT("REG_MULTI_SZ"),
  46. TEXT("REG_RESOURCE_LIST"),
  47. TEXT("REG_FULL_RESOURCE_DESCRIPTOR"),
  48. TEXT("REG_RESOURCE_REQUIREMENTS_LIST"),
  49. TEXT("REG_QWORD")
  50. };
  51. #define MAX_KNOWN_TYPE REG_QWORD
  52. VOID
  53. PASCAL
  54. RegEdit_OnValueListDelete(
  55. HWND hWnd
  56. );
  57. VOID
  58. PASCAL
  59. RegEdit_OnValueListRename(
  60. HWND hWnd
  61. );
  62. VOID
  63. PASCAL
  64. ValueList_EditLabel(
  65. HWND hValueListWnd,
  66. int ListIndex
  67. );
  68. /*******************************************************************************
  69. *
  70. * RegEdit_OnNewValue
  71. *
  72. * DESCRIPTION:
  73. *
  74. * PARAMETERS:
  75. * hWnd, handle of RegEdit window.
  76. *
  77. *******************************************************************************/
  78. VOID
  79. PASCAL
  80. RegEdit_OnNewValue(
  81. HWND hWnd,
  82. DWORD Type
  83. )
  84. {
  85. UINT NewValueNameID;
  86. TCHAR ValueName[MAXVALUENAME_LENGTH];
  87. DWORD Ignore;
  88. DWORD cbValueData;
  89. LV_ITEM LVItem;
  90. int ListIndex;
  91. UINT ErrorStringID;
  92. BYTE abValueDataBuffer[4]; // DWORD is largest init. value
  93. if (g_RegEditData.hCurrentSelectionKey == NULL)
  94. return;
  95. //
  96. // Loop through the registry trying to find a valid temporary name until
  97. // the user renames the key.
  98. //
  99. NewValueNameID = 1;
  100. while (NewValueNameID < MAX_VALUENAME_TEMPLATE_ID) {
  101. wsprintf(ValueName, g_RegEditData.pNewValueTemplate, NewValueNameID);
  102. if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName,
  103. NULL, &Ignore, NULL, &Ignore) != ERROR_SUCCESS) {
  104. //
  105. // For strings, we need to have at least one byte to represent the
  106. // null. For binary data, it's okay to have zero-length data.
  107. //
  108. switch (Type) {
  109. case REG_SZ:
  110. case REG_EXPAND_SZ:
  111. ((PTSTR) abValueDataBuffer)[0] = 0;
  112. cbValueData = sizeof(TCHAR);
  113. break;
  114. case REG_DWORD:
  115. ((LPDWORD) abValueDataBuffer)[0] = 0;
  116. cbValueData = sizeof(DWORD);
  117. break;
  118. case REG_BINARY:
  119. cbValueData = 0;
  120. break;
  121. case REG_MULTI_SZ:
  122. ((PTSTR) abValueDataBuffer)[0] = 0;
  123. cbValueData = sizeof(TCHAR);
  124. break;
  125. }
  126. if (RegSetValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, 0,
  127. Type, abValueDataBuffer, cbValueData) == ERROR_SUCCESS)
  128. break;
  129. else {
  130. ErrorStringID = IDS_NEWVALUECANNOTCREATE;
  131. goto error_ShowDialog;
  132. }
  133. }
  134. NewValueNameID++;
  135. }
  136. if (NewValueNameID == MAX_VALUENAME_TEMPLATE_ID) {
  137. ErrorStringID = IDS_NEWVALUENOUNIQUE;
  138. goto error_ShowDialog;
  139. }
  140. LVItem.mask = LVIF_TEXT | LVIF_IMAGE;
  141. LVItem.pszText = ValueName;
  142. LVItem.iItem = ListView_GetItemCount(g_RegEditData.hValueListWnd);
  143. LVItem.iSubItem = 0;
  144. LVItem.iImage = IsRegStringType(Type) ? IMAGEINDEX(IDI_STRING) :
  145. IMAGEINDEX(IDI_BINARY);
  146. if ((ListIndex = ListView_InsertItem(g_RegEditData.hValueListWnd,
  147. &LVItem)) != -1) {
  148. ValueList_SetItemDataText(g_RegEditData.hValueListWnd, ListIndex,
  149. abValueDataBuffer, cbValueData, Type);
  150. ValueList_EditLabel(g_RegEditData.hValueListWnd, ListIndex);
  151. }
  152. return;
  153. error_ShowDialog:
  154. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  155. MAKEINTRESOURCE(IDS_NEWVALUEERRORTITLE), MB_ICONERROR | MB_OK);
  156. }
  157. /*******************************************************************************
  158. *
  159. * RegEdit_OnValueListBeginLabelEdit
  160. *
  161. * DESCRIPTION:
  162. *
  163. * PARAMETERS:
  164. * hWnd, handle of RegEdit window.
  165. * lpLVDispInfo,
  166. *
  167. *******************************************************************************/
  168. BOOL
  169. PASCAL
  170. RegEdit_OnValueListBeginLabelEdit(
  171. HWND hWnd,
  172. LV_DISPINFO FAR* lpLVDispInfo
  173. )
  174. {
  175. //
  176. // B#7933: We don't want the user to hurt themselves by making it too easy
  177. // to rename keys and values. Only allow renames via the menus.
  178. //
  179. //
  180. // We don't get any information on the source of this editing action, so
  181. // we must maintain a flag that tells us whether or not this is "good".
  182. //
  183. if (!g_RegEditData.fAllowLabelEdits)
  184. return TRUE;
  185. //
  186. // All other labels are fair game. We need to disable our keyboard
  187. // accelerators so that the edit control can "see" them.
  188. //
  189. g_fDisableAccelerators = TRUE;
  190. return FALSE;
  191. }
  192. /*******************************************************************************
  193. *
  194. * RegEdit_OnValueListEndLabelEdit
  195. *
  196. * DESCRIPTION:
  197. *
  198. * PARAMETERS:
  199. *
  200. *******************************************************************************/
  201. BOOL
  202. PASCAL
  203. RegEdit_OnValueListEndLabelEdit(
  204. HWND hWnd,
  205. LV_DISPINFO FAR* lpLVDispInfo
  206. )
  207. {
  208. BOOL fSuccess = TRUE;
  209. HWND hValueListWnd;
  210. DWORD cbValueData;
  211. DWORD Ignore;
  212. DWORD Type;
  213. TCHAR ValueName[MAXVALUENAME_LENGTH];
  214. UINT ErrorStringID;
  215. PBYTE pbValueData;
  216. //
  217. // We can reenable our keyboard accelerators now that the edit control no
  218. // longer needs to "see" them.
  219. //
  220. g_fDisableAccelerators = FALSE;
  221. hValueListWnd = g_RegEditData.hValueListWnd;
  222. //
  223. // Check to see if the user cancelled the edit. If so, we don't care so
  224. // just return.
  225. //
  226. if (lpLVDispInfo-> item.pszText != NULL)
  227. {
  228. ListView_GetItemText(hValueListWnd, lpLVDispInfo-> item.iItem, 0,
  229. ValueName, sizeof(ValueName)/sizeof(TCHAR));
  230. // Check to see if the new value name is empty
  231. if (lpLVDispInfo->item.pszText[0] == 0)
  232. {
  233. ErrorStringID = IDS_RENAMEVALEMPTY;
  234. fSuccess = FALSE;
  235. }
  236. // Check to see if the new name already exists
  237. else if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, lpLVDispInfo->
  238. item.pszText, NULL, &Ignore, NULL, &Ignore) != ERROR_FILE_NOT_FOUND)
  239. {
  240. ErrorStringID = IDS_RENAMEVALEXISTS;
  241. fSuccess = FALSE;
  242. }
  243. // Set new name
  244. if (fSuccess)
  245. {
  246. fSuccess = FALSE;
  247. // Query for data size
  248. RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName,
  249. NULL, &Type, NULL, &cbValueData);
  250. // Allocate storage space
  251. pbValueData = LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type));
  252. if (pbValueData)
  253. {
  254. ErrorStringID = IDS_RENAMEVALOTHERERROR;
  255. if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, NULL,
  256. &Type, pbValueData, &cbValueData) == ERROR_SUCCESS)
  257. {
  258. if (RegSetValueEx(g_RegEditData.hCurrentSelectionKey,
  259. lpLVDispInfo->item.pszText, 0, Type, pbValueData, cbValueData) ==
  260. ERROR_SUCCESS)
  261. {
  262. if (RegDeleteValue(g_RegEditData.hCurrentSelectionKey, ValueName) ==
  263. ERROR_SUCCESS)
  264. {
  265. fSuccess = TRUE;
  266. }
  267. }
  268. }
  269. LocalFree(pbValueData);
  270. }
  271. else
  272. {
  273. ErrorStringID = IDS_EDITVALNOMEMORY;
  274. }
  275. }
  276. if (!fSuccess)
  277. {
  278. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  279. MAKEINTRESOURCE(IDS_RENAMEVALERRORTITLE), MB_ICONERROR | MB_OK,
  280. (LPTSTR) ValueName);
  281. }
  282. }
  283. return fSuccess;
  284. }
  285. /*******************************************************************************
  286. *
  287. * RegEdit_OnValueListCommand
  288. *
  289. * DESCRIPTION:
  290. * Handles the selection of a menu item by the user intended for the
  291. * ValueList child window.
  292. *
  293. * PARAMETERS:
  294. * hWnd, handle of RegEdit window.
  295. * MenuCommand, identifier of menu command.
  296. *
  297. *******************************************************************************/
  298. VOID
  299. PASCAL
  300. RegEdit_OnValueListCommand(
  301. HWND hWnd,
  302. int MenuCommand
  303. )
  304. {
  305. //
  306. // Check to see if this menu command should be handled by the main window's
  307. // command handler.
  308. //
  309. if (MenuCommand >= ID_FIRSTMAINMENUITEM && MenuCommand <=
  310. ID_LASTMAINMENUITEM)
  311. RegEdit_OnCommand(hWnd, MenuCommand, NULL, 0);
  312. else {
  313. switch (MenuCommand) {
  314. case ID_CONTEXTMENU:
  315. RegEdit_OnValueListContextMenu(hWnd, TRUE);
  316. break;
  317. case ID_MODIFY:
  318. RegEdit_OnValueListModify(hWnd, FALSE);
  319. break;
  320. case ID_DELETE:
  321. RegEdit_OnValueListDelete(hWnd);
  322. break;
  323. case ID_RENAME:
  324. RegEdit_OnValueListRename(hWnd);
  325. break;
  326. case ID_MODIFYBINARY:
  327. RegEdit_OnValueListModify(hWnd, TRUE);
  328. break;
  329. }
  330. }
  331. }
  332. /*******************************************************************************
  333. *
  334. * RegEdit_OnValueListContextMenu
  335. *
  336. * DESCRIPTION:
  337. *
  338. * PARAMETERS:
  339. *
  340. *******************************************************************************/
  341. VOID
  342. PASCAL
  343. RegEdit_OnValueListContextMenu(
  344. HWND hWnd,
  345. BOOL fByAccelerator
  346. )
  347. {
  348. HWND hValueListWnd;
  349. DWORD MessagePos;
  350. POINT MessagePoint;
  351. LV_HITTESTINFO LVHitTestInfo;
  352. int ListIndex;
  353. UINT MenuID;
  354. HMENU hContextMenu;
  355. HMENU hContextPopupMenu;
  356. int MenuCommand;
  357. hValueListWnd = g_RegEditData.hValueListWnd;
  358. //
  359. // If fByAcclerator is TRUE, then the user hit Shift-F10 to bring up the
  360. // context menu. Following the Cabinet's convention, this menu is
  361. // placed at (0,0) of the ListView client area.
  362. //
  363. if (fByAccelerator) {
  364. MessagePoint.x = 0;
  365. MessagePoint.y = 0;
  366. ClientToScreen(hValueListWnd, &MessagePoint);
  367. ListIndex = ListView_GetNextItem(hValueListWnd, -1, LVNI_SELECTED);
  368. }
  369. else {
  370. MessagePos = GetMessagePos();
  371. MessagePoint.x = GET_X_LPARAM(MessagePos);
  372. MessagePoint.y = GET_Y_LPARAM(MessagePos);
  373. LVHitTestInfo.pt = MessagePoint;
  374. ScreenToClient(hValueListWnd, &LVHitTestInfo.pt);
  375. ListIndex = ListView_HitTest(hValueListWnd, &LVHitTestInfo);
  376. }
  377. MenuID = (ListIndex != -1) ? IDM_VALUE_CONTEXT :
  378. IDM_VALUELIST_NOITEM_CONTEXT;
  379. if ((hContextMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(MenuID))) == NULL)
  380. return;
  381. hContextPopupMenu = GetSubMenu(hContextMenu, 0);
  382. if (ListIndex != -1) {
  383. RegEdit_SetValueListEditMenuItems(hContextMenu, ListIndex);
  384. SetMenuDefaultItem(hContextPopupMenu, ID_MODIFY, MF_BYCOMMAND);
  385. }
  386. // FEATURE: Fix constant
  387. else
  388. RegEdit_SetNewObjectEditMenuItems(GetSubMenu(hContextPopupMenu, 0));
  389. MenuCommand = TrackPopupMenuEx(hContextPopupMenu, TPM_RETURNCMD |
  390. TPM_RIGHTBUTTON | TPM_LEFTALIGN | TPM_TOPALIGN, MessagePoint.x,
  391. MessagePoint.y, hWnd, NULL);
  392. DestroyMenu(hContextMenu);
  393. RegEdit_OnValueListCommand(hWnd, MenuCommand);
  394. }
  395. /*******************************************************************************
  396. *
  397. * RegEdit_SetValueListEditMenuItems
  398. *
  399. * DESCRIPTION:
  400. * Shared routine between the main menu and the context menu to setup the
  401. * edit menu items.
  402. *
  403. * PARAMETERS:
  404. * hPopupMenu, handle of popup menu to modify.
  405. *
  406. *******************************************************************************/
  407. VOID
  408. PASCAL
  409. RegEdit_SetValueListEditMenuItems(
  410. HMENU hPopupMenu,
  411. int SelectedListIndex
  412. )
  413. {
  414. UINT SelectedCount;
  415. UINT EnableFlags;
  416. SelectedCount = ListView_GetSelectedCount(g_RegEditData.hValueListWnd);
  417. //
  418. // The edit option is only enabled when a single item is selected. Note
  419. // that this item is not in the main menu, but this should work fine.
  420. //
  421. if (SelectedCount == 1)
  422. EnableFlags = MF_ENABLED | MF_BYCOMMAND;
  423. else
  424. EnableFlags = MF_GRAYED | MF_BYCOMMAND;
  425. EnableMenuItem(hPopupMenu, ID_MODIFY, EnableFlags);
  426. //
  427. // The rename option is also only enabled when a single item is selected
  428. // and that item cannot be the default item. EnableFlags is already
  429. // disabled if the SelectedCount is not one from above.
  430. //
  431. if (SelectedListIndex == 0)
  432. EnableFlags = MF_GRAYED | MF_BYCOMMAND;
  433. EnableMenuItem(hPopupMenu, ID_RENAME, EnableFlags);
  434. //
  435. // The delete option is only enabled when multiple items are selected.
  436. //
  437. if (SelectedCount > 0)
  438. EnableFlags = MF_ENABLED | MF_BYCOMMAND;
  439. else
  440. EnableFlags = MF_GRAYED | MF_BYCOMMAND;
  441. EnableMenuItem(hPopupMenu, ID_DELETE, EnableFlags);
  442. }
  443. /*******************************************************************************
  444. *
  445. * RegEdit_OnValueListModify
  446. *
  447. * DESCRIPTION:
  448. *
  449. * PARAMETERS:
  450. *
  451. *******************************************************************************/
  452. VOID
  453. PASCAL
  454. RegEdit_OnValueListModify(HWND hWnd, BOOL fEditBinary)
  455. {
  456. // Verify that we only have one item selected
  457. // Don't beep for a double-clicking on the background.
  458. UINT SelectedCount = ListView_GetSelectedCount(g_RegEditData.hValueListWnd);
  459. if (SelectedCount > 0)
  460. {
  461. if (SelectedCount != 1)
  462. {
  463. MessageBeep(0);
  464. }
  465. else
  466. {
  467. RegEdit_EditCurrentValueListItem(hWnd, fEditBinary);
  468. }
  469. }
  470. }
  471. VOID PASCAL RegEdit_EditCurrentValueListItem(HWND hWnd, BOOL fEditBinary)
  472. {
  473. DWORD Type;
  474. UINT ErrorStringID;
  475. BOOL fError = FALSE;
  476. EDITVALUEPARAM EditValueParam;
  477. TCHAR ValueName[MAXVALUENAME_LENGTH];
  478. int ListIndex = ListView_GetNextItem(g_RegEditData.hValueListWnd, -1, LVNI_SELECTED);
  479. LONG err;
  480. // VALUE NAME
  481. ListView_GetItemText(g_RegEditData.hValueListWnd, ListIndex, 0, ValueName, ARRAYSIZE(ValueName));
  482. // This is the "(Default)" value. It either does not exist in the registry because
  483. // it's value is not set, or it exists in the registry as '\0' when its value is set
  484. if (ListIndex == 0)
  485. {
  486. ValueName[0] = TEXT('\0');
  487. }
  488. EditValueParam.pValueName = ValueName;
  489. // VALUE DATA
  490. // Query for size and type
  491. // Note that for the DefaultValue, the value may not actually exist yet. In that case we
  492. // will get back ERROR_FILE_NOT_FOUND as the error code.
  493. err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, NULL, &Type, NULL, &EditValueParam.cbValueData);
  494. if (err == ERROR_SUCCESS || (err == ERROR_FILE_NOT_FOUND && ValueName[0] == TEXT('\0')))
  495. {
  496. // Allocate storage space
  497. EditValueParam.pValueData = LocalAlloc(LPTR, EditValueParam.cbValueData+ExtraAllocLen(Type));
  498. if (EditValueParam.pValueData)
  499. {
  500. UINT TemplateID = IDD_EDITBINARYVALUE;
  501. DLGPROC lpDlgProc = EditBinaryValueDlgProc;
  502. BOOL fResourceType = FALSE;
  503. // Initialize with registry value
  504. err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, NULL, &Type, EditValueParam.pValueData, &EditValueParam.cbValueData);
  505. // Allow the special behavior for a key's Default Value.
  506. if (err == ERROR_FILE_NOT_FOUND && ValueName[0] == TEXT('\0')) {
  507. Type = REG_SZ;
  508. *((TCHAR*)EditValueParam.pValueData) = TEXT('\0');
  509. err = ERROR_SUCCESS;
  510. }
  511. if (err == ERROR_SUCCESS)
  512. {
  513. if (!fEditBinary)
  514. {
  515. switch (Type)
  516. {
  517. case REG_SZ:
  518. case REG_EXPAND_SZ:
  519. TemplateID = IDD_EDITSTRINGVALUE;
  520. lpDlgProc = EditStringValueDlgProc;
  521. break;
  522. case REG_MULTI_SZ:
  523. if(ValueList_MultiStringToString(&EditValueParam))
  524. {
  525. TemplateID = IDD_EDITMULTISZVALUE;
  526. lpDlgProc = EditStringValueDlgProc;
  527. }
  528. break;
  529. case REG_RESOURCE_LIST:
  530. case REG_FULL_RESOURCE_DESCRIPTOR:
  531. case REG_RESOURCE_REQUIREMENTS_LIST:
  532. fResourceType = TRUE;
  533. break;
  534. case REG_DWORD_BIG_ENDIAN:
  535. if (EditValueParam.cbValueData == sizeof(DWORD))
  536. {
  537. *((DWORD*)EditValueParam.pValueData) = ValueList_SwitchEndian(*((DWORD*)EditValueParam.pValueData));
  538. TemplateID = IDD_EDITDWORDVALUE;
  539. lpDlgProc = EditDwordValueDlgProc;
  540. }
  541. break;
  542. case REG_DWORD:
  543. if (EditValueParam.cbValueData == sizeof(DWORD))
  544. {
  545. TemplateID = IDD_EDITDWORDVALUE;
  546. lpDlgProc = EditDwordValueDlgProc;
  547. }
  548. break;
  549. }
  550. }
  551. if (fResourceType)
  552. {
  553. // only display, no editing
  554. DisplayResourceData(hWnd, Type, &EditValueParam);
  555. }
  556. else if (DialogBoxParam(g_hInstance, MAKEINTRESOURCE(TemplateID),
  557. hWnd, lpDlgProc, (LPARAM) &EditValueParam) == IDOK)
  558. {
  559. if ((Type == REG_MULTI_SZ) && (!fEditBinary))
  560. {
  561. ValueList_StringToMultiString(&EditValueParam);
  562. ValueList_RemoveEmptyStrings(hWnd, &EditValueParam);
  563. }
  564. if ((Type == REG_DWORD_BIG_ENDIAN) && (!fEditBinary) && EditValueParam.cbValueData == sizeof(DWORD))
  565. {
  566. *((DWORD*)EditValueParam.pValueData) = ValueList_SwitchEndian(*((DWORD*)EditValueParam.pValueData));
  567. }
  568. // set the registry value
  569. if (RegSetValueEx(g_RegEditData.hCurrentSelectionKey, ValueName, 0,
  570. Type, EditValueParam.pValueData, EditValueParam.cbValueData) !=
  571. ERROR_SUCCESS)
  572. {
  573. ErrorStringID = IDS_EDITVALCANNOTWRITE;
  574. fError = TRUE;
  575. }
  576. // set the display value
  577. ValueList_SetItemDataText(g_RegEditData.hValueListWnd, ListIndex,
  578. EditValueParam.pValueData, EditValueParam.cbValueData, Type);
  579. }
  580. }
  581. else
  582. {
  583. ErrorStringID = IDS_EDITVALCANNOTREAD;
  584. fError = TRUE;
  585. }
  586. LocalFree(EditValueParam.pValueData);
  587. }
  588. else
  589. {
  590. ErrorStringID = IDS_EDITVALNOMEMORY;
  591. fError = TRUE;
  592. }
  593. }
  594. else
  595. {
  596. ErrorStringID = IDS_EDITVALCANNOTREAD;
  597. fError = TRUE;
  598. }
  599. if (fError)
  600. {
  601. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  602. MAKEINTRESOURCE(IDS_EDITVALERRORTITLE), MB_ICONERROR | MB_OK,
  603. (LPTSTR) ValueName);
  604. }
  605. }
  606. /*******************************************************************************
  607. *
  608. * RegEdit_OnValueListDelete
  609. *
  610. * DESCRIPTION:
  611. *
  612. * PARAMETERS:
  613. *
  614. *******************************************************************************/
  615. VOID
  616. PASCAL
  617. RegEdit_OnValueListDelete(
  618. HWND hWnd
  619. )
  620. {
  621. HWND hValueListWnd;
  622. UINT ConfirmTextStringID;
  623. BOOL fErrorDeleting;
  624. int ListStartIndex;
  625. int ListIndex;
  626. TCHAR ValueName[MAXVALUENAME_LENGTH];
  627. hValueListWnd = g_RegEditData.hValueListWnd;
  628. ConfirmTextStringID = (ListView_GetSelectedCount(hValueListWnd) == 1) ?
  629. IDS_CONFIRMDELVALTEXT : IDS_CONFIRMDELVALMULTITEXT;
  630. if (InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ConfirmTextStringID),
  631. MAKEINTRESOURCE(IDS_CONFIRMDELVALTITLE), MB_ICONWARNING | MB_YESNO) !=
  632. IDYES)
  633. return;
  634. SetWindowRedraw(hValueListWnd, FALSE);
  635. fErrorDeleting = FALSE;
  636. ListStartIndex = -1;
  637. while ((ListIndex = ListView_GetNextItem(hValueListWnd, ListStartIndex,
  638. LVNI_SELECTED)) != -1) {
  639. if (ListIndex != 0) {
  640. ListView_GetItemText(hValueListWnd, ListIndex, 0, ValueName,
  641. sizeof(ValueName)/sizeof(TCHAR));
  642. }
  643. else
  644. ValueName[0] = 0;
  645. if (RegDeleteValue(g_RegEditData.hCurrentSelectionKey, ValueName) ==
  646. ERROR_SUCCESS) {
  647. if (ListIndex != 0)
  648. ListView_DeleteItem(hValueListWnd, ListIndex);
  649. else {
  650. ValueList_SetItemDataText(hValueListWnd, 0, NULL, 0, REG_SZ);
  651. ListStartIndex = 0;
  652. }
  653. }
  654. else {
  655. fErrorDeleting = TRUE;
  656. ListStartIndex = ListIndex;
  657. }
  658. }
  659. SetWindowRedraw(hValueListWnd, TRUE);
  660. if (fErrorDeleting)
  661. InternalMessageBox(g_hInstance, hWnd,
  662. MAKEINTRESOURCE(IDS_DELETEVALDELETEFAILED),
  663. MAKEINTRESOURCE(IDS_DELETEVALERRORTITLE), MB_ICONERROR | MB_OK);
  664. }
  665. /*******************************************************************************
  666. *
  667. * RegEdit_OnValueListRename
  668. *
  669. * DESCRIPTION:
  670. *
  671. * PARAMETERS:
  672. *
  673. *******************************************************************************/
  674. VOID
  675. PASCAL
  676. RegEdit_OnValueListRename(
  677. HWND hWnd
  678. )
  679. {
  680. HWND hValueListWnd;
  681. int ListIndex;
  682. hValueListWnd = g_RegEditData.hValueListWnd;
  683. if (ListView_GetSelectedCount(hValueListWnd) == 1 && (ListIndex =
  684. ListView_GetNextItem(hValueListWnd, -1, LVNI_SELECTED)) != 0)
  685. ValueList_EditLabel(g_RegEditData.hValueListWnd, ListIndex);
  686. }
  687. /*******************************************************************************
  688. *
  689. * RegEdit_OnValueListRefresh
  690. *
  691. * DESCRIPTION:
  692. *
  693. * PARAMETERS:
  694. *
  695. *******************************************************************************/
  696. LONG
  697. PASCAL
  698. RegEdit_OnValueListRefresh(HWND hWnd)
  699. {
  700. UINT ErrorStringID;
  701. BOOL fError = FALSE;
  702. BOOL fInsertedDefaultValue;
  703. HWND hValueListWnd = g_RegEditData.hValueListWnd;
  704. LONG result = ERROR_SUCCESS;
  705. RegEdit_SetWaitCursor(TRUE);
  706. SetWindowRedraw(hValueListWnd, FALSE);
  707. ListView_DeleteAllItems(hValueListWnd);
  708. if (g_RegEditData.hCurrentSelectionKey != NULL)
  709. {
  710. LV_ITEM LVItem;
  711. LONG PrevStyle;
  712. DWORD EnumIndex;
  713. TCHAR achValueName[MAXVALUENAME_LENGTH];
  714. LVItem.mask = LVIF_TEXT | LVIF_IMAGE;
  715. LVItem.pszText = achValueName;
  716. LVItem.iSubItem = 0;
  717. PrevStyle = SetWindowLong(hValueListWnd, GWL_STYLE,
  718. GetWindowLong(hValueListWnd, GWL_STYLE) | LVS_SORTASCENDING);
  719. EnumIndex = 0;
  720. fInsertedDefaultValue = FALSE;
  721. while (TRUE)
  722. {
  723. DWORD Type;
  724. DWORD cbValueData = 0;
  725. int ListIndex;
  726. PBYTE pbValueData;
  727. DWORD cchValueName = ARRAYSIZE(achValueName);
  728. // VALUE DATA
  729. // Query for data size
  730. result = RegEnumValue(g_RegEditData.hCurrentSelectionKey, EnumIndex++,
  731. achValueName, &cchValueName, NULL, &Type, NULL,
  732. &cbValueData);
  733. if (result != ERROR_SUCCESS)
  734. {
  735. break;
  736. }
  737. // allocate memory for data
  738. pbValueData = LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type));
  739. if (pbValueData)
  740. {
  741. if (RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, achValueName,
  742. NULL, &Type, pbValueData, &cbValueData) != ERROR_SUCCESS)
  743. {
  744. ErrorStringID = IDS_REFRESHCANNOTREAD;
  745. fError = TRUE;
  746. }
  747. else
  748. {
  749. if (cchValueName == 0)
  750. {
  751. fInsertedDefaultValue = TRUE;
  752. }
  753. LVItem.iImage = IsRegStringType(Type) ? IMAGEINDEX(IDI_STRING) :
  754. IMAGEINDEX(IDI_BINARY);
  755. ListIndex = ListView_InsertItem(hValueListWnd, &LVItem);
  756. ValueList_SetItemDataText(hValueListWnd, ListIndex,
  757. pbValueData, cbValueData, Type);
  758. }
  759. LocalFree(pbValueData);
  760. }
  761. else
  762. {
  763. fError = TRUE;
  764. ErrorStringID = IDS_REFRESHNOMEMORY;
  765. }
  766. if (fError)
  767. {
  768. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  769. MAKEINTRESOURCE(IDS_REFRESHERRORTITLE), MB_ICONERROR | MB_OK,
  770. (LPTSTR) achValueName);
  771. fError = FALSE;
  772. }
  773. }
  774. SetWindowLong(hValueListWnd, GWL_STYLE, PrevStyle);
  775. LVItem.iItem = 0;
  776. LVItem.pszText = g_RegEditData.pDefaultValue;
  777. LVItem.iImage = IMAGEINDEX(IDI_STRING);
  778. if (fInsertedDefaultValue)
  779. {
  780. LVItem.mask = LVIF_TEXT;
  781. ListView_SetItem(hValueListWnd, &LVItem);
  782. }
  783. else
  784. {
  785. ListView_InsertItem(hValueListWnd, &LVItem);
  786. ValueList_SetItemDataText(hValueListWnd, 0, NULL, 0, REG_SZ);
  787. }
  788. ListView_SetItemState(hValueListWnd, 0, LVIS_FOCUSED, LVIS_FOCUSED);
  789. }
  790. SetWindowRedraw(hValueListWnd, TRUE);
  791. RegEdit_SetWaitCursor(FALSE);
  792. return result;
  793. }
  794. /*******************************************************************************
  795. *
  796. * ValueList_SetItemDataText
  797. *
  798. * DESCRIPTION:
  799. *
  800. * PARAMETERS:
  801. * hValueListWnd, handle of ValueList window.
  802. * ListIndex, index into ValueList window.
  803. * pValueData, pointer to buffer containing data.
  804. * cbValueData, size of the above buffer.
  805. * Type, type of data this buffer contains (REG_* definition).
  806. *
  807. *******************************************************************************/
  808. VOID
  809. PASCAL
  810. ValueList_SetItemDataText(
  811. HWND hValueListWnd,
  812. int ListIndex,
  813. PBYTE pValueData,
  814. DWORD cbValueData,
  815. DWORD Type
  816. )
  817. {
  818. BOOL fMustDeleteString;
  819. TCHAR DataText[SIZE_DATATEXT];
  820. int BytesToWrite;
  821. PTSTR pString;
  822. fMustDeleteString = FALSE;
  823. //
  824. // When pValueData is NULL, then that's a special indicator to us that this
  825. // is the default value and it's value is undefined.
  826. //
  827. if (pValueData == NULL)
  828. pString = g_RegEditData.pValueNotSet;
  829. else if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ)) {
  830. wsprintf(DataText, s_StringDataFormatSpec, (LPTSTR) pValueData);
  831. if ((cbValueData/sizeof(TCHAR)) > MAXIMUM_STRINGDATATEXT + 1) // for null
  832. lstrcat(DataText, s_Ellipsis);
  833. pString = DataText;
  834. }
  835. else if (Type == REG_DWORD || Type == REG_DWORD_BIG_ENDIAN) {
  836. // FEATURE: Check for invalid cbValueData!
  837. if (cbValueData == sizeof(DWORD))
  838. {
  839. DWORD dw = *((DWORD*)pValueData);
  840. if (Type == REG_DWORD_BIG_ENDIAN)
  841. {
  842. dw = ValueList_SwitchEndian(dw);
  843. }
  844. pString = LoadDynamicString(IDS_DWORDDATAFORMATSPEC, dw);
  845. }
  846. else
  847. {
  848. pString = LoadDynamicString(IDS_INVALIDDWORDDATA);
  849. }
  850. fMustDeleteString = TRUE;
  851. }
  852. else if (Type == REG_MULTI_SZ) {
  853. int CharsAvailableInBuffer;
  854. int ComponentLength;
  855. PTCHAR Start;
  856. ZeroMemory(DataText,sizeof(DataText));
  857. CharsAvailableInBuffer = MAXIMUM_STRINGDATATEXT+1;
  858. Start = DataText;
  859. for(pString=(PTSTR)pValueData; *pString; pString+=ComponentLength+1) {
  860. ComponentLength = lstrlen(pString);
  861. //
  862. // Quirky behavior of lstrcpyn is exactly what we need here.
  863. //
  864. if(CharsAvailableInBuffer > 0) {
  865. lstrcpyn(Start,pString,CharsAvailableInBuffer);
  866. Start += ComponentLength;
  867. }
  868. CharsAvailableInBuffer -= ComponentLength;
  869. if(CharsAvailableInBuffer > 0) {
  870. lstrcpyn(Start,TEXT(" "),CharsAvailableInBuffer);
  871. Start += 1;
  872. }
  873. CharsAvailableInBuffer -= 1;
  874. }
  875. if(CharsAvailableInBuffer < 0) {
  876. lstrcpy(DataText+MAXIMUM_STRINGDATATEXT,s_Ellipsis);
  877. }
  878. pString = DataText;
  879. }
  880. else {
  881. if (cbValueData == 0)
  882. pString = g_RegEditData.pEmptyBinary;
  883. else {
  884. BytesToWrite = min(cbValueData, MAXIMUM_BINARYDATABYTES);
  885. pString = DataText;
  886. while (BytesToWrite--)
  887. pString += wsprintf(pString, s_BinaryDataFormatSpec,
  888. (BYTE) *pValueData++);
  889. *(--pString) = 0;
  890. if (cbValueData > MAXIMUM_BINARYDATABYTES)
  891. lstrcpy(pString, s_Ellipsis);
  892. pString = DataText;
  893. }
  894. }
  895. if(Type <= MAX_KNOWN_TYPE) {
  896. ListView_SetItemText(hValueListWnd, ListIndex, 1, (LPTSTR)s_TypeNames[Type]);
  897. } else {
  898. TCHAR TypeString[24];
  899. wsprintf(TypeString,TEXT("0x%x"),Type);
  900. ListView_SetItemText(hValueListWnd, ListIndex, 1, TypeString);
  901. }
  902. ListView_SetItemText(hValueListWnd, ListIndex, 2, pString);
  903. if (fMustDeleteString)
  904. DeleteDynamicString(pString);
  905. }
  906. /*******************************************************************************
  907. *
  908. * ValueList_EditLabel
  909. *
  910. * DESCRIPTION:
  911. *
  912. * PARAMETERS:
  913. * hValueListWnd, handle of ValueList window.
  914. * ListIndex, index of item to edit.
  915. *
  916. *******************************************************************************/
  917. VOID
  918. PASCAL
  919. ValueList_EditLabel(
  920. HWND hValueListWnd,
  921. int ListIndex
  922. )
  923. {
  924. g_RegEditData.fAllowLabelEdits = TRUE;
  925. //
  926. // We have to set the focus to the ListView or else ListView_EditLabel will
  927. // return FALSE. While we're at it, clear the selected state of all the
  928. // items to eliminate some flicker when we move the focus back to this
  929. // pane.
  930. //
  931. if (hValueListWnd != g_RegEditData.hFocusWnd) {
  932. ListView_SetItemState(hValueListWnd, -1, 0, LVIS_SELECTED |
  933. LVIS_FOCUSED);
  934. SetFocus(hValueListWnd);
  935. }
  936. ListView_EditLabel(hValueListWnd, ListIndex);
  937. g_RegEditData.fAllowLabelEdits = FALSE;
  938. }
  939. //------------------------------------------------------------------------------
  940. // ValueList_MultiStringToString
  941. //
  942. // DESCRIPTION: Replaces NULL with '\r\n' to convert a Multi-String to a String
  943. //
  944. // PARAMETERS: EditValueParam - the edit value information
  945. //------------------------------------------------------------------------------
  946. BOOL PASCAL ValueList_MultiStringToString(LPEDITVALUEPARAM pEditValueParam)
  947. {
  948. BOOL fSuccess = TRUE;
  949. int iStrLen = pEditValueParam->cbValueData / sizeof(TCHAR);
  950. if (iStrLen > 1)
  951. {
  952. int i;
  953. int cNullsToReplace = 0;
  954. PTSTR pszTemp = NULL;
  955. PTSTR psz = (TCHAR*)pEditValueParam->pValueData;
  956. // Determine new size
  957. for (i = iStrLen - 2; i >=0; i--)
  958. {
  959. if (psz[i] == TEXT('\0'))
  960. {
  961. cNullsToReplace++;
  962. }
  963. }
  964. // the new string is always atleast as big as the old str, so we can convert back
  965. pszTemp = LocalAlloc(LPTR, pEditValueParam->cbValueData + cNullsToReplace * sizeof(TCHAR));
  966. if (pszTemp)
  967. {
  968. int iCurrentChar = 0;
  969. int iLastNull = iStrLen - 1;
  970. // change NULL to '\r\n'
  971. for(i = 0; i < iLastNull; i++)
  972. {
  973. if (psz[i] == TEXT('\0'))
  974. {
  975. pszTemp[iCurrentChar++] = TEXT('\r');
  976. pszTemp[iCurrentChar] = TEXT('\n');
  977. }
  978. else
  979. {
  980. pszTemp[iCurrentChar] = psz[i];
  981. }
  982. iCurrentChar++;
  983. }
  984. pszTemp[iCurrentChar++] = TEXT('\0');
  985. pEditValueParam->pValueData = (PBYTE)pszTemp;
  986. pEditValueParam->cbValueData = iCurrentChar * sizeof(psz[0]);
  987. LocalFree(psz);
  988. }
  989. else
  990. {
  991. fSuccess = FALSE;
  992. }
  993. }
  994. return fSuccess;
  995. }
  996. //------------------------------------------------------------------------------
  997. // ValueList_StringToMultiString
  998. //
  999. // DESCRIPTION: Replaces '\r\n' with NULL
  1000. //
  1001. // PARAMETERS: EditValueParam - the edit value information
  1002. //------------------------------------------------------------------------------
  1003. VOID PASCAL ValueList_StringToMultiString(LPEDITVALUEPARAM pEditValueParam)
  1004. {
  1005. PTSTR psz = (TCHAR*)pEditValueParam->pValueData;
  1006. int iStrLen = pEditValueParam->cbValueData / sizeof(TCHAR);
  1007. if (iStrLen > 1)
  1008. {
  1009. int i = 0;
  1010. int iCurrentChar = 0;
  1011. // remove a return at the end of the string
  1012. // because another string does not follow it.
  1013. if (iStrLen >= 3)
  1014. {
  1015. if (psz[iStrLen - 3] == TEXT('\r'))
  1016. {
  1017. psz[iStrLen - 3] = TEXT('\0');
  1018. iStrLen -= 2;
  1019. }
  1020. }
  1021. for (i = 0; i < iStrLen; i++)
  1022. {
  1023. if (psz[i] == '\r')
  1024. {
  1025. psz[iCurrentChar++] = TEXT('\0');
  1026. i++; // jump past the '\n'
  1027. }
  1028. else
  1029. {
  1030. psz[iCurrentChar++] = psz[i];
  1031. }
  1032. }
  1033. // Null terminate multi-string
  1034. psz[iCurrentChar++] = TEXT('\0');
  1035. pEditValueParam->cbValueData = iCurrentChar * sizeof(psz[0]);
  1036. }
  1037. }
  1038. //------------------------------------------------------------------------------
  1039. // ValueList_RemoveEmptyStrings
  1040. //
  1041. // DESCRIPTION: Removes empty strings from multi-strings
  1042. //
  1043. // PARAMETERS: EditValueParam - the edit value information
  1044. //------------------------------------------------------------------------------
  1045. VOID PASCAL ValueList_RemoveEmptyStrings(HWND hWnd, LPEDITVALUEPARAM pEditValueParam)
  1046. {
  1047. PTSTR psz = (TCHAR*)pEditValueParam->pValueData;
  1048. int iStrLen = pEditValueParam->cbValueData / sizeof(TCHAR);
  1049. if (iStrLen > 1)
  1050. {
  1051. int i = 0;
  1052. int cNullStrings = 0;
  1053. int iCurrentChar = 0;
  1054. int iLastChar = pEditValueParam->cbValueData / sizeof(psz[0]) - 1;
  1055. for (i = 0; i < iLastChar; i++)
  1056. {
  1057. if (((psz[i] != TEXT('\0')) || (psz[i+1] != TEXT('\0'))) &&
  1058. ((psz[i] != TEXT('\0')) || (i != 0)))
  1059. {
  1060. psz[iCurrentChar++] = psz[i];
  1061. }
  1062. }
  1063. psz[iCurrentChar++] = TEXT('\0');
  1064. if (iCurrentChar > 1)
  1065. {
  1066. cNullStrings = iLastChar - iCurrentChar;
  1067. // Null terminate multi-string
  1068. psz[iCurrentChar++] = TEXT('\0');
  1069. // warn user of empty strings
  1070. if (cNullStrings)
  1071. {
  1072. UINT ErrorStringID
  1073. = (cNullStrings == 1) ? IDS_EDITMULTSZEMPTYSTR : IDS_EDITMULTSZEMPTYSTRS;
  1074. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  1075. MAKEINTRESOURCE(IDS_EDITWARNINGTITLE), MB_ICONERROR | MB_OK, NULL);
  1076. }
  1077. }
  1078. pEditValueParam->cbValueData = (iCurrentChar * sizeof(psz[0]));
  1079. }
  1080. }
  1081. //------------------------------------------------------------------------------
  1082. // ValueList_SwitchEndian
  1083. //
  1084. // DESCRIPTION: Switched a DWORD between little and big endian.
  1085. //
  1086. // PARAMETERS: dwSrc - the source DWORD to switch around
  1087. //------------------------------------------------------------------------------
  1088. DWORD PASCAL ValueList_SwitchEndian(DWORD dwSrc)
  1089. {
  1090. DWORD dwDest = 0;
  1091. BYTE * pbSrc = (BYTE *)&dwSrc;
  1092. BYTE * pbDest = (BYTE *)&dwDest;
  1093. int i;
  1094. for(i = 0; i < 4; i++)
  1095. {
  1096. pbDest[i] = pbSrc[3-i];
  1097. }
  1098. return dwDest;
  1099. }
  1100. VOID RegEdit_DisplayBinaryData(HWND hWnd)
  1101. {
  1102. DWORD Type;
  1103. UINT ErrorStringID;
  1104. BOOL fError = FALSE;
  1105. EDITVALUEPARAM EditValueParam;
  1106. TCHAR achValueName[MAXVALUENAME_LENGTH];
  1107. int ListIndex = ListView_GetNextItem(g_RegEditData.hValueListWnd, -1, LVNI_SELECTED);
  1108. LONG err;
  1109. ListView_GetItemText(g_RegEditData.hValueListWnd, ListIndex, 0, achValueName, ARRAYSIZE(achValueName));
  1110. if (ListIndex == 0)
  1111. {
  1112. // This is the "(Default)" value. It either does not exist in the registry because
  1113. // it's value is not set, or it exists in the registry as '\0' when its value is set
  1114. achValueName[0] = TEXT('\0');
  1115. }
  1116. EditValueParam.pValueName = achValueName;
  1117. // get size and type
  1118. err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, achValueName, NULL, &Type, NULL, &EditValueParam.cbValueData);
  1119. if (err == ERROR_SUCCESS || (err == ERROR_FILE_NOT_FOUND && achValueName[0] == TEXT('\0'))) {
  1120. // Allocate storage space
  1121. EditValueParam.pValueData = LocalAlloc(LPTR, EditValueParam.cbValueData+ExtraAllocLen(Type));
  1122. if (EditValueParam.pValueData)
  1123. {
  1124. err = RegEdit_QueryValueEx(g_RegEditData.hCurrentSelectionKey, achValueName, NULL, &Type, EditValueParam.pValueData, &EditValueParam.cbValueData);
  1125. // Allow the special behavior for a key's Default Value.
  1126. if (err == ERROR_FILE_NOT_FOUND && achValueName[0] == TEXT('\0')) {
  1127. Type = REG_SZ;
  1128. *((TCHAR*)EditValueParam.pValueData) = TEXT('\0');
  1129. err = ERROR_SUCCESS;
  1130. }
  1131. if (err == ERROR_SUCCESS) {
  1132. DisplayBinaryData(hWnd, &EditValueParam, Type);
  1133. } else {
  1134. ErrorStringID = IDS_EDITVALCANNOTREAD;
  1135. fError = TRUE;
  1136. }
  1137. LocalFree(EditValueParam.pValueData);
  1138. }
  1139. else
  1140. {
  1141. ErrorStringID = IDS_EDITVALNOMEMORY;
  1142. fError = TRUE;
  1143. }
  1144. }
  1145. else
  1146. {
  1147. ErrorStringID = IDS_EDITVALCANNOTREAD;
  1148. fError = TRUE;
  1149. }
  1150. if (fError)
  1151. {
  1152. InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(ErrorStringID),
  1153. MAKEINTRESOURCE(IDS_EDITVALERRORTITLE), MB_ICONERROR | MB_OK,
  1154. (LPTSTR) achValueName);
  1155. }
  1156. }