listview.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. /*
  2. * Regedit listviews
  3. *
  4. * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
  5. * Copyright (C) 2008 Alexander N. Sørnes <alex@thehandofagony.com>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  20. */
  21. #include <windows.h>
  22. #include <winternl.h>
  23. #include <commctrl.h>
  24. #include <stdlib.h>
  25. #include "main.h"
  26. #include "wine/heap.h"
  27. static INT Image_String;
  28. static INT Image_Binary;
  29. /*******************************************************************************
  30. * Global and Local Variables:
  31. */
  32. DWORD g_columnToSort = ~0U;
  33. BOOL g_invertSort = FALSE;
  34. WCHAR *g_currentPath;
  35. HKEY g_currentRootKey;
  36. static WCHAR g_szValueNotSet[64];
  37. #define MAX_LIST_COLUMNS (IDS_LIST_COLUMN_LAST - IDS_LIST_COLUMN_FIRST + 1)
  38. static int default_column_widths[MAX_LIST_COLUMNS] = { 200, 175, 400 };
  39. static int column_alignment[MAX_LIST_COLUMNS] = { LVCFMT_LEFT, LVCFMT_LEFT, LVCFMT_LEFT };
  40. LPWSTR GetItemText(HWND hwndLV, UINT item)
  41. {
  42. WCHAR *curStr;
  43. unsigned int maxLen = 128;
  44. if (item == 0) return NULL; /* first item is ALWAYS a default */
  45. curStr = heap_xalloc(maxLen * sizeof(WCHAR));
  46. do {
  47. ListView_GetItemTextW(hwndLV, item, 0, curStr, maxLen);
  48. if (lstrlenW(curStr) < maxLen - 1) return curStr;
  49. maxLen *= 2;
  50. curStr = heap_xrealloc(curStr, maxLen * sizeof(WCHAR));
  51. } while (TRUE);
  52. heap_free(curStr);
  53. return NULL;
  54. }
  55. WCHAR *GetValueName(HWND hwndLV)
  56. {
  57. INT item;
  58. item = SendMessageW(hwndLV, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED, 0));
  59. if (item == -1) return NULL;
  60. return GetItemText(hwndLV, item);
  61. }
  62. BOOL update_listview_path(const WCHAR *path)
  63. {
  64. heap_free(g_currentPath);
  65. g_currentPath = heap_xalloc((lstrlenW(path) + 1) * sizeof(WCHAR));
  66. lstrcpyW(g_currentPath, path);
  67. return TRUE;
  68. }
  69. /* convert '\0' separated string list into ',' separated string list */
  70. static void MakeMULTISZDisplayable(LPWSTR multi)
  71. {
  72. do
  73. {
  74. for (; *multi; multi++)
  75. ;
  76. if (*(multi+1))
  77. {
  78. *multi = ',';
  79. multi++;
  80. }
  81. } while (*multi);
  82. }
  83. /*******************************************************************************
  84. * Local module support methods
  85. */
  86. void format_value_data(HWND hwndLV, int index, DWORD type, void *data, DWORD size)
  87. {
  88. switch (type)
  89. {
  90. case REG_SZ:
  91. case REG_EXPAND_SZ:
  92. ListView_SetItemTextW(hwndLV, index, 2, data ? data : g_szValueNotSet);
  93. break;
  94. case REG_DWORD:
  95. case REG_DWORD_BIG_ENDIAN:
  96. {
  97. DWORD value = *(DWORD *)data;
  98. WCHAR buf[64];
  99. WCHAR format[] = {'0','x','%','0','8','x',' ','(','%','u',')',0};
  100. if (type == REG_DWORD_BIG_ENDIAN)
  101. value = RtlUlongByteSwap(value);
  102. wsprintfW(buf, format, value, value);
  103. ListView_SetItemTextW(hwndLV, index, 2, buf);
  104. break;
  105. }
  106. case REG_MULTI_SZ:
  107. MakeMULTISZDisplayable(data);
  108. ListView_SetItemTextW(hwndLV, index, 2, data);
  109. break;
  110. case REG_BINARY:
  111. case REG_NONE:
  112. default:
  113. {
  114. unsigned int i;
  115. BYTE *pData = data;
  116. WCHAR *strBinary = heap_xalloc(size * sizeof(WCHAR) * 3 + sizeof(WCHAR));
  117. WCHAR format[] = {'%','0','2','X',' ',0};
  118. for (i = 0; i < size; i++)
  119. wsprintfW( strBinary + i*3, format, pData[i] );
  120. strBinary[size * 3] = 0;
  121. ListView_SetItemTextW(hwndLV, index, 2, strBinary);
  122. heap_free(strBinary);
  123. break;
  124. }
  125. }
  126. }
  127. int AddEntryToList(HWND hwndLV, WCHAR *Name, DWORD dwValType, void *ValBuf, DWORD dwCount, int pos)
  128. {
  129. LINE_INFO *linfo;
  130. LVITEMW item = { 0 };
  131. int index;
  132. linfo = heap_xalloc(sizeof(LINE_INFO));
  133. linfo->dwValType = dwValType;
  134. linfo->val_len = dwCount;
  135. if (Name)
  136. {
  137. linfo->name = heap_xalloc((lstrlenW(Name) + 1) * sizeof(WCHAR));
  138. lstrcpyW(linfo->name, Name);
  139. }
  140. else linfo->name = NULL;
  141. if (ValBuf && dwCount)
  142. {
  143. linfo->val = heap_xalloc(dwCount);
  144. memcpy(linfo->val, ValBuf, dwCount);
  145. }
  146. else linfo->val = NULL;
  147. item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
  148. item.iItem = (pos == -1) ? SendMessageW(hwndLV, LVM_GETITEMCOUNT, 0, 0) : pos;
  149. item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
  150. item.pszText = Name ? Name : LPSTR_TEXTCALLBACKW;
  151. item.cchTextMax = Name ? lstrlenW(item.pszText) : 0;
  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_Binary;
  161. break;
  162. }
  163. item.lParam = (LPARAM)linfo;
  164. if ((index = ListView_InsertItemW(hwndLV, &item)) != -1)
  165. format_value_data(hwndLV, index, dwValType, ValBuf, dwCount);
  166. return index;
  167. }
  168. static BOOL InitListViewImageList(HWND hWndListView)
  169. {
  170. HIMAGELIST himl;
  171. HICON hicon;
  172. INT cx = GetSystemMetrics(SM_CXSMICON);
  173. INT cy = GetSystemMetrics(SM_CYSMICON);
  174. himl = ImageList_Create(cx, cy, ILC_MASK, 0, 2);
  175. if (!himl)
  176. return FALSE;
  177. hicon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_STRING),
  178. IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR);
  179. Image_String = ImageList_AddIcon(himl, hicon);
  180. hicon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_BIN),
  181. IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR);
  182. Image_Binary = ImageList_AddIcon(himl, hicon);
  183. SendMessageW( hWndListView, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM) himl );
  184. /* fail if some of the icons failed to load */
  185. if (ImageList_GetImageCount(himl) < 2)
  186. return FALSE;
  187. return TRUE;
  188. }
  189. static BOOL CreateListColumns(HWND hWndListView)
  190. {
  191. WCHAR szText[50];
  192. int index;
  193. LVCOLUMNW lvC;
  194. /* Create columns. */
  195. lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  196. lvC.pszText = szText;
  197. /* Load the column labels from the resource file. */
  198. for (index = 0; index < MAX_LIST_COLUMNS; index++) {
  199. lvC.iSubItem = index;
  200. lvC.cx = default_column_widths[index];
  201. lvC.fmt = column_alignment[index];
  202. LoadStringW(hInst, IDS_LIST_COLUMN_FIRST + index, szText, ARRAY_SIZE(szText));
  203. if (ListView_InsertColumnW(hWndListView, index, &lvC) == -1) return FALSE;
  204. }
  205. return TRUE;
  206. }
  207. /* OnGetDispInfo - processes the LVN_GETDISPINFO notification message. */
  208. void OnGetDispInfo(NMLVDISPINFOW *plvdi)
  209. {
  210. static WCHAR buffer[200];
  211. static WCHAR reg_szT[] = {'R','E','G','_','S','Z',0},
  212. reg_expand_szT[] = {'R','E','G','_','E','X','P','A','N','D','_','S','Z',0},
  213. reg_binaryT[] = {'R','E','G','_','B','I','N','A','R','Y',0},
  214. reg_dwordT[] = {'R','E','G','_','D','W','O','R','D',0},
  215. reg_dword_big_endianT[] = {'R','E','G','_','D','W','O','R','D','_',
  216. 'B','I','G','_','E','N','D','I','A','N',0},
  217. reg_multi_szT[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0},
  218. reg_linkT[] = {'R','E','G','_','L','I','N','K',0},
  219. reg_resource_listT[] = {'R','E','G','_','R','E','S','O','U','R','C','E','_','L','I','S','T',0},
  220. reg_noneT[] = {'R','E','G','_','N','O','N','E',0},
  221. emptyT[] = {0};
  222. plvdi->item.pszText = NULL;
  223. plvdi->item.cchTextMax = 0;
  224. switch (plvdi->item.iSubItem) {
  225. case 0:
  226. plvdi->item.pszText = g_pszDefaultValueName;
  227. break;
  228. case 1:
  229. {
  230. DWORD data_type = ((LINE_INFO *)plvdi->item.lParam)->dwValType;
  231. switch (data_type) {
  232. case REG_SZ:
  233. plvdi->item.pszText = reg_szT;
  234. break;
  235. case REG_EXPAND_SZ:
  236. plvdi->item.pszText = reg_expand_szT;
  237. break;
  238. case REG_BINARY:
  239. plvdi->item.pszText = reg_binaryT;
  240. break;
  241. case REG_DWORD:
  242. plvdi->item.pszText = reg_dwordT;
  243. break;
  244. case REG_DWORD_BIG_ENDIAN:
  245. plvdi->item.pszText = reg_dword_big_endianT;
  246. break;
  247. case REG_MULTI_SZ:
  248. plvdi->item.pszText = reg_multi_szT;
  249. break;
  250. case REG_LINK:
  251. plvdi->item.pszText = reg_linkT;
  252. break;
  253. case REG_RESOURCE_LIST:
  254. plvdi->item.pszText = reg_resource_listT;
  255. break;
  256. case REG_NONE:
  257. plvdi->item.pszText = reg_noneT;
  258. break;
  259. default:
  260. {
  261. WCHAR fmt[] = {'0','x','%','x',0};
  262. wsprintfW(buffer, fmt, data_type);
  263. plvdi->item.pszText = buffer;
  264. break;
  265. }
  266. }
  267. break;
  268. }
  269. case 2:
  270. plvdi->item.pszText = g_szValueNotSet;
  271. break;
  272. case 3:
  273. plvdi->item.pszText = emptyT;
  274. break;
  275. }
  276. }
  277. int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  278. {
  279. LINE_INFO*l, *r;
  280. l = (LINE_INFO*)lParam1;
  281. r = (LINE_INFO*)lParam2;
  282. if (!l->name) return -1;
  283. if (!r->name) return +1;
  284. if (g_columnToSort == ~0U)
  285. g_columnToSort = 0;
  286. if (g_columnToSort == 1)
  287. return g_invertSort ? (int)r->dwValType - (int)l->dwValType : (int)l->dwValType - (int)r->dwValType;
  288. if (g_columnToSort == 2) {
  289. /* FIXME: Sort on value */
  290. return 0;
  291. }
  292. return g_invertSort ? lstrcmpiW(r->name, l->name) : lstrcmpiW(l->name, r->name);
  293. }
  294. HWND StartValueRename(HWND hwndLV)
  295. {
  296. int item;
  297. item = SendMessageW(hwndLV, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED | LVNI_SELECTED, 0));
  298. if (item < 1) { /* cannot rename default key */
  299. MessageBeep(MB_ICONHAND);
  300. return 0;
  301. }
  302. return (HWND)SendMessageW(hwndLV, LVM_EDITLABELW, item, 0);
  303. }
  304. HWND CreateListView(HWND hwndParent, UINT id)
  305. {
  306. RECT rcClient;
  307. HWND hwndLV;
  308. WCHAR ListView[] = {'L','i','s','t',' ','V','i','e','w',0};
  309. /* prepare strings */
  310. LoadStringW(hInst, IDS_REGISTRY_VALUE_NOT_SET, g_szValueNotSet, ARRAY_SIZE(g_szValueNotSet));
  311. /* Get the dimensions of the parent window's client area, and create the list view control. */
  312. GetClientRect(hwndParent, &rcClient);
  313. hwndLV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, ListView,
  314. WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS,
  315. 0, 0, rcClient.right, rcClient.bottom,
  316. hwndParent, ULongToHandle(id), hInst, NULL);
  317. if (!hwndLV) return NULL;
  318. SendMessageW(hwndLV, LVM_SETUNICODEFORMAT, TRUE, 0);
  319. SendMessageW(hwndLV, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
  320. /* Initialize the image list */
  321. if (!InitListViewImageList(hwndLV)) goto fail;
  322. if (!CreateListColumns(hwndLV)) goto fail;
  323. return hwndLV;
  324. fail:
  325. DestroyWindow(hwndLV);
  326. return NULL;
  327. }
  328. BOOL RefreshListView(HWND hwndLV, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR highlightValue)
  329. {
  330. BOOL result = FALSE;
  331. DWORD max_sub_key_len;
  332. DWORD max_val_name_len, valNameLen;
  333. DWORD max_val_size, valSize;
  334. DWORD val_count, index, valType;
  335. WCHAR* valName = 0;
  336. BYTE* valBuf = 0;
  337. HKEY hKey = 0;
  338. LONG errCode;
  339. LVITEMW item;
  340. if (!hwndLV) return FALSE;
  341. SendMessageW(hwndLV, WM_SETREDRAW, FALSE, 0);
  342. errCode = RegOpenKeyExW(hKeyRoot, keyPath, 0, KEY_READ, &hKey);
  343. if (errCode != ERROR_SUCCESS) goto done;
  344. g_columnToSort = ~0U;
  345. SendMessageW(hwndLV, LVM_DELETEALLITEMS, 0, 0);
  346. /* get size information and resize the buffers if necessary */
  347. errCode = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL,
  348. &val_count, &max_val_name_len, &max_val_size, NULL, NULL);
  349. if (errCode != ERROR_SUCCESS) goto done;
  350. /* account for the terminator char */
  351. max_val_name_len++;
  352. max_val_size++;
  353. valName = heap_xalloc(max_val_name_len * sizeof(WCHAR));
  354. valBuf = heap_xalloc(max_val_size);
  355. valSize = max_val_size;
  356. if (RegQueryValueExW(hKey, NULL, NULL, &valType, valBuf, &valSize) == ERROR_FILE_NOT_FOUND) {
  357. AddEntryToList(hwndLV, NULL, REG_SZ, NULL, 0, -1);
  358. }
  359. for(index = 0; index < val_count; index++) {
  360. valNameLen = max_val_name_len;
  361. valSize = max_val_size;
  362. valType = 0;
  363. errCode = RegEnumValueW(hKey, index, valName, &valNameLen, NULL, &valType, valBuf, &valSize);
  364. if (errCode != ERROR_SUCCESS) goto done;
  365. valBuf[valSize] = 0;
  366. AddEntryToList(hwndLV, valName[0] ? valName : NULL, valType, valBuf, valSize, -1);
  367. }
  368. memset(&item, 0, sizeof(item));
  369. if (!highlightValue)
  370. {
  371. item.state = item.stateMask = LVIS_FOCUSED;
  372. SendMessageW(hwndLV, LVM_SETITEMSTATE, 0, (LPARAM)&item);
  373. }
  374. SendMessageW(hwndLV, LVM_SORTITEMS, (WPARAM)hwndLV, (LPARAM)CompareFunc);
  375. g_currentRootKey = hKeyRoot;
  376. if (keyPath != g_currentPath && !update_listview_path(keyPath))
  377. goto done;
  378. result = TRUE;
  379. done:
  380. heap_free(valBuf);
  381. heap_free(valName);
  382. SendMessageW(hwndLV, WM_SETREDRAW, TRUE, 0);
  383. if (hKey) RegCloseKey(hKey);
  384. return result;
  385. }