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 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
46 typedef struct _LANGANDCODEPAGE_
50 } LANGANDCODEPAGE
, *LPLANGANDCODEPAGE
;
52 /*************************************************************************
54 * SH_FileGeneralFileType [Internal]
56 * retrieves file extension description from registry and sets it in dialog
58 * TODO: retrieve file extension default icon and load it
59 * find executable name from registry, retrieve description from executable
63 SH_FileGeneralSetFileType(HWND hwndDlg
, WCHAR
* filext
)
66 WCHAR value
[MAX_PATH
];
67 DWORD lname
= MAX_PATH
;
68 DWORD lvalue
= MAX_PATH
;
74 TRACE("fileext %s\n", debugstr_w(filext
));
79 hDlgCtrl
= GetDlgItem(hwndDlg
, 14005);
84 if (RegOpenKeyW(HKEY_CLASSES_ROOT
, filext
, &hKey
) != ERROR_SUCCESS
)
86 /* the fileextension is unknown, so default to string "FileExtension File" */
87 SendMessageW(hDlgCtrl
, WM_GETTEXT
, (WPARAM
)MAX_PATH
, (LPARAM
)value
);
88 sprintfW(name
, value
, &filext
[1]);
89 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)name
);
92 result
= RegEnumValueW(hKey
, 0, name
, &lname
, NULL
, NULL
, (LPBYTE
)value
, &lvalue
);
95 if (result
!= ERROR_SUCCESS
)
97 if (RegOpenKeyW(HKEY_CLASSES_ROOT
, value
, &hKey
) == ERROR_SUCCESS
)
99 lvalue
= lname
= MAX_PATH
;
100 result
= RegEnumValueW(hKey
,0, name
, &lname
, NULL
, NULL
, (LPBYTE
)value
, &lvalue
);
104 /* file extension type */
105 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)value
);
108 /*************************************************************************
110 * SHFileGeneralGetFileTimeString [Internal]
112 * formats a given LPFILETIME struct into readable user format
116 SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime
, WCHAR
* lpResult
)
121 static const WCHAR wFormat
[] = {'%','0','2','d','/','%','0','2','d','/','%','0','4','d',' ',' ','%','0','2','d',':','%','0','2','u',0};
123 if (lpFileTime
== NULL
|| lpResult
== NULL
)
126 if (!FileTimeToLocalFileTime(lpFileTime
, &ft
))
129 FileTimeToSystemTime(&ft
, &dt
);
133 sprintfW (lpResult
, wFormat
, dt
.wDay
, dt
.wMonth
, wYear
, dt
.wHour
, dt
.wMinute
);
135 TRACE("result %s\n",debugstr_w(lpResult
));
139 /*************************************************************************
141 * SH_FileGeneralSetText [Internal]
143 * sets file path string and filename string
148 SH_FileGeneralSetText(HWND hwndDlg
, WCHAR
* lpstr
)
153 WCHAR buff
[MAX_PATH
];
159 lpdir
= strrchrW(lpstr
, '\\'); /* find the last occurence of '\\' */
161 plength
= strlenW(lpstr
);
162 flength
= strlenW(lpdir
);
166 /* location text field */
167 strncpyW(buff
, lpstr
, plength
- flength
);
168 buff
[plength
- flength
] = UNICODE_NULL
;
169 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
170 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)buff
);
175 /* text filename field */
176 strncpyW(buff
, &lpdir
[1], flength
);
177 hDlgCtrl
= GetDlgItem(hwndDlg
, 14001);
178 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)buff
);
184 /*************************************************************************
186 * SH_FileGeneralSetFileSizeTime [Internal]
188 * retrieves file information from file and sets in dialog
193 SH_FileGeneralSetFileSizeTime(HWND hwndDlg
, WCHAR
* lpfilename
, PULARGE_INTEGER lpfilesize
)
197 FILETIME create_time
;
198 FILETIME accessed_time
;
200 WCHAR resultstr
[MAX_PATH
];
202 LARGE_INTEGER file_size
;
204 if (lpfilename
== NULL
)
207 hFile
= CreateFileW(lpfilename
,
209 FILE_SHARE_READ
,NULL
,
211 FILE_ATTRIBUTE_NORMAL
,
214 if (hFile
== INVALID_HANDLE_VALUE
)
216 WARN("failed to open file %s\n", debugstr_w(lpfilename
));
220 result
= GetFileTime(hFile
, &create_time
, &accessed_time
, &write_time
);
224 WARN("GetFileTime failed\n");
227 if (SHFileGeneralGetFileTimeString(&create_time
,resultstr
))
229 hDlgCtrl
= GetDlgItem(hwndDlg
, 14015);
230 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
233 if (SHFileGeneralGetFileTimeString(&accessed_time
, resultstr
))
235 hDlgCtrl
= GetDlgItem(hwndDlg
, 14017);
236 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
239 if (SHFileGeneralGetFileTimeString(&write_time
, resultstr
))
241 hDlgCtrl
= GetDlgItem(hwndDlg
, 14019);
242 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
245 if (!GetFileSizeEx(hFile
, &file_size
))
247 WARN("GetFileSize failed\n");
252 if (!StrFormatByteSizeW(file_size
.QuadPart
, resultstr
, sizeof(resultstr
) / sizeof(WCHAR
)))
254 hDlgCtrl
= GetDlgItem(hwndDlg
, 14011);
255 TRACE("result size %u resultstr %s\n", file_size
.QuadPart
, debugstr_w(resultstr
));
256 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)resultstr
);
259 lpfilesize
->QuadPart
= (ULONGLONG
)file_size
.QuadPart
;
264 /*************************************************************************
266 * SH_SetFileVersionText [Internal]
272 SH_FileVersionQuerySetText(HWND hwndDlg
, DWORD dlgId
, LPVOID pInfo
, WCHAR
* text
, WCHAR
** resptr
)
277 if(hwndDlg
== NULL
|| resptr
== NULL
|| text
== NULL
)
280 if(VerQueryValueW(pInfo
, text
, (LPVOID
*)resptr
, &reslen
))
282 /* file description property */
283 hDlgCtrl
= GetDlgItem(hwndDlg
, dlgId
);
284 TRACE("%s :: %s\n",debugstr_w(text
), debugstr_w(*resptr
));
285 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)0, (LPARAM
)*resptr
);
291 /*************************************************************************
293 * SH_FileVersionQuerySetListText [Internal]
295 * retrieves a version string and adds it to listbox
301 SH_FileVersionQuerySetListText(HWND hwndDlg
, LPVOID pInfo
, const WCHAR
* text
, WCHAR
**resptr
, WORD lang
, WORD code
)
306 static const WCHAR wFormat
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n',
307 'f','o','\\','%','0','4','x','%','0','4','x','\\','%','s',0 };
310 TRACE("text %s, resptr %p hwndDlg %p\n",debugstr_w(text
), resptr
, hwndDlg
);
312 if(hwndDlg
== NULL
|| resptr
== NULL
|| text
== NULL
)
315 sprintfW(buff
, wFormat
, lang
, code
, text
);
316 if(VerQueryValueW(pInfo
, buff
, (LPVOID
*)resptr
, &reslen
))
318 /* listbox name property */
319 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
320 TRACE("%s :: %s\n",debugstr_w(text
), debugstr_w(*resptr
));
321 index
= SendMessageW(hDlgCtrl
, LB_ADDSTRING
, (WPARAM
)-1, (LPARAM
)text
);
322 SendMessageW(hDlgCtrl
, LB_SETITEMDATA
, (WPARAM
)index
, (LPARAM
)(WCHAR
*)*resptr
);
328 /*************************************************************************
330 * SH_FileVersionInitialize [Internal]
332 * sets all file version properties in dialog
335 SH_FileVersionInitialize(HWND hwndDlg
, WCHAR
* lpfilename
)
346 LPLANGANDCODEPAGE lplangcode
;
348 static const WCHAR wVersionFormat
[] = { '%','d','.','%','d','.','%','d','.','%','d',0 };
349 static const WCHAR wFileDescriptionFormat
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
350 '\\','%','0','4','x','%','0','4','x','\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
351 static const WCHAR wLegalCopyrightFormat
[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
352 '\\','%','0','4','x','%','0','4','x','\\','L','e','g','a','l','C','o','p','y','r','i','g','h','t',0 };
353 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 };
354 static const WCHAR wCompanyName
[] = { 'C','o','m','p','a','n','y','N','a','m','e',0 };
355 static const WCHAR wFileVersion
[] = { 'F','i','l','e','V','e','r','s','i','o','n',0 };
356 static const WCHAR wInternalName
[] = { 'I','n','t','e','r','n','a','l','N','a','m','e',0 };
357 static const WCHAR wOriginalFilename
[] = { 'O','r','i','g','i','n','a','l','F','i','l','e','n','a','m','e',0 };
358 static const WCHAR wProductName
[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
359 static const WCHAR wProductVersion
[] = { 'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0 };
360 static const WCHAR wSlash
[] = { '\\',0 };
366 if(!(versize
= GetFileVersionInfoSizeW(lpfilename
, &handle
)))
368 WARN("GetFileVersionInfoSize failed\n");
372 if(!(pBuf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, versize
)))
374 WARN("HeapAlloc failed bytes %x\n",versize
);
378 if(!GetFileVersionInfoW(lpfilename
, handle
, versize
, pBuf
))
380 HeapFree(GetProcessHeap(), 0, pBuf
);
383 if(VerQueryValueW(pBuf
, wSlash
, &info
, &infolen
))
385 VS_FIXEDFILEINFO
* inf
= (VS_FIXEDFILEINFO
*)info
;
386 sprintfW(buff
, wVersionFormat
,inf
->dwFileVersionMS
& 0xFFFF0000,
387 inf
->dwFileVersionMS
& 0x0000FFFF,
388 inf
->dwFileVersionLS
& 0xFFFF0000,
389 inf
->dwFileVersionLS
& 0x0000FFFF);
391 hDlgCtrl
= GetDlgItem(hwndDlg
, 14001);
392 TRACE("MS %x LS %x res %s \n",inf
->dwFileVersionMS
, inf
->dwFileVersionLS
, debugstr_w(buff
));
393 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)buff
);
395 if(VerQueryValueW(pBuf
, wTranslation
, (LPVOID
*)&lplangcode
, &infolen
))
397 /* FIXME find language from current locale / if not available,
399 * for now default to first available language
401 lang
= lplangcode
->lang
;
402 code
= lplangcode
->code
;
405 sprintfW(buff
, wFileDescriptionFormat
, lang
, code
);
406 SH_FileVersionQuerySetText(hwndDlg
, 14003, pBuf
, buff
, &str
);
408 sprintfW(buff
, wLegalCopyrightFormat
, lang
, code
);
409 SH_FileVersionQuerySetText(hwndDlg
, 14005, pBuf
, buff
, &str
);
411 /* listbox properties */
412 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wCompanyName
, &str
, lang
, code
);
413 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wFileVersion
, &str
, lang
, code
);
414 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wInternalName
, &str
, lang
, code
);
416 /* FIXME insert language identifier */
418 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wOriginalFilename
, &str
, lang
, code
);
419 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wProductName
, &str
, lang
, code
);
420 SH_FileVersionQuerySetListText(hwndDlg
, pBuf
, wProductVersion
, &str
, lang
, code
);
421 SetWindowLong(hwndDlg
, DWL_USER
, (LONG
)pBuf
);
423 /* select first item */
424 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
425 SendMessageW(hDlgCtrl
, LB_SETCURSEL
, 0, 0);
426 str
= (WCHAR
*)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, (WPARAM
)0, (LPARAM
)NULL
);
427 hDlgCtrl
= GetDlgItem(hwndDlg
, 14010);
428 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)str
);
432 /*************************************************************************
434 * SH_FileVersionDlgProc
436 * wnd proc of 'Version' property sheet page
440 SH_FileVersionDlgProc(
447 LPPROPSHEETPAGE ppsp
;
453 ppsp
= (LPPROPSHEETPAGE
)lParam
;
457 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n",hwndDlg
, lParam
, ppsp
->lParam
);
459 lpstr
= (WCHAR
*)ppsp
->lParam
;
464 return SH_FileVersionInitialize(hwndDlg
, lpstr
);
468 if(LOWORD(wParam
) == 14009 && HIWORD(wParam
) == LBN_DBLCLK
)
474 hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
475 lresult
= SendMessageW(hDlgCtrl
, LB_GETCURSEL
, (WPARAM
)NULL
, (LPARAM
)NULL
);
476 if(lresult
== LB_ERR
)
480 str
= (WCHAR
*)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, (WPARAM
)lresult
, (LPARAM
)NULL
);
486 hDlgCtrl
= GetDlgItem(hwndDlg
, 14010);
487 TRACE("hDlgCtrl %x string %s \n",hDlgCtrl
, debugstr_w(str
));
488 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)str
);
492 buf
= (LPVOID
)GetWindowLong(hwndDlg
, DWL_USER
);
493 HeapFree(GetProcessHeap(), 0, buf
);
500 /*************************************************************************
502 * SH_FileGeneralDlgProc
504 * wnd proc of 'General' property sheet page
510 SH_FileGeneralDlgProc(
517 LPPROPSHEETPAGEW ppsp
;
522 ppsp
= (LPPROPSHEETPAGEW
)lParam
;
525 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n",hwndDlg
, lParam
, ppsp
->lParam
);
527 lpstr
= (WCHAR
*)ppsp
->lParam
;
531 ERR("no filename\n");
534 /* set general text properties filename filelocation and icon */
535 SH_FileGeneralSetText(hwndDlg
, lpstr
);
536 /* enumerate file extension from registry and application which opens it*/
537 SH_FileGeneralSetFileType(hwndDlg
, strrchrW(lpstr
, '.'));
538 /* set file time create/modfied/accessed */
539 SH_FileGeneralSetFileSizeTime(hwndDlg
, lpstr
, NULL
);
548 /*************************************************************************
550 * SH_ShowPropertiesDialog
552 * called from ShellExecuteExW32
554 * lpf contains (quoted) path of folder/file
556 * TODO: provide button change application type if file has registered type
557 * make filename field editable and apply changes to filename on close
561 SH_ShowPropertiesDialog(WCHAR
* lpf
)
563 PROPSHEETHEADERW pinfo
;
564 HPROPSHEETPAGE hppages
[MAX_PROPERTY_SHEET_PAGE
];
565 HPROPSHEETPAGE hpage
;
566 WCHAR wFileName
[MAX_PATH
];
570 TRACE("SH_ShowPropertiesDialog entered filename %s\n", debugstr_w(lpf
));
578 memset(hppages
, 0x0, sizeof(HPROPSHEETPAGE
) * MAX_PROPERTY_SHEET_PAGE
);
581 /* remove quotes from lpf */
582 LPWSTR src
= lpf
+ 1;
583 LPWSTR dst
= wFileName
;
585 while(*src
&& *src
!='"')
592 strcpyW(wFileName
, lpf
);
595 if (PathIsDirectoryW(wFileName
) || strlenW(wFileName
) == 3)
597 FIXME("directory / drive resources are missing\n");
600 hpage
= SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", SH_FileGeneralDlgProc
, (LPARAM
)wFileName
);
605 hppages
[num_pages
] = hpage
;
607 if ( GetFileVersionInfoSizeW(lpf
, &dwHandle
) )
609 if ( (hpage
= SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG",SH_FileVersionDlgProc
, (LPARAM
)lpf
))!= NULL
)
611 hppages
[num_pages
] = hpage
;
615 memset(&pinfo
, 0x0, sizeof(PROPSHEETHEADERW
));
616 pinfo
.dwSize
= sizeof(PROPSHEETHEADERW
);
617 pinfo
.dwFlags
= PSH_NOCONTEXTHELP
| PSH_PROPTITLE
;
618 pinfo
.nPages
= num_pages
;
619 pinfo
.phpage
= hppages
;
620 pinfo
.pszCaption
= wFileName
;
621 return (PropertySheetW(&pinfo
) != -1);