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