28b09a073560acb0bd5f902c28d847b009025fbf
[reactos.git] / reactos / dll / win32 / shell32 / fprop.c
1 /*
2 * Shell Library Functions
3 *
4 * Copyright 2005 Johannes Anderwald
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <precomp.h>
22
23 WINE_DEFAULT_DEBUG_CHANNEL(shell);
24
25 #define MAX_PROPERTY_SHEET_PAGE 32
26
27 typedef struct _LANGANDCODEPAGE_
28 {
29 WORD lang;
30 WORD code;
31 } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
32
33 HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj);
34
35 /*************************************************************************
36 *
37 * SH_CreatePropertySheetPage [Internal]
38 *
39 * creates a property sheet page from an resource name
40 *
41 */
42
43 HPROPSHEETPAGE
44 SH_CreatePropertySheetPage(LPSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle)
45 {
46 HRSRC hRes;
47 LPVOID lpsztemplate;
48 PROPSHEETPAGEW ppage;
49
50 if (resname == NULL)
51 return (HPROPSHEETPAGE)0;
52
53 hRes = FindResourceA(shell32_hInstance, resname, (LPSTR)RT_DIALOG);
54
55 if (hRes == NULL)
56 {
57 ERR("failed to find resource name\n");
58 return (HPROPSHEETPAGE)0;
59 }
60
61 lpsztemplate = LoadResource(shell32_hInstance, hRes);
62
63 if (lpsztemplate == NULL)
64 return (HPROPSHEETPAGE)0;
65
66 memset(&ppage, 0x0, sizeof(PROPSHEETPAGEW));
67 ppage.dwSize = sizeof(PROPSHEETPAGEW);
68 ppage.dwFlags = PSP_DLGINDIRECT;
69 ppage.u.pResource = lpsztemplate;
70 ppage.pfnDlgProc = dlgproc;
71 ppage.lParam = lParam;
72 ppage.pszTitle = szTitle;
73
74 if (szTitle)
75 {
76 ppage.dwFlags |= PSP_USETITLE;
77 }
78
79 return CreatePropertySheetPageW(&ppage);
80 }
81
82 /*************************************************************************
83 *
84 * SH_FileGeneralFileType [Internal]
85 *
86 * retrieves file extension description from registry and sets it in dialog
87 *
88 * TODO: retrieve file extension default icon and load it
89 * find executable name from registry, retrieve description from executable
90 */
91
92 BOOL
93 SH_FileGeneralSetFileType(HWND hwndDlg, WCHAR *filext)
94 {
95 WCHAR name[MAX_PATH];
96 WCHAR value[MAX_PATH];
97 DWORD lname = MAX_PATH;
98 DWORD lvalue = MAX_PATH;
99 HKEY hKey;
100 LONG result;
101 HWND hDlgCtrl;
102
103 TRACE("fileext %s\n", debugstr_w(filext));
104
105 if (filext == NULL)
106 return FALSE;
107
108 hDlgCtrl = GetDlgItem(hwndDlg, 14005);
109
110 if (hDlgCtrl == NULL)
111 return FALSE;
112
113 if (RegOpenKeyW(HKEY_CLASSES_ROOT, filext, &hKey) != ERROR_SUCCESS)
114 {
115 /* the file extension is unknown, so default to string "FileExtension File" */
116 SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)value);
117 swprintf(name, value, &filext[1]);
118 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)name);
119 return TRUE;
120 }
121
122 result = RegEnumValueW(hKey, 0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue);
123 RegCloseKey(hKey);
124
125 if (result != ERROR_SUCCESS)
126 return FALSE;
127
128 if (RegOpenKeyW(HKEY_CLASSES_ROOT, value, &hKey) == ERROR_SUCCESS)
129 {
130 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", value, MAX_PATH, NULL, 0, NULL) != ERROR_SUCCESS)
131 {
132 lvalue = lname = MAX_PATH;
133 result = RegEnumValueW(hKey, 0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue);
134 }
135
136 lname = MAX_PATH;
137
138 if (RegGetValueW(hKey, L"DefaultIcon", NULL, RRF_RT_REG_SZ, NULL, name, &lname) == ERROR_SUCCESS)
139 {
140 UINT IconIndex;
141 WCHAR szBuffer[MAX_PATH];
142 WCHAR *Offset;
143 HICON hIcon = 0;
144 HRSRC hResource;
145 LPVOID pResource = NULL;
146 HGLOBAL hGlobal;
147 HANDLE hLibrary;
148 Offset = wcsrchr(name, L',');
149
150 if (Offset)
151 {
152 IconIndex = _wtoi(Offset + 2);
153 *Offset = L'\0';
154 name[MAX_PATH - 1] = L'\0';
155
156 if (ExpandEnvironmentStringsW(name, szBuffer, MAX_PATH))
157 {
158 szBuffer[MAX_PATH - 1] = L'\0';
159 hLibrary = LoadLibraryExW(szBuffer, NULL, LOAD_LIBRARY_AS_DATAFILE);
160 if (hLibrary)
161 {
162 hResource = FindResourceW(hLibrary, MAKEINTRESOURCEW(IconIndex), (LPCWSTR)RT_ICON);
163 if (hResource)
164 {
165 hGlobal = LoadResource(shell32_hInstance, hResource);
166 if (hGlobal)
167 {
168 pResource = LockResource(hGlobal);
169 if (pResource != NULL)
170 {
171 hIcon = CreateIconFromResource(pResource, SizeofResource(shell32_hInstance, hResource), TRUE, 0x00030000);
172 TRACE("hIcon %p,- szBuffer %s IconIndex %u error %u icon %p hResource %p pResource %p\n",
173 hIcon,
174 debugstr_w(szBuffer),
175 IconIndex,
176 MAKEINTRESOURCEW(IconIndex),
177 hResource,
178 pResource);
179 SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)hIcon, 0);
180 }
181 }
182 }
183 FreeLibrary(hLibrary);
184 }
185 }
186 }
187 }
188 RegCloseKey(hKey);
189 }
190
191 /* file extension type */
192 value[MAX_PATH - 1] = L'\0';
193 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)value);
194
195 return TRUE;
196 }
197
198 /*************************************************************************
199 *
200 * SHFileGeneralGetFileTimeString [Internal]
201 *
202 * formats a given LPFILETIME struct into readable user format
203 */
204
205 BOOL
206 SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime, WCHAR *lpResult)
207 {
208 FILETIME ft;
209 SYSTEMTIME dt;
210 WORD wYear;
211 static const WCHAR wFormat[] = {
212 '%', '0', '2', 'd', '/', '%', '0', '2', 'd', '/', '%', '0', '4', 'd',
213 ' ', ' ', '%', '0', '2', 'd', ':', '%', '0', '2', 'u', 0 };
214
215 if (lpFileTime == NULL || lpResult == NULL)
216 return FALSE;
217
218 if (!FileTimeToLocalFileTime(lpFileTime, &ft))
219 return FALSE;
220
221 FileTimeToSystemTime(&ft, &dt);
222
223 wYear = dt.wYear;
224
225 /* ddmmyy */
226 swprintf(lpResult, wFormat, dt.wDay, dt.wMonth, wYear, dt.wHour, dt.wMinute);
227
228 TRACE("result %s\n", debugstr_w(lpResult));
229 return TRUE;
230 }
231
232 /*************************************************************************
233 *
234 * SH_FileGeneralSetText [Internal]
235 *
236 * sets file path string and filename string
237 *
238 */
239
240 BOOL
241 SH_FileGeneralSetText(HWND hwndDlg, WCHAR *lpstr)
242 {
243 int flength;
244 int plength;
245 WCHAR *lpdir;
246 WCHAR buff[MAX_PATH];
247 HWND hDlgCtrl;
248
249 if (lpstr == NULL)
250 return FALSE;
251
252 lpdir = wcschr(lpstr, '\\'); /* find the last occurence of '\\' */
253
254 plength = wcslen(lpstr);
255 flength = wcslen(lpdir);
256
257 if (lpdir)
258 {
259 /* location text field */
260 wcsncpy(buff, lpstr, plength - flength);
261 buff[plength - flength] = UNICODE_NULL;
262 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
263 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
264 }
265
266 if (flength > 1)
267 {
268 /* text filename field */
269 wcsncpy(buff, &lpdir[1], flength);
270 hDlgCtrl = GetDlgItem(hwndDlg, 14001);
271 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
272 }
273
274 return TRUE;
275 }
276
277 /*************************************************************************
278 *
279 * SH_FileGeneralSetFileSizeTime [Internal]
280 *
281 * retrieves file information from file and sets in dialog
282 *
283 */
284
285 BOOL
286 SH_FileGeneralSetFileSizeTime(HWND hwndDlg, WCHAR *lpfilename, PULARGE_INTEGER lpfilesize)
287 {
288 BOOL result;
289 HANDLE hFile;
290 FILETIME create_time;
291 FILETIME accessed_time;
292 FILETIME write_time;
293 WCHAR resultstr[MAX_PATH];
294 HWND hDlgCtrl;
295 LARGE_INTEGER file_size;
296
297 if (lpfilename == NULL)
298 return FALSE;
299
300 hFile = CreateFileW(lpfilename,
301 GENERIC_READ,
302 FILE_SHARE_READ,
303 NULL,
304 OPEN_EXISTING,
305 FILE_ATTRIBUTE_NORMAL,
306 NULL);
307
308 if (hFile == INVALID_HANDLE_VALUE)
309 {
310 WARN("failed to open file %s\n", debugstr_w(lpfilename));
311 return FALSE;
312 }
313
314 result = GetFileTime(hFile, &create_time, &accessed_time, &write_time);
315
316 if (!result)
317 {
318 WARN("GetFileTime failed\n");
319 return FALSE;
320 }
321
322 if (SHFileGeneralGetFileTimeString(&create_time, resultstr))
323 {
324 hDlgCtrl = GetDlgItem(hwndDlg, 14015);
325 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
326 }
327
328 if (SHFileGeneralGetFileTimeString(&accessed_time, resultstr))
329 {
330 hDlgCtrl = GetDlgItem(hwndDlg, 14017);
331 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
332 }
333
334 if (SHFileGeneralGetFileTimeString(&write_time, resultstr))
335 {
336 hDlgCtrl = GetDlgItem(hwndDlg, 14019);
337 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
338 }
339
340 if (!GetFileSizeEx(hFile, &file_size))
341 {
342 WARN("GetFileSize failed\n");
343 CloseHandle(hFile);
344 return FALSE;
345 }
346
347 CloseHandle(hFile);
348
349 if (!StrFormatByteSizeW(file_size.QuadPart,
350 resultstr,
351 sizeof(resultstr) / sizeof(WCHAR)))
352 return FALSE;
353
354 hDlgCtrl = GetDlgItem(hwndDlg, 14011);
355
356 TRACE("result size %u resultstr %s\n", file_size.QuadPart, debugstr_w(resultstr));
357 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
358
359 if (lpfilesize)
360 lpfilesize->QuadPart = (ULONGLONG)file_size.QuadPart;
361
362 return TRUE;
363 }
364
365 /*************************************************************************
366 *
367 * SH_SetFileVersionText [Internal]
368 *
369 *
370 */
371
372 BOOL
373 SH_FileVersionQuerySetText(HWND hwndDlg, DWORD dlgId, LPVOID pInfo, WCHAR *text, WCHAR **resptr)
374 {
375 UINT reslen;
376 HWND hDlgCtrl;
377
378 if (hwndDlg == NULL || resptr == NULL || text == NULL)
379 return FALSE;
380
381 if (VerQueryValueW(pInfo, text, (LPVOID *)resptr, &reslen))
382 {
383 /* file description property */
384 hDlgCtrl = GetDlgItem(hwndDlg, dlgId);
385 TRACE("%s :: %s\n", debugstr_w(text), debugstr_w(*resptr));
386 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)0, (LPARAM)*resptr);
387 return TRUE;
388 }
389
390 return FALSE;
391 }
392
393 /*************************************************************************
394 *
395 * SH_FileVersionQuerySetListText [Internal]
396 *
397 * retrieves a version string and adds it to listbox
398 *
399 */
400
401 BOOL
402 SH_FileVersionQuerySetListText(HWND hwndDlg, LPVOID pInfo, const WCHAR *text, WCHAR **resptr, WORD lang, WORD code)
403 {
404 UINT reslen;
405 HWND hDlgCtrl;
406 UINT index;
407 static const WCHAR wFormat[] = {
408 '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o',
409 '\\', '%', '0', '4', 'x', '%', '0', '4', 'x', '\\', '%', 's', 0 };
410 WCHAR buff[256];
411
412 TRACE("text %s, resptr %p hwndDlg %p\n", debugstr_w(text), resptr, hwndDlg);
413
414 if (hwndDlg == NULL || resptr == NULL || text == NULL)
415 return FALSE;
416
417 swprintf(buff, wFormat, lang, code, text);
418
419 if (VerQueryValueW(pInfo, buff, (LPVOID *)resptr, &reslen))
420 {
421 /* listbox name property */
422 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
423 TRACE("%s :: %s\n", debugstr_w(text), debugstr_w(*resptr));
424 index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)text);
425 SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)index, (LPARAM)(WCHAR *)*resptr);
426 return TRUE;
427 }
428
429 return FALSE;
430 }
431
432 /*************************************************************************
433 *
434 * SH_FileVersionInitialize [Internal]
435 *
436 * sets all file version properties in dialog
437 */
438
439 BOOL
440 SH_FileVersionInitialize(HWND hwndDlg, WCHAR *lpfilename)
441 {
442 LPVOID pBuf;
443 DWORD versize;
444 DWORD handle;
445 LPVOID info = NULL;
446 UINT infolen;
447 WCHAR buff[256];
448 HWND hDlgCtrl;
449 WORD lang = 0;
450 WORD code = 0;
451 LPLANGANDCODEPAGE lplangcode;
452 WCHAR *str;
453 static const WCHAR wVersionFormat[] = {
454 '%', 'd', '.', '%', 'd', '.', '%', 'd', '.', '%', 'd', 0 };
455 static const WCHAR wFileDescriptionFormat[] = {
456 '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o',
457 '\\', '%', '0', '4', 'x', '%', '0', '4', 'x',
458 '\\', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 0 };
459 static const WCHAR wLegalCopyrightFormat[] = {
460 '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o',
461 '\\', '%', '0', '4', 'x', '%', '0', '4', 'x',
462 '\\', 'L', 'e', 'g', 'a', 'l', 'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h', 't', 0 };
463 static const WCHAR wTranslation[] = {
464 'V', 'a', 'r', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o',
465 '\\', 'T', 'r', 'a', 'n', 's', 'l', 'a', 't', 'i', 'o', 'n', 0 };
466 static const WCHAR wCompanyName[] = {
467 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'N', 'a', 'm', 'e', 0 };
468 static const WCHAR wFileVersion[] = {
469 'F', 'i', 'l', 'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 };
470 static const WCHAR wInternalName[] = {
471 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'N', 'a', 'm', 'e', 0 };
472 static const WCHAR wOriginalFilename[] = {
473 'O', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'F', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 };
474 static const WCHAR wProductName[] = {
475 'P', 'r', 'o', 'd', 'u', 'c', 't', 'N', 'a', 'm', 'e', 0 };
476 static const WCHAR wProductVersion[] = {
477 'P', 'r', 'o', 'd', 'u', 'c', 't', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 };
478 static const WCHAR wSlash[] = { '\\', 0 };
479
480 if (lpfilename == 0)
481 return FALSE;
482
483 if (!(versize = GetFileVersionInfoSizeW(lpfilename, &handle)))
484 {
485 WARN("GetFileVersionInfoSize failed\n");
486 return FALSE;
487 }
488
489 if (!(pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, versize)))
490 {
491 WARN("HeapAlloc failed bytes %x\n", versize);
492 return FALSE;
493 }
494
495 if (!GetFileVersionInfoW(lpfilename, handle, versize, pBuf))
496 {
497 HeapFree(GetProcessHeap(), 0, pBuf);
498 return FALSE;
499 }
500
501 if (VerQueryValueW(pBuf, wSlash, &info, &infolen))
502 {
503 VS_FIXEDFILEINFO *inf = (VS_FIXEDFILEINFO *)info;
504 swprintf(buff, wVersionFormat, HIWORD(inf->dwFileVersionMS),
505 LOWORD(inf->dwFileVersionMS),
506 HIWORD(inf->dwFileVersionLS),
507 LOWORD(inf->dwFileVersionLS));
508 hDlgCtrl = GetDlgItem(hwndDlg, 14001);
509 TRACE("MS %x LS %x res %s \n", inf->dwFileVersionMS, inf->dwFileVersionLS, debugstr_w(buff));
510 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
511 }
512
513 if (VerQueryValueW(pBuf, wTranslation, (LPVOID *)&lplangcode, &infolen))
514 {
515 /* FIXME find language from current locale / if not available,
516 * default to english
517 * for now default to first available language
518 */
519 lang = lplangcode->lang;
520 code = lplangcode->code;
521 }
522
523 swprintf(buff, wFileDescriptionFormat, lang, code);
524 SH_FileVersionQuerySetText(hwndDlg, 14003, pBuf, buff, &str);
525
526 swprintf(buff, wLegalCopyrightFormat, lang, code);
527 SH_FileVersionQuerySetText(hwndDlg, 14005, pBuf, buff, &str);
528
529 /* listbox properties */
530 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wCompanyName, &str, lang, code);
531 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wFileVersion, &str, lang, code);
532 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wInternalName, &str, lang, code);
533
534 /* FIXME insert language identifier */
535
536 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wOriginalFilename, &str, lang, code);
537 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wProductName, &str, lang, code);
538 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wProductVersion, &str, lang, code);
539 SetWindowLong(hwndDlg, DWL_USER, (LONG)pBuf);
540
541 /* select first item */
542 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
543 SendMessageW(hDlgCtrl, LB_SETCURSEL, 0, 0);
544 str = (WCHAR *) SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)0, (LPARAM)NULL);
545 hDlgCtrl = GetDlgItem(hwndDlg, 14010);
546 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)str);
547
548 return TRUE;
549 }
550
551 /*************************************************************************
552 *
553 * SH_FileVersionDlgProc
554 *
555 * wnd proc of 'Version' property sheet page
556 */
557
558 INT_PTR
559 CALLBACK
560 SH_FileVersionDlgProc(HWND hwndDlg,
561 UINT uMsg,
562 WPARAM wParam,
563 LPARAM lParam)
564 {
565 LPPROPSHEETPAGE ppsp;
566 WCHAR *lpstr;
567 LPVOID *buf;
568
569 switch (uMsg)
570 {
571 case WM_INITDIALOG:
572 ppsp = (LPPROPSHEETPAGE)lParam;
573
574 if (ppsp == NULL)
575 break;
576
577 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam);
578
579 lpstr = (WCHAR *)ppsp->lParam;
580
581 if (lpstr == NULL)
582 break;
583
584 return SH_FileVersionInitialize(hwndDlg, lpstr);
585
586 case WM_COMMAND:
587 if (LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_DBLCLK)
588 {
589 HWND hDlgCtrl;
590 LRESULT lresult;
591 WCHAR *str;
592
593 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
594 lresult = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL);
595
596 if (lresult == LB_ERR)
597 break;
598
599 str = (WCHAR *) SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)lresult, (LPARAM)NULL);
600
601 if (str == NULL)
602 break;
603
604 hDlgCtrl = GetDlgItem(hwndDlg, 14010);
605 TRACE("hDlgCtrl %x string %s \n", hDlgCtrl, debugstr_w(str));
606 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)str);
607
608 return TRUE;
609 }
610 break;
611
612 case WM_DESTROY:
613 buf = (LPVOID) GetWindowLong(hwndDlg, DWL_USER);
614 HeapFree(GetProcessHeap(), 0, buf);
615 break;
616
617 default:
618 break;
619 }
620
621 return FALSE;
622 }
623
624 /*************************************************************************
625 *
626 * SH_FileGeneralDlgProc
627 *
628 * wnd proc of 'General' property sheet page
629 *
630 */
631
632 INT_PTR
633 CALLBACK
634 SH_FileGeneralDlgProc(HWND hwndDlg,
635 UINT uMsg,
636 WPARAM wParam,
637 LPARAM lParam)
638 {
639 LPPROPSHEETPAGEW ppsp;
640 WCHAR *lpstr;
641
642 switch (uMsg)
643 {
644 case WM_INITDIALOG:
645 ppsp = (LPPROPSHEETPAGEW)lParam;
646
647 if (ppsp == NULL)
648 break;
649
650 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg, lParam, ppsp->lParam);
651
652 lpstr = (WCHAR *)ppsp->lParam;
653
654 if (lpstr == NULL)
655 {
656 ERR("no filename\n");
657 break;
658 }
659
660 /* set general text properties filename filelocation and icon */
661 SH_FileGeneralSetText(hwndDlg, lpstr);
662
663 /* enumerate file extension from registry and application which opens it */
664 SH_FileGeneralSetFileType(hwndDlg, wcsrchr(lpstr, '.'));
665
666 /* set file time create/modfied/accessed */
667 SH_FileGeneralSetFileSizeTime(hwndDlg, lpstr, NULL);
668
669 return TRUE;
670
671 default:
672 break;
673 }
674
675 return FALSE;
676 }
677
678 BOOL
679 CALLBACK
680 AddShellPropSheetExCallback(HPROPSHEETPAGE hPage,
681 LPARAM lParam)
682 {
683 PROPSHEETHEADERW *pinfo = (PROPSHEETHEADERW *)lParam;
684
685 if (pinfo->nPages < MAX_PROPERTY_SHEET_PAGE)
686 {
687 pinfo->u3.phpage[pinfo->nPages++] = hPage;
688 return TRUE;
689 }
690
691 return FALSE;
692 }
693
694 int
695 EnumPropSheetExt(LPWSTR wFileName, PROPSHEETHEADERW *pinfo, int NumPages, HPSXA *hpsxa, IDataObject *pDataObj)
696 {
697 WCHAR szName[MAX_PATH] = { 0 };
698 WCHAR *pOffset;
699 UINT Length;
700 DWORD dwName;
701 int Pages;
702 CLSID clsid;
703
704 pOffset = wcsrchr(wFileName, L'.');
705
706 if (!pOffset)
707 {
708 Length = wcslen(szName);
709
710 if (Length + 6 > sizeof(szName) / sizeof(szName[0]))
711 return 0;
712
713 if (CLSIDFromString(wFileName, &clsid) == NOERROR)
714 {
715 wcscpy(szName, L"CLSID\\");
716 wcscpy(&szName[6], wFileName);
717 }
718 else
719 {
720 wcscpy(szName, wFileName);
721 }
722 }
723 else
724 {
725 Length = wcslen(pOffset);
726
727 if (Length >= sizeof(szName) / sizeof(szName[0]))
728 return 0;
729
730 wcscpy(szName, pOffset);
731 }
732
733 TRACE("EnumPropSheetExt szName %s\n", debugstr_w(szName));
734
735 hpsxa[0] = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, szName, NumPages, pDataObj);
736 hpsxa[1] = NULL;
737
738 Pages = SHAddFromPropSheetExtArray(hpsxa[0], AddShellPropSheetExCallback, (LPARAM)pinfo);
739
740 if (pOffset)
741 {
742 /* try to load property sheet handlers from prog id key */
743 dwName = sizeof(szName);
744
745 if (RegGetValueW(HKEY_CLASSES_ROOT, pOffset, NULL, RRF_RT_REG_SZ, NULL, szName, &dwName) == ERROR_SUCCESS)
746 {
747 TRACE("EnumPropSheetExt szName %s, pOffset %s\n", debugstr_w(szName), debugstr_w(pOffset));
748 szName[(sizeof(szName) / sizeof(WCHAR)) - 1] = L'\0';
749 hpsxa[1] = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, szName, NumPages - Pages, pDataObj);
750 Pages += SHAddFromPropSheetExtArray(hpsxa[1], AddShellPropSheetExCallback, (LPARAM)pinfo);
751 }
752 }
753
754 return Pages;
755 }
756
757 /*************************************************************************
758 *
759 * SH_ShowPropertiesDialog
760 *
761 * called from ShellExecuteExW32
762 *
763 * lpf contains (quoted) path of folder/file
764 *
765 * TODO: provide button change application type if file has registered type
766 * make filename field editable and apply changes to filename on close
767 */
768
769 BOOL
770 SH_ShowPropertiesDialog(WCHAR *lpf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST *apidl)
771 {
772 PROPSHEETHEADERW pinfo;
773 HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE];
774 WCHAR wFileName[MAX_PATH];
775 DWORD dwHandle = 0;
776 WCHAR *pFileName;
777 HPSXA hpsxa[2];
778 INT_PTR res;
779 IDataObject *pDataObj = NULL;
780 HRESULT hResult;
781
782 TRACE("SH_ShowPropertiesDialog entered filename %s\n", debugstr_w(lpf));
783
784 if (lpf == NULL)
785 return FALSE;
786
787 if (!wcslen(lpf))
788 return FALSE;
789
790 memset(hppages, 0x0, sizeof(HPROPSHEETPAGE) * MAX_PROPERTY_SHEET_PAGE);
791
792 if (lpf[0] == '"')
793 {
794 /* remove quotes from lpf */
795 LPCWSTR src = lpf + 1;
796 LPWSTR dst = wFileName;
797
798 while (*src && *src != '"')
799 *dst++ = *src++;
800
801 *dst = '\0';
802 }
803 else
804 {
805 wcscpy(wFileName, lpf);
806 }
807
808 if (PathIsDirectoryW(wFileName))
809 {
810 return SH_ShowFolderProperties(wFileName);
811 }
812
813 if (wcslen(wFileName) == 3)
814 {
815 return SH_ShowDriveProperties(wFileName, pidlFolder, apidl);
816 }
817
818 pFileName = wcsrchr(wFileName, '\\');
819
820 if (!pFileName)
821 pFileName = wFileName;
822 else
823 pFileName++;
824
825 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
826 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
827 pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE;
828 pinfo.u3.phpage = hppages;
829 pinfo.pszCaption = pFileName;
830
831 hppages[pinfo.nPages] =
832 SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG",
833 SH_FileGeneralDlgProc,
834 (LPARAM)wFileName,
835 NULL);
836
837 if (hppages[pinfo.nPages])
838 pinfo.nPages++;
839
840 hResult = SHCreateDataObject(pidlFolder, 1, apidl, NULL, &IID_IDataObject, (LPVOID *)&pDataObj);
841
842 if (hResult == S_OK)
843 {
844 if (!EnumPropSheetExt(wFileName, &pinfo, MAX_PROPERTY_SHEET_PAGE - 1, hpsxa, pDataObj))
845 {
846 hpsxa[0] = NULL;
847 hpsxa[1] = NULL;
848 }
849 }
850
851 if (GetFileVersionInfoSizeW(lpf, &dwHandle))
852 {
853 hppages[pinfo.nPages] =
854 SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG",
855 SH_FileVersionDlgProc,
856 (LPARAM)wFileName,
857 NULL);
858 if (hppages[pinfo.nPages])
859 pinfo.nPages++;
860 }
861
862 res = PropertySheetW(&pinfo);
863
864 if (hResult == S_OK)
865 {
866 SHDestroyPropSheetExtArray(hpsxa[0]);
867 SHDestroyPropSheetExtArray(hpsxa[1]);
868 IDataObject_Release(pDataObj);
869 }
870
871 return (res != -1);
872 }
873
874 /*EOF */