c400e408fc811c587702524085eade62e05955ed
[reactos.git] / reactos / dll / win32 / shell32 / dialogs / folder_options.cpp
1 /*
2 * Open With Context Menu extension
3 *
4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@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 St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL (fprop);
24
25 #define MAX_PROPERTY_SHEET_PAGE (32)
26
27 /// Folder Options:
28 /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}
29 /// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
30 /// Verbs: Open / RunAs
31 /// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
32
33 /// ShellFolder Attributes: 0x0
34
35 typedef struct
36 {
37 WCHAR FileExtension[30];
38 WCHAR FileDescription[100];
39 WCHAR ClassKey[MAX_PATH];
40 DWORD EditFlags;
41 } FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY;
42
43 typedef struct
44 {
45 LPCWSTR szKeyName;
46 UINT ResourceID;
47 } FOLDER_VIEW_ENTRY, PFOLDER_VIEW_ENTRY;
48 /*
49 static FOLDER_VIEW_ENTRY s_Options[] =
50 {
51 { L"AlwaysShowMenus", IDS_ALWAYSSHOWMENUS },
52 { L"AutoCheckSelect", -1 },
53 { L"ClassicViewState", -1 },
54 { L"DontPrettyPath", -1 },
55 { L"Filter", -1 },
56 { L"FolderContentsInfoTip", IDS_FOLDERCONTENTSTIP },
57 { L"FriendlyTree", -1 },
58 { L"Hidden", -1, },
59 { L"HideFileExt", IDS_HIDEFILEEXT },
60 { L"HideIcons", -1},
61 { L"IconsOnly", -1},
62 { L"ListviewAlphaSelect", -1},
63 { L"ListviewShadow", -1},
64 { L"ListviewWatermark", -1},
65 { L"MapNetDrvBtn", -1},
66 { L"PersistBrowsers", -1},
67 { L"SeperateProcess", IDS_SEPERATEPROCESS},
68 { L"ServerAdminUI", -1},
69 { L"SharingWizardOn", IDS_USESHAREWIZARD},
70 { L"ShowCompColor", IDS_COMPCOLOR},
71 { L"ShowInfoTip", IDS_SHOWINFOTIP},
72 { L"ShowPreviewHandlers", -1},
73 { L"ShowSuperHidden", IDS_HIDEOSFILES},
74 { L"ShowTypeOverlay", -1},
75 { L"Start_ShowMyGames", -1},
76 { L"StartMenuInit", -1},
77 { L"SuperHidden", -1},
78 { L"TypeAhead", -1},
79 { L"Webview", -1},
80 { NULL, -1}
81
82 };
83 */
84
85 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
86
87 INT_PTR
88 CALLBACK
89 FolderOptionsGeneralDlg(
90 HWND hwndDlg,
91 UINT uMsg,
92 WPARAM wParam,
93 LPARAM lParam
94 )
95 {
96 return FALSE;
97 }
98
99 static
100 VOID
101 InitializeFolderOptionsListCtrl(HWND hwndDlg)
102 {
103 RECT clientRect;
104 LVCOLUMNW col;
105 WCHAR szName[50];
106 HWND hDlgCtrl;
107
108 hDlgCtrl = GetDlgItem(hwndDlg, 14003);
109
110 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
111 szName[0] = 0;
112 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
113
114 GetClientRect(hDlgCtrl, &clientRect);
115 ZeroMemory(&col, sizeof(LV_COLUMN));
116 col.mask = LVCF_SUBITEM | LVCF_WIDTH | LVCF_FMT;
117 col.iSubItem = 0;
118 col.pszText = szName;
119 col.fmt = LVCFMT_LEFT;
120 col.cx = (clientRect.right - clientRect.left) - GetSystemMetrics(SM_CXVSCROLL);
121 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMN, 0, (LPARAM)&col);
122
123
124
125 }
126
127 INT_PTR
128 CALLBACK
129 FolderOptionsViewDlg(
130 HWND hwndDlg,
131 UINT uMsg,
132 WPARAM wParam,
133 LPARAM lParam
134 )
135 {
136 switch(uMsg)
137 {
138 case WM_INITDIALOG:
139 InitializeFolderOptionsListCtrl(hwndDlg);
140 return TRUE;
141 }
142
143 return FALSE;
144
145 }
146
147 static
148 VOID
149 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl)
150 {
151 RECT clientRect;
152 LVCOLUMNW col;
153 WCHAR szName[50];
154 DWORD dwStyle;
155 int columnSize = 140;
156
157
158 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
159 {
160 /* default to english */
161 wcscpy(szName, L"Extensions");
162 }
163
164 /* make sure its null terminated */
165 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
166
167 GetClientRect(hDlgCtrl, &clientRect);
168 ZeroMemory(&col, sizeof(LV_COLUMN));
169 columnSize = 140; //FIXME
170 col.iSubItem = 0;
171 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
172 col.fmt = LVCFMT_FIXED_WIDTH;
173 col.cx = columnSize | LVCFMT_LEFT;
174 col.cchTextMax = wcslen(szName);
175 col.pszText = szName;
176 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
177
178 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR)))
179 {
180 /* default to english */
181 wcscpy(szName, L"File Types");
182 ERR("Failed to load localized string!\n");
183 }
184
185 col.iSubItem = 1;
186 col.cx = clientRect.right - clientRect.left - columnSize;
187 col.cchTextMax = wcslen(szName);
188 col.pszText = szName;
189 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col);
190
191 /* set full select style */
192 dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
193 dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
194 SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
195 }
196
197 INT
198 FindItem(HWND hDlgCtrl, WCHAR * ItemName)
199 {
200 LVFINDINFOW findInfo;
201 ZeroMemory(&findInfo, sizeof(LVFINDINFOW));
202
203 findInfo.flags = LVFI_STRING;
204 findInfo.psz = ItemName;
205 return ListView_FindItem(hDlgCtrl, 0, &findInfo);
206 }
207
208 static
209 VOID
210 InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile)
211 {
212 PFOLDER_FILE_TYPE_ENTRY Entry;
213 HKEY hKey;
214 LVITEMW lvItem;
215 DWORD dwSize;
216 DWORD dwType;
217
218 if (szName[0] != L'.')
219 {
220 /* FIXME handle URL protocol handlers */
221 return;
222 }
223
224 /* allocate file type entry */
225 Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY));
226
227 if (!Entry)
228 return;
229
230 /* open key */
231 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
232 {
233 HeapFree(GetProcessHeap(), 0, Entry);
234 return;
235 }
236
237 /* FIXME check for duplicates */
238
239 /* query for the default key */
240 dwSize = sizeof(Entry->ClassKey);
241 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS)
242 {
243 /* no link available */
244 Entry->ClassKey[0] = 0;
245 }
246
247 if (Entry->ClassKey[0])
248 {
249 HKEY hTemp;
250 /* try open linked key */
251 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
252 {
253 /* use linked key */
254 RegCloseKey(hKey);
255 hKey = hTemp;
256 }
257 }
258
259 /* read friendly type name */
260 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
261 {
262 /* read file description */
263 dwSize = sizeof(Entry->FileDescription);
264 Entry->FileDescription[0] = 0;
265
266 /* read default key */
267 RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize);
268 }
269
270 /* Read the EditFlags value */
271 Entry->EditFlags = 0;
272 if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize))
273 {
274 if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD))
275 RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize);
276 }
277
278 /* close key */
279 RegCloseKey(hKey);
280
281 /* Do not add excluded entries */
282 if (Entry->EditFlags & 0x00000001) //FTA_Exclude
283 {
284 HeapFree(GetProcessHeap(), 0, Entry);
285 return;
286 }
287
288 /* convert extension to upper case */
289 wcscpy(Entry->FileExtension, szName);
290 _wcsupr(Entry->FileExtension);
291
292 if (!Entry->FileDescription[0])
293 {
294 /* construct default 'FileExtensionFile' by formatting the uppercase extension
295 with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */
296
297 StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]);
298 }
299
300 ZeroMemory(&lvItem, sizeof(LVITEMW));
301 lvItem.mask = LVIF_TEXT | LVIF_PARAM;
302 lvItem.iSubItem = 0;
303 lvItem.pszText = &Entry->FileExtension[1];
304 lvItem.iItem = *iItem;
305 lvItem.lParam = (LPARAM)Entry;
306 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
307
308 ZeroMemory(&lvItem, sizeof(LVITEMW));
309 lvItem.mask = LVIF_TEXT;
310 lvItem.pszText = Entry->FileDescription;
311 lvItem.iItem = *iItem;
312 lvItem.iSubItem = 1;
313 ListView_SetItem(hDlgCtrl, &lvItem);
314
315 (*iItem)++;
316 }
317
318 static
319 int
320 CALLBACK
321 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
322 {
323 PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2;
324 int x;
325
326 Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1;
327 Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2;
328
329 x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
330 if (x != 0)
331 return x;
332
333 return wcsicmp(Entry1->FileDescription, Entry2->FileDescription);
334 }
335
336 static
337 PFOLDER_FILE_TYPE_ENTRY
338 InitializeFileTypesListCtrl(HWND hwndDlg)
339 {
340 HWND hDlgCtrl;
341 DWORD dwIndex = 0;
342 WCHAR szName[50];
343 WCHAR szFile[100];
344 DWORD dwName;
345 LVITEMW lvItem;
346 INT iItem = 0;
347
348 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
349 InitializeFileTypesListCtrlColumns(hDlgCtrl);
350
351 szFile[0] = 0;
352 if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile)))
353 {
354 /* default to english */
355 wcscpy(szFile, L"%s File");
356 }
357 szFile[(_countof(szFile)) - 1] = 0;
358
359 dwName = _countof(szName);
360
361 while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
362 {
363 InsertFileType(hDlgCtrl, szName, &iItem, szFile);
364 dwName = _countof(szName);
365 }
366
367 /* Leave if the list is empty */
368 if (iItem == 0)
369 return NULL;
370
371 /* sort list */
372 ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL);
373
374 /* select first item */
375 ZeroMemory(&lvItem, sizeof(LVITEMW));
376 lvItem.mask = LVIF_STATE;
377 lvItem.stateMask = (UINT)-1;
378 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
379 lvItem.iItem = 0;
380 ListView_SetItem(hDlgCtrl, &lvItem);
381
382 lvItem.mask = LVIF_PARAM;
383 ListView_GetItem(hDlgCtrl, &lvItem);
384
385 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
386 }
387
388 static
389 PFOLDER_FILE_TYPE_ENTRY
390 FindSelectedItem(
391 HWND hDlgCtrl)
392 {
393 UINT Count, Index;
394 LVITEMW lvItem;
395
396 Count = ListView_GetItemCount(hDlgCtrl);
397
398 for (Index = 0; Index < Count; Index++)
399 {
400 ZeroMemory(&lvItem, sizeof(LVITEM));
401 lvItem.mask = LVIF_PARAM | LVIF_STATE;
402 lvItem.iItem = Index;
403 lvItem.stateMask = (UINT) - 1;
404
405 if (ListView_GetItem(hDlgCtrl, &lvItem))
406 {
407 if (lvItem.state & LVIS_SELECTED)
408 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
409 }
410 }
411
412 return NULL;
413 }
414
415 INT_PTR
416 CALLBACK
417 FolderOptionsFileTypesDlg(
418 HWND hwndDlg,
419 UINT uMsg,
420 WPARAM wParam,
421 LPARAM lParam)
422 {
423 LPNMLISTVIEW lppl;
424 LVITEMW lvItem;
425 WCHAR Buffer[255], FormatBuffer[255];
426 PFOLDER_FILE_TYPE_ENTRY pItem;
427 OPENASINFO Info;
428
429 switch(uMsg)
430 {
431 case WM_INITDIALOG:
432 pItem = InitializeFileTypesListCtrl(hwndDlg);
433
434 /* Disable the Delete button if the listview is empty or
435 the selected item should not be deleted by the user */
436 if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove
437 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
438 return TRUE;
439
440 case WM_COMMAND:
441 switch(LOWORD(wParam))
442 {
443 case 14006:
444 pItem = FindSelectedItem(GetDlgItem(hwndDlg, 14000));
445 if (pItem)
446 {
447 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
448 Info.pcszClass = pItem->FileExtension;
449 SHOpenWithDialog(hwndDlg, &Info);
450 }
451 break;
452 }
453 break;
454
455 case WM_NOTIFY:
456 lppl = (LPNMLISTVIEW) lParam;
457
458 if (lppl->hdr.code == LVN_ITEMCHANGING)
459 {
460 ZeroMemory(&lvItem, sizeof(LVITEM));
461 lvItem.mask = LVIF_PARAM;
462 lvItem.iItem = lppl->iItem;
463 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem))
464 return TRUE;
465
466 pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
467 if (!pItem)
468 return TRUE;
469
470 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
471 {
472 /* new focused item */
473 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
474 {
475 /* use default english format string */
476 wcscpy(FormatBuffer, L"Details for '%s' extension");
477 }
478
479 /* format buffer */
480 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]);
481 /* update dialog */
482 SetDlgItemTextW(hwndDlg, 14003, Buffer);
483
484 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
485 {
486 /* use default english format string */
487 wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced.");
488 }
489 /* format buffer */
490 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]);
491 /* update dialog */
492 SetDlgItemTextW(hwndDlg, 14007, Buffer);
493
494 /* Enable the Delete button */
495 if (pItem->EditFlags & 0x00000010) // FTA_NoRemove
496 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
497 else
498 EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
499 }
500 }
501 else if (lppl->hdr.code == PSN_SETACTIVE)
502 {
503 /* On page activation, set the focus to the listview */
504 SetFocus(GetDlgItem(hwndDlg, 14000));
505 }
506 break;
507 }
508
509 return FALSE;
510 }
511
512 static
513 VOID
514 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst)
515 {
516 PROPSHEETHEADERW pinfo;
517 HPROPSHEETPAGE hppages[3];
518 HPROPSHEETPAGE hpage;
519 UINT num_pages = 0;
520 WCHAR szOptions[100];
521
522 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL);
523 if (hpage)
524 hppages[num_pages++] = hpage;
525
526 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL);
527 if (hpage)
528 hppages[num_pages++] = hpage;
529
530 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL);
531 if (hpage)
532 hppages[num_pages++] = hpage;
533
534 szOptions[0] = L'\0';
535 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR));
536 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0';
537
538 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
539 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
540 pinfo.dwFlags = PSH_NOCONTEXTHELP;
541 pinfo.nPages = num_pages;
542 pinfo.phpage = hppages;
543 pinfo.pszCaption = szOptions;
544
545 PropertySheetW(&pinfo);
546 }
547
548 static
549 VOID
550 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
551 {
552 switch(fOptions)
553 {
554 case 0:
555 ShowFolderOptionsDialog(hWnd, hInst);
556 break;
557 case 1:
558 // show taskbar options dialog
559 FIXME("notify explorer to show taskbar options dialog");
560 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0);
561 break;
562 default:
563 FIXME("unrecognized options id %d\n", fOptions);
564 }
565 }
566
567 /*************************************************************************
568 * Options_RunDLL (SHELL32.@)
569 */
570 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
571 {
572 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
573 }
574
575 /*************************************************************************
576 * Options_RunDLLA (SHELL32.@)
577 */
578 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
579 {
580 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
581 }
582
583 /*************************************************************************
584 * Options_RunDLLW (SHELL32.@)
585 */
586 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
587 {
588 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
589 }