2 * Shell Library Functions
4 * Copyright 2005 Johannes Anderwald
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.
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.
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
22 #include "wine/port.h"
34 #include "wine/debug.h"
39 #include "shell32_main.h"
41 #include "undocshell.h"
44 typedef struct _LANGANDCODEPAGE_
48 } LANGANDCODEPAGE
, *LPLANGANDCODEPAGE
;
50 /*************************************************************************
52 * SH_FileGeneralFileType [Internal]
54 * retrieves file extension description from registry and sets it in dialog
56 * TODO: retrieve file extension default icon and load it
57 * find executable name from registry, retrieve description from executable
61 SH_FileGeneralSetFileType(HWND hwndDlg
, WCHAR
* filext
)
64 WCHAR value
[MAX_PATH
];
65 DWORD lname
= MAX_PATH
;
66 DWORD lvalue
= MAX_PATH
;
72 TRACE("fileext %s\n", debugstr_w(filext
));
77 hDlgCtrl
= GetDlgItem(hwndDlg
, 14005);
82 if (RegOpenKeyW(HKEY_CLASSES_ROOT
, filext
, &hKey
) != ERROR_SUCCESS
)
84 /* the fileextension is unknown, so default to string "FileExtension File" */
85 SendMessageW(hDlgCtrl
, WM_GETTEXT
, (WPARAM
)MAX_PATH
, (LPARAM
)value
);
86 sprintfW(name
, value
, &filext
[1]);
87 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)name
);
90 result
= RegEnumValueW(hKey
, 0, name
, &lname
, NULL
, NULL
, (LPBYTE
)value
, &lvalue
);
93 if (result
!= ERROR_SUCCESS
)
95 if (RegOpenKeyW(HKEY_CLASSES_ROOT
, value
, &hKey
) == ERROR_SUCCESS
)
97 lvalue
= lname
= MAX_PATH
;
98 result
= RegEnumValueW(hKey
,0, name
, &lname
, NULL
, NULL
, (LPBYTE
)value
, &lvalue
);
102 /* file extension type */
103 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)value
);
106 /*************************************************************************
108 * SHFileGeneralGetFileTimeString [Internal]
110 * formats a given LPFILETIME struct into readable user format
114 SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime
, WCHAR
* lpResult
)
119 static const WCHAR wFormat
[] = {'%','0','2','d','/','%','0','2','d','/','%','0','4','d',' ',' ','%','0','2','d',':','%','0','2','u',0};
121 if (lpFileTime
== NULL
|| lpResult
== NULL
)
124 if (!FileTimeToLocalFileTime(lpFileTime
, &ft
))
127 FileTimeToSystemTime(&ft
, &dt
);
131 sprintfW (lpResult
, wFormat
, dt
.wDay
, dt
.wMonth
, wYear
, dt
.wHour
, dt
.wMinute
);
133 TRACE("result %s\n",debugstr_w(lpResult
));
137 /*************************************************************************
139 * SH_FileGeneralSetText [Internal]
141 * sets file path string and filename string
146 SH_FileGeneralSetText(HWND hwndDlg
, WCHAR
* lpstr
)
151 WCHAR buff
[MAX_PATH
];
157 lpdir
= strrchrW(lpstr
, '\\'); /* find the last occurence of '\\' */
159 plength
= strlenW(lpstr
);
160 flength
= strlenW(lpdir
);
164 /* location text field */
165 strncpyW(buff
, lpstr
, plength
- flength
);
166 buff
[plength
- flength
] = UNICODE_NULL
;
167 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
168 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)buff
);
173 /* text filename field */
174 strncpyW(buff
, &lpdir
[1], flength
);
175 hDlgCtrl
= GetDlgItem(hwndDlg
, 14001);
176 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)buff
);
182 /*************************************************************************
184 * SH_FileGeneralSetFileSizeTime [Internal]
186 * retrieves file information from file and sets in dialog
191 SH_FileGeneralSetFileSizeTime(HWND hwndDlg
, WCHAR
* lpfilename
, PULARGE_INTEGER lpfilesize
)
195 FILETIME create_time
;
196 FILETIME accessed_time
;
198 WCHAR resultstr
[MAX_PATH
];
200 LARGE_INTEGER file_size
;
201 WCHAR szFormat
[] = { '%','u',' ','B','y','t','e','s',0 };
203 if (lpfilename
== NULL
)
206 hFile
= CreateFileW(lpfilename
,
208 FILE_SHARE_READ
,NULL
,
210 FILE_ATTRIBUTE_NORMAL
,
213 if (hFile
== INVALID_HANDLE_VALUE
)
215 WARN("failed to open file %s\n", debugstr_w(lpfilename
));
219 result
= GetFileTime(hFile
, &create_time
, &accessed_time
, &write_time
);
223 WARN("GetFileTime failed\n");
226 if (SHFileGeneralGetFileTimeString(&create_time
,resultstr
))
228 hDlgCtrl
= GetDlgItem(hwndDlg
, 14015);
229 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
232 if (SHFileGeneralGetFileTimeString(&accessed_time
, resultstr
))
234 hDlgCtrl
= GetDlgItem(hwndDlg
, 14017);
235 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
238 if (SHFileGeneralGetFileTimeString(&write_time
, resultstr
))
240 hDlgCtrl
= GetDlgItem(hwndDlg
, 14019);
241 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
244 if (!GetFileSizeEx(hFile
, &file_size
))
246 WARN("GetFileSize failed\n");
252 if (!StrFormatByteSizeW(file_size
.QuadPart
, resultstr
, sizeof(resultstr
)))
255 sprintfW(resultstr
, szFormat
, file_size
.QuadPart
);
258 hDlgCtrl
= GetDlgItem(hwndDlg
, 14011);
259 TRACE("result size %u resultstr %s\n", file_size
.QuadPart
, debugstr_w(resultstr
));
260 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
263 lpfilesize
->QuadPart
= (ULONGLONG
)file_size
.QuadPart
;
268 /*************************************************************************
270 * SH_SetFileVersionText [Internal]
276 SH_FileVersionQuerySetText(HWND hwndDlg
, DWORD dlgId
, LPVOID pInfo
, WCHAR
* text
, WCHAR
** resptr
)
281 if(hwndDlg
== NULL
|| resptr
== NULL
|| text
== NULL
)
284 if(VerQueryValueW(pInfo
, text
, (LPVOID
*)resptr
, &reslen
))
286 /* file description property */
287 hDlgCtrl
= GetDlgItem(hwndDlg
, dlgId
);
288 TRACE("%s :: %s\n",debugstr_w(text
), debugstr_w(*resptr
));
289 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)*resptr
);
295 /*************************************************************************
297 * SH_FileVersionQuerySetListText [Internal]
299 * retrieves a version string and adds it to listbox
305 SH_FileVersionQuerySetListText(HWND hwndDlg
, LPVOID pInfo
, const WCHAR
* text
, WCHAR
**resptr
, WORD lang
, WORD code
)
310 static const WCHAR wFormat
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n',
311 'f','o','\\','%','0','4','x','%','0','4','x','\\','%','s',0 };
314 TRACE("text %s, resptr %p hwndDlg %p\n",debugstr_w(text
), resptr
, hwndDlg
);
316 if(hwndDlg
== NULL
|| resptr
== NULL
|| text
== NULL
)
319 sprintfW(buff
, wFormat
, lang
, code
, text
);
320 if(VerQueryValueW(pInfo
, buff
, (LPVOID
*)resptr
, &reslen
))
322 /* listbox name property */
323 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
324 TRACE("%s :: %s\n",debugstr_w(text
), debugstr_w(*resptr
));
325 index
= SendMessageW(hDlgCtrl
, LB_ADDSTRING
, (WPARAM
)-1, (LPARAM
)text
);
326 SendMessageW(hDlgCtrl
, LB_SETITEMDATA
, (WPARAM
)index
, (LPARAM
)(WCHAR
*)*resptr
);
332 /*************************************************************************
334 * SH_FileVersionInitialize [Internal]
336 * sets all file version properties in dialog
339 SH_FileVersionInitialize(HWND hwndDlg
, WCHAR
* lpfilename
)
350 LPLANGANDCODEPAGE lplangcode
;
352 static const WCHAR wVersionFormat
[] = { '%','d','.','%','d','.','%','d','.','%','d',0 };
353 static const WCHAR wFileDescriptionFormat
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
354 '\\','%','0','4','x','%','0','4','x','\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
355 static const WCHAR wLegalCopyrightFormat
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
356 '\\','%','0','4','x','%','0','4','x','\\','L','e','g','a','l','C','o','p','y','r','i','g','h','t',0 };
357 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 };
358 static const WCHAR wCompanyName
[] = { 'C','o','m','p','a','n','y','N','a','m','e',0 };
359 static const WCHAR wFileVersion
[] = { 'F','i','l','e','V','e','r','s','i','o','n',0 };
360 static const WCHAR wInternalName
[] = { 'I','n','t','e','r','n','a','l','N','a','m','e',0 };
361 static const WCHAR wOriginalFilename
[] = { 'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0 };
362 static const WCHAR wProductName
[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
363 static const WCHAR wProductVersion
[] = { 'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0 };
364 static const WCHAR wSlash
[] = { '\\',0 };
370 if(!(versize
= GetFileVersionInfoSizeW(lpfilename
, &handle
)))
372 WARN("GetFileVersionInfoSize failed\n");
376 if(!(pBuf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, versize
)))
378 WARN("HeapAlloc failed bytes %x\n",versize
);
382 if(!GetFileVersionInfoW(lpfilename
, handle
, versize
, pBuf
))
384 HeapFree(GetProcessHeap(), 0, pBuf
);
387 if(VerQueryValueW(pBuf
, wSlash
, &info
, &infolen
))
389 VS_FIXEDFILEINFO
* inf
= (VS_FIXEDFILEINFO
*)info
;
390 sprintfW(buff
, wVersionFormat
,inf
->dwFileVersionMS
& 0xFFFF0000,
391 inf
->dwFileVersionMS
& 0x0000FFFF,
392 inf
->dwFileVersionLS
& 0xFFFF0000,
393 inf
->dwFileVersionLS
& 0x0000FFFF);
395 hDlgCtrl
= GetDlgItem(hwndDlg
, 14001);
396 TRACE("MS %x LS %x res %s \n",inf
->dwFileVersionMS
, inf
->dwFileVersionLS
, debugstr_w(buff
));
397 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)buff
);
399 if(VerQueryValueW(pBuf
, wTranslation
, (LPVOID
*)&lplangcode
, &infolen
))
401 /* FIXME find language from current locale / if not available,
403 * for now default to first available language
405 lang
= lplangcode
->lang
;
406 code
= lplangcode
->code
;
409 sprintfW(buff
, wFileDescriptionFormat
, lang
, code
);
410 SH_FileVersionQuerySetText(hwndDlg
, 14003, pBuf
, buff
, &str
);
412 sprintfW(buff
, wLegalCopyrightFormat
, lang
, code
);
413 SH_FileVersionQuerySetText(hwndDlg
, 14005, pBuf
, buff
, &str
);
415 /* listbox properties */
416 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wCompanyName
, &str
, lang
, code
);
417 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wFileVersion
, &str
, lang
, code
);
418 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wInternalName
, &str
, lang
, code
);
420 /* FIXME insert language identifier */
422 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wOriginalFilename
, &str
, lang
, code
);
423 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wProductName
, &str
, lang
, code
);
424 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wProductVersion
, &str
, lang
, code
);
425 SetWindowLong(hwndDlg
, DWL_USER
, (LONG
)pBuf
);
427 /* select first item */
428 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
429 SendMessageW(hDlgCtrl
, LB_SETCURSEL
, 0, 0);
430 str
= (WCHAR
*)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, (WPARAM
)0, (LPARAM
)NULL
);
431 hDlgCtrl
= GetDlgItem(hwndDlg
, 14010);
432 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)str
);
436 /*************************************************************************
438 * SH_FileVersionDlgProc
440 * wnd proc of 'Version' property sheet page
444 SH_FileVersionDlgProc(
451 LPPROPSHEETPAGE ppsp
;
457 ppsp
= (LPPROPSHEETPAGE
)lParam
;
461 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n",hwndDlg
, lParam
, ppsp
->lParam
);
463 lpstr
= (WCHAR
*)ppsp
->lParam
;
468 return SH_FileVersionInitialize(hwndDlg
, lpstr
);
472 if(LOWORD(wParam
) == 14009 && HIWORD(wParam
) == LBN_DBLCLK
)
478 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
479 lresult
= SendMessageW(hDlgCtrl
, LB_GETCURSEL
, (WPARAM
)NULL
, (LPARAM
)NULL
);
480 if(lresult
== LB_ERR
)
484 str
= (WCHAR
*)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, (WPARAM
)lresult
, (LPARAM
)NULL
);
490 hDlgCtrl
= GetDlgItem(hwndDlg
, 14010);
491 TRACE("hDlgCtrl %x string %s \n",hDlgCtrl
, debugstr_w(str
));
492 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)str
);
496 buf
= (LPVOID
)GetWindowLong(hwndDlg
, DWL_USER
);
497 HeapFree(GetProcessHeap(), 0, buf
);
504 /*************************************************************************
506 * SH_FileGeneralDlgProc
508 * wnd proc of 'General' property sheet page
514 SH_FileGeneralDlgProc(
521 LPPROPSHEETPAGEW ppsp
;
526 ppsp
= (LPPROPSHEETPAGEW
)lParam
;
529 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n",hwndDlg
, lParam
, ppsp
->lParam
);
531 lpstr
= (WCHAR
*)ppsp
->lParam
;
535 ERR("no filename\n");
538 /* set general text properties filename filelocation and icon */
539 SH_FileGeneralSetText(hwndDlg
, lpstr
);
540 /* enumerate file extension from registry and application which opens it*/
541 SH_FileGeneralSetFileType(hwndDlg
, strrchrW(lpstr
, '.'));
542 /* set file time create/modfied/accessed */
543 SH_FileGeneralSetFileSizeTime(hwndDlg
, lpstr
, NULL
);
552 /*************************************************************************
554 * SH_ShowPropertiesDialog
556 * called from ShellExecuteExW32
558 * lpf contains (quoted) path of folder/file
560 * TODO: provide button change application type if file has registered type
561 * make filename field editable and apply changes to filename on close
565 SH_ShowPropertiesDialog(WCHAR
* lpf
)
567 PROPSHEETHEADERW pinfo
;
568 HPROPSHEETPAGE hppages
[MAX_PROPERTY_SHEET_PAGE
];
569 HPROPSHEETPAGE hpage
;
570 WCHAR wFileName
[MAX_PATH
];
574 TRACE("SH_ShowPropertiesDialog entered\n");
582 memset(hppages
, 0x0, sizeof(HPROPSHEETPAGE
) * MAX_PROPERTY_SHEET_PAGE
);
585 /* remove quotes from lpf */
586 LPWSTR src
= lpf
+ 1;
587 LPWSTR dst
= wFileName
;
589 while(*src
&& *src
!='"')
596 strcpyW(wFileName
, lpf
);
599 if (PathIsDirectoryW(wFileName
) || strlenW(wFileName
) == 3)
601 FIXME("directory / drive resources are missing\n");
604 hpage
= SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", SH_FileGeneralDlgProc
, (LPARAM
)wFileName
);
609 hppages
[num_pages
] = hpage
;
611 if ( GetFileVersionInfoSizeW(lpf
, &dwHandle
) )
613 if ( (hpage
= SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG",SH_FileVersionDlgProc
, (LPARAM
)lpf
))!= NULL
)
615 hppages
[num_pages
] = hpage
;
619 memset(&pinfo
, 0x0, sizeof(PROPSHEETHEADERW
));
620 pinfo
.dwSize
= sizeof(PROPSHEETHEADERW
);
621 pinfo
.dwFlags
= PSH_NOCONTEXTHELP
| PSH_PROPTITLE
;
622 pinfo
.nPages
= num_pages
;
623 pinfo
.phpage
= hppages
;
624 pinfo
.pszCaption
= wFileName
;
625 return (PropertySheetW(&pinfo
) != -1);