2 * Provides default file shell extension
4 * Copyright 2005 Johannes Anderwald
5 * Copyright 2012 Rafal Harabien
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
26 EXTERN_C BOOL
PathIsExeW(LPCWSTR lpszPath
);
28 BOOL
CFileVersionInfo::Load(LPCWSTR pwszPath
)
30 ULONG cbInfo
= GetFileVersionInfoSizeW(pwszPath
, NULL
);
33 WARN("GetFileVersionInfoSize %ls failed\n", pwszPath
);
37 m_pInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbInfo
);
40 ERR("HeapAlloc failed bytes %x\n", cbInfo
);
44 if (!GetFileVersionInfoW(pwszPath
, 0, cbInfo
, m_pInfo
))
46 ERR("GetFileVersionInfoW failed\n");
50 LPLANGANDCODEPAGE lpLangCode
;
52 if (!VerQueryValueW(m_pInfo
, L
"\\VarFileInfo\\Translation", (LPVOID
*)&lpLangCode
, &cBytes
) || cBytes
< sizeof(LANGANDCODEPAGE
))
54 ERR("VerQueryValueW failed\n");
58 /* FIXME: find language from current locale / if not available,
60 * for now default to first available language
62 m_wLang
= lpLangCode
->wLang
;
63 m_wCode
= lpLangCode
->wCode
;
64 TRACE("Lang %hx Code %hu\n", m_wLang
, m_wCode
);
69 LPCWSTR
CFileVersionInfo::GetString(LPCWSTR pwszName
)
75 swprintf(wszBuf
, L
"\\StringFileInfo\\%04x%04x\\%s", m_wLang
, m_wCode
, pwszName
);
77 /* Query string in version block */
78 LPCWSTR pwszResult
= NULL
;
80 if (!VerQueryValueW(m_pInfo
, wszBuf
, (LPVOID
*)&pwszResult
, &cBytes
))
86 swprintf(wszBuf
, L
"\\StringFileInfo\\%04x%04x\\%s", MAKELANGID(LANG_ENGLISH
, SUBLANG_ENGLISH_US
), 1252, pwszName
);
87 if (!VerQueryValueW(m_pInfo
, wszBuf
, (LPVOID
*)&pwszResult
, &cBytes
))
92 ERR("VerQueryValueW %ls failed\n", pwszName
);
94 TRACE("%ls: %ls\n", pwszName
, pwszResult
);
99 VS_FIXEDFILEINFO
*CFileVersionInfo::GetFixedInfo()
104 VS_FIXEDFILEINFO
*pInfo
;
106 if (!VerQueryValueW(m_pInfo
, L
"\\", (PVOID
*)&pInfo
, &cBytes
))
111 LPCWSTR
CFileVersionInfo::GetLangName()
118 if (!VerLanguageNameW(m_wLang
, m_wszLang
, _countof(m_wszLang
)))
119 ERR("VerLanguageNameW failed\n");
126 SH_FormatInteger(LONGLONG Num
, LPWSTR pwszResult
, UINT cchResultMax
)
128 // Print the number in uniform mode
130 swprintf(wszNumber
, L
"%I64u", Num
);
132 // Get system strings for decimal and thousand separators.
133 WCHAR wszDecimalSep
[8], wszThousandSep
[8];
134 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_SDECIMAL
, wszDecimalSep
, _countof(wszDecimalSep
));
135 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
, wszThousandSep
, _countof(wszThousandSep
));
137 // Initialize format for printing the number in bytes
139 ZeroMemory(&nf
, sizeof(nf
));
140 nf
.lpDecimalSep
= wszDecimalSep
;
141 nf
.lpThousandSep
= wszThousandSep
;
143 // Get system string for groups separator
144 WCHAR wszGrouping
[12];
145 INT cchGrouping
= GetLocaleInfoW(LOCALE_USER_DEFAULT
,
148 _countof(wszGrouping
));
150 // Convert grouping specs from string to integer
151 for (INT i
= 0; i
< cchGrouping
; i
++)
153 WCHAR wch
= wszGrouping
[i
];
155 if (wch
>= L
'0' && wch
<= L
'9')
156 nf
.Grouping
= nf
.Grouping
* 10 + (wch
- L
'0');
157 else if (wch
!= L
';')
161 if ((nf
.Grouping
% 10) == 0)
167 INT cchResult
= GetNumberFormatW(LOCALE_USER_DEFAULT
,
177 // GetNumberFormatW returns number of characters including UNICODE_NULL
178 return cchResult
- 1;
182 SH_FormatByteSize(LONGLONG cbSize
, LPWSTR pwszResult
, UINT cchResultMax
)
184 /* Write formated bytes count */
185 INT cchWritten
= SH_FormatInteger(cbSize
, pwszResult
, cchResultMax
);
189 /* Copy " bytes" to buffer */
190 LPWSTR pwszEnd
= pwszResult
+ cchWritten
;
191 size_t cchRemaining
= cchResultMax
- cchWritten
;
192 StringCchCopyExW(pwszEnd
, cchRemaining
, L
" ", &pwszEnd
, &cchRemaining
, 0);
193 cchWritten
= LoadStringW(shell32_hInstance
, IDS_BYTES_FORMAT
, pwszEnd
, cchRemaining
);
194 cchRemaining
-= cchWritten
;
196 return cchResultMax
- cchRemaining
;
199 /*************************************************************************
201 * SH_FormatFileSizeWithBytes
203 * Format a size in bytes to string.
205 * lpQwSize = Pointer to 64bit large integer to format
206 * pszBuf = Buffer to fill with output string
207 * cchBuf = size of pszBuf in characters
212 SH_FormatFileSizeWithBytes(const PULARGE_INTEGER lpQwSize
, LPWSTR pwszResult
, UINT cchResultMax
)
214 /* Format bytes in KBs, MBs etc */
215 if (StrFormatByteSizeW(lpQwSize
->QuadPart
, pwszResult
, cchResultMax
) == NULL
)
218 /* If there is less bytes than 1KB, we have nothing to do */
219 if (lpQwSize
->QuadPart
< 1024)
222 /* Concatenate " (" */
223 UINT cchWritten
= wcslen(pwszResult
);
224 LPWSTR pwszEnd
= pwszResult
+ cchWritten
;
225 size_t cchRemaining
= cchResultMax
- cchWritten
;
226 StringCchCopyExW(pwszEnd
, cchRemaining
, L
" (", &pwszEnd
, &cchRemaining
, 0);
228 /* Write formated bytes count */
229 cchWritten
= SH_FormatByteSize(lpQwSize
->QuadPart
, pwszEnd
, cchRemaining
);
230 pwszEnd
+= cchWritten
;
231 cchRemaining
-= cchWritten
;
233 /* Copy ")" to the buffer */
234 StringCchCopyW(pwszEnd
, cchRemaining
, L
")");
239 /*************************************************************************
241 * SH_CreatePropertySheetPage [Internal]
243 * creates a property sheet page from a resource id
248 SH_CreatePropertySheetPage(WORD wDialogId
, DLGPROC pfnDlgProc
, LPARAM lParam
, LPCWSTR pwszTitle
)
252 memset(&Page
, 0x0, sizeof(PROPSHEETPAGEW
));
253 Page
.dwSize
= sizeof(PROPSHEETPAGEW
);
254 Page
.dwFlags
= PSP_DEFAULT
;
255 Page
.hInstance
= shell32_hInstance
;
256 Page
.pszTemplate
= MAKEINTRESOURCE(wDialogId
);
257 Page
.pfnDlgProc
= pfnDlgProc
;
258 Page
.lParam
= lParam
;
259 Page
.pszTitle
= pwszTitle
;
262 Page
.dwFlags
|= PSP_USETITLE
;
264 return CreatePropertySheetPageW(&Page
);
268 CFileDefExt::InitOpensWithField(HWND hwndDlg
)
270 WCHAR wszBuf
[MAX_PATH
] = L
"";
271 WCHAR wszPath
[MAX_PATH
] = L
"";
272 DWORD dwSize
= sizeof(wszBuf
);
273 BOOL bUnknownApp
= TRUE
;
274 LPCWSTR pwszExt
= PathFindExtensionW(m_wszPath
);
276 if (RegGetValueW(HKEY_CLASSES_ROOT
, pwszExt
, L
"", RRF_RT_REG_SZ
, NULL
, wszBuf
, &dwSize
) == ERROR_SUCCESS
)
279 StringCbCatW(wszBuf
, sizeof(wszBuf
), L
"\\shell\\open\\command");
280 dwSize
= sizeof(wszPath
);
281 if (RegGetValueW(HKEY_CLASSES_ROOT
, wszBuf
, L
"", RRF_RT_REG_SZ
, NULL
, wszPath
, &dwSize
) == ERROR_SUCCESS
)
283 /* Get path from command line */
284 ExpandEnvironmentStringsW(wszPath
, wszBuf
, _countof(wszBuf
));
285 PathRemoveArgs(wszBuf
);
286 PathUnquoteSpacesW(wszBuf
);
287 PathSearchAndQualify(wszBuf
, wszPath
, _countof(wszPath
));
290 if (ExtractIconExW(wszPath
, 0, NULL
, &hIcon
, 1))
292 HWND hIconCtrl
= GetDlgItem(hwndDlg
, 14025);
293 HWND hDescrCtrl
= GetDlgItem(hwndDlg
, 14007);
294 ShowWindow(hIconCtrl
, SW_SHOW
);
295 RECT rcIcon
, rcDescr
;
296 GetWindowRect(hIconCtrl
, &rcIcon
);
298 rcIcon
.right
= rcIcon
.left
+ GetSystemMetrics(SM_CXSMICON
);
299 rcIcon
.bottom
= rcIcon
.top
+ GetSystemMetrics(SM_CYSMICON
);
301 MapWindowPoints(NULL
, hwndDlg
, (LPPOINT
)&rcIcon
, 2);
302 GetWindowRect(hDescrCtrl
, &rcDescr
);
303 MapWindowPoints(NULL
, hwndDlg
, (LPPOINT
)&rcDescr
, 2);
304 INT cxOffset
= rcIcon
.right
+ 2 - rcDescr
.left
;
305 SetWindowPos(hDescrCtrl
, NULL
,
306 rcDescr
.left
+ cxOffset
, rcDescr
.top
,
307 rcDescr
.right
- rcDescr
.left
- cxOffset
, rcDescr
.bottom
- rcDescr
.top
,
309 SendMessageW(hIconCtrl
, STM_SETICON
, (WPARAM
)hIcon
, 0);
311 ERR("Failed to extract icon\n");
313 if (PathFileExistsW(wszPath
))
315 /* Get file description */
316 CFileVersionInfo VerInfo
;
317 VerInfo
.Load(wszPath
);
318 LPCWSTR pwszDescr
= VerInfo
.GetString(L
"FileDescription");
320 SetDlgItemTextW(hwndDlg
, 14007, pwszDescr
);
323 /* File has no description - display filename */
324 LPWSTR pwszFilename
= PathFindFileNameW(wszPath
);
325 PathRemoveExtension(pwszFilename
);
326 pwszFilename
[0] = towupper(pwszFilename
[0]);
327 SetDlgItemTextW(hwndDlg
, 14007, pwszFilename
);
333 WARN("RegGetValueW %ls failed\n", wszBuf
);
335 WARN("RegGetValueW %ls failed\n", pwszExt
);
339 /* Unknown application */
340 LoadStringW(shell32_hInstance
, IDS_UNKNOWN_APP
, wszBuf
, _countof(wszBuf
));
341 SetDlgItemTextW(hwndDlg
, 14007, wszBuf
);
345 /*************************************************************************
347 * SH_FileGeneralFileType [Internal]
349 * retrieves file extension description from registry and sets it in dialog
351 * TODO: retrieve file extension default icon and load it
352 * find executable name from registry, retrieve description from executable
356 CFileDefExt::InitFileType(HWND hwndDlg
)
358 TRACE("path %s\n", debugstr_w(m_wszPath
));
360 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14005);
361 if (hDlgCtrl
== NULL
)
364 /* Get file information */
366 if (!SHGetFileInfoW(m_wszPath
, 0, &fi
, sizeof(fi
), SHGFI_TYPENAME
|SHGFI_ICON
))
368 ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_wszPath
, GetLastError());
369 fi
.szTypeName
[0] = L
'\0';
373 LPCWSTR pwszExt
= PathFindExtensionW(m_wszPath
);
378 if (!fi
.szTypeName
[0])
380 /* The file type is unknown, so default to string "FileExtension File" */
381 size_t cchRemaining
= 0;
382 LPWSTR pwszEnd
= NULL
;
384 StringCchPrintfExW(wszBuf
, _countof(wszBuf
), &pwszEnd
, &cchRemaining
, 0, L
"%s ", pwszExt
+ 1);
385 SendMessageW(hDlgCtrl
, WM_GETTEXT
, (WPARAM
)cchRemaining
, (LPARAM
)pwszEnd
);
387 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)wszBuf
);
391 /* Update file type */
392 StringCbPrintfW(wszBuf
, sizeof(wszBuf
), L
"%s (%s)", fi
.szTypeName
, pwszExt
);
393 SendMessageW(hDlgCtrl
, WM_SETTEXT
, (WPARAM
)NULL
, (LPARAM
)wszBuf
);
397 /* Update file icon */
399 SendDlgItemMessageW(hwndDlg
, 14000, STM_SETICON
, (WPARAM
)fi
.hIcon
, 0);
401 ERR("No icon %ls\n", m_wszPath
);
406 /*************************************************************************
408 * CFileDefExt::InitFilePath [Internal]
410 * sets file path string and filename string
415 CFileDefExt::InitFilePath(HWND hwndDlg
)
417 /* Find the filename */
418 WCHAR
*pwszFilename
= PathFindFileNameW(m_wszPath
);
420 if (pwszFilename
> m_wszPath
)
423 WCHAR wszLocation
[MAX_PATH
];
424 StringCchCopyNW(wszLocation
, _countof(wszLocation
), m_wszPath
, pwszFilename
- m_wszPath
);
425 PathRemoveBackslashW(wszLocation
);
427 SetDlgItemTextW(hwndDlg
, 14009, wszLocation
);
431 SetDlgItemTextW(hwndDlg
, 14001, pwszFilename
);
436 /*************************************************************************
438 * CFileDefExt::GetFileTimeString [Internal]
440 * formats a given LPFILETIME struct into readable user format
444 CFileDefExt::GetFileTimeString(LPFILETIME lpFileTime
, LPWSTR pwszResult
, UINT cchResult
)
449 if (!FileTimeToLocalFileTime(lpFileTime
, &ft
) || !FileTimeToSystemTime(&ft
, &st
))
452 size_t cchRemaining
= cchResult
;
453 LPWSTR pwszEnd
= pwszResult
;
454 int cchWritten
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, pwszEnd
, cchRemaining
);
456 --cchWritten
; // GetDateFormatW returns count with terminating zero
458 ERR("GetDateFormatW failed\n");
459 cchRemaining
-= cchWritten
;
460 pwszEnd
+= cchWritten
;
462 StringCchCopyExW(pwszEnd
, cchRemaining
, L
", ", &pwszEnd
, &cchRemaining
, 0);
464 cchWritten
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, pwszEnd
, cchRemaining
);
466 --cchWritten
; // GetTimeFormatW returns count with terminating zero
468 ERR("GetTimeFormatW failed\n");
469 TRACE("result %s\n", debugstr_w(pwszResult
));
473 /*************************************************************************
475 * CFileDefExt::InitFileAttr [Internal]
477 * retrieves file information from file and sets in dialog
482 CFileDefExt::InitFileAttr(HWND hwndDlg
)
485 WIN32_FIND_DATAW FileInfo
; // WIN32_FILE_ATTRIBUTE_DATA
486 WCHAR wszBuf
[MAX_PATH
];
488 TRACE("InitFileAttr %ls\n", m_wszPath
);
491 * There are situations where GetFileAttributes(Ex) can fail even if the
492 * specified path represents a file. This happens when e.g. the file is a
493 * locked system file, such as C:\pagefile.sys . In this case, the function
494 * returns INVALID_FILE_ATTRIBUTES and GetLastError returns ERROR_SHARING_VIOLATION.
495 * (this would allow us to distinguish between this failure and a failure
496 * due to the fact that the path actually refers to a directory).
498 * Because we really want to retrieve the file attributes/size/date&time,
499 * we do the following trick:
500 * - First we call GetFileAttributesEx. If it succeeds we know we have
501 * a file or a directory, and we have retrieved its attributes.
502 * - If GetFileAttributesEx fails, we call FindFirstFile on the full path.
503 * While we could have called FindFirstFile at first and skip GetFileAttributesEx
504 * altogether, we do it after GetFileAttributesEx because it performs more
505 * work to retrieve the file attributes. However it actually works even
506 * for locked system files.
507 * - If FindFirstFile succeeds we have retrieved its attributes.
508 * - Otherwise (FindFirstFile has failed), we do not retrieve anything.
510 * The following code also relies on the fact that the first 6 members
511 * of WIN32_FIND_DATA are *exactly* the same as the WIN32_FILE_ATTRIBUTE_DATA
512 * structure. Therefore it is safe to use a single WIN32_FIND_DATA
513 * structure for both the GetFileAttributesEx and FindFirstFile calls.
516 Success
= GetFileAttributesExW(m_wszPath
,
517 GetFileExInfoStandard
,
518 (LPWIN32_FILE_ATTRIBUTE_DATA
)&FileInfo
);
521 HANDLE hFind
= FindFirstFileW(m_wszPath
, &FileInfo
);
522 Success
= (hFind
!= INVALID_HANDLE_VALUE
);
529 /* Update attribute checkboxes */
530 if (FileInfo
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
531 SendDlgItemMessage(hwndDlg
, 14021, BM_SETCHECK
, BST_CHECKED
, 0);
532 if (FileInfo
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
533 SendDlgItemMessage(hwndDlg
, 14022, BM_SETCHECK
, BST_CHECKED
, 0);
534 if (FileInfo
.dwFileAttributes
& FILE_ATTRIBUTE_ARCHIVE
)
535 SendDlgItemMessage(hwndDlg
, 14023, BM_SETCHECK
, BST_CHECKED
, 0);
537 /* Update creation time */
538 if (GetFileTimeString(&FileInfo
.ftCreationTime
, wszBuf
, _countof(wszBuf
)))
539 SetDlgItemTextW(hwndDlg
, 14015, wszBuf
);
541 /* For files display last access and last write time */
544 if (GetFileTimeString(&FileInfo
.ftLastAccessTime
, wszBuf
, _countof(wszBuf
)))
545 SetDlgItemTextW(hwndDlg
, 14019, wszBuf
);
547 if (GetFileTimeString(&FileInfo
.ftLastWriteTime
, wszBuf
, _countof(wszBuf
)))
548 SetDlgItemTextW(hwndDlg
, 14017, wszBuf
);
550 /* Update size of file */
551 ULARGE_INTEGER FileSize
;
552 FileSize
.u
.LowPart
= FileInfo
.nFileSizeLow
;
553 FileSize
.u
.HighPart
= FileInfo
.nFileSizeHigh
;
554 if (SH_FormatFileSizeWithBytes(&FileSize
, wszBuf
, _countof(wszBuf
)))
555 SetDlgItemTextW(hwndDlg
, 14011, wszBuf
);
561 /* For directories files have to be counted */
563 _CountFolderAndFilesData
*data
= static_cast<_CountFolderAndFilesData
*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_CountFolderAndFilesData
)));
565 data
->pwszBuf
= static_cast<LPWSTR
>(HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) * MAX_PATH
));
566 data
->cchBufMax
= MAX_PATH
;
567 data
->hwndDlg
= hwndDlg
;
569 StringCchCopyW(data
->pwszBuf
, MAX_PATH
, m_wszPath
);
571 SHCreateThread(CFileDefExt::_CountFolderAndFilesThreadProc
, data
, NULL
, NULL
);
573 /* Update size field */
574 if (SH_FormatFileSizeWithBytes(&m_DirSize
, wszBuf
, _countof(wszBuf
)))
575 SetDlgItemTextW(hwndDlg
, 14011, wszBuf
);
577 /* Display files and folders count */
578 WCHAR wszFormat
[256];
579 LoadStringW(shell32_hInstance
, IDS_FILE_FOLDER
, wszFormat
, _countof(wszFormat
));
580 StringCchPrintfW(wszBuf
, _countof(wszBuf
), wszFormat
, m_cFiles
, m_cFolders
);
581 SetDlgItemTextW(hwndDlg
, 14027, wszBuf
);
584 /* Hide Advanced button. TODO: Implement advanced dialog and enable this button if filesystem supports compression or encryption */
585 ShowWindow(GetDlgItem(hwndDlg
, 14028), SW_HIDE
);
590 /*************************************************************************
592 * CFileDefExt::InitGeneralPage [Internal]
594 * sets all file general properties in dialog
598 CFileDefExt::InitGeneralPage(HWND hwndDlg
)
600 /* Set general text properties filename filelocation and icon */
601 InitFilePath(hwndDlg
);
603 /* Set file type and icon */
604 InitFileType(hwndDlg
);
606 /* Set open with application */
609 if (!PathIsExeW(m_wszPath
))
610 InitOpensWithField(hwndDlg
);
613 WCHAR wszBuf
[MAX_PATH
];
614 LoadStringW(shell32_hInstance
, IDS_EXE_DESCRIPTION
, wszBuf
, _countof(wszBuf
));
615 SetDlgItemTextW(hwndDlg
, 14006, wszBuf
);
616 ShowWindow(GetDlgItem(hwndDlg
, 14024), SW_HIDE
);
618 /* hidden button 14024 allows to draw edit 14007 larger than defined in resources , we use edit 14009 as idol */
619 RECT rectIdol
, rectToAdjust
;
620 GetClientRect(GetDlgItem(hwndDlg
, 14009), &rectIdol
);
621 GetClientRect(GetDlgItem(hwndDlg
, 14007), &rectToAdjust
);
622 SetWindowPos(GetDlgItem(hwndDlg
, 14007), HWND_TOP
, 0, 0,
623 rectIdol
.right
-rectIdol
.left
/* make it as wide as its idol */,
624 rectToAdjust
.bottom
-rectToAdjust
.top
/* but keep its current height */,
625 SWP_NOMOVE
| SWP_NOZORDER
);
627 LPCWSTR pwszDescr
= m_VerInfo
.GetString(L
"FileDescription");
629 SetDlgItemTextW(hwndDlg
, 14007, pwszDescr
);
632 StringCbCopyW(wszBuf
, sizeof(wszBuf
), PathFindFileNameW(m_wszPath
));
633 PathRemoveExtension(wszBuf
);
634 SetDlgItemTextW(hwndDlg
, 14007, wszBuf
);
639 /* Set file created/modfied/accessed time, size and attributes */
640 InitFileAttr(hwndDlg
);
645 /*************************************************************************
647 * CFileDefExt::GeneralPageProc
649 * wnd proc of 'General' property sheet page
654 CFileDefExt::GeneralPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
656 CFileDefExt
*pFileDefExt
= reinterpret_cast<CFileDefExt
*>(GetWindowLongPtr(hwndDlg
, DWLP_USER
));
661 LPPROPSHEETPAGEW ppsp
= (LPPROPSHEETPAGEW
)lParam
;
663 if (ppsp
== NULL
|| !ppsp
->lParam
)
666 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg
, lParam
, ppsp
->lParam
);
668 pFileDefExt
= reinterpret_cast<CFileDefExt
*>(ppsp
->lParam
);
669 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pFileDefExt
);
670 pFileDefExt
->InitGeneralPage(hwndDlg
);
674 if (LOWORD(wParam
) == 14024) /* Opens With - Change */
677 oainfo
.pcszFile
= pFileDefExt
->m_wszPath
;
678 oainfo
.pcszClass
= NULL
;
679 oainfo
.oaifInFlags
= OAIF_REGISTER_EXT
|OAIF_FORCE_REGISTRATION
;
680 return SUCCEEDED(SHOpenWithDialog(hwndDlg
, &oainfo
));
682 else if (LOWORD(wParam
) == 14021 || LOWORD(wParam
) == 14022 || LOWORD(wParam
) == 14023) /* checkboxes */
683 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
684 else if (LOWORD(wParam
) == 14001) /* Name */
686 if (HIWORD(wParam
) == EN_CHANGE
)
687 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
692 LPPSHNOTIFY lppsn
= (LPPSHNOTIFY
)lParam
;
693 if (lppsn
->hdr
.code
== PSN_APPLY
)
695 /* Update attributes first */
696 DWORD dwAttr
= GetFileAttributesW(pFileDefExt
->m_wszPath
);
699 dwAttr
&= ~(FILE_ATTRIBUTE_READONLY
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_ARCHIVE
);
701 if (BST_CHECKED
== SendDlgItemMessageW(hwndDlg
, 14021, BM_GETCHECK
, 0, 0))
702 dwAttr
|= FILE_ATTRIBUTE_READONLY
;
703 if (BST_CHECKED
== SendDlgItemMessageW(hwndDlg
, 14022, BM_GETCHECK
, 0, 0))
704 dwAttr
|= FILE_ATTRIBUTE_HIDDEN
;
705 if (BST_CHECKED
== SendDlgItemMessageW(hwndDlg
, 14023, BM_GETCHECK
, 0, 0))
706 dwAttr
|= FILE_ATTRIBUTE_ARCHIVE
;
708 if (!SetFileAttributesW(pFileDefExt
->m_wszPath
, dwAttr
))
709 ERR("SetFileAttributesW failed\n");
712 /* Update filename now */
713 WCHAR wszBuf
[MAX_PATH
];
714 StringCchCopyW(wszBuf
, _countof(wszBuf
), pFileDefExt
->m_wszPath
);
715 LPWSTR pwszFilename
= PathFindFileNameW(wszBuf
);
716 UINT cchFilenameMax
= _countof(wszBuf
) - (pwszFilename
- wszBuf
);
717 if (GetDlgItemTextW(hwndDlg
, 14001, pwszFilename
, cchFilenameMax
))
719 if (!MoveFileW(pFileDefExt
->m_wszPath
, wszBuf
))
720 ERR("MoveFileW failed\n");
723 SetWindowLongPtr(hwndDlg
, DWLP_MSGRESULT
, PSNRET_NOERROR
);
728 case PSM_QUERYSIBLINGS
:
731 HWND hIconCtrl
= GetDlgItem(hwndDlg
, 14025);
732 HICON hIcon
= (HICON
)SendMessageW(hIconCtrl
, STM_GETICON
, 0, 0);
735 SendMessageW(hIconCtrl
, STM_SETICON
, (WPARAM
)hIcon
, 0);
738 pFileDefExt
->InitGeneralPage(hwndDlg
);
739 return FALSE
; // continue
748 /*************************************************************************
750 * CFileDefExt::InitVersionPage [Internal]
752 * sets all file version properties in dialog
756 CFileDefExt::InitVersionPage(HWND hwndDlg
)
759 VS_FIXEDFILEINFO
*pInfo
= m_VerInfo
.GetFixedInfo();
762 WCHAR wszVersion
[256];
763 swprintf(wszVersion
, L
"%u.%u.%u.%u", HIWORD(pInfo
->dwFileVersionMS
),
764 LOWORD(pInfo
->dwFileVersionMS
),
765 HIWORD(pInfo
->dwFileVersionLS
),
766 LOWORD(pInfo
->dwFileVersionLS
));
767 TRACE("MS %x LS %x ver %s \n", pInfo
->dwFileVersionMS
, pInfo
->dwFileVersionLS
, debugstr_w(wszVersion
));
768 SetDlgItemTextW(hwndDlg
, 14001, wszVersion
);
772 SetVersionLabel(hwndDlg
, 14003, L
"FileDescription");
773 SetVersionLabel(hwndDlg
, 14005, L
"LegalCopyright");
775 /* Add items to listbox */
776 AddVersionString(hwndDlg
, L
"CompanyName");
777 LPCWSTR pwszLang
= m_VerInfo
.GetLangName();
780 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
781 UINT Index
= SendMessageW(hDlgCtrl
, LB_ADDSTRING
, (WPARAM
)-1, (LPARAM
)L
"Language");
782 SendMessageW(hDlgCtrl
, LB_SETITEMDATA
, (WPARAM
)Index
, (LPARAM
)(WCHAR
*)pwszLang
);
784 AddVersionString(hwndDlg
, L
"ProductName");
785 AddVersionString(hwndDlg
, L
"InternalName");
786 AddVersionString(hwndDlg
, L
"OriginalFilename");
787 AddVersionString(hwndDlg
, L
"FileVersion");
788 AddVersionString(hwndDlg
, L
"ProductVersion");
790 /* Attach file version to dialog window */
791 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)this);
793 /* Select first item */
794 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
795 SendMessageW(hDlgCtrl
, LB_SETCURSEL
, 0, 0);
796 LPCWSTR pwszText
= (LPCWSTR
)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, (WPARAM
)0, (LPARAM
)NULL
);
797 if (pwszText
&& pwszText
!= (LPCWSTR
)LB_ERR
)
798 SetDlgItemTextW(hwndDlg
, 14010, pwszText
);
803 /*************************************************************************
805 * CFileDefExt::SetVersionLabel [Internal]
807 * retrieves a version string and uses it to set label text
811 CFileDefExt::SetVersionLabel(HWND hwndDlg
, DWORD idCtrl
, LPCWSTR pwszName
)
813 if (hwndDlg
== NULL
|| pwszName
== NULL
)
816 LPCWSTR pwszValue
= m_VerInfo
.GetString(pwszName
);
819 /* file description property */
820 TRACE("%s :: %s\n", debugstr_w(pwszName
), debugstr_w(pwszValue
));
821 SetDlgItemTextW(hwndDlg
, idCtrl
, pwszValue
);
828 /*************************************************************************
830 * CFileDefExt::AddVersionString [Internal]
832 * retrieves a version string and adds it to listbox
836 CFileDefExt::AddVersionString(HWND hwndDlg
, LPCWSTR pwszName
)
838 TRACE("pwszName %s, hwndDlg %p\n", debugstr_w(pwszName
), hwndDlg
);
840 if (hwndDlg
== NULL
|| pwszName
== NULL
)
843 LPCWSTR pwszValue
= m_VerInfo
.GetString(pwszName
);
846 /* listbox name property */
847 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14009);
848 TRACE("%s :: %s\n", debugstr_w(pwszName
), debugstr_w(pwszValue
));
849 UINT Index
= SendMessageW(hDlgCtrl
, LB_ADDSTRING
, (WPARAM
) -1, (LPARAM
)pwszName
);
850 SendMessageW(hDlgCtrl
, LB_SETITEMDATA
, (WPARAM
)Index
, (LPARAM
)(WCHAR
*)pwszValue
);
857 /*************************************************************************
859 * CFileDefExt::VersionPageProc
861 * wnd proc of 'Version' property sheet page
865 CFileDefExt::VersionPageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
871 LPPROPSHEETPAGE ppsp
= (LPPROPSHEETPAGE
)lParam
;
873 if (ppsp
== NULL
|| !ppsp
->lParam
)
876 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg
, lParam
, ppsp
->lParam
);
878 CFileDefExt
*pFileDefExt
= reinterpret_cast<CFileDefExt
*>(ppsp
->lParam
);
879 return pFileDefExt
->InitVersionPage(hwndDlg
);
882 if (LOWORD(wParam
) == 14009 && HIWORD(wParam
) == LBN_SELCHANGE
)
884 HWND hDlgCtrl
= (HWND
)lParam
;
886 LRESULT Index
= SendMessageW(hDlgCtrl
, LB_GETCURSEL
, (WPARAM
)NULL
, (LPARAM
)NULL
);
890 LPCWSTR pwszData
= (LPCWSTR
)SendMessageW(hDlgCtrl
, LB_GETITEMDATA
, (WPARAM
)Index
, (LPARAM
)NULL
);
891 if (pwszData
== NULL
)
894 TRACE("hDlgCtrl %x string %s\n", hDlgCtrl
, debugstr_w(pwszData
));
895 SetDlgItemTextW(hwndDlg
, 14010, pwszData
);
902 case PSM_QUERYSIBLINGS
:
903 return FALSE
; // continue
911 /*************************************************************************/
912 /* Folder Customize */
914 static const WCHAR s_szShellClassInfo
[] = L
".ShellClassInfo";
915 static const WCHAR s_szIconIndex
[] = L
"IconIndex";
916 static const WCHAR s_szIconFile
[] = L
"IconFile";
917 static const WCHAR s_szIconResource
[] = L
"IconResource";
919 // IDD_FOLDER_CUSTOMIZE
921 CFileDefExt::FolderCustomizePageProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
923 CFileDefExt
*pFileDefExt
= reinterpret_cast<CFileDefExt
*>(GetWindowLongPtr(hwndDlg
, DWLP_USER
));
928 LPPROPSHEETPAGE ppsp
= (LPPROPSHEETPAGE
)lParam
;
930 if (ppsp
== NULL
|| !ppsp
->lParam
)
933 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg
, lParam
, ppsp
->lParam
);
935 pFileDefExt
= reinterpret_cast<CFileDefExt
*>(ppsp
->lParam
);
936 return pFileDefExt
->InitFolderCustomizePage(hwndDlg
);
940 switch (LOWORD(wParam
))
942 case IDC_FOLDERCUST_CHANGE_ICON
:
943 pFileDefExt
->OnFolderCustChangeIcon(hwndDlg
);
946 case IDC_FOLDERCUST_CHOOSE_PIC
:
950 case IDC_FOLDERCUST_RESTORE_DEFAULTS
:
958 LPPSHNOTIFY lppsn
= (LPPSHNOTIFY
)lParam
;
959 if (lppsn
->hdr
.code
== PSN_APPLY
)
962 if (pFileDefExt
->OnFolderCustApply(hwndDlg
))
964 SetWindowLongPtr(hwndDlg
, DWLP_MSGRESULT
, PSNRET_NOERROR
);
968 SetWindowLongPtr(hwndDlg
, DWLP_MSGRESULT
, PSNRET_INVALID_NOCHANGEPAGE
);
975 case PSM_QUERYSIBLINGS
:
976 return FALSE
; // continue
979 pFileDefExt
->OnFolderCustDestroy(hwndDlg
);
989 // IDD_FOLDER_CUSTOMIZE WM_DESTROY
990 void CFileDefExt::OnFolderCustDestroy(HWND hwndDlg
)
992 ::DestroyIcon(m_hFolderIcon
);
993 m_hFolderIcon
= NULL
;
995 /* Detach the object from dialog window */
996 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)0);
999 void CFileDefExt::UpdateFolderIcon(HWND hwndDlg
)
1001 // destroy icon if any
1004 ::DestroyIcon(m_hFolderIcon
);
1005 m_hFolderIcon
= NULL
;
1009 if (m_szFolderIconPath
[0] == 0 && m_nFolderIconIndex
== 0)
1011 m_hFolderIcon
= LoadIconW(shell32_hInstance
, MAKEINTRESOURCEW(IDI_SHELL_FOLDER
));
1015 ExtractIconExW(m_szFolderIconPath
, m_nFolderIconIndex
, &m_hFolderIcon
, NULL
, 1);
1019 SendDlgItemMessageW(hwndDlg
, IDC_FOLDERCUST_ICON
, STM_SETICON
, (WPARAM
)m_hFolderIcon
, 0);
1022 // IDD_FOLDER_CUSTOMIZE WM_INITDIALOG
1023 BOOL
CFileDefExt::InitFolderCustomizePage(HWND hwndDlg
)
1025 /* Attach the object to dialog window */
1026 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)this);
1028 EnableWindow(GetDlgItem(hwndDlg
, IDC_FOLDERCUST_COMBOBOX
), FALSE
);
1029 EnableWindow(GetDlgItem(hwndDlg
, IDC_FOLDERCUST_CHECKBOX
), FALSE
);
1030 EnableWindow(GetDlgItem(hwndDlg
, IDC_FOLDERCUST_CHOOSE_PIC
), FALSE
);
1031 EnableWindow(GetDlgItem(hwndDlg
, IDC_FOLDERCUST_RESTORE_DEFAULTS
), FALSE
);
1033 // build the desktop.ini file path
1034 WCHAR szIniFile
[MAX_PATH
];
1035 StringCchCopyW(szIniFile
, _countof(szIniFile
), m_wszPath
);
1036 PathAppendW(szIniFile
, L
"desktop.ini");
1038 // desktop.ini --> m_szFolderIconPath, m_nFolderIconIndex
1039 m_szFolderIconPath
[0] = 0;
1040 m_nFolderIconIndex
= 0;
1041 if (GetPrivateProfileStringW(s_szShellClassInfo
, s_szIconFile
, NULL
,
1042 m_szFolderIconPath
, _countof(m_szFolderIconPath
), szIniFile
))
1044 m_nFolderIconIndex
= GetPrivateProfileIntW(s_szShellClassInfo
, s_szIconIndex
, 0, szIniFile
);
1046 else if (GetPrivateProfileStringW(s_szShellClassInfo
, s_szIconResource
, NULL
,
1047 m_szFolderIconPath
, _countof(m_szFolderIconPath
), szIniFile
))
1049 m_nFolderIconIndex
= PathParseIconLocationW(m_szFolderIconPath
);
1053 UpdateFolderIcon(hwndDlg
);
1058 // IDD_FOLDER_CUSTOMIZE IDC_FOLDERCUST_CHANGE_ICON
1059 void CFileDefExt::OnFolderCustChangeIcon(HWND hwndDlg
)
1061 WCHAR szPath
[MAX_PATH
];
1064 // m_szFolderIconPath, m_nFolderIconIndex --> szPath, nIconIndex
1065 if (m_szFolderIconPath
[0])
1067 StringCchCopyW(szPath
, _countof(szPath
), m_szFolderIconPath
);
1068 nIconIndex
= m_nFolderIconIndex
;
1076 // let the user choose the icon
1077 if (PickIconDlg(hwndDlg
, szPath
, _countof(szPath
), &nIconIndex
))
1080 m_bFolderIconIsSet
= TRUE
;
1081 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
1084 StringCchCopyW(m_szFolderIconPath
, _countof(m_szFolderIconPath
), szPath
);
1085 m_nFolderIconIndex
= nIconIndex
;
1086 UpdateFolderIcon(hwndDlg
);
1090 // IDD_FOLDER_CUSTOMIZE PSN_APPLY
1091 BOOL
CFileDefExt::OnFolderCustApply(HWND hwndDlg
)
1093 // build the desktop.ini file path
1094 WCHAR szIniFile
[MAX_PATH
];
1095 StringCchCopyW(szIniFile
, _countof(szIniFile
), m_wszPath
);
1096 PathAppendW(szIniFile
, L
"desktop.ini");
1098 if (m_bFolderIconIsSet
) // it is set!
1102 // change folder attributes (-S -R)
1103 attrs
= GetFileAttributesW(m_wszPath
);
1104 attrs
&= ~(FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_READONLY
);
1105 SetFileAttributesW(m_wszPath
, attrs
);
1107 // change desktop.ini attributes (-S -H -R)
1108 attrs
= GetFileAttributesW(szIniFile
);
1109 attrs
&= ~(FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
);
1110 SetFileAttributesW(szIniFile
, attrs
);
1112 if (m_szFolderIconPath
[0])
1114 // write IconFile and IconIndex
1115 WritePrivateProfileStringW(s_szShellClassInfo
, s_szIconFile
, m_szFolderIconPath
, szIniFile
);
1118 StringCchPrintfW(szInt
, _countof(szInt
), L
"%d", m_nFolderIconIndex
);
1119 WritePrivateProfileStringW(s_szShellClassInfo
, s_szIconIndex
, szInt
, szIniFile
);
1122 WritePrivateProfileStringW(NULL
, NULL
, NULL
, szIniFile
);
1126 // erase three values
1127 WritePrivateProfileStringW(s_szShellClassInfo
, s_szIconFile
, NULL
, szIniFile
);
1128 WritePrivateProfileStringW(s_szShellClassInfo
, s_szIconIndex
, NULL
, szIniFile
);
1129 WritePrivateProfileStringW(s_szShellClassInfo
, s_szIconResource
, NULL
, szIniFile
);
1132 WritePrivateProfileStringW(NULL
, NULL
, NULL
, szIniFile
);
1135 // change desktop.ini attributes (+S +H)
1136 attrs
= GetFileAttributesW(szIniFile
);
1137 attrs
|= FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
;
1138 SetFileAttributesW(szIniFile
, attrs
);
1140 // change folder attributes (+R)
1141 attrs
= GetFileAttributesW(m_wszPath
);
1142 attrs
|= FILE_ATTRIBUTE_READONLY
;
1143 SetFileAttributesW(m_wszPath
, attrs
);
1145 // notify to the siblings
1146 PropSheet_QuerySiblings(GetParent(hwndDlg
), 0, 0);
1149 m_bFolderIconIsSet
= FALSE
;
1155 /*****************************************************************************/
1157 CFileDefExt::CFileDefExt():
1158 m_bDir(FALSE
), m_cFiles(0), m_cFolders(0)
1160 m_wszPath
[0] = L
'\0';
1161 m_DirSize
.QuadPart
= 0ull;
1163 m_szFolderIconPath
[0] = 0;
1164 m_nFolderIconIndex
= 0;
1165 m_hFolderIcon
= NULL
;
1166 m_bFolderIconIsSet
= FALSE
;
1169 CFileDefExt::~CFileDefExt()
1175 CFileDefExt::Initialize(LPCITEMIDLIST pidlFolder
, IDataObject
*pDataObj
, HKEY hkeyProgID
)
1181 TRACE("%p %p %p %p\n", this, pidlFolder
, pDataObj
, hkeyProgID
);
1186 format
.cfFormat
= CF_HDROP
;
1188 format
.dwAspect
= DVASPECT_CONTENT
;
1190 format
.tymed
= TYMED_HGLOBAL
;
1192 hr
= pDataObj
->GetData(&format
, &stgm
);
1196 if (!DragQueryFileW((HDROP
)stgm
.hGlobal
, 0, m_wszPath
, _countof(m_wszPath
)))
1198 ERR("DragQueryFileW failed\n");
1199 ReleaseStgMedium(&stgm
);
1203 ReleaseStgMedium(&stgm
);
1205 TRACE("File properties %ls\n", m_wszPath
);
1206 m_bDir
= PathIsDirectoryW(m_wszPath
) ? TRUE
: FALSE
;
1208 m_VerInfo
.Load(m_wszPath
);
1214 CFileDefExt::QueryContextMenu(HMENU hmenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
1221 CFileDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
1228 CFileDefExt::GetCommandString(UINT_PTR idCmd
, UINT uType
, UINT
*pwReserved
, LPSTR pszName
, UINT cchMax
)
1235 CFileDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage
, LPARAM lParam
)
1237 HPROPSHEETPAGE hPage
;
1238 WORD wResId
= m_bDir
? IDD_FOLDER_PROPERTIES
: IDD_FILE_PROPERTIES
;
1240 hPage
= SH_CreatePropertySheetPage(wResId
,
1245 pfnAddPage(hPage
, lParam
);
1247 if (!m_bDir
&& GetFileVersionInfoSizeW(m_wszPath
, NULL
))
1249 hPage
= SH_CreatePropertySheetPage(IDD_FILE_VERSION
,
1254 pfnAddPage(hPage
, lParam
);
1259 hPage
= SH_CreatePropertySheetPage(IDD_FOLDER_CUSTOMIZE
,
1260 FolderCustomizePageProc
,
1264 pfnAddPage(hPage
, lParam
);
1271 CFileDefExt::ReplacePage(UINT uPageID
, LPFNADDPROPSHEETPAGE pfnReplacePage
, LPARAM lParam
)
1278 CFileDefExt::SetSite(IUnknown
*punk
)
1285 CFileDefExt::GetSite(REFIID iid
, void **ppvSite
)
1292 CFileDefExt::_CountFolderAndFilesThreadProc(LPVOID lpParameter
)
1294 _CountFolderAndFilesData
*data
= static_cast<_CountFolderAndFilesData
*>(lpParameter
);
1296 data
->This
->CountFolderAndFiles(data
->hwndDlg
, data
->pwszBuf
, data
->cchBufMax
, &ticks
);
1298 //Release the CFileDefExt and data object holds in the copying thread.
1299 data
->This
->Release();
1300 HeapFree(GetProcessHeap(), 0, data
->pwszBuf
);
1301 HeapFree(GetProcessHeap(), 0, data
);
1307 CFileDefExt::CountFolderAndFiles(HWND hwndDlg
, LPWSTR pwszBuf
, UINT cchBufMax
, DWORD
*ticks
)
1309 /* Find filename position */
1310 UINT cchBuf
= wcslen(pwszBuf
);
1311 WCHAR
*pwszFilename
= pwszBuf
+ cchBuf
;
1312 size_t cchFilenameMax
= cchBufMax
- cchBuf
;
1313 if (!cchFilenameMax
)
1315 *(pwszFilename
++) = '\\';
1318 /* Find all files, FIXME: shouldn't be "*"? */
1319 StringCchCopyW(pwszFilename
, cchFilenameMax
, L
"*");
1321 WIN32_FIND_DATAW wfd
;
1322 HANDLE hFind
= FindFirstFileW(pwszBuf
, &wfd
);
1323 if (hFind
== INVALID_HANDLE_VALUE
)
1325 ERR("FindFirstFileW %ls failed\n", pwszBuf
);
1331 *ticks
= GetTickCount();
1337 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1339 /* Don't process "." and ".." items */
1340 if (!wcscmp(wfd
.cFileName
, L
".") || !wcscmp(wfd
.cFileName
, L
".."))
1345 StringCchCopyW(pwszFilename
, cchFilenameMax
, wfd
.cFileName
);
1346 CountFolderAndFiles(hwndDlg
, pwszBuf
, cchBufMax
, ticks
);
1352 ULARGE_INTEGER FileSize
;
1353 FileSize
.u
.LowPart
= wfd
.nFileSizeLow
;
1354 FileSize
.u
.HighPart
= wfd
.nFileSizeHigh
;
1355 m_DirSize
.QuadPart
+= FileSize
.QuadPart
;
1357 if (GetTickCount() - *ticks
> (DWORD
) 300)
1359 /* FIXME Using IsWindow is generally ill advised */
1360 if (IsWindow(hwndDlg
))
1362 WCHAR wszBuf
[MAX_PATH
];
1364 if (SH_FormatFileSizeWithBytes(&m_DirSize
, wszBuf
, _countof(wszBuf
)))
1365 SetDlgItemTextW(hwndDlg
, 14011, wszBuf
);
1367 /* Display files and folders count */
1368 WCHAR wszFormat
[256];
1369 LoadStringW(shell32_hInstance
, IDS_FILE_FOLDER
, wszFormat
, _countof(wszFormat
));
1370 StringCchPrintfW(wszBuf
, _countof(wszBuf
), wszFormat
, m_cFiles
, m_cFolders
);
1371 SetDlgItemTextW(hwndDlg
, 14027, wszBuf
);
1372 *ticks
= GetTickCount();
1377 } while(FindNextFileW(hFind
, &wfd
));
1379 if (root
&& IsWindow(hwndDlg
))
1381 WCHAR wszBuf
[MAX_PATH
];
1383 if (SH_FormatFileSizeWithBytes(&m_DirSize
, wszBuf
, _countof(wszBuf
)))
1384 SetDlgItemTextW(hwndDlg
, 14011, wszBuf
);
1386 /* Display files and folders count */
1387 WCHAR wszFormat
[256];
1388 LoadStringW(shell32_hInstance
, IDS_FILE_FOLDER
, wszFormat
, _countof(wszFormat
));
1389 StringCchPrintfW(wszBuf
, _countof(wszBuf
), wszFormat
, m_cFiles
, m_cFolders
);
1390 SetDlgItemTextW(hwndDlg
, 14027, wszBuf
);