- Implement ProtocolResetComplete
[reactos.git] / dll / win32 / shell32 / folder_options.c
1 /*
2 * Open With Context Menu extension
3 *
4 * Copyright 2007 Johannes Anderwald <janderwald@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 <string.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "winerror.h"
27 #include "wine/debug.h"
28
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "pidl.h"
32 #include "undocshell.h"
33 #include "shlobj.h"
34 #include "objbase.h"
35 #include "commdlg.h"
36
37 #include "shell32_main.h"
38 #include "shellfolder.h"
39 #include "shresdef.h"
40 #include "stdio.h"
41 #include "shlwapi.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL (fprop);
44 #define MAX_PROPERTY_SHEET_PAGE (32)
45
46 /// Folder Options:
47 /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}
48 /// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210
49 /// Verbs: Open / RunAs
50 /// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0
51
52 /// ShellFolder Attributes: 0x0
53
54 typedef struct
55 {
56 DWORD cFiles;
57 DWORD cFolder;
58 LARGE_INTEGER bSize;
59 HWND hwndDlg;
60 WCHAR szFolderPath[MAX_PATH];
61 }FOLDER_PROPERTIES_CONTEXT, *PFOLDER_PROPERTIES_CONTEXT;
62
63
64 INT_PTR
65 CALLBACK
66 FolderOptionsGeneralDlg(
67 HWND hwndDlg,
68 UINT uMsg,
69 WPARAM wParam,
70 LPARAM lParam
71 )
72 {
73
74
75
76 return FALSE;
77 }
78
79 INT_PTR
80 CALLBACK
81 FolderOptionsViewDlg(
82 HWND hwndDlg,
83 UINT uMsg,
84 WPARAM wParam,
85 LPARAM lParam
86 )
87 {
88
89
90
91 return FALSE;
92 }
93
94 VOID
95 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl)
96 {
97 RECT clientRect;
98 LVCOLUMNW col;
99 WCHAR szName[50];
100
101 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR)))
102 szName[0] = 0;
103 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0;
104
105 GetClientRect(hDlgCtrl, &clientRect);
106 ZeroMemory(&col, sizeof(LV_COLUMN));
107 col.mask = LVCF_SUBITEM | LVCF_WIDTH | LVCF_FMT;
108 col.iSubItem = 0;
109 col.pszText = szName;
110 col.fmt = LVCFMT_LEFT;
111 col.cx = (clientRect.right - clientRect.left) - GetSystemMetrics(SM_CXVSCROLL);
112 (void)ListView_InsertColumnW(hDlgCtrl, 0, &col);
113 }
114 INT
115 FindItem(HWND hDlgCtrl, WCHAR * ItemName)
116 {
117 LVFINDINFOW findInfo;
118 ZeroMemory(&findInfo, sizeof(LVFINDINFOW));
119
120 findInfo.flags = LVFI_STRING;
121 findInfo.psz = ItemName;
122 return ListView_FindItem(hDlgCtrl, 0, &findInfo);
123 }
124
125 VOID
126 InsertFileType(HWND hDlgCtrl, WCHAR * szName, DWORD Size, INT iItem)
127 {
128 WCHAR szPath[100];
129 HKEY hKey;
130 LVITEMW lvItem;
131 DWORD dwSize;
132
133 if (FindItem(hDlgCtrl, szName) != -1)
134 return;
135
136 wcscpy(szPath, szName);
137 /* get the name */
138 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
139 {
140 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", szName, Size, NULL, 0, NULL) != ERROR_SUCCESS)
141 {
142 dwSize = Size;
143 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)szName, &dwSize) != ERROR_SUCCESS)
144 {
145 wcscpy(szName, szPath);
146 }
147 }
148 RegCloseKey(hKey);
149 szName[(Size/sizeof(WCHAR))-1] = 0;
150 }
151 wcscat(szPath, L"\\shell");
152
153 ZeroMemory(&lvItem, sizeof(LVITEMW));
154 lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
155 lvItem.state = LVIS_SELECTED;
156 lvItem.pszText = szName;
157 lvItem.iItem = iItem;
158
159 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
160 {
161 lvItem.lParam = 0;
162 (void)ListView_InsertItemW(hDlgCtrl, &lvItem);
163 RegCloseKey(hKey);
164 }
165 }
166
167 BOOL
168 InitializeFileTypesListCtrl(HWND hwndDlg)
169 {
170 HWND hDlgCtrl;
171 DWORD dwIndex = 0;
172 WCHAR szName[50];
173 DWORD dwName;
174 INT iItem = 0;
175
176
177 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
178 InitializeFileTypesListCtrlColumns(hDlgCtrl);
179
180
181
182 dwName = sizeof(szName) / sizeof(WCHAR);
183
184 while(RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
185 {
186 InsertFileType(hDlgCtrl, szName, sizeof(szName), iItem++);
187 dwName = sizeof(szName) / sizeof(WCHAR);
188 }
189 return TRUE;
190 }
191
192
193 INT_PTR
194 CALLBACK
195 FolderOptionsFileTypesDlg(
196 HWND hwndDlg,
197 UINT uMsg,
198 WPARAM wParam,
199 LPARAM lParam
200 )
201 {
202 switch(uMsg)
203 {
204 case WM_INITDIALOG:
205 InitializeFileTypesListCtrl(hwndDlg);
206 return TRUE;
207 }
208
209
210 return FALSE;
211 }
212
213
214 VOID
215 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst)
216 {
217 PROPSHEETHEADERW pinfo;
218 HPROPSHEETPAGE hppages[3];
219 HPROPSHEETPAGE hpage;
220 UINT num_pages = 0;
221 WCHAR szOptions[100];
222
223 hpage = SH_CreatePropertySheetPage("FOLDER_OPTIONS_GENERAL_DLG", FolderOptionsGeneralDlg, 0, NULL);
224 if (hpage)
225 hppages[num_pages++] = hpage;
226
227 hpage = SH_CreatePropertySheetPage("FOLDER_OPTIONS_VIEW_DLG", FolderOptionsViewDlg, 0, NULL);
228 if (hpage)
229 hppages[num_pages++] = hpage;
230
231 hpage = SH_CreatePropertySheetPage("FOLDER_OPTIONS_FILETYPES_DLG", FolderOptionsFileTypesDlg, 0, NULL);
232 if (hpage)
233 hppages[num_pages++] = hpage;
234
235 szOptions[0] = L'\0';
236 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR));
237 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0';
238
239 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
240 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
241 pinfo.dwFlags = PSH_NOCONTEXTHELP;
242 pinfo.nPages = num_pages;
243 pinfo.u3.phpage = hppages;
244 pinfo.pszCaption = szOptions;
245
246 PropertySheetW(&pinfo);
247 }
248
249 VOID
250 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow)
251 {
252 switch(fOptions)
253 {
254 case 0:
255 ShowFolderOptionsDialog(hWnd, hInst);
256 break;
257 case 1:
258 // show taskbar options dialog
259 FIXME("notify explorer to show taskbar options dialog");
260 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0);
261 break;
262 default:
263 FIXME("unrecognized options id %d\n", fOptions);
264 }
265 }
266
267 /*************************************************************************
268 * Options_RunDLL (SHELL32.@)
269 */
270 VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
271 {
272 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
273 }
274 /*************************************************************************
275 * Options_RunDLLA (SHELL32.@)
276 */
277 VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow)
278 {
279 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow);
280 }
281
282 /*************************************************************************
283 * Options_RunDLLW (SHELL32.@)
284 */
285 VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow)
286 {
287 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow);
288 }
289
290 static
291 DWORD WINAPI
292 CountFolderAndFiles(LPVOID lParam)
293 {
294 WIN32_FIND_DATAW FindData;
295 HANDLE hFile;
296 UINT Length;
297 LPWSTR pOffset;
298 BOOL ret;
299 PFOLDER_PROPERTIES_CONTEXT pContext = (PFOLDER_PROPERTIES_CONTEXT) lParam;
300
301 pOffset = PathAddBackslashW(pContext->szFolderPath);
302 if (!pOffset)
303 return 0;
304
305 Length = pOffset - pContext->szFolderPath;
306
307 wcscpy(pOffset, L"*.*");
308 hFile = FindFirstFileW(pContext->szFolderPath, &FindData);
309 if (hFile == INVALID_HANDLE_VALUE)
310 return 0;
311
312 do
313 {
314 ret = FindNextFileW(hFile, &FindData);
315 if (ret)
316 {
317 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
318 {
319 if (FindData.cFileName[0] == L'.' && FindData.cFileName[1] == L'.' &&
320 FindData.cFileName[2] == L'\0')
321 continue;
322
323 pContext->cFolder++;
324 wcscpy(pOffset, FindData.cFileName);
325 CountFolderAndFiles((LPVOID)pContext);
326 pOffset[0] = L'\0';
327 }
328 else
329 {
330 pContext->cFiles++;
331 pContext->bSize.u.LowPart += FindData.nFileSizeLow;
332 pContext->bSize.u.HighPart += FindData.nFileSizeHigh;
333 }
334 }
335 else if (GetLastError() == ERROR_NO_MORE_FILES)
336 {
337 break;
338 }
339 }while(1);
340
341 FindClose(hFile);
342 return 1;
343 }
344
345 static
346 VOID
347 InitializeFolderGeneralDlg(PFOLDER_PROPERTIES_CONTEXT pContext)
348 {
349 LPWSTR pFolderName;
350 WIN32_FILE_ATTRIBUTE_DATA FolderAttribute;
351 FILETIME ft;
352 SYSTEMTIME dt;
353 WCHAR szBuffer[MAX_PATH+5];
354 WCHAR szFormat[30] = {0};
355
356 static const WCHAR wFormat[] = {'%','0','2','d','/','%','0','2','d','/','%','0','4','d',' ',' ','%','0','2','d',':','%','0','2','u',0};
357
358 pFolderName = wcsrchr(pContext->szFolderPath, L'\\');
359 if (!pFolderName)
360 return;
361
362 /* set folder name */
363 SendDlgItemMessageW(pContext->hwndDlg, 14001, WM_SETTEXT, 0, (LPARAM) (pFolderName + 1));
364 /* set folder location */
365 pFolderName[0] = L'\0';
366 if (wcslen(pContext->szFolderPath) == 2)
367 {
368 /* folder is located at root */
369 WCHAR szDrive[4] = {L'C',L':',L'\\',L'\0'};
370 szDrive[0] = pContext->szFolderPath[0];
371 SendDlgItemMessageW(pContext->hwndDlg, 14007, WM_SETTEXT, 0, (LPARAM) szDrive);
372 }
373 else
374 {
375 SendDlgItemMessageW(pContext->hwndDlg, 14007, WM_SETTEXT, 0, (LPARAM) pContext->szFolderPath);
376 }
377 pFolderName[0] = L'\\';
378 /* get folder properties */
379 if (GetFileAttributesExW(pContext->szFolderPath, GetFileExInfoStandard, (LPVOID)&FolderAttribute))
380 {
381 if (FolderAttribute.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
382 {
383 /* check readonly button */
384 SendDlgItemMessage(pContext->hwndDlg, 14021, BM_SETCHECK, BST_CHECKED, 0);
385 }
386
387 if (FolderAttribute.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
388 {
389 /* check hidden button */
390 SendDlgItemMessage(pContext->hwndDlg, 14022, BM_SETCHECK, BST_CHECKED, 0);
391 }
392
393 if (FileTimeToLocalFileTime(&FolderAttribute.ftCreationTime, &ft))
394 {
395 FileTimeToSystemTime(&ft, &dt);
396 sprintfW (szBuffer, wFormat, dt.wDay, dt.wMonth, dt.wYear, dt.wHour, dt.wMinute);
397 SendDlgItemMessageW(pContext->hwndDlg, 14015, WM_SETTEXT, 0, (LPARAM) szBuffer);
398 }
399 }
400 /* now enumerate enumerate contents */
401 wcscpy(szBuffer, pContext->szFolderPath);
402 CountFolderAndFiles((LPVOID)pContext);
403 wcscpy(pContext->szFolderPath, szBuffer);
404 /* set folder details */
405 LoadStringW(shell32_hInstance, IDS_FILE_FOLDER, szFormat, sizeof(szFormat)/sizeof(WCHAR));
406 szFormat[(sizeof(szFormat)/sizeof(WCHAR))-1] = L'\0';
407 sprintfW(szBuffer, szFormat, pContext->cFiles, pContext->cFolder);
408 SendDlgItemMessageW(pContext->hwndDlg, 14011, WM_SETTEXT, 0, (LPARAM) szBuffer);
409
410 if (StrFormatByteSizeW(pContext->bSize.QuadPart, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
411 {
412 /* store folder size */
413 SendDlgItemMessageW(pContext->hwndDlg, 14009, WM_SETTEXT, 0, (LPARAM) szBuffer);
414 }
415 }
416
417
418 INT_PTR
419 CALLBACK
420 FolderPropertiesGeneralDlg(
421 HWND hwndDlg,
422 UINT uMsg,
423 WPARAM wParam,
424 LPARAM lParam
425 )
426 {
427 LPPROPSHEETPAGEW ppsp;
428 PFOLDER_PROPERTIES_CONTEXT pContext;
429 HICON hIcon;
430 WIN32_FILE_ATTRIBUTE_DATA FolderAttribute;
431 LONG res;
432 LPPSHNOTIFY lppsn;
433 DWORD Attribute;
434
435 switch(uMsg)
436 {
437 case WM_INITDIALOG:
438 ppsp = (LPPROPSHEETPAGEW)lParam;
439 if (ppsp == NULL)
440 break;
441 hIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPEN));
442 if (hIcon)
443 SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)hIcon, 0);
444
445 pContext = SHAlloc(sizeof(FOLDER_PROPERTIES_CONTEXT));
446 if (pContext)
447 {
448 ZeroMemory(pContext, sizeof(FOLDER_PROPERTIES_CONTEXT));
449 pContext->hwndDlg = hwndDlg;
450 wcscpy(pContext->szFolderPath, (LPWSTR)ppsp->lParam);
451 SetWindowLongPtr(hwndDlg, DWL_USER, (LONG_PTR)pContext);
452 InitializeFolderGeneralDlg(pContext);
453 }
454 return TRUE;
455 case WM_COMMAND:
456 if (HIWORD(wParam) == BN_CLICKED)
457 {
458 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
459 }
460 break;
461 case WM_DESTROY:
462 pContext = (PFOLDER_PROPERTIES_CONTEXT)GetWindowLong(hwndDlg, DWL_USER);
463 SHFree((LPVOID)pContext);
464 break;
465 case WM_NOTIFY:
466 pContext = (PFOLDER_PROPERTIES_CONTEXT)GetWindowLong(hwndDlg, DWL_USER);
467 lppsn = (LPPSHNOTIFY) lParam;
468 if (lppsn->hdr.code == PSN_APPLY)
469 {
470 if (GetFileAttributesExW(pContext->szFolderPath, GetFileExInfoStandard, (LPVOID)&FolderAttribute))
471 {
472 res = SendDlgItemMessageW(hwndDlg, 14021, BM_GETCHECK, 0, 0);
473 if (res == BST_CHECKED)
474 FolderAttribute.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
475 else
476 FolderAttribute.dwFileAttributes &= (~FILE_ATTRIBUTE_READONLY);
477
478 res = SendDlgItemMessageW(hwndDlg, 14022, BM_GETCHECK, 0, 0);
479 if (res == BST_CHECKED)
480 FolderAttribute.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
481 else
482 FolderAttribute.dwFileAttributes &= (~FILE_ATTRIBUTE_HIDDEN);
483
484 Attribute = FolderAttribute.dwFileAttributes &
485 (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY);
486
487 SetFileAttributesW(pContext->szFolderPath, Attribute);
488 }
489 SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
490 return TRUE;
491 }
492 break;
493 }
494 return FALSE;
495 }
496
497 static
498 BOOL
499 CALLBACK
500 FolderAddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam)
501 {
502 PROPSHEETHEADERW *ppsh = (PROPSHEETHEADERW *)lParam;
503 if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE)
504 {
505 ppsh->u3.phpage[ppsh->nPages++] = hpage;
506 return TRUE;
507 }
508 return FALSE;
509 }
510
511 BOOL
512 SH_ShowFolderProperties(LPWSTR pwszFolder)
513 {
514 HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE];
515 HPROPSHEETPAGE hpage;
516 PROPSHEETHEADERW psh;
517 BOOL ret;
518 WCHAR szName[MAX_PATH] = {0};
519 HPSXA hpsx;
520 LPWSTR pFolderName;
521
522 if (!PathIsDirectoryW(pwszFolder))
523 return FALSE;
524
525 pFolderName = wcsrchr(pwszFolder, L'\\');
526 if (!pFolderName)
527 return FALSE;
528
529 wcscpy(szName, pFolderName + 1);
530
531 hpage = SH_CreatePropertySheetPage("SHELL_FOLDER_GENERAL_DLG", FolderPropertiesGeneralDlg, (LPARAM)pwszFolder, NULL);
532 if (!hpage)
533 return FALSE;
534
535 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
536 hppages[psh.nPages] = hpage;
537 psh.nPages++;
538 psh.dwSize = sizeof(PROPSHEETHEADERW);
539 psh.dwFlags = PSH_PROPTITLE;
540 psh.hwndParent = NULL;
541 psh.u3.phpage = hppages;
542 psh.pszCaption = szName;
543
544 hpsx = SHCreatePropSheetExtArray(HKEY_CLASSES_ROOT,
545 L"Folder",
546 MAX_PROPERTY_SHEET_PAGE-1);
547
548 SHAddFromPropSheetExtArray(hpsx,
549 (LPFNADDPROPSHEETPAGE)FolderAddPropSheetPageProc,
550 (LPARAM)&psh);
551
552 ret = PropertySheetW(&psh);
553 if (ret < 0)
554 return FALSE;
555 else
556 return TRUE;
557 }
558
559