|  | /* | 
|  | * Regedit listviews | 
|  | * | 
|  | * Copyright (C) 2002 Robert Dickenson <robd@reactos.org> | 
|  | * Copyright (C) 2008 Alexander N. Sørnes <alex@thehandofagony.com> | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include <windows.h> | 
|  | #include <commctrl.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "main.h" | 
|  |  | 
|  | #include "wine/unicode.h" | 
|  | static INT Image_String; | 
|  | static INT Image_Binary; | 
|  |  | 
|  | typedef struct tagLINE_INFO | 
|  | { | 
|  | DWORD dwValType; | 
|  | LPWSTR name; | 
|  | void* val; | 
|  | size_t val_len; | 
|  | } LINE_INFO; | 
|  |  | 
|  | /******************************************************************************* | 
|  | * Global and Local Variables: | 
|  | */ | 
|  |  | 
|  | static WNDPROC g_orgListWndProc; | 
|  | static DWORD g_columnToSort = ~0U; | 
|  | static BOOL  g_invertSort = FALSE; | 
|  | static LPWSTR g_valueName; | 
|  | static LPWSTR g_currentPath; | 
|  | static HKEY g_currentRootKey; | 
|  | static WCHAR g_szValueNotSet[64]; | 
|  |  | 
|  | #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1) | 
|  | static int default_column_widths[MAX_LIST_COLUMNS] = { 200, 175, 400 }; | 
|  | static int column_alignment[MAX_LIST_COLUMNS] = { LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_LEFT }; | 
|  |  | 
|  | LPWSTR GetItemText(HWND hwndLV, UINT item) | 
|  | { | 
|  | LPWSTR newStr, curStr; | 
|  | unsigned int maxLen = 128; | 
|  |  | 
|  | curStr = HeapAlloc(GetProcessHeap(), 0, maxLen * sizeof(WCHAR)); | 
|  | if (!curStr) return NULL; | 
|  | if (item == 0) { /* first item is ALWAYS a default */ | 
|  | HeapFree(GetProcessHeap(), 0, curStr); | 
|  | return NULL; | 
|  | } | 
|  | do { | 
|  | ListView_GetItemTextW(hwndLV, item, 0, curStr, maxLen * sizeof(WCHAR)); | 
|  | if (lstrlenW(curStr) < maxLen - 1) return curStr; | 
|  | newStr = HeapReAlloc(GetProcessHeap(), 0, curStr, maxLen * 2 * sizeof(WCHAR)); | 
|  | if (!newStr) break; | 
|  | curStr = newStr; | 
|  | maxLen *= 2; | 
|  | } while (TRUE); | 
|  | HeapFree(GetProcessHeap(), 0, curStr); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | LPCWSTR GetValueName(HWND hwndLV) | 
|  | { | 
|  | INT item; | 
|  |  | 
|  | if (g_valueName != LPSTR_TEXTCALLBACKW) | 
|  | HeapFree(GetProcessHeap(), 0,  g_valueName); | 
|  | g_valueName = NULL; | 
|  |  | 
|  | item = ListView_GetNextItem(hwndLV, -1, LVNI_FOCUSED); | 
|  | if (item == -1) return NULL; | 
|  |  | 
|  | g_valueName = GetItemText(hwndLV, item); | 
|  |  | 
|  | return g_valueName; | 
|  | } | 
|  |  | 
|  | /* convert '\0' separated string list into ',' separated string list */ | 
|  | static void MakeMULTISZDisplayable(LPWSTR multi) | 
|  | { | 
|  | do | 
|  | { | 
|  | for (; *multi; multi++) | 
|  | ; | 
|  | if (*(multi+1)) | 
|  | { | 
|  | *multi = ','; | 
|  | multi++; | 
|  | } | 
|  | } while (*multi); | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | * Local module support methods | 
|  | */ | 
|  | static void AddEntryToList(HWND hwndLV, LPWSTR Name, DWORD dwValType, | 
|  | void* ValBuf, DWORD dwCount, BOOL bHighlight) | 
|  | { | 
|  | LINE_INFO* linfo; | 
|  | LVITEMW item; | 
|  | int index; | 
|  |  | 
|  | linfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LINE_INFO) + dwCount); | 
|  | linfo->dwValType = dwValType; | 
|  | linfo->val_len = dwCount; | 
|  | CopyMemory(&linfo[1], ValBuf, dwCount); | 
|  |  | 
|  | if (Name) | 
|  | { | 
|  | linfo->name = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(Name) + 1) * sizeof(WCHAR)); | 
|  | lstrcpyW(linfo->name, Name); | 
|  | } else | 
|  | { | 
|  | linfo->name = NULL; | 
|  | } | 
|  |  | 
|  | item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE; | 
|  | item.iItem = ListView_GetItemCount(hwndLV);/*idx;  */ | 
|  | item.iSubItem = 0; | 
|  | item.state = 0; | 
|  | item.stateMask = LVIS_FOCUSED | LVIS_SELECTED; | 
|  | item.pszText = Name ? Name : LPSTR_TEXTCALLBACKW; | 
|  | item.cchTextMax = Name ? lstrlenW(item.pszText) : 0; | 
|  | if (bHighlight) { | 
|  | item.stateMask = item.state = LVIS_FOCUSED | LVIS_SELECTED; | 
|  | } | 
|  | switch (dwValType) | 
|  | { | 
|  | case REG_SZ: | 
|  | case REG_EXPAND_SZ: | 
|  | case REG_MULTI_SZ: | 
|  | item.iImage = Image_String; | 
|  | break; | 
|  | default: | 
|  | item.iImage = Image_Binary; | 
|  | break; | 
|  | } | 
|  | item.lParam = (LPARAM)linfo; | 
|  |  | 
|  | #if (_WIN32_IE >= 0x0300) | 
|  | item.iIndent = 0; | 
|  | #endif | 
|  |  | 
|  | index = ListView_InsertItemW(hwndLV, &item); | 
|  | if (index != -1) { | 
|  | switch (dwValType) { | 
|  | case REG_SZ: | 
|  | case REG_EXPAND_SZ: | 
|  | if (ValBuf) { | 
|  | ListView_SetItemTextW(hwndLV, index, 2, ValBuf); | 
|  | } else { | 
|  | ListView_SetItemTextW(hwndLV, index, 2, g_szValueNotSet); | 
|  | } | 
|  | break; | 
|  | case REG_DWORD: { | 
|  | WCHAR buf[64]; | 
|  | WCHAR format[] = {'0','x','%','0','8','x',' ','(','%','u',')',0}; | 
|  | wsprintfW(buf, format, *(DWORD*)ValBuf, *(DWORD*)ValBuf); | 
|  | ListView_SetItemTextW(hwndLV, index, 2, buf); | 
|  | } | 
|  | break; | 
|  | case REG_BINARY: { | 
|  | unsigned int i; | 
|  | LPBYTE pData = ValBuf; | 
|  | LPWSTR strBinary = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(WCHAR) * 3 + sizeof(WCHAR)); | 
|  | WCHAR format[] = {'%','0','2','X',' ',0}; | 
|  | for (i = 0; i < dwCount; i++) | 
|  | wsprintfW( strBinary + i*3, format, pData[i] ); | 
|  | strBinary[dwCount * 3] = 0; | 
|  | ListView_SetItemTextW(hwndLV, index, 2, strBinary); | 
|  | HeapFree(GetProcessHeap(), 0, strBinary); | 
|  | } | 
|  | break; | 
|  | case REG_MULTI_SZ: | 
|  | MakeMULTISZDisplayable(ValBuf); | 
|  | ListView_SetItemTextW(hwndLV, index, 2, ValBuf); | 
|  | break; | 
|  | default: | 
|  | { | 
|  | WCHAR szText[128]; | 
|  | LoadStringW(hInst, IDS_REGISTRY_VALUE_CANT_DISPLAY, szText, COUNT_OF(szText)); | 
|  | ListView_SetItemTextW(hwndLV, index, 2, szText); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static BOOL InitListViewImageList(HWND hWndListView) | 
|  | { | 
|  | HIMAGELIST himl; | 
|  | HICON hicon; | 
|  | INT cx = GetSystemMetrics(SM_CXSMICON); | 
|  | INT cy = GetSystemMetrics(SM_CYSMICON); | 
|  |  | 
|  | himl = ImageList_Create(cx, cy, ILC_MASK, 0, 2); | 
|  | if (!himl) | 
|  | return FALSE; | 
|  |  | 
|  | hicon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_STRING), | 
|  | IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR); | 
|  | Image_String = ImageList_AddIcon(himl, hicon); | 
|  |  | 
|  | hicon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_BIN), | 
|  | IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR); | 
|  | Image_Binary = ImageList_AddIcon(himl, hicon); | 
|  |  | 
|  | SendMessageW( hWndListView, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM) himl ); | 
|  |  | 
|  | /* fail if some of the icons failed to load */ | 
|  | if (ImageList_GetImageCount(himl) < 2) | 
|  | return FALSE; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static BOOL CreateListColumns(HWND hWndListView) | 
|  | { | 
|  | WCHAR szText[50]; | 
|  | int index; | 
|  | LVCOLUMNW lvC; | 
|  |  | 
|  | /* Create columns. */ | 
|  | lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; | 
|  | lvC.pszText = szText; | 
|  |  | 
|  | /* Load the column labels from the resource file. */ | 
|  | for (index = 0; index < MAX_LIST_COLUMNS; index++) { | 
|  | lvC.iSubItem = index; | 
|  | lvC.cx = default_column_widths[index]; | 
|  | lvC.fmt = column_alignment[index]; | 
|  | LoadStringW(hInst, IDS_LIST_COLUMN_FIRST + index, szText, sizeof(szText)/sizeof(WCHAR)); | 
|  | if (ListView_InsertColumnW(hWndListView, index, &lvC) == -1) return FALSE; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /* OnGetDispInfo - processes the LVN_GETDISPINFO notification message.  */ | 
|  |  | 
|  | static void OnGetDispInfo(NMLVDISPINFOW* plvdi) | 
|  | { | 
|  | static WCHAR buffer[200]; | 
|  | static WCHAR reg_szT[]               = {'R','E','G','_','S','Z',0}, | 
|  | reg_expand_szT[]        = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0}, | 
|  | reg_binaryT[]           = {'R','E','G','_','B','I','N','A','R','Y',0}, | 
|  | reg_dwordT[]            = {'R','E','G','_','D','W','O','R','D',0}, | 
|  | reg_dword_big_endianT[] = {'R','E','G','_','D','W','O','R','D','_', | 
|  | 'B','I','G','_','E','N','D','I','A','N',0}, | 
|  | reg_multi_szT[]         = {'R','E','G','_','M','U','L','T','I','_','S','Z',0}, | 
|  | reg_linkT[]             = {'R','E','G','_','L','I','N','K',0}, | 
|  | reg_resource_listT[]    = {'R','E','G','_','R','E','S','O','U','R','C','E','_','L','I','S','T',0}, | 
|  | reg_noneT[]             = {'R','E','G','_','N','O','N','E',0}, | 
|  | emptyT[]                = {0}; | 
|  |  | 
|  | plvdi->item.pszText = NULL; | 
|  | plvdi->item.cchTextMax = 0; | 
|  |  | 
|  | switch (plvdi->item.iSubItem) { | 
|  | case 0: | 
|  | plvdi->item.pszText = g_pszDefaultValueName; | 
|  | break; | 
|  | case 1: | 
|  | switch (((LINE_INFO*)plvdi->item.lParam)->dwValType) { | 
|  | case REG_SZ: | 
|  | plvdi->item.pszText = reg_szT; | 
|  | break; | 
|  | case REG_EXPAND_SZ: | 
|  | plvdi->item.pszText = reg_expand_szT; | 
|  | break; | 
|  | case REG_BINARY: | 
|  | plvdi->item.pszText = reg_binaryT; | 
|  | break; | 
|  | case REG_DWORD: | 
|  | plvdi->item.pszText = reg_dwordT; | 
|  | break; | 
|  | case REG_DWORD_BIG_ENDIAN: | 
|  | plvdi->item.pszText = reg_dword_big_endianT; | 
|  | break; | 
|  | case REG_MULTI_SZ: | 
|  | plvdi->item.pszText = reg_multi_szT; | 
|  | break; | 
|  | case REG_LINK: | 
|  | plvdi->item.pszText = reg_linkT; | 
|  | break; | 
|  | case REG_RESOURCE_LIST: | 
|  | plvdi->item.pszText = reg_resource_listT; | 
|  | break; | 
|  | case REG_NONE: | 
|  | plvdi->item.pszText = reg_noneT; | 
|  | break; | 
|  | default: | 
|  | { | 
|  | WCHAR szUnknownFmt[64]; | 
|  | LoadStringW(hInst, IDS_REGISTRY_UNKNOWN_TYPE, szUnknownFmt, COUNT_OF(szUnknownFmt)); | 
|  | wsprintfW(buffer, szUnknownFmt, plvdi->item.lParam); | 
|  | plvdi->item.pszText = buffer; | 
|  | break; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case 2: | 
|  | plvdi->item.pszText = g_szValueNotSet; | 
|  | break; | 
|  | case 3: | 
|  | plvdi->item.pszText = emptyT; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) | 
|  | { | 
|  | LINE_INFO*l, *r; | 
|  | l = (LINE_INFO*)lParam1; | 
|  | r = (LINE_INFO*)lParam2; | 
|  | if (!l->name) return -1; | 
|  | if (!r->name) return +1; | 
|  |  | 
|  | if (g_columnToSort == ~0U) | 
|  | g_columnToSort = 0; | 
|  |  | 
|  | if (g_columnToSort == 1 && l->dwValType != r->dwValType) | 
|  | return g_invertSort ? (int)r->dwValType - (int)l->dwValType : (int)l->dwValType - (int)r->dwValType; | 
|  | if (g_columnToSort == 2) { | 
|  | /* FIXME: Sort on value */ | 
|  | } | 
|  | return g_invertSort ? lstrcmpiW(r->name, l->name) : lstrcmpiW(l->name, r->name); | 
|  | } | 
|  |  | 
|  | HWND StartValueRename(HWND hwndLV) | 
|  | { | 
|  | int item; | 
|  |  | 
|  | item = ListView_GetNextItem(hwndLV, -1, LVNI_FOCUSED | LVNI_SELECTED); | 
|  | if (item < 1) { /* cannot rename default key */ | 
|  | MessageBeep(MB_ICONHAND); | 
|  | return 0; | 
|  | } | 
|  | return ListView_EditLabel(hwndLV, item); | 
|  | } | 
|  |  | 
|  | static BOOL _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | switch (LOWORD(wParam)) { | 
|  | /*    case ID_FILE_OPEN: */ | 
|  | /*        break; */ | 
|  | default: | 
|  | return FALSE; | 
|  | } | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static LRESULT CALLBACK ListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | switch (message) { | 
|  | case WM_COMMAND: | 
|  | if (!_CmdWndProc(hWnd, message, wParam, lParam)) { | 
|  | return CallWindowProc(g_orgListWndProc, hWnd, message, wParam, lParam); | 
|  | } | 
|  | break; | 
|  | case WM_NOTIFY_REFLECT: | 
|  | switch (((LPNMHDR)lParam)->code) { | 
|  |  | 
|  | case LVN_BEGINLABELEDITW: | 
|  | if (!((NMLVDISPINFOW *)lParam)->item.iItem) | 
|  | return 1; | 
|  | return 0; | 
|  | case LVN_GETDISPINFOW: | 
|  | OnGetDispInfo((NMLVDISPINFOW*)lParam); | 
|  | break; | 
|  | case LVN_COLUMNCLICK: | 
|  | if (g_columnToSort == ((LPNMLISTVIEW)lParam)->iSubItem) | 
|  | g_invertSort = !g_invertSort; | 
|  | else { | 
|  | g_columnToSort = ((LPNMLISTVIEW)lParam)->iSubItem; | 
|  | g_invertSort = FALSE; | 
|  | } | 
|  |  | 
|  | SendMessageW(hWnd, LVM_SORTITEMS, (WPARAM)hWnd, (LPARAM)CompareFunc); | 
|  | break; | 
|  | case LVN_ENDLABELEDITW: { | 
|  | LPNMLVDISPINFOW dispInfo = (LPNMLVDISPINFOW)lParam; | 
|  | LPWSTR oldName = GetItemText(hWnd, dispInfo->item.iItem); | 
|  | LONG ret; | 
|  | if (!oldName) return -1; /* cannot rename a default value */ | 
|  | ret = RenameValue(hWnd, g_currentRootKey, g_currentPath, oldName, dispInfo->item.pszText); | 
|  | if (ret) | 
|  | { | 
|  | RefreshListView(hWnd, g_currentRootKey, g_currentPath, dispInfo->item.pszText); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, oldName); | 
|  | return 0; | 
|  | } | 
|  | case NM_RETURN: { | 
|  | int cnt = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED | LVNI_SELECTED); | 
|  | if (cnt != -1) | 
|  | SendMessageW(hFrameWnd, WM_COMMAND, ID_EDIT_MODIFY, 0); | 
|  | } | 
|  | break; | 
|  | case NM_DBLCLK: { | 
|  | NMITEMACTIVATE* nmitem = (LPNMITEMACTIVATE)lParam; | 
|  | LVHITTESTINFO info; | 
|  |  | 
|  | /* if (nmitem->hdr.hwndFrom != hWnd) break; unnecessary because of WM_NOTIFY_REFLECT */ | 
|  | /*            if (nmitem->hdr.idFrom != IDW_LISTVIEW) break;  */ | 
|  | /*            if (nmitem->hdr.code != ???) break;  */ | 
|  | #ifdef _MSC_VER | 
|  | switch (nmitem->uKeyFlags) { | 
|  | case LVKF_ALT:     /*  The ALT key is pressed.   */ | 
|  | /* properties dialog box ? */ | 
|  | break; | 
|  | case LVKF_CONTROL: /*  The CTRL key is pressed. */ | 
|  | /* run dialog box for providing parameters... */ | 
|  | break; | 
|  | case LVKF_SHIFT:   /*  The SHIFT key is pressed.    */ | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | info.pt.x = nmitem->ptAction.x; | 
|  | info.pt.y = nmitem->ptAction.y; | 
|  | if (ListView_HitTest(hWnd, &info) != -1) { | 
|  | ListView_SetItemState(hWnd, -1, 0, LVIS_FOCUSED|LVIS_SELECTED); | 
|  | ListView_SetItemState(hWnd, info.iItem, LVIS_FOCUSED|LVIS_SELECTED, | 
|  | LVIS_FOCUSED|LVIS_SELECTED); | 
|  | SendMessageW(hFrameWnd, WM_COMMAND, ID_EDIT_MODIFY, 0); | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return 0; /* shouldn't call default ! */ | 
|  | } | 
|  | break; | 
|  | case WM_CONTEXTMENU: { | 
|  | int cnt = ListView_GetNextItem(hWnd, -1, LVNI_SELECTED); | 
|  | TrackPopupMenu(GetSubMenu(hPopupMenus, cnt == -1 ? PM_NEW : PM_MODIFYVALUE), | 
|  | TPM_RIGHTBUTTON, (short)LOWORD(lParam), (short)HIWORD(lParam), | 
|  | 0, hFrameWnd, NULL); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | return CallWindowProc(g_orgListWndProc, hWnd, message, wParam, lParam); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | HWND CreateListView(HWND hwndParent, UINT id) | 
|  | { | 
|  | RECT rcClient; | 
|  | HWND hwndLV; | 
|  | WCHAR ListView[] = {'L','i','s','t',' ','V','i','e','w',0}; | 
|  |  | 
|  | /* prepare strings */ | 
|  | LoadStringW(hInst, IDS_REGISTRY_VALUE_NOT_SET, g_szValueNotSet, COUNT_OF(g_szValueNotSet)); | 
|  |  | 
|  | /* Get the dimensions of the parent window's client area, and create the list view control.  */ | 
|  | GetClientRect(hwndParent, &rcClient); | 
|  | hwndLV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, ListView, | 
|  | WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS, | 
|  | 0, 0, rcClient.right, rcClient.bottom, | 
|  | hwndParent, ULongToHandle(id), hInst, NULL); | 
|  | if (!hwndLV) return NULL; | 
|  | SendMessageW(hwndLV, LVM_SETUNICODEFORMAT, TRUE, 0); | 
|  | SendMessageW(hwndLV, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); | 
|  |  | 
|  | /* Initialize the image list */ | 
|  | if (!InitListViewImageList(hwndLV)) goto fail; | 
|  | if (!CreateListColumns(hwndLV)) goto fail; | 
|  | g_orgListWndProc = (WNDPROC) SetWindowLongPtrW(hwndLV, GWLP_WNDPROC, (LPARAM)ListWndProc); | 
|  | return hwndLV; | 
|  | fail: | 
|  | DestroyWindow(hwndLV); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | BOOL RefreshListView(HWND hwndLV, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR highlightValue) | 
|  | { | 
|  | BOOL result = FALSE; | 
|  | DWORD max_sub_key_len; | 
|  | DWORD max_val_name_len, valNameLen; | 
|  | DWORD max_val_size, valSize; | 
|  | DWORD val_count, index, valType; | 
|  | WCHAR* valName = 0; | 
|  | BYTE* valBuf = 0; | 
|  | HKEY hKey = 0; | 
|  | LONG errCode; | 
|  | INT count, i; | 
|  | LVITEMW item; | 
|  |  | 
|  | if (!hwndLV) return FALSE; | 
|  |  | 
|  | SendMessageW(hwndLV, WM_SETREDRAW, FALSE, 0); | 
|  |  | 
|  | errCode = RegOpenKeyExW(hKeyRoot, keyPath, 0, KEY_READ, &hKey); | 
|  | if (errCode != ERROR_SUCCESS) goto done; | 
|  |  | 
|  | count = ListView_GetItemCount(hwndLV); | 
|  | for (i = 0; i < count; i++) { | 
|  | item.mask = LVIF_PARAM; | 
|  | item.iItem = i; | 
|  | SendMessageW( hwndLV, LVM_GETITEM, 0, (LPARAM)&item ); | 
|  | HeapFree(GetProcessHeap(), 0, ((LINE_INFO*)item.lParam)->name); | 
|  | HeapFree(GetProcessHeap(), 0, (void*)item.lParam); | 
|  | } | 
|  | g_columnToSort = ~0U; | 
|  | SendMessageW( hwndLV, LVM_DELETEALLITEMS, 0, 0L ); | 
|  |  | 
|  | /* get size information and resize the buffers if necessary */ | 
|  | errCode = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL, | 
|  | &val_count, &max_val_name_len, &max_val_size, NULL, NULL); | 
|  | if (errCode != ERROR_SUCCESS) goto done; | 
|  |  | 
|  | /* account for the terminator char */ | 
|  | max_val_name_len++; | 
|  | max_val_size++; | 
|  |  | 
|  | valName = HeapAlloc(GetProcessHeap(), 0, max_val_name_len * sizeof(WCHAR)); | 
|  | if (!valName) | 
|  | goto done; | 
|  | valBuf = HeapAlloc(GetProcessHeap(), 0, max_val_size); | 
|  | if (!valBuf) | 
|  | goto done; | 
|  |  | 
|  | if (RegQueryValueExW(hKey, NULL, NULL, &valType, valBuf, &valSize) == ERROR_FILE_NOT_FOUND) { | 
|  | AddEntryToList(hwndLV, NULL, REG_SZ, NULL, 0, !highlightValue); | 
|  | } | 
|  | for(index = 0; index < val_count; index++) { | 
|  | BOOL bSelected = (valName == highlightValue); /* NOT a bug, we check for double NULL here */ | 
|  | valNameLen = max_val_name_len; | 
|  | valSize = max_val_size; | 
|  | valType = 0; | 
|  | errCode = RegEnumValueW(hKey, index, valName, &valNameLen, NULL, &valType, valBuf, &valSize); | 
|  | if (errCode != ERROR_SUCCESS) goto done; | 
|  | valBuf[valSize] = 0; | 
|  | if (highlightValue && !lstrcmpW(valName, highlightValue)) | 
|  | bSelected = TRUE; | 
|  | AddEntryToList(hwndLV, valName[0] ? valName : NULL, valType, valBuf, valSize, bSelected); | 
|  | } | 
|  | SendMessageW(hwndLV, LVM_SORTITEMS, (WPARAM)hwndLV, (LPARAM)CompareFunc); | 
|  |  | 
|  | g_currentRootKey = hKeyRoot; | 
|  | if (keyPath != g_currentPath) { | 
|  | HeapFree(GetProcessHeap(), 0, g_currentPath); | 
|  | g_currentPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(keyPath) + 1) * sizeof(WCHAR)); | 
|  | if (!g_currentPath) goto done; | 
|  | lstrcpyW(g_currentPath, keyPath); | 
|  | } | 
|  |  | 
|  | result = TRUE; | 
|  |  | 
|  | done: | 
|  | HeapFree(GetProcessHeap(), 0, valBuf); | 
|  | HeapFree(GetProcessHeap(), 0, valName); | 
|  | SendMessageW(hwndLV, WM_SETREDRAW, TRUE, 0); | 
|  | if (hKey) RegCloseKey(hKey); | 
|  |  | 
|  | return result; | 
|  | } |