[SHELL32]
[reactos.git] / dll / win32 / shell32 / 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 } FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY;
41
42 typedef struct
43 {
44 LPCWSTR szKeyName;
45 UINT ResourceID;
46 } FOLDER_VIEW_ENTRY, PFOLDER_VIEW_ENTRY;
47 /*
48 static FOLDER_VIEW_ENTRY s_Options[] =
49 {
50 { L"AlwaysShowMenus", IDS_ALWAYSSHOWMENUS },
51 { L"AutoCheckSelect", -1 },
52 { L"ClassicViewState", -1 },
53 { L"DontPrettyPath", -1 },
54 { L"Filter", -1 },
55 { L"FolderContentsInfoTip", IDS_FOLDERCONTENTSTIP },
56 { L"FriendlyTree", -1 },
57 { L"Hidden", -1, },
58 { L"HideFileExt", IDS_HIDEFILEEXT },
59 { L"HideIcons", -1},
60 { L"IconsOnly", -1},
61 { L"ListviewAlphaSelect", -1},
62 { L"ListviewShadow", -1},
63 { L"ListviewWatermark", -1},
64 { L"MapNetDrvBtn", -1},
65 { L"PersistBrowsers", -1},
66 { L"SeperateProcess", IDS_SEPERATEPROCESS},
67 { L"ServerAdminUI", -1},
68 { L"SharingWizardOn", IDS_USESHAREWIZARD},
69 { L"ShowCompColor", IDS_COMPCOLOR},
70 { L"ShowInfoTip", IDS_SHOWINFOTIP},
71 { L"ShowPreviewHandlers", -1},
72 { L"ShowSuperHidden", IDS_HIDEOSFILES},
73 { L"ShowTypeOverlay", -1},
74 { L"Start_ShowMyGames", -1},
75 { L"StartMenuInit", -1},
76 { L"SuperHidden", -1},
77 { L"TypeAhead", -1},
78 { L"Webview", -1},
79 { NULL, -1}
80
81 };
82 */
83
84 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
85
86 static
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 static
128 INT_PTR
129 CALLBACK
130 FolderOptionsViewDlg(
131 HWND hwndDlg,
132 UINT uMsg,
133 WPARAM wParam,
134 LPARAM lParam
135 )
136 {
137 switch(uMsg)
138 {
139 case WM_INITDIALOG:
140 InitializeFolderOptionsListCtrl(hwndDlg);
141 return TRUE;
142 }
143
144 return FALSE;
145
146 }
147
148 static
149 VOID
150 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl)
151 {
152 RECT clientRect;
153 LVCOLUMNW col;
154 WCHAR szName[50];
155 DWORD dwStyle;
156 int columnSize = 140;
157
158
159 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
160 {
161 /* default to english */
162 wcscpy(szName, L"Extensions");
163 }
164
165 /* make sure its null terminated */
166 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
167
168 GetClientRect(hDlgCtrl, &clientRect);
169 ZeroMemory(&col, sizeof(LV_COLUMN));
170 columnSize = 140; //FIXME
171 col.iSubItem = 0;
172 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
173 col.fmt = LVCFMT_FIXED_WIDTH;
174 col.cx = columnSize | LVCFMT_LEFT;
175 col.cchTextMax = wcslen(szName);
176 col.pszText = szName;
177 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col);
178
179 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR)))
180 {
181 /* default to english */
182 wcscpy(szName, L"FileTypes");
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
217 if (szName[0] != L'.')
218 {
219 /* FIXME handle URL protocol handlers */
220 return;
221 }
222
223 /* allocate file type entry */
224 Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY));
225
226 if (!Entry)
227 return;
228
229 /* open key */
230 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
231 {
232 HeapFree(GetProcessHeap(), 0, Entry);
233 return;
234 }
235
236 /* FIXME check for duplicates */
237
238 /* query for the default key */
239 dwSize = sizeof(Entry->ClassKey);
240 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS)
241 {
242 /* no link available */
243 Entry->ClassKey[0] = 0;
244 }
245
246 if (Entry->ClassKey[0])
247 {
248 HKEY hTemp;
249 /* try open linked key */
250 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS)
251 {
252 /* use linked key */
253 RegCloseKey(hKey);
254 hKey = hTemp;
255 }
256 }
257
258 /* read friendly type name */
259 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS)
260 {
261 /* read file description */
262 dwSize = sizeof(Entry->FileDescription);
263 Entry->FileDescription[0] = 0;
264
265 /* read default key */
266 RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize);
267 }
268
269 /* close key */
270 RegCloseKey(hKey);
271
272 /* convert extension to upper case */
273 wcscpy(Entry->FileExtension, szName);
274 _wcsupr(Entry->FileExtension);
275
276 if (!Entry->FileDescription[0])
277 {
278 /* construct default 'FileExtensionFile' */
279 wcscpy(Entry->FileDescription, &Entry->FileExtension[1]);
280 wcscat(Entry->FileDescription, L" ");
281 wcscat(Entry->FileDescription, szFile);
282 }
283
284 ZeroMemory(&lvItem, sizeof(LVITEMW));
285 lvItem.mask = LVIF_TEXT | LVIF_PARAM;
286 lvItem.iSubItem = 0;
287 lvItem.pszText = &Entry->FileExtension[1];
288 lvItem.iItem = *iItem;
289 lvItem.lParam = (LPARAM)Entry;
290 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem);
291
292 ZeroMemory(&lvItem, sizeof(LVITEMW));
293 lvItem.mask = LVIF_TEXT;
294 lvItem.pszText = Entry->FileDescription;
295 lvItem.iItem = *iItem;
296 lvItem.iSubItem = 1;
297
298 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&lvItem);
299 (*iItem)++;
300 }
301
302 static
303 int
304 CALLBACK
305 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
306 {
307 PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2;
308
309 Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1;
310 Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2;
311
312 return wcsicmp(Entry1->FileExtension, Entry2->FileExtension);
313 }
314
315 static
316 BOOL
317 InitializeFileTypesListCtrl(HWND hwndDlg)
318 {
319 HWND hDlgCtrl;
320 DWORD dwIndex = 0;
321 WCHAR szName[50];
322 WCHAR szFile[100];
323 DWORD dwName;
324 LVITEMW lvItem;
325 INT iItem = 0;
326
327 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
328 InitializeFileTypesListCtrlColumns(hDlgCtrl);
329
330 szFile[0] = 0;
331 if (!LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, szFile, sizeof(szFile) / sizeof(WCHAR)))
332 {
333 /* default to english */
334 wcscpy(szFile, L"File");
335 }
336 szFile[(sizeof(szFile)/sizeof(WCHAR))-1] = 0;
337
338 dwName = sizeof(szName) / sizeof(WCHAR);
339
340 while(RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
341 {
342 InsertFileType(hDlgCtrl, szName, &iItem, szFile);
343 dwName = sizeof(szName) / sizeof(WCHAR);
344 }
345
346 /* sort list */
347 ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL);
348
349 /* select first item */
350 ZeroMemory(&lvItem, sizeof(LVITEMW));
351 lvItem.mask = LVIF_STATE;
352 lvItem.stateMask = (UINT) - 1;
353 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED;
354 lvItem.iItem = 0;
355 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&lvItem);
356
357 return TRUE;
358 }
359
360 static
361 PFOLDER_FILE_TYPE_ENTRY
362 FindSelectedItem(
363 HWND hDlgCtrl)
364 {
365 UINT Count, Index;
366 LVITEMW lvItem;
367
368 Count = ListView_GetItemCount(hDlgCtrl);
369
370 for (Index = 0; Index < Count; Index++)
371 {
372 ZeroMemory(&lvItem, sizeof(LVITEM));
373 lvItem.mask = LVIF_PARAM | LVIF_STATE;
374 lvItem.iItem = Index;
375 lvItem.stateMask = (UINT) - 1;
376
377 if (ListView_GetItem(hDlgCtrl, &lvItem))
378 {
379 if (lvItem.state & LVIS_SELECTED)
380 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
381 }
382 }
383
384 return NULL;
385 }
386
387 static
388 INT_PTR
389 CALLBACK
390 FolderOptionsFileTypesDlg(
391 HWND hwndDlg,
392 UINT uMsg,
393 WPARAM wParam,
394 LPARAM lParam
395 )
396 {
397 LPNMLISTVIEW lppl;
398 LVITEMW lvItem;
399 WCHAR Buffer[255], FormatBuffer[255];
400 PFOLDER_FILE_TYPE_ENTRY pItem;
401 OPENASINFO Info;
402
403 switch(uMsg)
404 {
405 case WM_INITDIALOG:
406 InitializeFileTypesListCtrl(hwndDlg);
407 return TRUE;
408 case WM_COMMAND:
409 switch(LOWORD(wParam))
410 {
411 case 14006:
412 pItem = FindSelectedItem(GetDlgItem(hwndDlg, 14000));
413 if (pItem)
414 {
415 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT;
416 Info.pcszClass = pItem->FileExtension;
417 SHOpenWithDialog(hwndDlg, &Info);
418 }
419 break;
420 }
421
422 break;
423 case WM_NOTIFY:
424 lppl = (LPNMLISTVIEW) lParam;
425
426 if (lppl->hdr.code == LVN_ITEMCHANGING)
427 {
428 ZeroMemory(&lvItem, sizeof(LVITEM));
429 lvItem.mask = LVIF_PARAM;
430 lvItem.iItem = lppl->iItem;
431 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem))
432 return TRUE;
433
434 pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam;
435 if (!pItem)
436 return TRUE;
437
438 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
439 {
440 /* new focused item */
441 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
442 {
443 /* use default english format string */
444 wcscpy(FormatBuffer, L"Details for '%s' extension");
445 }
446
447 /* format buffer */
448 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]);
449 /* update dialog */
450 SetDlgItemTextW(hwndDlg, 14003, Buffer);
451
452 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR)))
453 {
454 /* use default english format string */
455 wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced.");
456 }
457 /* format buffer */
458 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]);
459 /* update dialog */
460 SetDlgItemTextW(hwndDlg, 14007, Buffer);
461 }
462 }
463 break;
464 }
465
466 return FALSE;
467 }
468
469 static
470 VOID
471 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst)
472 {
473 PROPSHEETHEADERW pinfo;
474 HPROPSHEETPAGE hppages[3];
475 HPROPSHEETPAGE hpage;
476 UINT num_pages = 0;
477 WCHAR szOptions[100];
478
479 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL);
480 if (hpage)
481 hppages[num_pages++] = hpage;
482
483 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL);
484 if (hpage)
485 hppages[num_pages++] = hpage;
486
487 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL);
488 if (hpage)
489 hppages[num_pages++] = hpage;
490
491 szOptions[0] = L'\0';
492 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR));
493 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0';
494
495 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
496 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
497 pinfo.dwFlags = PSH_NOCONTEXTHELP;
498 pinfo.nPages = num_pages;
499 pinfo.phpage = hppages;
500 pinfo.pszCaption = szOptions;
501
502 PropertySheetW(&pinfo);
503 }
504
505 static
506 VOID
507 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
508 {
509 switch(fOptions)
510 {
511 case 0:
512 ShowFolderOptionsDialog(hWnd, hInst);
513 break;
514 case 1:
515 // show taskbar options dialog
516 FIXME("notify explorer to show taskbar options dialog");
517 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0);
518 break;
519 default:
520 FIXME("unrecognized options id %d\n", fOptions);
521 }
522 }
523
524 /*************************************************************************
525 * Options_RunDLL (SHELL32.@)
526 */
527 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
528 {
529 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
530 }
531
532 /*************************************************************************
533 * Options_RunDLLA (SHELL32.@)
534 */
535 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
536 {
537 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
538 }
539
540 /*************************************************************************
541 * Options_RunDLLW (SHELL32.@)
542 */
543 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
544 {
545 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
546 }