Sync with trunk r63383 .
[reactos.git] / base / applications / regedit / listview.c
1 /*
2 * Regedit listviews
3 *
4 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "regedit.h"
22
23 #define CX_ICON 16
24 #define CY_ICON 16
25 #define NUM_ICONS 2
26
27 int Image_String = 0;
28 int Image_Bin = 0;
29 INT iListViewSelect = -1;
30
31 typedef struct tagLINE_INFO
32 {
33 DWORD dwValType;
34 LPWSTR name;
35 void* val;
36 size_t val_len;
37 } LINE_INFO, *PLINE_INFO;
38
39 typedef struct tagSORT_INFO
40 {
41 INT iSortingColumn;
42 BOOL bSortAscending;
43 } SORT_INFO, *PSORT_INFO;
44
45 /*******************************************************************************
46 * Global and Local Variables:
47 */
48
49 static INT g_iSortedColumn = 0;
50
51 #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1)
52 static const int default_column_widths[MAX_LIST_COLUMNS] = { 200, 175, 400 };
53 static const int column_alignment[MAX_LIST_COLUMNS] = { LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_LEFT };
54
55 LPCWSTR GetValueName(HWND hwndLV, int iStartAt)
56 {
57 int item;
58 LVITEMW LVItem;
59 PLINE_INFO lineinfo;
60
61 /*
62 if a new item is inserted, then no allocation,
63 otherwise the heap block will be lost!
64 */
65 item = ListView_GetNextItem(hwndLV, iStartAt, LVNI_SELECTED);
66 if (item == -1) return NULL;
67
68 /*
69 Should be always TRUE anyways
70 */
71 LVItem.iItem = item;
72 LVItem.iSubItem = 0;
73 LVItem.mask = LVIF_PARAM;
74 if (ListView_GetItem(hwndLV, &LVItem) == FALSE)
75 return NULL;
76
77 lineinfo = (PLINE_INFO)LVItem.lParam;
78 if (lineinfo == NULL)
79 return NULL;
80
81 return lineinfo->name;
82 }
83
84 VOID SetValueName(HWND hwndLV, LPCWSTR pszValueName)
85 {
86 INT i, c;
87 LVFINDINFOW fi;
88
89 c = ListView_GetItemCount(hwndLV);
90 for(i = 0; i < c; i++)
91 {
92 ListView_SetItemState(hwndLV, i, 0, LVIS_FOCUSED | LVIS_SELECTED);
93 }
94 if (pszValueName == NULL)
95 i = 0;
96 else
97 {
98 fi.flags = LVFI_STRING;
99 fi.psz = pszValueName;
100 i = ListView_FindItem(hwndLV, -1, &fi);
101 }
102 ListView_SetItemState(hwndLV, i, LVIS_FOCUSED | LVIS_SELECTED,
103 LVIS_FOCUSED | LVIS_SELECTED);
104 iListViewSelect = i;
105 }
106
107 BOOL IsDefaultValue(HWND hwndLV, int i)
108 {
109 PLINE_INFO lineinfo;
110 LVITEMW Item;
111
112 Item.mask = LVIF_PARAM;
113 Item.iItem = i;
114 if(ListView_GetItem(hwndLV, &Item))
115 {
116 lineinfo = (PLINE_INFO)Item.lParam;
117 return lineinfo && (!lineinfo->name || !wcscmp(lineinfo->name, L""));
118 }
119 return FALSE;
120 }
121
122 /*******************************************************************************
123 * Local module support methods
124 */
125 static void AddEntryToList(HWND hwndLV, LPWSTR Name, DWORD dwValType, void* ValBuf, DWORD dwCount, int Position, BOOL ValExists)
126 {
127 PLINE_INFO linfo;
128 LVITEMW item;
129 int index;
130
131 linfo = (PLINE_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINE_INFO) + dwCount);
132 linfo->dwValType = dwValType;
133 linfo->val_len = dwCount;
134 if (dwCount > 0)
135 {
136 memcpy(&linfo[1], ValBuf, dwCount);
137 linfo->val = &linfo[1];
138 }
139 linfo->name = _wcsdup(Name);
140
141 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
142 item.iItem = (Position == -1 ? 0: Position);
143 item.iSubItem = 0;
144 item.state = 0;
145 item.stateMask = 0;
146 item.pszText = Name;
147 item.cchTextMax = (int)wcslen(item.pszText);
148 if (item.cchTextMax == 0)
149 item.pszText = LPSTR_TEXTCALLBACK;
150 item.iImage = 0;
151 item.lParam = (LPARAM)linfo;
152 switch(dwValType)
153 {
154 case REG_SZ:
155 case REG_EXPAND_SZ:
156 case REG_MULTI_SZ:
157 item.iImage = Image_String;
158 break;
159 default:
160 item.iImage = Image_Bin;
161 break;
162 }
163
164 /* item.lParam = (LPARAM)ValBuf; */
165 #if (_WIN32_IE >= 0x0300)
166 item.iIndent = 0;
167 #endif
168
169 index = ListView_InsertItem(hwndLV, &item);
170 if (index != -1)
171 {
172 switch (dwValType)
173 {
174 case REG_SZ:
175 case REG_EXPAND_SZ:
176 if(dwCount > 0)
177 {
178 ListView_SetItemText(hwndLV, index, 2, ValBuf);
179 }
180 else if(!ValExists)
181 {
182 WCHAR buffer[255];
183 /* load (value not set) string */
184 LoadStringW(hInst, IDS_VALUE_NOT_SET, buffer, COUNT_OF(buffer));
185 ListView_SetItemText(hwndLV, index, 2, buffer);
186 }
187 break;
188 case REG_MULTI_SZ:
189 {
190 LPWSTR src, str;
191 if(dwCount >= 2)
192 {
193 src = (LPWSTR)ValBuf;
194 str = HeapAlloc(GetProcessHeap(), 0, dwCount + sizeof(WCHAR));
195 if(str != NULL)
196 {
197 *str = L'\0';
198 /* concatenate all srings */
199 while(*src != L'\0')
200 {
201 wcscat(str, src);
202 wcscat(str, L" ");
203 src += wcslen(src) + 1;
204 }
205 ListView_SetItemText(hwndLV, index, 2, str);
206 HeapFree(GetProcessHeap(), 0, str);
207 }
208 else
209 ListView_SetItemText(hwndLV, index, 2, L"");
210 }
211 else
212 ListView_SetItemText(hwndLV, index, 2, L"");
213 }
214 break;
215 case REG_DWORD:
216 {
217 WCHAR buf[200];
218 if(dwCount == sizeof(DWORD))
219 {
220 wsprintf(buf, L"0x%08x (%u)", *(DWORD*)ValBuf, *(DWORD*)ValBuf);
221 }
222 else
223 {
224 LoadStringW(hInst, IDS_INVALID_DWORD, buf, COUNT_OF(buf));
225 }
226 ListView_SetItemText(hwndLV, index, 2, buf);
227 }
228 /* lpsRes = convertHexToDWORDStr(lpbData, dwLen); */
229 break;
230 default:
231 {
232 unsigned int i;
233 LPBYTE pData = (LPBYTE)ValBuf;
234 LPWSTR strBinary;
235 if(dwCount > 0)
236 {
237 strBinary = HeapAlloc(GetProcessHeap(), 0, (dwCount * sizeof(WCHAR) * 3) + sizeof(WCHAR));
238 for (i = 0; i < dwCount; i++)
239 {
240 wsprintf( strBinary + i*3, L"%02X ", pData[i] );
241 }
242 strBinary[dwCount * 3] = 0;
243 ListView_SetItemText(hwndLV, index, 2, strBinary);
244 HeapFree(GetProcessHeap(), 0, strBinary);
245 }
246 else
247 {
248 WCHAR szText[128];
249 LoadStringW(hInst, IDS_BINARY_EMPTY, szText, COUNT_OF(szText));
250 ListView_SetItemText(hwndLV, index, 2, szText);
251 }
252 }
253 break;
254 }
255 }
256 }
257
258 static BOOL CreateListColumns(HWND hWndListView)
259 {
260 WCHAR szText[50];
261 int index;
262 LVCOLUMN lvC;
263
264 /* Create columns. */
265 lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
266 lvC.pszText = szText;
267
268 /* Load the column labels from the resource file. */
269 for (index = 0; index < MAX_LIST_COLUMNS; index++)
270 {
271 lvC.iSubItem = index;
272 lvC.cx = default_column_widths[index];
273 lvC.fmt = column_alignment[index];
274 LoadStringW(hInst, IDS_LIST_COLUMN_FIRST + index, szText, COUNT_OF(szText));
275 if (ListView_InsertColumn(hWndListView, index, &lvC) == -1) return FALSE;
276 }
277 return TRUE;
278 }
279
280 static BOOL InitListViewImageLists(HWND hwndLV)
281 {
282 HIMAGELIST himl; /* handle to image list */
283 HICON hico; /* handle to icon */
284
285 /* Create the image list. */
286 if ((himl = ImageList_Create(CX_ICON, CY_ICON,
287 ILC_MASK, 0, NUM_ICONS)) == NULL)
288 {
289 return FALSE;
290 }
291
292 hico = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_BIN));
293 Image_Bin = ImageList_AddIcon(himl, hico);
294
295 hico = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_STRING));
296 Image_String = ImageList_AddIcon(himl, hico);
297
298 /* Fail if not all of the images were added. */
299 if (ImageList_GetImageCount(himl) < NUM_ICONS)
300 {
301 return FALSE;
302 }
303
304 /* Associate the image list with the tree view control. */
305 (void)ListView_SetImageList(hwndLV, himl, LVSIL_SMALL);
306
307 return TRUE;
308 }
309
310 /* OnGetDispInfo - processes the LVN_GETDISPINFO notification message. */
311
312 static void OnGetDispInfo(NMLVDISPINFO* plvdi)
313 {
314 static WCHAR buffer[200];
315
316 plvdi->item.pszText = NULL;
317 plvdi->item.cchTextMax = 0;
318
319 switch (plvdi->item.iSubItem)
320 {
321 case 0:
322 LoadStringW(hInst, IDS_DEFAULT_VALUE_NAME, buffer, COUNT_OF(buffer));
323 plvdi->item.pszText = buffer;
324 break;
325 case 1:
326 switch (((LINE_INFO*)plvdi->item.lParam)->dwValType)
327 {
328 case REG_NONE:
329 plvdi->item.pszText = L"REG_NONE";
330 break;
331 case REG_SZ:
332 plvdi->item.pszText = L"REG_SZ";
333 break;
334 case REG_EXPAND_SZ:
335 plvdi->item.pszText = L"REG_EXPAND_SZ";
336 break;
337 case REG_BINARY:
338 plvdi->item.pszText = L"REG_BINARY";
339 break;
340 case REG_DWORD: /* REG_DWORD_LITTLE_ENDIAN */
341 plvdi->item.pszText = L"REG_DWORD";
342 break;
343 case REG_DWORD_BIG_ENDIAN:
344 plvdi->item.pszText = L"REG_DWORD_BIG_ENDIAN";
345 break;
346 case REG_LINK:
347 plvdi->item.pszText = L"REG_LINK";
348 break;
349 case REG_MULTI_SZ:
350 plvdi->item.pszText = L"REG_MULTI_SZ";
351 break;
352 case REG_RESOURCE_LIST:
353 plvdi->item.pszText = L"REG_RESOURCE_LIST";
354 break;
355 case REG_FULL_RESOURCE_DESCRIPTOR:
356 plvdi->item.pszText = L"REG_FULL_RESOURCE_DESCRIPTOR";
357 break;
358 case REG_RESOURCE_REQUIREMENTS_LIST:
359 plvdi->item.pszText = L"REG_RESOURCE_REQUIREMENTS_LIST";
360 break;
361 case REG_QWORD: /* REG_QWORD_LITTLE_ENDIAN */
362 plvdi->item.pszText = L"REG_QWORD";
363 break;
364 default:
365 {
366 WCHAR buf2[200];
367 LoadStringW(hInst, IDS_UNKNOWN_TYPE, buf2, COUNT_OF(buf2));
368 wsprintf(buffer, buf2, ((LINE_INFO*)plvdi->item.lParam)->dwValType);
369 plvdi->item.pszText = buffer;
370 break;
371 }
372 }
373 break;
374 case 3:
375 plvdi->item.pszText = L"";
376 break;
377 }
378 }
379
380 static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
381 {
382 PSORT_INFO pSortInfo = (PSORT_INFO)lParamSort;
383 LINE_INFO *l, *r;
384 DWORD dw1, dw2;
385 DWORDLONG qw1, qw2;
386
387 l = (LINE_INFO*)lParam1;
388 r = (LINE_INFO*)lParam2;
389
390 if (pSortInfo->iSortingColumn == 1 && l->dwValType != r->dwValType)
391 {
392 /* Sort by type */
393 if (pSortInfo->bSortAscending)
394 return ((int)l->dwValType - (int)r->dwValType);
395 else
396 return ((int)r->dwValType - (int)l->dwValType);
397 }
398 if (pSortInfo->iSortingColumn == 2)
399 {
400 /* Sort by value */
401 if (l->dwValType != r->dwValType)
402 {
403 if (pSortInfo->bSortAscending)
404 return ((int)l->dwValType - (int)r->dwValType);
405 else
406 return ((int)r->dwValType - (int)l->dwValType);
407 }
408
409 if (l->val == NULL && r->val == NULL)
410 return 0;
411
412 if (pSortInfo->bSortAscending)
413 {
414 if (l->val == NULL)
415 return -1;
416 if (r->val == NULL)
417 return 1;
418 }
419 else
420 {
421 if (l->val == NULL)
422 return 1;
423 if (r->val == NULL)
424 return -1;
425 }
426
427 switch(l->dwValType)
428 {
429 case REG_DWORD:
430 {
431 dw1 = *(DWORD*)l->val;
432 dw2 = *(DWORD*)r->val;
433 if (pSortInfo->bSortAscending)
434 // return (dw1 > dw2 ? 1 : -1);
435 return ((int)dw1 - (int)dw2);
436 else
437 // return (dw1 > dw2 ? -1 : 1);
438 return ((int)dw2 - (int)dw1);
439 }
440
441 case REG_QWORD: /* REG_QWORD_LITTLE_ENDIAN */
442 {
443 qw1 = *(DWORDLONG*)l->val;
444 qw2 = *(DWORDLONG*)r->val;
445 if (pSortInfo->bSortAscending)
446 // return (qw1 > qw2 ? 1 : -1);
447 return ((int)qw1 - (int)qw2);
448 else
449 // return (qw1 > qw2 ? -1 : 1);
450 return ((int)qw2 - (int)qw1);
451 }
452
453 default:
454 {
455 INT nCompare = 0;
456
457 if (pSortInfo->bSortAscending)
458 {
459 nCompare = memcmp(l->val, r->val, min(l->val_len, r->val_len));
460 if (nCompare == 0)
461 nCompare = l->val_len - r->val_len;
462 }
463 else
464 {
465 nCompare = memcmp(r->val, l->val, min(r->val_len, l->val_len));
466 if (nCompare == 0)
467 nCompare = r->val_len - l->val_len;
468 }
469
470 return nCompare;
471 }
472 }
473 }
474
475 /* Sort by name */
476 return (pSortInfo->bSortAscending ? StrCmpLogicalW(l->name, r->name) : StrCmpLogicalW(r->name, l->name));
477 }
478
479 static BOOL ListView_Sort(HWND hListView, int iSortingColumn, int iSortedColumn)
480 {
481 if ( (GetWindowLongPtr(hListView, GWL_STYLE) & ~LVS_NOSORTHEADER) &&
482 (iSortingColumn >= 0) )
483 {
484 BOOL bSortAscending;
485 SORT_INFO SortInfo;
486
487 HWND hHeader = ListView_GetHeader(hListView);
488 HDITEM hColumn = {0};
489
490 /* If we are sorting according to another column, uninitialize the old one */
491 if ( (iSortedColumn >= 0) && (iSortingColumn != iSortedColumn) )
492 {
493 hColumn.mask = HDI_FORMAT;
494 Header_GetItem(hHeader, iSortedColumn, &hColumn);
495 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
496 Header_SetItem(hHeader, iSortedColumn, &hColumn);
497 }
498
499 /* Get the sorting state of the new column */
500 hColumn.mask = HDI_FORMAT;
501 Header_GetItem(hHeader, iSortingColumn, &hColumn);
502
503 /*
504 * Check whether we are sorting the list because the user clicked
505 * on a column, or because we are refreshing the list:
506 *
507 * iSortedColumn >= 0 - User clicked on a column; holds the
508 * old sorting column index.
509 * iSortedColumn < 0 - List being refreshed.
510 */
511 if (iSortedColumn >= 0)
512 {
513 /* Invert the sorting direction */
514 bSortAscending = ((hColumn.fmt & HDF_SORTUP) == 0);
515 }
516 else
517 {
518 /*
519 * If the sorting state of the column is uninitialized,
520 * initialize it by default to ascending sorting.
521 */
522 if ((hColumn.fmt & (HDF_SORTUP | HDF_SORTDOWN)) == 0)
523 hColumn.fmt |= HDF_SORTUP;
524
525 /* Keep the same sorting direction */
526 bSortAscending = ((hColumn.fmt & HDF_SORTUP) != 0);
527 }
528
529 /* Set the new column sorting state */
530 hColumn.fmt &= ~(bSortAscending ? HDF_SORTDOWN : HDF_SORTUP );
531 hColumn.fmt |= (bSortAscending ? HDF_SORTUP : HDF_SORTDOWN);
532 Header_SetItem(hHeader, iSortingColumn, &hColumn);
533
534 /* Sort the list */
535 SortInfo.iSortingColumn = iSortingColumn;
536 SortInfo.bSortAscending = bSortAscending;
537 return ListView_SortItems(hListView, CompareFunc, (LPARAM)&SortInfo);
538 }
539 else
540 return TRUE;
541 }
542
543 BOOL ListWndNotifyProc(HWND hWnd, WPARAM wParam, LPARAM lParam, BOOL *Result)
544 {
545 NMLVDISPINFO* Info;
546 int iSortingColumn;
547 UNREFERENCED_PARAMETER(wParam);
548 *Result = TRUE;
549 switch (((LPNMHDR)lParam)->code)
550 {
551 case LVN_GETDISPINFO:
552 OnGetDispInfo((NMLVDISPINFO*)lParam);
553 return TRUE;
554 case LVN_COLUMNCLICK:
555 iSortingColumn = ((LPNMLISTVIEW)lParam)->iSubItem;
556 (void)ListView_Sort(hWnd, iSortingColumn, g_iSortedColumn);
557 g_iSortedColumn = iSortingColumn;
558 return TRUE;
559 case NM_DBLCLK:
560 case NM_RETURN:
561 {
562 SendMessageW(hFrameWnd, WM_COMMAND, MAKEWPARAM(ID_EDIT_MODIFY, 0), 0);
563 }
564 return TRUE;
565 case NM_SETFOCUS:
566 g_pChildWnd->nFocusPanel = 0;
567 break;
568 case LVN_BEGINLABELEDIT:
569 Info = (NMLVDISPINFO*)lParam;
570 if(Info)
571 {
572 PLINE_INFO lineinfo = (PLINE_INFO)Info->item.lParam;
573 if(!lineinfo->name || !wcscmp(lineinfo->name, L""))
574 {
575 *Result = TRUE;
576 }
577 else
578 {
579 *Result = FALSE;
580 }
581 }
582 else
583 *Result = TRUE;
584 return TRUE;
585 case LVN_ENDLABELEDIT:
586 Info = (NMLVDISPINFO*)lParam;
587 if(Info && Info->item.pszText)
588 {
589 PLINE_INFO lineinfo = (PLINE_INFO)Info->item.lParam;
590 if(!lineinfo->name || !wcscmp(lineinfo->name, L""))
591 {
592 *Result = FALSE;
593 }
594 else
595 {
596 if(wcslen(Info->item.pszText) == 0)
597 {
598 WCHAR msg[128], caption[128];
599
600 LoadStringW(hInst, IDS_ERR_RENVAL_TOEMPTY, msg, COUNT_OF(msg));
601 LoadStringW(hInst, IDS_ERR_RENVAL_CAPTION, caption, COUNT_OF(caption));
602 MessageBoxW(0, msg, caption, 0);
603 *Result = TRUE;
604 }
605 else
606 {
607 HKEY hKeyRoot;
608 LPCWSTR keyPath;
609 LONG lResult;
610
611 keyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot);
612 lResult = RenameValue(hKeyRoot, keyPath, Info->item.pszText, lineinfo->name);
613 lineinfo->name = realloc(lineinfo->name, (wcslen(Info->item.pszText)+1)*sizeof(WCHAR));
614 if (lineinfo->name != NULL)
615 wcscpy(lineinfo->name, Info->item.pszText);
616
617 *Result = TRUE;
618 return (lResult == ERROR_SUCCESS);
619 }
620 }
621 }
622 else
623 *Result = TRUE;
624
625 return TRUE;
626 }
627 return FALSE;
628 }
629
630 HWND CreateListView(HWND hwndParent, HMENU id)
631 {
632 RECT rcClient;
633 HWND hwndLV;
634
635 /* Get the dimensions of the parent window's client area, and create the list view control. */
636 GetClientRect(hwndParent, &rcClient);
637 hwndLV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"List View",
638 WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS | LVS_SHOWSELALWAYS,
639 0, 0, rcClient.right, rcClient.bottom,
640 hwndParent, id, hInst, NULL);
641 if (!hwndLV) return NULL;
642
643 /* Initialize the image list, and add items to the control. */
644 if (!CreateListColumns(hwndLV)) goto fail;
645 if (!InitListViewImageLists(hwndLV)) goto fail;
646
647 return hwndLV;
648 fail:
649 DestroyWindow(hwndLV);
650 return NULL;
651 }
652
653 void DestroyListView(HWND hwndLV)
654 {
655 INT count, i;
656 LVITEMW item;
657
658 count = ListView_GetItemCount(hwndLV);
659 for (i = 0; i < count; i++)
660 {
661 item.mask = LVIF_PARAM;
662 item.iItem = i;
663 (void)ListView_GetItem(hwndLV, &item);
664 free(((LINE_INFO*)item.lParam)->name);
665 HeapFree(GetProcessHeap(), 0, (void*)item.lParam);
666 }
667
668 }
669
670 BOOL RefreshListView(HWND hwndLV, HKEY hKey, LPCWSTR keyPath)
671 {
672 DWORD max_sub_key_len;
673 DWORD max_val_name_len;
674 DWORD max_val_size;
675 DWORD val_count;
676 HKEY hNewKey;
677 LONG errCode;
678 INT i, c;
679 BOOL AddedDefault = FALSE;
680
681 if (!hwndLV) return FALSE;
682
683 (void)ListView_EditLabel(hwndLV, -1);
684
685 SendMessageW(hwndLV, WM_SETREDRAW, FALSE, 0);
686 DestroyListView(hwndLV);
687
688 (void)ListView_DeleteAllItems(hwndLV);
689
690 if(!hKey) return FALSE;
691
692 errCode = RegOpenKeyExW(hKey, keyPath, 0, KEY_READ, &hNewKey);
693 if (errCode != ERROR_SUCCESS) return FALSE;
694
695 /* get size information and resize the buffers if necessary */
696 errCode = RegQueryInfoKeyW(hNewKey, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL,
697 &val_count, &max_val_name_len, &max_val_size, NULL, NULL);
698
699 if (errCode == ERROR_SUCCESS)
700 {
701 WCHAR* ValName = HeapAlloc(GetProcessHeap(), 0, ++max_val_name_len * sizeof(WCHAR));
702 DWORD dwValNameLen = max_val_name_len;
703 BYTE* ValBuf = HeapAlloc(GetProcessHeap(), 0, max_val_size + sizeof(WCHAR));
704 DWORD dwValSize = max_val_size;
705 DWORD dwIndex = 0L;
706 DWORD dwValType;
707 /* if (RegQueryValueExW(hNewKey, NULL, NULL, &dwValType, ValBuf, &dwValSize) == ERROR_SUCCESS) { */
708 /* AddEntryToList(hwndLV, L"(Default)", dwValType, ValBuf, dwValSize); */
709 /* } */
710 /* dwValSize = max_val_size; */
711 while (RegEnumValueW(hNewKey, dwIndex, ValName, &dwValNameLen, NULL, &dwValType, ValBuf, &dwValSize) == ERROR_SUCCESS)
712 {
713 /* Add a terminating 0 character. Usually this is only necessary for strings. */
714 ValBuf[dwValSize] = ValBuf[dwValSize + 1] = 0;
715
716 AddEntryToList(hwndLV, ValName, dwValType, ValBuf, dwValSize, -1, TRUE);
717 dwValNameLen = max_val_name_len;
718 dwValSize = max_val_size;
719 dwValType = 0L;
720 ++dwIndex;
721 if(!wcscmp(ValName, L""))
722 {
723 AddedDefault = TRUE;
724 }
725 }
726 HeapFree(GetProcessHeap(), 0, ValBuf);
727 HeapFree(GetProcessHeap(), 0, ValName);
728 }
729 RegCloseKey(hNewKey);
730
731 if(!AddedDefault)
732 {
733 AddEntryToList(hwndLV, L"", REG_SZ, NULL, 0, 0, FALSE);
734 }
735 c = ListView_GetItemCount(hwndLV);
736 for(i = 0; i < c; i++)
737 {
738 ListView_SetItemState(hwndLV, i, 0, LVIS_FOCUSED | LVIS_SELECTED);
739 }
740 ListView_SetItemState(hwndLV, iListViewSelect,
741 LVIS_FOCUSED | LVIS_SELECTED,
742 LVIS_FOCUSED | LVIS_SELECTED);
743 (void)ListView_Sort(hwndLV, g_iSortedColumn, -1);
744 SendMessageW(hwndLV, WM_SETREDRAW, TRUE, 0);
745
746 return TRUE;
747 }