listview.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. if (type == REG_DWORD_BIG_ENDIAN)
  100. value = RtlUlongByteSwap(value);
  101. wsprintfW(buf, L"0x%08x (%u)", value, value);
  102. ListView_SetItemTextW(hwndLV, index, 2, buf);
  103. break;
  104. }
  105. case REG_MULTI_SZ:
  106. MakeMULTISZDisplayable(data);
  107. ListView_SetItemTextW(hwndLV, index, 2, data);
  108. break;
  109. case REG_BINARY:
  110. case REG_NONE:
  111. default:
  112. {
  113. unsigned int i;
  114. BYTE *pData = data;
  115. WCHAR *strBinary = heap_xalloc(size * sizeof(WCHAR) * 3 + sizeof(WCHAR));
  116. for (i = 0; i < size; i++)
  117. wsprintfW( strBinary + i*3, L"%02X ", pData[i] );
  118. strBinary[size * 3] = 0;
  119. ListView_SetItemTextW(hwndLV, index, 2, strBinary);
  120. heap_free(strBinary);
  121. break;
  122. }
  123. }
  124. }
  125. int AddEntryToList(HWND hwndLV, WCHAR *Name, DWORD dwValType, void *ValBuf, DWORD dwCount, int pos)
  126. {
  127. LINE_INFO *linfo;
  128. LVITEMW item = { 0 };
  129. int index;
  130. linfo = heap_xalloc(sizeof(LINE_INFO));
  131. linfo->dwValType = dwValType;
  132. linfo->val_len = dwCount;
  133. if (Name)
  134. {
  135. linfo->name = heap_xalloc((lstrlenW(Name) + 1) * sizeof(WCHAR));
  136. lstrcpyW(linfo->name, Name);
  137. }
  138. else linfo->name = NULL;
  139. if (ValBuf && dwCount)
  140. {
  141. linfo->val = heap_xalloc(dwCount);
  142. memcpy(linfo->val, ValBuf, dwCount);
  143. }
  144. else linfo->val = NULL;
  145. item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
  146. item.iItem = (pos == -1) ? SendMessageW(hwndLV, LVM_GETITEMCOUNT, 0, 0) : pos;
  147. item.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
  148. item.pszText = Name ? Name : LPSTR_TEXTCALLBACKW;
  149. item.cchTextMax = Name ? lstrlenW(item.pszText) : 0;
  150. switch (dwValType)
  151. {
  152. case REG_SZ:
  153. case REG_EXPAND_SZ:
  154. case REG_MULTI_SZ:
  155. item.iImage = Image_String;
  156. break;
  157. default:
  158. item.iImage = Image_Binary;
  159. break;
  160. }
  161. item.lParam = (LPARAM)linfo;
  162. if ((index = ListView_InsertItemW(hwndLV, &item)) != -1)
  163. format_value_data(hwndLV, index, dwValType, ValBuf, dwCount);
  164. return index;
  165. }
  166. static BOOL InitListViewImageList(HWND hWndListView)
  167. {
  168. HIMAGELIST himl;
  169. HICON hicon;
  170. INT cx = GetSystemMetrics(SM_CXSMICON);
  171. INT cy = GetSystemMetrics(SM_CYSMICON);
  172. himl = ImageList_Create(cx, cy, ILC_MASK, 0, 2);
  173. if (!himl)
  174. return FALSE;
  175. hicon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_STRING),
  176. IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR);
  177. Image_String = ImageList_AddIcon(himl, hicon);
  178. hicon = LoadImageW(hInst, MAKEINTRESOURCEW(IDI_BIN),
  179. IMAGE_ICON, cx, cy, LR_DEFAULTCOLOR);
  180. Image_Binary = ImageList_AddIcon(himl, hicon);
  181. SendMessageW( hWndListView, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM) himl );
  182. /* fail if some of the icons failed to load */
  183. if (ImageList_GetImageCount(himl) < 2)
  184. return FALSE;
  185. return TRUE;
  186. }
  187. static BOOL CreateListColumns(HWND hWndListView)
  188. {
  189. WCHAR szText[50];
  190. int index;
  191. LVCOLUMNW lvC;
  192. /* Create columns. */
  193. lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  194. lvC.pszText = szText;
  195. /* Load the column labels from the resource file. */
  196. for (index = 0; index < MAX_LIST_COLUMNS; index++) {
  197. lvC.iSubItem = index;
  198. lvC.cx = default_column_widths[index];
  199. lvC.fmt = column_alignment[index];
  200. LoadStringW(hInst, IDS_LIST_COLUMN_FIRST + index, szText, ARRAY_SIZE(szText));
  201. if (ListView_InsertColumnW(hWndListView, index, &lvC) == -1) return FALSE;
  202. }
  203. return TRUE;
  204. }
  205. /* OnGetDispInfo - processes the LVN_GETDISPINFO notification message. */
  206. void OnGetDispInfo(NMLVDISPINFOW *plvdi)
  207. {
  208. static WCHAR buffer[200];
  209. static WCHAR reg_szT[] = L"REG_SZ",
  210. reg_expand_szT[] = L"REG_EXPAND_SZ",
  211. reg_binaryT[] = L"REG_BINARY",
  212. reg_dwordT[] = L"REG_DWORD",
  213. reg_dword_big_endianT[] = L"REG_DWORD_BIG_ENDIAN",
  214. reg_multi_szT[] = L"REG_MULTI_SZ",
  215. reg_linkT[] = L"REG_LINK",
  216. reg_resource_listT[] = L"REG_RESOURCE_LIST",
  217. reg_noneT[] = L"REG_NONE",
  218. emptyT[] = L"";
  219. plvdi->item.pszText = NULL;
  220. plvdi->item.cchTextMax = 0;
  221. switch (plvdi->item.iSubItem) {
  222. case 0:
  223. plvdi->item.pszText = g_pszDefaultValueName;
  224. break;
  225. case 1:
  226. {
  227. DWORD data_type = ((LINE_INFO *)plvdi->item.lParam)->dwValType;
  228. switch (data_type) {
  229. case REG_SZ:
  230. plvdi->item.pszText = reg_szT;
  231. break;
  232. case REG_EXPAND_SZ:
  233. plvdi->item.pszText = reg_expand_szT;
  234. break;
  235. case REG_BINARY:
  236. plvdi->item.pszText = reg_binaryT;
  237. break;
  238. case REG_DWORD:
  239. plvdi->item.pszText = reg_dwordT;
  240. break;
  241. case REG_DWORD_BIG_ENDIAN:
  242. plvdi->item.pszText = reg_dword_big_endianT;
  243. break;
  244. case REG_MULTI_SZ:
  245. plvdi->item.pszText = reg_multi_szT;
  246. break;
  247. case REG_LINK:
  248. plvdi->item.pszText = reg_linkT;
  249. break;
  250. case REG_RESOURCE_LIST:
  251. plvdi->item.pszText = reg_resource_listT;
  252. break;
  253. case REG_NONE:
  254. plvdi->item.pszText = reg_noneT;
  255. break;
  256. default:
  257. {
  258. wsprintfW(buffer, L"0x%x", data_type);
  259. plvdi->item.pszText = buffer;
  260. break;
  261. }
  262. }
  263. break;
  264. }
  265. case 2:
  266. plvdi->item.pszText = g_szValueNotSet;
  267. break;
  268. case 3:
  269. plvdi->item.pszText = emptyT;
  270. break;
  271. }
  272. }
  273. int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  274. {
  275. LINE_INFO*l, *r;
  276. l = (LINE_INFO*)lParam1;
  277. r = (LINE_INFO*)lParam2;
  278. if (!l->name) return -1;
  279. if (!r->name) return +1;
  280. if (g_columnToSort == ~0U)
  281. g_columnToSort = 0;
  282. if (g_columnToSort == 1)
  283. return g_invertSort ? (int)r->dwValType - (int)l->dwValType : (int)l->dwValType - (int)r->dwValType;
  284. if (g_columnToSort == 2) {
  285. /* FIXME: Sort on value */
  286. return 0;
  287. }
  288. return g_invertSort ? lstrcmpiW(r->name, l->name) : lstrcmpiW(l->name, r->name);
  289. }
  290. HWND StartValueRename(HWND hwndLV)
  291. {
  292. int item;
  293. item = SendMessageW(hwndLV, LVM_GETNEXTITEM, -1, MAKELPARAM(LVNI_FOCUSED | LVNI_SELECTED, 0));
  294. if (item < 1) { /* cannot rename default key */
  295. MessageBeep(MB_ICONHAND);
  296. return 0;
  297. }
  298. return (HWND)SendMessageW(hwndLV, LVM_EDITLABELW, item, 0);
  299. }
  300. HWND CreateListView(HWND hwndParent, UINT id)
  301. {
  302. RECT rcClient;
  303. HWND hwndLV;
  304. /* prepare strings */
  305. LoadStringW(hInst, IDS_REGISTRY_VALUE_NOT_SET, g_szValueNotSet, ARRAY_SIZE(g_szValueNotSet));
  306. /* Get the dimensions of the parent window's client area, and create the list view control. */
  307. GetClientRect(hwndParent, &rcClient);
  308. hwndLV = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, L"List View",
  309. WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS,
  310. 0, 0, rcClient.right, rcClient.bottom,
  311. hwndParent, ULongToHandle(id), hInst, NULL);
  312. if (!hwndLV) return NULL;
  313. SendMessageW(hwndLV, LVM_SETUNICODEFORMAT, TRUE, 0);
  314. SendMessageW(hwndLV, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
  315. /* Initialize the image list */
  316. if (!InitListViewImageList(hwndLV)) goto fail;
  317. if (!CreateListColumns(hwndLV)) goto fail;
  318. return hwndLV;
  319. fail:
  320. DestroyWindow(hwndLV);
  321. return NULL;
  322. }
  323. BOOL RefreshListView(HWND hwndLV, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR highlightValue)
  324. {
  325. BOOL result = FALSE;
  326. DWORD max_sub_key_len;
  327. DWORD max_val_name_len, valNameLen;
  328. DWORD max_val_size, valSize;
  329. DWORD val_count, index, valType;
  330. WCHAR* valName = 0;
  331. BYTE* valBuf = 0;
  332. HKEY hKey = 0;
  333. LONG errCode;
  334. LVITEMW item;
  335. if (!hwndLV) return FALSE;
  336. SendMessageW(hwndLV, WM_SETREDRAW, FALSE, 0);
  337. errCode = RegOpenKeyExW(hKeyRoot, keyPath, 0, KEY_READ, &hKey);
  338. if (errCode != ERROR_SUCCESS) goto done;
  339. g_columnToSort = ~0U;
  340. SendMessageW(hwndLV, LVM_DELETEALLITEMS, 0, 0);
  341. /* get size information and resize the buffers if necessary */
  342. errCode = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL,
  343. &val_count, &max_val_name_len, &max_val_size, NULL, NULL);
  344. if (errCode != ERROR_SUCCESS) goto done;
  345. /* account for the terminator char */
  346. max_val_name_len++;
  347. max_val_size++;
  348. valName = heap_xalloc(max_val_name_len * sizeof(WCHAR));
  349. valBuf = heap_xalloc(max_val_size);
  350. valSize = max_val_size;
  351. if (RegQueryValueExW(hKey, NULL, NULL, &valType, valBuf, &valSize) == ERROR_FILE_NOT_FOUND) {
  352. AddEntryToList(hwndLV, NULL, REG_SZ, NULL, 0, -1);
  353. }
  354. for(index = 0; index < val_count; index++) {
  355. valNameLen = max_val_name_len;
  356. valSize = max_val_size;
  357. valType = 0;
  358. errCode = RegEnumValueW(hKey, index, valName, &valNameLen, NULL, &valType, valBuf, &valSize);
  359. if (errCode != ERROR_SUCCESS) goto done;
  360. valBuf[valSize] = 0;
  361. AddEntryToList(hwndLV, valName[0] ? valName : NULL, valType, valBuf, valSize, -1);
  362. }
  363. memset(&item, 0, sizeof(item));
  364. if (!highlightValue)
  365. {
  366. item.state = item.stateMask = LVIS_FOCUSED;
  367. SendMessageW(hwndLV, LVM_SETITEMSTATE, 0, (LPARAM)&item);
  368. }
  369. SendMessageW(hwndLV, LVM_SORTITEMS, (WPARAM)hwndLV, (LPARAM)CompareFunc);
  370. g_currentRootKey = hKeyRoot;
  371. if (keyPath != g_currentPath && !update_listview_path(keyPath))
  372. goto done;
  373. result = TRUE;
  374. done:
  375. heap_free(valBuf);
  376. heap_free(valName);
  377. SendMessageW(hwndLV, WM_SETREDRAW, TRUE, 0);
  378. if (hKey) RegCloseKey(hKey);
  379. return result;
  380. }