Leaked source code of windows server 2003
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.

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