Fixed a bug with file version informations
[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 #define COBJMACROS
22 #define NONAMELESSUNION
23
24 #include "config.h"
25 #include "wine/port.h"
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include "winerror.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "commdlg.h"
36 #include "wine/debug.h"
37
38 #include "shellapi.h"
39 #include <shlwapi.h>
40 #include "shlobj.h"
41 #include "shell32_main.h"
42 #include "shresdef.h"
43 #include "undocshell.h"
44 #include "prsht.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(shell);
47
48 #define MAX_PROPERTY_SHEET_PAGE 32
49
50 typedef struct _LANGANDCODEPAGE_
51 {
52 WORD lang;
53 WORD code;
54 } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
55
56 /*************************************************************************
57 *
58 * SH_CreatePropertySheetPage [Internal]
59 *
60 * creates a property sheet page from an resource name
61 *
62 */
63 HPROPSHEETPAGE
64 SH_CreatePropertySheetPage(LPSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle)
65 {
66 HRSRC hRes;
67 LPVOID lpsztemplate;
68 PROPSHEETPAGEW ppage;
69
70 if (resname == NULL)
71 return (HPROPSHEETPAGE)0;
72
73 hRes = FindResourceA(shell32_hInstance, resname, (LPSTR)RT_DIALOG);
74
75 if (hRes == NULL)
76 {
77 ERR("failed to find resource name\n");
78 return (HPROPSHEETPAGE)0;
79 }
80 lpsztemplate = LoadResource(shell32_hInstance, hRes);
81 if (lpsztemplate == NULL)
82 return (HPROPSHEETPAGE)0;
83
84 memset(&ppage, 0x0, sizeof(PROPSHEETPAGEW));
85 ppage.dwSize = sizeof(PROPSHEETPAGEW);
86 ppage.dwFlags = PSP_DLGINDIRECT;
87 ppage.u.pResource = lpsztemplate;
88 ppage.pfnDlgProc = dlgproc;
89 ppage.lParam = lParam;
90 ppage.pszTitle = szTitle;
91 if (szTitle)
92 {
93 ppage.dwFlags |= PSP_USETITLE;
94 }
95 return CreatePropertySheetPageW(&ppage);
96 }
97
98
99
100
101
102
103
104 /*************************************************************************
105 *
106 * SH_FileGeneralFileType [Internal]
107 *
108 * retrieves file extension description from registry and sets it in dialog
109 *
110 * TODO: retrieve file extension default icon and load it
111 * find executable name from registry, retrieve description from executable
112 */
113
114 BOOL
115 SH_FileGeneralSetFileType(HWND hwndDlg, WCHAR * filext)
116 {
117 WCHAR name[MAX_PATH];
118 WCHAR value[MAX_PATH];
119 DWORD lname = MAX_PATH;
120 DWORD lvalue = MAX_PATH;
121
122 HKEY hKey;
123 LONG result;
124 HWND hDlgCtrl;
125
126 TRACE("fileext %s\n", debugstr_w(filext));
127
128 if (filext == NULL)
129 return FALSE;
130
131 hDlgCtrl = GetDlgItem(hwndDlg, 14005);
132
133 if (hDlgCtrl == NULL)
134 return FALSE;
135
136 if (RegOpenKeyW(HKEY_CLASSES_ROOT, filext, &hKey) != ERROR_SUCCESS)
137 {
138 /* the fileextension is unknown, so default to string "FileExtension File" */
139 SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)value);
140 sprintfW(name, value, &filext[1]);
141 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)name);
142 return TRUE;
143 }
144 result = RegEnumValueW(hKey, 0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue);
145 RegCloseKey(hKey);
146
147 if (result != ERROR_SUCCESS)
148 return FALSE;
149 if (RegOpenKeyW(HKEY_CLASSES_ROOT, value, &hKey) == ERROR_SUCCESS)
150 {
151 lvalue = lname = MAX_PATH;
152 result = RegEnumValueW(hKey,0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue);
153 RegCloseKey(hKey);
154 }
155
156 /* file extension type */
157 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)value);
158 return TRUE;
159 }
160 /*************************************************************************
161 *
162 * SHFileGeneralGetFileTimeString [Internal]
163 *
164 * formats a given LPFILETIME struct into readable user format
165 */
166
167 BOOL
168 SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime, WCHAR * lpResult)
169 {
170 FILETIME ft;
171 SYSTEMTIME dt;
172 WORD wYear;
173 static const WCHAR wFormat[] = {'%','0','2','d','/','%','0','2','d','/','%','0','4','d',' ',' ','%','0','2','d',':','%','0','2','u',0};
174
175 if (lpFileTime == NULL || lpResult == NULL)
176 return FALSE;
177
178 if (!FileTimeToLocalFileTime(lpFileTime, &ft))
179 return FALSE;
180
181 FileTimeToSystemTime(&ft, &dt);
182
183 wYear = dt.wYear;
184 /* ddmmyy */
185 sprintfW (lpResult, wFormat, dt.wDay, dt.wMonth, wYear, dt.wHour, dt.wMinute);
186
187 TRACE("result %s\n",debugstr_w(lpResult));
188 return TRUE;
189 }
190
191 /*************************************************************************
192 *
193 * SH_FileGeneralSetText [Internal]
194 *
195 * sets file path string and filename string
196 *
197 */
198
199 BOOL
200 SH_FileGeneralSetText(HWND hwndDlg, WCHAR * lpstr)
201 {
202 int flength;
203 int plength;
204 WCHAR * lpdir;
205 WCHAR buff[MAX_PATH];
206 HWND hDlgCtrl;
207
208 if (lpstr == NULL)
209 return FALSE;
210
211 lpdir = strrchrW(lpstr, '\\'); /* find the last occurence of '\\' */
212
213 plength = strlenW(lpstr);
214 flength = strlenW(lpdir);
215
216 if (lpdir)
217 {
218 /* location text field */
219 strncpyW(buff, lpstr, plength - flength);
220 buff[plength - flength] = UNICODE_NULL;
221 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
222 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
223 }
224
225 if(flength > 1)
226 {
227 /* text filename field */
228 strncpyW(buff, &lpdir[1], flength);
229 hDlgCtrl = GetDlgItem(hwndDlg, 14001);
230 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
231 }
232
233 return TRUE;
234 }
235
236 /*************************************************************************
237 *
238 * SH_FileGeneralSetFileSizeTime [Internal]
239 *
240 * retrieves file information from file and sets in dialog
241 *
242 */
243
244 BOOL
245 SH_FileGeneralSetFileSizeTime(HWND hwndDlg, WCHAR * lpfilename, PULARGE_INTEGER lpfilesize)
246 {
247 BOOL result;
248 HANDLE hFile;
249 FILETIME create_time;
250 FILETIME accessed_time;
251 FILETIME write_time;
252 WCHAR resultstr[MAX_PATH];
253 HWND hDlgCtrl;
254 LARGE_INTEGER file_size;
255
256 if (lpfilename == NULL)
257 return FALSE;
258
259 hFile = CreateFileW(lpfilename,
260 GENERIC_READ,
261 FILE_SHARE_READ,NULL,
262 OPEN_EXISTING,
263 FILE_ATTRIBUTE_NORMAL,
264 NULL);
265
266 if (hFile == INVALID_HANDLE_VALUE)
267 {
268 WARN("failed to open file %s\n", debugstr_w(lpfilename));
269 return FALSE;
270 }
271
272 result = GetFileTime(hFile, &create_time, &accessed_time, &write_time);
273
274 if (!result)
275 {
276 WARN("GetFileTime failed\n");
277 return FALSE;
278 }
279 if (SHFileGeneralGetFileTimeString(&create_time,resultstr))
280 {
281 hDlgCtrl = GetDlgItem(hwndDlg, 14015);
282 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
283 }
284
285 if (SHFileGeneralGetFileTimeString(&accessed_time, resultstr))
286 {
287 hDlgCtrl = GetDlgItem(hwndDlg, 14017);
288 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
289 }
290
291 if (SHFileGeneralGetFileTimeString(&write_time, resultstr))
292 {
293 hDlgCtrl = GetDlgItem(hwndDlg, 14019);
294 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
295 }
296
297 if (!GetFileSizeEx(hFile, &file_size))
298 {
299 WARN("GetFileSize failed\n");
300 CloseHandle(hFile);
301 return FALSE;
302 }
303 CloseHandle(hFile);
304 if (!StrFormatByteSizeW(file_size.QuadPart, resultstr, sizeof(resultstr) / sizeof(WCHAR)))
305 return FALSE;
306 hDlgCtrl = GetDlgItem(hwndDlg, 14011);
307 TRACE("result size %u resultstr %s\n", file_size.QuadPart, debugstr_w(resultstr));
308 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr);
309
310 if (lpfilesize)
311 lpfilesize->QuadPart = (ULONGLONG)file_size.QuadPart;
312
313 return TRUE;
314 }
315
316 /*************************************************************************
317 *
318 * SH_SetFileVersionText [Internal]
319 *
320 *
321 */
322
323 BOOL
324 SH_FileVersionQuerySetText(HWND hwndDlg, DWORD dlgId, LPVOID pInfo, WCHAR * text, WCHAR ** resptr)
325 {
326 UINT reslen;
327 HWND hDlgCtrl;
328
329 if(hwndDlg == NULL || resptr == NULL || text == NULL)
330 return FALSE;
331
332 if(VerQueryValueW(pInfo, text, (LPVOID *)resptr, &reslen))
333 {
334 /* file description property */
335 hDlgCtrl = GetDlgItem(hwndDlg, dlgId);
336 TRACE("%s :: %s\n",debugstr_w(text), debugstr_w(*resptr));
337 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)0, (LPARAM)*resptr);
338 return TRUE;
339 }
340 return FALSE;
341 }
342
343 /*************************************************************************
344 *
345 * SH_FileVersionQuerySetListText [Internal]
346 *
347 * retrieves a version string and adds it to listbox
348 *
349 */
350
351
352 BOOL
353 SH_FileVersionQuerySetListText(HWND hwndDlg, LPVOID pInfo, const WCHAR * text, WCHAR **resptr, WORD lang, WORD code)
354 {
355 UINT reslen;
356 HWND hDlgCtrl;
357 UINT index;
358 static const WCHAR wFormat[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n',
359 'f','o','\\','%','0','4','x','%','0','4','x','\\','%','s',0 };
360 WCHAR buff[256];
361
362 TRACE("text %s, resptr %p hwndDlg %p\n",debugstr_w(text), resptr, hwndDlg);
363
364 if(hwndDlg == NULL || resptr == NULL || text == NULL)
365 return FALSE;
366
367 sprintfW(buff, wFormat, lang, code, text);
368 if(VerQueryValueW(pInfo, buff, (LPVOID *)resptr, &reslen))
369 {
370 /* listbox name property */
371 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
372 TRACE("%s :: %s\n",debugstr_w(text), debugstr_w(*resptr));
373 index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)text);
374 SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)index, (LPARAM)(WCHAR*)*resptr);
375 return TRUE;
376 }
377 return FALSE;
378 }
379
380 /*************************************************************************
381 *
382 * SH_FileVersionInitialize [Internal]
383 *
384 * sets all file version properties in dialog
385 */
386 BOOL
387 SH_FileVersionInitialize(HWND hwndDlg, WCHAR * lpfilename)
388 {
389 LPVOID pBuf;
390 DWORD versize;
391 DWORD handle;
392 LPVOID info = NULL;
393 UINT infolen;
394 WCHAR buff[256];
395 HWND hDlgCtrl;
396 WORD lang = 0;
397 WORD code = 0;
398 LPLANGANDCODEPAGE lplangcode;
399 WCHAR * str;
400 static const WCHAR wVersionFormat[] = { '%','d','.','%','d','.','%','d','.','%','d',0 };
401 static const WCHAR wFileDescriptionFormat[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
402 '\\','%','0','4','x','%','0','4','x','\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
403 static const WCHAR wLegalCopyrightFormat[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
404 '\\','%','0','4','x','%','0','4','x','\\','L','e','g','a','l','C','o','p','y','r','i','g','h','t',0 };
405 static const WCHAR wTranslation[] = { 'V','a','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n',0 };
406 static const WCHAR wCompanyName[] = { 'C','o','m','p','a','n','y','N','a','m','e',0 };
407 static const WCHAR wFileVersion[] = { 'F','i','l','e','V','e','r','s','i','o','n',0 };
408 static const WCHAR wInternalName[] = { 'I','n','t','e','r','n','a','l','N','a','m','e',0 };
409 static const WCHAR wOriginalFilename[] = { 'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0 };
410 static const WCHAR wProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
411 static const WCHAR wProductVersion[] = { 'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0 };
412 static const WCHAR wSlash[] = { '\\',0 };
413
414
415 if(lpfilename == 0)
416 return FALSE;
417
418 if(!(versize = GetFileVersionInfoSizeW(lpfilename, &handle)))
419 {
420 WARN("GetFileVersionInfoSize failed\n");
421 return FALSE;
422 }
423
424 if(!(pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, versize)))
425 {
426 WARN("HeapAlloc failed bytes %x\n",versize);
427 return FALSE;
428 }
429
430 if(!GetFileVersionInfoW(lpfilename, handle, versize, pBuf))
431 {
432 HeapFree(GetProcessHeap(), 0, pBuf);
433 return FALSE;
434 }
435 if(VerQueryValueW(pBuf, wSlash, &info, &infolen))
436 {
437 VS_FIXEDFILEINFO * inf = (VS_FIXEDFILEINFO *)info;
438 sprintfW(buff, wVersionFormat, HIWORD(inf->dwFileVersionMS),
439 LOWORD(inf->dwFileVersionMS),
440 HIWORD(inf->dwFileVersionLS),
441 LOWORD(inf->dwFileVersionLS));
442
443 hDlgCtrl = GetDlgItem(hwndDlg, 14001);
444 TRACE("MS %x LS %x res %s \n",inf->dwFileVersionMS, inf->dwFileVersionLS, debugstr_w(buff));
445 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff);
446 }
447 if(VerQueryValueW(pBuf, wTranslation, (LPVOID *)&lplangcode, &infolen))
448 {
449 /* FIXME find language from current locale / if not available,
450 * default to english
451 * for now default to first available language
452 */
453 lang = lplangcode->lang;
454 code = lplangcode->code;
455 }
456
457 sprintfW(buff, wFileDescriptionFormat, lang, code);
458 SH_FileVersionQuerySetText(hwndDlg, 14003, pBuf, buff, &str);
459
460 sprintfW(buff, wLegalCopyrightFormat, lang, code);
461 SH_FileVersionQuerySetText(hwndDlg, 14005, pBuf, buff, &str);
462
463 /* listbox properties */
464 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wCompanyName, &str, lang, code);
465 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wFileVersion, &str, lang, code);
466 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wInternalName, &str, lang, code);
467
468 /* FIXME insert language identifier */
469
470 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wOriginalFilename, &str, lang, code);
471 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wProductName, &str, lang, code);
472 SH_FileVersionQuerySetListText(hwndDlg, pBuf, wProductVersion, &str, lang, code);
473 SetWindowLong(hwndDlg, DWL_USER, (LONG)pBuf);
474
475 /* select first item */
476 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
477 SendMessageW(hDlgCtrl, LB_SETCURSEL, 0, 0);
478 str = (WCHAR *)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)0, (LPARAM)NULL);
479 hDlgCtrl = GetDlgItem(hwndDlg, 14010);
480 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)str);
481 return TRUE;
482 }
483
484 /*************************************************************************
485 *
486 * SH_FileVersionDlgProc
487 *
488 * wnd proc of 'Version' property sheet page
489 */
490 INT_PTR
491 CALLBACK
492 SH_FileVersionDlgProc(
493 HWND hwndDlg,
494 UINT uMsg,
495 WPARAM wParam,
496 LPARAM lParam
497 )
498 {
499 LPPROPSHEETPAGE ppsp;
500 WCHAR * lpstr;
501 LPVOID * buf;
502 switch(uMsg)
503 {
504 case WM_INITDIALOG:
505 ppsp = (LPPROPSHEETPAGE)lParam;
506 if(ppsp == NULL)
507 break;
508
509 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n",hwndDlg, lParam, ppsp->lParam);
510
511 lpstr = (WCHAR *)ppsp->lParam;
512
513 if(lpstr == NULL)
514 break;
515
516 return SH_FileVersionInitialize(hwndDlg, lpstr);
517
518
519 case WM_COMMAND:
520 if(LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_DBLCLK)
521 {
522 HWND hDlgCtrl;
523 LRESULT lresult;
524 WCHAR * str;
525
526 hDlgCtrl = GetDlgItem(hwndDlg, 14009);
527 lresult = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL);
528 if(lresult == LB_ERR)
529 {
530 break;
531 }
532 str = (WCHAR *)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)lresult, (LPARAM)NULL);
533
534 if(str == NULL)
535 {
536 break;
537 }
538 hDlgCtrl = GetDlgItem(hwndDlg, 14010);
539 TRACE("hDlgCtrl %x string %s \n",hDlgCtrl, debugstr_w(str));
540 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)str);
541 return TRUE;
542 }
543 break;
544
545 case WM_DESTROY:
546 buf = (LPVOID)GetWindowLong(hwndDlg, DWL_USER);
547 HeapFree(GetProcessHeap(), 0, buf);
548 break;
549
550 default:
551 break;
552 }
553 return FALSE;
554 }
555
556 /*************************************************************************
557 *
558 * SH_FileGeneralDlgProc
559 *
560 * wnd proc of 'General' property sheet page
561 *
562 */
563
564 INT_PTR
565 CALLBACK
566 SH_FileGeneralDlgProc(
567 HWND hwndDlg,
568 UINT uMsg,
569 WPARAM wParam,
570 LPARAM lParam
571 )
572 {
573 LPPROPSHEETPAGEW ppsp;
574 WCHAR * lpstr;
575 switch(uMsg)
576 {
577 case WM_INITDIALOG:
578 ppsp = (LPPROPSHEETPAGEW)lParam;
579 if (ppsp == NULL)
580 break;
581 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n",hwndDlg, lParam, ppsp->lParam);
582
583 lpstr = (WCHAR *)ppsp->lParam;
584
585 if ( lpstr == NULL)
586 {
587 ERR("no filename\n");
588 break;
589 }
590 /* set general text properties filename filelocation and icon */
591 SH_FileGeneralSetText(hwndDlg, lpstr);
592 /* enumerate file extension from registry and application which opens it*/
593 SH_FileGeneralSetFileType(hwndDlg, strrchrW(lpstr, '.'));
594 /* set file time create/modfied/accessed */
595 SH_FileGeneralSetFileSizeTime(hwndDlg, lpstr, NULL);
596 return TRUE;
597 default:
598 break;
599 }
600 return FALSE;
601 }
602
603
604 /*************************************************************************
605 *
606 * SH_ShowPropertiesDialog
607 *
608 * called from ShellExecuteExW32
609 *
610 * lpf contains (quoted) path of folder/file
611 *
612 * TODO: provide button change application type if file has registered type
613 * make filename field editable and apply changes to filename on close
614 */
615
616 BOOL
617 SH_ShowPropertiesDialog(WCHAR * lpf)
618 {
619 PROPSHEETHEADERW pinfo;
620 HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE];
621 HPROPSHEETPAGE hpage;
622 WCHAR wFileName[MAX_PATH];
623 UINT num_pages = 0;
624 DWORD dwHandle = 0;
625
626 TRACE("SH_ShowPropertiesDialog entered filename %s\n", debugstr_w(lpf));
627
628 if (lpf== NULL)
629 return FALSE;
630
631 if ( !strlenW(lpf) )
632 return FALSE;
633
634 memset(hppages, 0x0, sizeof(HPROPSHEETPAGE) * MAX_PROPERTY_SHEET_PAGE);
635 if (lpf[0] == '"')
636 {
637 /* remove quotes from lpf */
638 LPWSTR src = lpf + 1;
639 LPWSTR dst = wFileName;
640
641 while(*src && *src!='"')
642 *dst++ = *src++;
643
644 *dst = '\0';
645 }
646 else
647 {
648 strcpyW(wFileName, lpf);
649 }
650
651 if (PathIsDirectoryW(wFileName) || strlenW(wFileName) == 3)
652 {
653 FIXME("directory / drive resources are missing\n");
654 return FALSE;
655 }
656 hpage = SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", SH_FileGeneralDlgProc, (LPARAM)wFileName, NULL);
657
658 if (hpage == NULL)
659 return FALSE;
660
661 hppages[num_pages] = hpage;
662 num_pages++;
663 if ( GetFileVersionInfoSizeW(lpf, &dwHandle) )
664 {
665 if ( (hpage = SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG",SH_FileVersionDlgProc, (LPARAM)lpf, NULL))!= NULL)
666 {
667 hppages[num_pages] = hpage;
668 num_pages++;
669 }
670 }
671 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
672 pinfo.dwSize = sizeof(PROPSHEETHEADERW);
673 pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE;
674 pinfo.nPages = num_pages;
675 pinfo.u3.phpage = hppages;
676 pinfo.pszCaption = wFileName;
677 return (PropertySheetW(&pinfo) != -1);
678 }
679 /*EOF */