reactos/dll/win32/shell32/dialogs/filedefext.cpp
Oleg Dubinskiy eb96d377d1
[SHELL32] Allow custom shortcut overlay icon (#6419)
Use correct icon index in SIC_OverlayShortcutImage() to properly load
shortcut overlay icon from registry instead of always using default icon.
This allows to use custom shortcut icon set by user, in case it was
specified there.

As FIXME comment stated, the icon indexes were not implemented in the far
past, so this workaround was badly required. But now they are implemented,
so no need to always use default resource from shell32, enable the correct
code instead.

Also adapt this to CShellLink::CreateShortcutIcon() when the shortcut icon
is being changed in its properties dialog, as well as in CNewMenu class
when displaying menu items for creating a new folder or a shortcut.

Addendum to f9a5344254. CORE-14758
2024-03-04 16:30:43 +03:00

1480 lines
47 KiB
C++

/*
* Provides default file shell extension
*
* Copyright 2005 Johannes Anderwald
* Copyright 2012 Rafal Harabien
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "precomp.h"
#define NTOS_MODE_USER
#include <ndk/iofuncs.h>
#include <ndk/obfuncs.h>
WINE_DEFAULT_DEBUG_CHANNEL(shell);
EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath);
BOOL GetPhysicalFileSize(LPCWSTR PathBuffer, PULARGE_INTEGER Size)
{
UNICODE_STRING FileName;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
FILE_STANDARD_INFORMATION FileInfo;
NTSTATUS Status;
if (!RtlDosPathNameToNtPathName_U(PathBuffer, &FileName, NULL, NULL))
{
ERR("RtlDosPathNameToNtPathName_U failed\n");
return FALSE;
}
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&FileHandle,
FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
RtlFreeUnicodeString(&FileName);
if (!NT_SUCCESS(Status))
{
ERR("NtOpenFile failed for %S (Status 0x%08lx)\n", PathBuffer, Status);
return FALSE;
}
/* Query the file size */
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileInfo,
sizeof(FileInfo),
FileStandardInformation);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
{
ERR("NtQueryInformationFile failed for %S (Status: %08lX)\n", PathBuffer, Status);
return FALSE;
}
Size->QuadPart = FileInfo.AllocationSize.QuadPart;
return TRUE;
}
BOOL CFileVersionInfo::Load(LPCWSTR pwszPath)
{
ULONG cbInfo = GetFileVersionInfoSizeW(pwszPath, NULL);
if (!cbInfo)
{
WARN("GetFileVersionInfoSize %ls failed\n", pwszPath);
return FALSE;
}
m_pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbInfo);
if (!m_pInfo)
{
ERR("HeapAlloc failed bytes %x\n", cbInfo);
return FALSE;
}
if (!GetFileVersionInfoW(pwszPath, 0, cbInfo, m_pInfo))
{
ERR("GetFileVersionInfoW failed\n");
return FALSE;
}
LPLANGANDCODEPAGE lpLangCode;
UINT cBytes;
if (!VerQueryValueW(m_pInfo, L"\\VarFileInfo\\Translation", (LPVOID *)&lpLangCode, &cBytes) || cBytes < sizeof(LANGANDCODEPAGE))
{
ERR("VerQueryValueW failed\n");
return FALSE;
}
/* FIXME: find language from current locale / if not available,
* default to english
* for now default to first available language
*/
m_wLang = lpLangCode->wLang;
m_wCode = lpLangCode->wCode;
TRACE("Lang %hx Code %hu\n", m_wLang, m_wCode);
return TRUE;
}
LPCWSTR CFileVersionInfo::GetString(LPCWSTR pwszName)
{
if (!m_pInfo)
return NULL;
WCHAR wszBuf[256];
swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\%s", m_wLang, m_wCode, pwszName);
/* Query string in version block */
LPCWSTR pwszResult = NULL;
UINT cBytes = 0;
if (!VerQueryValueW(m_pInfo, wszBuf, (LPVOID *)&pwszResult, &cBytes))
pwszResult = NULL;
if (!pwszResult)
{
/* Try US English */
swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\%s", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 1252, pwszName);
if (!VerQueryValueW(m_pInfo, wszBuf, (LPVOID *)&pwszResult, &cBytes))
pwszResult = NULL;
}
if (!pwszResult)
ERR("VerQueryValueW %ls failed\n", pwszName);
else
TRACE("%ls: %ls\n", pwszName, pwszResult);
return pwszResult;
}
VS_FIXEDFILEINFO *CFileVersionInfo::GetFixedInfo()
{
if (!m_pInfo)
return NULL;
VS_FIXEDFILEINFO *pInfo;
UINT cBytes;
if (!VerQueryValueW(m_pInfo, L"\\", (PVOID*)&pInfo, &cBytes))
return NULL;
return pInfo;
}
LPCWSTR CFileVersionInfo::GetLangName()
{
if (!m_pInfo)
return NULL;
if (!m_wszLang[0])
{
if (!VerLanguageNameW(m_wLang, m_wszLang, _countof(m_wszLang)))
ERR("VerLanguageNameW failed\n");
}
return m_wszLang;
}
UINT
SH_FormatInteger(LONGLONG Num, LPWSTR pwszResult, UINT cchResultMax)
{
// Print the number in uniform mode
WCHAR wszNumber[24];
swprintf(wszNumber, L"%I64u", Num);
// Get system strings for decimal and thousand separators.
WCHAR wszDecimalSep[8], wszThousandSep[8];
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, wszDecimalSep, _countof(wszDecimalSep));
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, wszThousandSep, _countof(wszThousandSep));
// Initialize format for printing the number in bytes
NUMBERFMTW nf;
ZeroMemory(&nf, sizeof(nf));
nf.lpDecimalSep = wszDecimalSep;
nf.lpThousandSep = wszThousandSep;
// Get system string for groups separator
WCHAR wszGrouping[12];
INT cchGrouping = GetLocaleInfoW(LOCALE_USER_DEFAULT,
LOCALE_SGROUPING,
wszGrouping,
_countof(wszGrouping));
// Convert grouping specs from string to integer
for (INT i = 0; i < cchGrouping; i++)
{
WCHAR wch = wszGrouping[i];
if (wch >= L'0' && wch <= L'9')
nf.Grouping = nf.Grouping * 10 + (wch - L'0');
else if (wch != L';')
break;
}
if ((nf.Grouping % 10) == 0)
nf.Grouping /= 10;
else
nf.Grouping *= 10;
// Format the number
INT cchResult = GetNumberFormatW(LOCALE_USER_DEFAULT,
0,
wszNumber,
&nf,
pwszResult,
cchResultMax);
if (!cchResult)
return 0;
// GetNumberFormatW returns number of characters including UNICODE_NULL
return cchResult - 1;
}
UINT
SH_FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax)
{
/* Write formated bytes count */
INT cchWritten = SH_FormatInteger(cbSize, pwszResult, cchResultMax);
if (!cchWritten)
return 0;
/* Copy " bytes" to buffer */
LPWSTR pwszEnd = pwszResult + cchWritten;
size_t cchRemaining = cchResultMax - cchWritten;
StringCchCopyExW(pwszEnd, cchRemaining, L" ", &pwszEnd, &cchRemaining, 0);
cchWritten = LoadStringW(shell32_hInstance, IDS_BYTES_FORMAT, pwszEnd, cchRemaining);
cchRemaining -= cchWritten;
return cchResultMax - cchRemaining;
}
/*************************************************************************
*
* SH_FormatFileSizeWithBytes
*
* Format a size in bytes to string.
*
* lpQwSize = Pointer to 64bit large integer to format
* pszBuf = Buffer to fill with output string
* cchBuf = size of pszBuf in characters
*
*/
LPWSTR
SH_FormatFileSizeWithBytes(const PULARGE_INTEGER lpQwSize, LPWSTR pwszResult, UINT cchResultMax)
{
/* Format bytes in KBs, MBs etc */
if (StrFormatByteSizeW(lpQwSize->QuadPart, pwszResult, cchResultMax) == NULL)
return NULL;
/* If there is less bytes than 1KB, we have nothing to do */
if (lpQwSize->QuadPart < 1024)
return pwszResult;
/* Concatenate " (" */
UINT cchWritten = wcslen(pwszResult);
LPWSTR pwszEnd = pwszResult + cchWritten;
size_t cchRemaining = cchResultMax - cchWritten;
StringCchCopyExW(pwszEnd, cchRemaining, L" (", &pwszEnd, &cchRemaining, 0);
/* Write formated bytes count */
cchWritten = SH_FormatByteSize(lpQwSize->QuadPart, pwszEnd, cchRemaining);
pwszEnd += cchWritten;
cchRemaining -= cchWritten;
/* Copy ")" to the buffer */
StringCchCopyW(pwszEnd, cchRemaining, L")");
return pwszResult;
}
/*************************************************************************
*
* SH_CreatePropertySheetPage [Internal]
*
* creates a property sheet page from a resource id
*
*/
HPROPSHEETPAGE
SH_CreatePropertySheetPage(WORD wDialogId, DLGPROC pfnDlgProc, LPARAM lParam, LPCWSTR pwszTitle)
{
PROPSHEETPAGEW Page;
memset(&Page, 0x0, sizeof(PROPSHEETPAGEW));
Page.dwSize = sizeof(PROPSHEETPAGEW);
Page.dwFlags = PSP_DEFAULT;
Page.hInstance = shell32_hInstance;
Page.pszTemplate = MAKEINTRESOURCE(wDialogId);
Page.pfnDlgProc = pfnDlgProc;
Page.lParam = lParam;
Page.pszTitle = pwszTitle;
if (pwszTitle)
Page.dwFlags |= PSP_USETITLE;
return CreatePropertySheetPageW(&Page);
}
VOID
CFileDefExt::InitOpensWithField(HWND hwndDlg)
{
WCHAR wszBuf[MAX_PATH] = L"";
WCHAR wszPath[MAX_PATH] = L"";
DWORD dwSize = sizeof(wszBuf);
BOOL bUnknownApp = TRUE;
LPCWSTR pwszExt = PathFindExtensionW(m_wszPath);
if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS)
{
bUnknownApp = FALSE;
StringCbCatW(wszBuf, sizeof(wszBuf), L"\\shell\\open\\command");
dwSize = sizeof(wszPath);
if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"", RRF_RT_REG_SZ, NULL, wszPath, &dwSize) == ERROR_SUCCESS)
{
/* Get path from command line */
ExpandEnvironmentStringsW(wszPath, wszBuf, _countof(wszBuf));
PathRemoveArgs(wszBuf);
PathUnquoteSpacesW(wszBuf);
PathSearchAndQualify(wszBuf, wszPath, _countof(wszPath));
HICON hIcon;
if (ExtractIconExW(wszPath, 0, NULL, &hIcon, 1))
{
HWND hIconCtrl = GetDlgItem(hwndDlg, 14025);
HWND hDescrCtrl = GetDlgItem(hwndDlg, 14007);
ShowWindow(hIconCtrl, SW_SHOW);
RECT rcIcon, rcDescr;
GetWindowRect(hIconCtrl, &rcIcon);
rcIcon.right = rcIcon.left + GetSystemMetrics(SM_CXSMICON);
rcIcon.bottom = rcIcon.top + GetSystemMetrics(SM_CYSMICON);
MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rcIcon, 2);
GetWindowRect(hDescrCtrl, &rcDescr);
MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rcDescr, 2);
INT cxOffset = rcIcon.right + 2 - rcDescr.left;
SetWindowPos(hDescrCtrl, NULL,
rcDescr.left + cxOffset, rcDescr.top,
rcDescr.right - rcDescr.left - cxOffset, rcDescr.bottom - rcDescr.top,
SWP_NOZORDER);
SendMessageW(hIconCtrl, STM_SETICON, (WPARAM)hIcon, 0);
} else
ERR("Failed to extract icon\n");
if (PathFileExistsW(wszPath))
{
/* Get file description */
CFileVersionInfo VerInfo;
VerInfo.Load(wszPath);
LPCWSTR pwszDescr = VerInfo.GetString(L"FileDescription");
if (pwszDescr)
SetDlgItemTextW(hwndDlg, 14007, pwszDescr);
else
{
/* File has no description - display filename */
LPWSTR pwszFilename = PathFindFileNameW(wszPath);
PathRemoveExtension(pwszFilename);
pwszFilename[0] = towupper(pwszFilename[0]);
SetDlgItemTextW(hwndDlg, 14007, pwszFilename);
}
}
else
bUnknownApp = TRUE;
} else
WARN("RegGetValueW %ls failed\n", wszBuf);
} else
WARN("RegGetValueW %ls failed\n", pwszExt);
if (bUnknownApp)
{
/* Unknown application */
LoadStringW(shell32_hInstance, IDS_UNKNOWN_APP, wszBuf, _countof(wszBuf));
SetDlgItemTextW(hwndDlg, 14007, wszBuf);
}
}
/*************************************************************************
*
* SH_FileGeneralFileType [Internal]
*
* retrieves file extension description from registry and sets it in dialog
*
* TODO: retrieve file extension default icon and load it
* find executable name from registry, retrieve description from executable
*/
BOOL
CFileDefExt::InitFileType(HWND hwndDlg)
{
TRACE("path %s\n", debugstr_w(m_wszPath));
HWND hDlgCtrl = GetDlgItem(hwndDlg, 14005);
if (hDlgCtrl == NULL)
return FALSE;
/* Get file information */
SHFILEINFOW fi;
if (!SHGetFileInfoW(m_wszPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME|SHGFI_ICON))
{
ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_wszPath, GetLastError());
fi.szTypeName[0] = L'\0';
fi.hIcon = NULL;
}
LPCWSTR pwszExt = PathFindExtensionW(m_wszPath);
if (pwszExt[0])
{
WCHAR wszBuf[256];
if (!fi.szTypeName[0])
{
/* The file type is unknown, so default to string "FileExtension File" */
size_t cchRemaining = 0;
LPWSTR pwszEnd = NULL;
StringCchPrintfExW(wszBuf, _countof(wszBuf), &pwszEnd, &cchRemaining, 0, L"%s ", pwszExt + 1);
SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)cchRemaining, (LPARAM)pwszEnd);
SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf);
}
else
{
/* Update file type */
StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s (%s)", fi.szTypeName, pwszExt);
SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf);
}
}
/* Update file icon */
if (fi.hIcon)
SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)fi.hIcon, 0);
else
ERR("No icon %ls\n", m_wszPath);
return TRUE;
}
/*************************************************************************
*
* CFileDefExt::InitFilePath [Internal]
*
* sets file path string and filename string
*
*/
BOOL
CFileDefExt::InitFilePath(HWND hwndDlg)
{
/* Find the filename */
WCHAR *pwszFilename = PathFindFileNameW(m_wszPath);
if (pwszFilename > m_wszPath)
{
/* Location field */
WCHAR wszLocation[MAX_PATH];
StringCchCopyNW(wszLocation, _countof(wszLocation), m_wszPath, pwszFilename - m_wszPath);
PathRemoveBackslashW(wszLocation);
SetDlgItemTextW(hwndDlg, 14009, wszLocation);
}
/* Filename field */
SetDlgItemTextW(hwndDlg, 14001, pwszFilename);
return TRUE;
}
/*************************************************************************
*
* CFileDefExt::GetFileTimeString [Internal]
*
* formats a given LPFILETIME struct into readable user format
*/
BOOL
CFileDefExt::GetFileTimeString(LPFILETIME lpFileTime, LPWSTR pwszResult, UINT cchResult)
{
FILETIME ft;
SYSTEMTIME st;
if (!FileTimeToLocalFileTime(lpFileTime, &ft) || !FileTimeToSystemTime(&ft, &st))
return FALSE;
size_t cchRemaining = cchResult;
LPWSTR pwszEnd = pwszResult;
int cchWritten = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, pwszEnd, cchRemaining);
if (cchWritten)
--cchWritten; // GetDateFormatW returns count with terminating zero
else
ERR("GetDateFormatW failed\n");
cchRemaining -= cchWritten;
pwszEnd += cchWritten;
StringCchCopyExW(pwszEnd, cchRemaining, L", ", &pwszEnd, &cchRemaining, 0);
cchWritten = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, pwszEnd, cchRemaining);
if (cchWritten)
--cchWritten; // GetTimeFormatW returns count with terminating zero
else
ERR("GetTimeFormatW failed\n");
TRACE("result %s\n", debugstr_w(pwszResult));
return TRUE;
}
/*************************************************************************
*
* CFileDefExt::InitFileAttr [Internal]
*
* retrieves file information from file and sets in dialog
*
*/
BOOL
CFileDefExt::InitFileAttr(HWND hwndDlg)
{
BOOL Success;
WIN32_FIND_DATAW FileInfo; // WIN32_FILE_ATTRIBUTE_DATA
WCHAR wszBuf[MAX_PATH];
TRACE("InitFileAttr %ls\n", m_wszPath);
/*
* There are situations where GetFileAttributes(Ex) can fail even if the
* specified path represents a file. This happens when e.g. the file is a
* locked system file, such as C:\pagefile.sys . In this case, the function
* returns INVALID_FILE_ATTRIBUTES and GetLastError returns ERROR_SHARING_VIOLATION.
* (this would allow us to distinguish between this failure and a failure
* due to the fact that the path actually refers to a directory).
*
* Because we really want to retrieve the file attributes/size/date&time,
* we do the following trick:
* - First we call GetFileAttributesEx. If it succeeds we know we have
* a file or a directory, and we have retrieved its attributes.
* - If GetFileAttributesEx fails, we call FindFirstFile on the full path.
* While we could have called FindFirstFile at first and skip GetFileAttributesEx
* altogether, we do it after GetFileAttributesEx because it performs more
* work to retrieve the file attributes. However it actually works even
* for locked system files.
* - If FindFirstFile succeeds we have retrieved its attributes.
* - Otherwise (FindFirstFile has failed), we do not retrieve anything.
*
* The following code also relies on the fact that the first 6 members
* of WIN32_FIND_DATA are *exactly* the same as the WIN32_FILE_ATTRIBUTE_DATA
* structure. Therefore it is safe to use a single WIN32_FIND_DATA
* structure for both the GetFileAttributesEx and FindFirstFile calls.
*/
Success = GetFileAttributesExW(m_wszPath,
GetFileExInfoStandard,
(LPWIN32_FILE_ATTRIBUTE_DATA)&FileInfo);
if (!Success)
{
HANDLE hFind = FindFirstFileW(m_wszPath, &FileInfo);
Success = (hFind != INVALID_HANDLE_VALUE);
if (Success)
FindClose(hFind);
}
if (Success)
{
/* Update attribute checkboxes */
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
SendDlgItemMessage(hwndDlg, 14021, BM_SETCHECK, BST_CHECKED, 0);
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
SendDlgItemMessage(hwndDlg, 14022, BM_SETCHECK, BST_CHECKED, 0);
if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
SendDlgItemMessage(hwndDlg, 14023, BM_SETCHECK, BST_CHECKED, 0);
/* Update creation time */
if (GetFileTimeString(&FileInfo.ftCreationTime, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14015, wszBuf);
/* For files display last access and last write time */
if (!m_bDir)
{
if (GetFileTimeString(&FileInfo.ftLastAccessTime, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14019, wszBuf);
if (GetFileTimeString(&FileInfo.ftLastWriteTime, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14017, wszBuf);
/* Update size of file */
ULARGE_INTEGER FileSize;
FileSize.u.LowPart = FileInfo.nFileSizeLow;
FileSize.u.HighPart = FileInfo.nFileSizeHigh;
if (SH_FormatFileSizeWithBytes(&FileSize, wszBuf, _countof(wszBuf)))
{
SetDlgItemTextW(hwndDlg, 14011, wszBuf);
// Compute file on disk. If fails, use logical size
if (GetPhysicalFileSize(m_wszPath, &FileSize))
SH_FormatFileSizeWithBytes(&FileSize, wszBuf, _countof(wszBuf));
else
ERR("Unreliable size on disk\n");
SetDlgItemTextW(hwndDlg, 14012, wszBuf);
}
}
}
if (m_bDir)
{
/* For directories files have to be counted */
_CountFolderAndFilesData *data = static_cast<_CountFolderAndFilesData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_CountFolderAndFilesData)));
data->This = this;
data->pwszBuf = static_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR) * MAX_PATH));
data->hwndDlg = hwndDlg;
this->AddRef();
StringCchCopyW(data->pwszBuf, MAX_PATH, m_wszPath);
SHCreateThread(CFileDefExt::_CountFolderAndFilesThreadProc, data, NULL, NULL);
/* Update size field */
if (SH_FormatFileSizeWithBytes(&m_DirSize, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14011, wszBuf);
if (SH_FormatFileSizeWithBytes(&m_DirSizeOnDisc, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14012, wszBuf);
/* Display files and folders count */
WCHAR wszFormat[256];
LoadStringW(shell32_hInstance, IDS_FILE_FOLDER, wszFormat, _countof(wszFormat));
StringCchPrintfW(wszBuf, _countof(wszBuf), wszFormat, m_cFiles, m_cFolders);
SetDlgItemTextW(hwndDlg, 14027, wszBuf);
}
/* Hide Advanced button. TODO: Implement advanced dialog and enable this button if filesystem supports compression or encryption */
ShowWindow(GetDlgItem(hwndDlg, 14028), SW_HIDE);
return TRUE;
}
/*************************************************************************
*
* CFileDefExt::InitGeneralPage [Internal]
*
* sets all file general properties in dialog
*/
BOOL
CFileDefExt::InitGeneralPage(HWND hwndDlg)
{
/* Set general text properties filename filelocation and icon */
InitFilePath(hwndDlg);
/* Set file type and icon */
InitFileType(hwndDlg);
/* Set open with application */
if (!m_bDir)
{
if (!PathIsExeW(m_wszPath))
InitOpensWithField(hwndDlg);
else
{
WCHAR wszBuf[MAX_PATH];
LoadStringW(shell32_hInstance, IDS_EXE_DESCRIPTION, wszBuf, _countof(wszBuf));
SetDlgItemTextW(hwndDlg, 14006, wszBuf);
ShowWindow(GetDlgItem(hwndDlg, 14024), SW_HIDE);
/* hidden button 14024 allows to draw edit 14007 larger than defined in resources , we use edit 14009 as idol */
RECT rectIdol, rectToAdjust;
GetClientRect(GetDlgItem(hwndDlg, 14009), &rectIdol);
GetClientRect(GetDlgItem(hwndDlg, 14007), &rectToAdjust);
SetWindowPos(GetDlgItem(hwndDlg, 14007), HWND_TOP, 0, 0,
rectIdol.right-rectIdol.left /* make it as wide as its idol */,
rectToAdjust.bottom-rectToAdjust.top /* but keep its current height */,
SWP_NOMOVE | SWP_NOZORDER );
LPCWSTR pwszDescr = m_VerInfo.GetString(L"FileDescription");
if (pwszDescr)
SetDlgItemTextW(hwndDlg, 14007, pwszDescr);
else
{
StringCbCopyW(wszBuf, sizeof(wszBuf), PathFindFileNameW(m_wszPath));
PathRemoveExtension(wszBuf);
SetDlgItemTextW(hwndDlg, 14007, wszBuf);
}
}
}
/* Set file created/modfied/accessed time, size and attributes */
InitFileAttr(hwndDlg);
return TRUE;
}
/*************************************************************************
*
* CFileDefExt::GeneralPageProc
*
* wnd proc of 'General' property sheet page
*
*/
INT_PTR CALLBACK
CFileDefExt::GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CFileDefExt *pFileDefExt = reinterpret_cast<CFileDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam;
if (ppsp == NULL || !ppsp->lParam)
break;
TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg, lParam, ppsp->lParam);
pFileDefExt = reinterpret_cast<CFileDefExt *>(ppsp->lParam);
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pFileDefExt);
pFileDefExt->InitGeneralPage(hwndDlg);
break;
}
case WM_COMMAND:
if (LOWORD(wParam) == 14024) /* Opens With - Change */
{
OPENASINFO oainfo;
oainfo.pcszFile = pFileDefExt->m_wszPath;
oainfo.pcszClass = NULL;
oainfo.oaifInFlags = OAIF_REGISTER_EXT|OAIF_FORCE_REGISTRATION;
return SUCCEEDED(SHOpenWithDialog(hwndDlg, &oainfo));
}
else if (LOWORD(wParam) == 14021 || LOWORD(wParam) == 14022 || LOWORD(wParam) == 14023) /* checkboxes */
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
else if (LOWORD(wParam) == 14001) /* Name */
{
if (HIWORD(wParam) == EN_CHANGE)
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
}
break;
case WM_NOTIFY:
{
LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
if (lppsn->hdr.code == PSN_APPLY)
{
/* Update attributes first */
DWORD dwAttr = GetFileAttributesW(pFileDefExt->m_wszPath);
if (dwAttr)
{
dwAttr &= ~(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE);
if (BST_CHECKED == SendDlgItemMessageW(hwndDlg, 14021, BM_GETCHECK, 0, 0))
dwAttr |= FILE_ATTRIBUTE_READONLY;
if (BST_CHECKED == SendDlgItemMessageW(hwndDlg, 14022, BM_GETCHECK, 0, 0))
dwAttr |= FILE_ATTRIBUTE_HIDDEN;
if (BST_CHECKED == SendDlgItemMessageW(hwndDlg, 14023, BM_GETCHECK, 0, 0))
dwAttr |= FILE_ATTRIBUTE_ARCHIVE;
if (!SetFileAttributesW(pFileDefExt->m_wszPath, dwAttr))
ERR("SetFileAttributesW failed\n");
}
/* Update filename now */
WCHAR wszBuf[MAX_PATH];
StringCchCopyW(wszBuf, _countof(wszBuf), pFileDefExt->m_wszPath);
LPWSTR pwszFilename = PathFindFileNameW(wszBuf);
UINT cchFilenameMax = _countof(wszBuf) - (pwszFilename - wszBuf);
if (GetDlgItemTextW(hwndDlg, 14001, pwszFilename, cchFilenameMax))
{
if (!MoveFileW(pFileDefExt->m_wszPath, wszBuf))
ERR("MoveFileW failed\n");
}
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
return TRUE;
}
break;
}
case PSM_QUERYSIBLINGS:
{
// reset icon
HWND hIconCtrl = GetDlgItem(hwndDlg, 14025);
HICON hIcon = (HICON)SendMessageW(hIconCtrl, STM_GETICON, 0, 0);
DestroyIcon(hIcon);
hIcon = NULL;
SendMessageW(hIconCtrl, STM_SETICON, (WPARAM)hIcon, 0);
// refresh the page
pFileDefExt->InitGeneralPage(hwndDlg);
return FALSE; // continue
}
default:
break;
}
return FALSE;
}
/*************************************************************************
*
* CFileDefExt::InitVersionPage [Internal]
*
* sets all file version properties in dialog
*/
BOOL
CFileDefExt::InitVersionPage(HWND hwndDlg)
{
/* Get fixed info */
VS_FIXEDFILEINFO *pInfo = m_VerInfo.GetFixedInfo();
if (pInfo)
{
WCHAR wszVersion[256];
swprintf(wszVersion, L"%u.%u.%u.%u", HIWORD(pInfo->dwFileVersionMS),
LOWORD(pInfo->dwFileVersionMS),
HIWORD(pInfo->dwFileVersionLS),
LOWORD(pInfo->dwFileVersionLS));
TRACE("MS %x LS %x ver %s \n", pInfo->dwFileVersionMS, pInfo->dwFileVersionLS, debugstr_w(wszVersion));
SetDlgItemTextW(hwndDlg, 14001, wszVersion);
}
/* Update labels */
SetVersionLabel(hwndDlg, 14003, L"FileDescription");
SetVersionLabel(hwndDlg, 14005, L"LegalCopyright");
/* Add items to listbox */
AddVersionString(hwndDlg, L"CompanyName");
LPCWSTR pwszLang = m_VerInfo.GetLangName();
if (pwszLang)
{
HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009);
UINT Index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)L"Language");
SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)Index, (LPARAM)(WCHAR *)pwszLang);
}
AddVersionString(hwndDlg, L"ProductName");
AddVersionString(hwndDlg, L"InternalName");
AddVersionString(hwndDlg, L"OriginalFilename");
AddVersionString(hwndDlg, L"FileVersion");
AddVersionString(hwndDlg, L"ProductVersion");
AddVersionString(hwndDlg, L"Comments");
AddVersionString(hwndDlg, L"LegalTrademarks");
if (pInfo && (pInfo->dwFileFlags & VS_FF_PRIVATEBUILD))
AddVersionString(hwndDlg, L"PrivateBuild");
if (pInfo && (pInfo->dwFileFlags & VS_FF_SPECIALBUILD))
AddVersionString(hwndDlg, L"SpecialBuild");
/* Attach file version to dialog window */
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)this);
/* Select first item */
HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009);
SendMessageW(hDlgCtrl, LB_SETCURSEL, 0, 0);
LPCWSTR pwszText = (LPCWSTR)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)0, (LPARAM)NULL);
if (pwszText && pwszText != (LPCWSTR)LB_ERR)
SetDlgItemTextW(hwndDlg, 14010, pwszText);
return TRUE;
}
/*************************************************************************
*
* CFileDefExt::SetVersionLabel [Internal]
*
* retrieves a version string and uses it to set label text
*/
BOOL
CFileDefExt::SetVersionLabel(HWND hwndDlg, DWORD idCtrl, LPCWSTR pwszName)
{
if (hwndDlg == NULL || pwszName == NULL)
return FALSE;
LPCWSTR pwszValue = m_VerInfo.GetString(pwszName);
if (pwszValue)
{
/* file description property */
TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue));
SetDlgItemTextW(hwndDlg, idCtrl, pwszValue);
return TRUE;
}
return FALSE;
}
/*************************************************************************
*
* CFileDefExt::AddVersionString [Internal]
*
* retrieves a version string and adds it to listbox
*/
BOOL
CFileDefExt::AddVersionString(HWND hwndDlg, LPCWSTR pwszName)
{
TRACE("pwszName %s, hwndDlg %p\n", debugstr_w(pwszName), hwndDlg);
if (hwndDlg == NULL || pwszName == NULL)
return FALSE;
LPCWSTR pwszValue = m_VerInfo.GetString(pwszName);
if (pwszValue)
{
/* listbox name property */
HWND hDlgCtrl = GetDlgItem(hwndDlg, 14009);
TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue));
UINT Index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM) -1, (LPARAM)pwszName);
SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)Index, (LPARAM)(WCHAR *)pwszValue);
return TRUE;
}
return FALSE;
}
/*************************************************************************
*
* CFileDefExt::VersionPageProc
*
* wnd proc of 'Version' property sheet page
*/
INT_PTR CALLBACK
CFileDefExt::VersionPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam;
if (ppsp == NULL || !ppsp->lParam)
break;
TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam);
CFileDefExt *pFileDefExt = reinterpret_cast<CFileDefExt *>(ppsp->lParam);
return pFileDefExt->InitVersionPage(hwndDlg);
}
case WM_COMMAND:
if (LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_SELCHANGE)
{
HWND hDlgCtrl = (HWND)lParam;
LRESULT Index = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL);
if (Index == LB_ERR)
break;
LPCWSTR pwszData = (LPCWSTR)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)Index, (LPARAM)NULL);
if (pwszData == NULL)
break;
CString str(pwszData);
str.Trim();
TRACE("hDlgCtrl %x string %s\n", hDlgCtrl, debugstr_w(str));
SetDlgItemTextW(hwndDlg, 14010, str);
return TRUE;
}
break;
case WM_DESTROY:
break;
case PSM_QUERYSIBLINGS:
return FALSE; // continue
default:
break;
}
return FALSE;
}
/*************************************************************************/
/* Folder Customize */
static const WCHAR s_szShellClassInfo[] = L".ShellClassInfo";
static const WCHAR s_szIconIndex[] = L"IconIndex";
static const WCHAR s_szIconFile[] = L"IconFile";
static const WCHAR s_szIconResource[] = L"IconResource";
// IDD_FOLDER_CUSTOMIZE
INT_PTR CALLBACK
CFileDefExt::FolderCustomizePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CFileDefExt *pFileDefExt = reinterpret_cast<CFileDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam;
if (ppsp == NULL || !ppsp->lParam)
break;
TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam);
pFileDefExt = reinterpret_cast<CFileDefExt *>(ppsp->lParam);
return pFileDefExt->InitFolderCustomizePage(hwndDlg);
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_FOLDERCUST_CHANGE_ICON:
pFileDefExt->OnFolderCustChangeIcon(hwndDlg);
break;
case IDC_FOLDERCUST_CHOOSE_PIC:
// TODO:
break;
case IDC_FOLDERCUST_RESTORE_DEFAULTS:
// TODO:
break;
}
break;
case WM_NOTIFY:
{
LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
if (lppsn->hdr.code == PSN_APPLY)
{
// apply or not
if (pFileDefExt->OnFolderCustApply(hwndDlg))
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
}
else
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
}
return TRUE;
}
break;
}
case PSM_QUERYSIBLINGS:
return FALSE; // continue
case WM_DESTROY:
pFileDefExt->OnFolderCustDestroy(hwndDlg);
break;
default:
break;
}
return FALSE;
}
// IDD_FOLDER_CUSTOMIZE WM_DESTROY
void CFileDefExt::OnFolderCustDestroy(HWND hwndDlg)
{
::DestroyIcon(m_hFolderIcon);
m_hFolderIcon = NULL;
/* Detach the object from dialog window */
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)0);
}
void CFileDefExt::UpdateFolderIcon(HWND hwndDlg)
{
// destroy icon if any
if (m_hFolderIcon)
{
::DestroyIcon(m_hFolderIcon);
m_hFolderIcon = NULL;
}
// create the icon
if (m_szFolderIconPath[0] == 0 && m_nFolderIconIndex == 0)
{
// Windows ignores shell customization here and uses the default icon
m_hFolderIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER));
}
else
{
ExtractIconExW(m_szFolderIconPath, m_nFolderIconIndex, &m_hFolderIcon, NULL, 1);
}
// set icon
SendDlgItemMessageW(hwndDlg, IDC_FOLDERCUST_ICON, STM_SETICON, (WPARAM)m_hFolderIcon, 0);
}
// IDD_FOLDER_CUSTOMIZE WM_INITDIALOG
BOOL CFileDefExt::InitFolderCustomizePage(HWND hwndDlg)
{
/* Attach the object to dialog window */
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)this);
EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDERCUST_COMBOBOX), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDERCUST_CHECKBOX), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDERCUST_CHOOSE_PIC), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDERCUST_RESTORE_DEFAULTS), FALSE);
// build the desktop.ini file path
WCHAR szIniFile[MAX_PATH];
StringCchCopyW(szIniFile, _countof(szIniFile), m_wszPath);
PathAppendW(szIniFile, L"desktop.ini");
// desktop.ini --> m_szFolderIconPath, m_nFolderIconIndex
m_szFolderIconPath[0] = 0;
m_nFolderIconIndex = 0;
if (GetPrivateProfileStringW(s_szShellClassInfo, s_szIconFile, NULL,
m_szFolderIconPath, _countof(m_szFolderIconPath), szIniFile))
{
m_nFolderIconIndex = GetPrivateProfileIntW(s_szShellClassInfo, s_szIconIndex, 0, szIniFile);
}
else if (GetPrivateProfileStringW(s_szShellClassInfo, s_szIconResource, NULL,
m_szFolderIconPath, _countof(m_szFolderIconPath), szIniFile))
{
m_nFolderIconIndex = PathParseIconLocationW(m_szFolderIconPath);
}
// update icon
UpdateFolderIcon(hwndDlg);
return TRUE;
}
// IDD_FOLDER_CUSTOMIZE IDC_FOLDERCUST_CHANGE_ICON
void CFileDefExt::OnFolderCustChangeIcon(HWND hwndDlg)
{
WCHAR szPath[MAX_PATH];
INT nIconIndex;
// m_szFolderIconPath, m_nFolderIconIndex --> szPath, nIconIndex
if (m_szFolderIconPath[0])
{
StringCchCopyW(szPath, _countof(szPath), m_szFolderIconPath);
nIconIndex = m_nFolderIconIndex;
}
else
{
szPath[0] = 0;
nIconIndex = 0;
}
// let the user choose the icon
if (PickIconDlg(hwndDlg, szPath, _countof(szPath), &nIconIndex))
{
// changed
m_bFolderIconIsSet = TRUE;
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
// update
StringCchCopyW(m_szFolderIconPath, _countof(m_szFolderIconPath), szPath);
m_nFolderIconIndex = nIconIndex;
UpdateFolderIcon(hwndDlg);
}
}
// IDD_FOLDER_CUSTOMIZE PSN_APPLY
BOOL CFileDefExt::OnFolderCustApply(HWND hwndDlg)
{
// build the desktop.ini file path
WCHAR szIniFile[MAX_PATH];
StringCchCopyW(szIniFile, _countof(szIniFile), m_wszPath);
PathAppendW(szIniFile, L"desktop.ini");
if (m_bFolderIconIsSet) // it is set!
{
DWORD attrs;
// change folder attributes (-S -R)
attrs = GetFileAttributesW(m_wszPath);
attrs &= ~(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY);
SetFileAttributesW(m_wszPath, attrs);
// change desktop.ini attributes (-S -H -R)
attrs = GetFileAttributesW(szIniFile);
attrs &= ~(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
SetFileAttributesW(szIniFile, attrs);
if (m_szFolderIconPath[0])
{
// write IconFile and IconIndex
WritePrivateProfileStringW(s_szShellClassInfo, s_szIconFile, m_szFolderIconPath, szIniFile);
WCHAR szInt[32];
StringCchPrintfW(szInt, _countof(szInt), L"%d", m_nFolderIconIndex);
WritePrivateProfileStringW(s_szShellClassInfo, s_szIconIndex, szInt, szIniFile);
// flush!
WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile);
}
else
{
// erase three values
WritePrivateProfileStringW(s_szShellClassInfo, s_szIconFile, NULL, szIniFile);
WritePrivateProfileStringW(s_szShellClassInfo, s_szIconIndex, NULL, szIniFile);
WritePrivateProfileStringW(s_szShellClassInfo, s_szIconResource, NULL, szIniFile);
// flush!
WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile);
}
// change desktop.ini attributes (+S +H)
attrs = GetFileAttributesW(szIniFile);
attrs |= FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
SetFileAttributesW(szIniFile, attrs);
// change folder attributes (+R)
attrs = GetFileAttributesW(m_wszPath);
attrs |= FILE_ATTRIBUTE_READONLY;
SetFileAttributesW(m_wszPath, attrs);
// notify to the siblings
PropSheet_QuerySiblings(GetParent(hwndDlg), 0, 0);
// done!
m_bFolderIconIsSet = FALSE;
}
return TRUE;
}
/*****************************************************************************/
CFileDefExt::CFileDefExt():
m_bDir(FALSE), m_cFiles(0), m_cFolders(0)
{
m_wszPath[0] = L'\0';
m_DirSize.QuadPart = 0ull;
m_DirSizeOnDisc.QuadPart = 0ull;
m_szFolderIconPath[0] = 0;
m_nFolderIconIndex = 0;
m_hFolderIcon = NULL;
m_bFolderIconIsSet = FALSE;
}
CFileDefExt::~CFileDefExt()
{
}
HRESULT WINAPI
CFileDefExt::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID)
{
FORMATETC format;
STGMEDIUM stgm;
HRESULT hr;
TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID);
if (!pDataObj)
return E_FAIL;
format.cfFormat = CF_HDROP;
format.ptd = NULL;
format.dwAspect = DVASPECT_CONTENT;
format.lindex = -1;
format.tymed = TYMED_HGLOBAL;
hr = pDataObj->GetData(&format, &stgm);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, m_wszPath, _countof(m_wszPath)))
{
ERR("DragQueryFileW failed\n");
ReleaseStgMedium(&stgm);
return E_FAIL;
}
ReleaseStgMedium(&stgm);
TRACE("File properties %ls\n", m_wszPath);
m_bDir = PathIsDirectoryW(m_wszPath) ? TRUE : FALSE;
if (!m_bDir)
m_VerInfo.Load(m_wszPath);
return S_OK;
}
HRESULT WINAPI
CFileDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CFileDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CFileDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CFileDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
{
HPROPSHEETPAGE hPage;
WORD wResId = m_bDir ? IDD_FOLDER_PROPERTIES : IDD_FILE_PROPERTIES;
hPage = SH_CreatePropertySheetPage(wResId,
GeneralPageProc,
(LPARAM)this,
NULL);
if (hPage)
pfnAddPage(hPage, lParam);
if (!m_bDir && GetFileVersionInfoSizeW(m_wszPath, NULL))
{
hPage = SH_CreatePropertySheetPage(IDD_FILE_VERSION,
VersionPageProc,
(LPARAM)this,
NULL);
if (hPage)
pfnAddPage(hPage, lParam);
}
if (m_bDir)
{
hPage = SH_CreatePropertySheetPage(IDD_FOLDER_CUSTOMIZE,
FolderCustomizePageProc,
(LPARAM)this,
NULL);
if (hPage)
pfnAddPage(hPage, lParam);
}
return S_OK;
}
HRESULT WINAPI
CFileDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CFileDefExt::SetSite(IUnknown *punk)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
HRESULT WINAPI
CFileDefExt::GetSite(REFIID iid, void **ppvSite)
{
UNIMPLEMENTED;
return E_NOTIMPL;
}
DWORD WINAPI
CFileDefExt::_CountFolderAndFilesThreadProc(LPVOID lpParameter)
{
_CountFolderAndFilesData *data = static_cast<_CountFolderAndFilesData*>(lpParameter);
DWORD ticks = 0;
data->This->CountFolderAndFiles(data->hwndDlg, data->pwszBuf, &ticks);
//Release the CFileDefExt and data object holds in the copying thread.
data->This->Release();
HeapFree(GetProcessHeap(), 0, data->pwszBuf);
HeapFree(GetProcessHeap(), 0, data);
return 0;
}
BOOL
CFileDefExt::CountFolderAndFiles(HWND hwndDlg, LPCWSTR pwszBuf, DWORD *ticks)
{
CString sBuf = pwszBuf;
sBuf += L"\\" ;
CString sSearch = sBuf;
sSearch += L"*" ;
CString sFileName;
WIN32_FIND_DATAW wfd;
HANDLE hFind = FindFirstFileW(sSearch, &wfd);
if (hFind == INVALID_HANDLE_VALUE)
{
ERR("FindFirstFileW %ls failed\n", sSearch.GetString());
return FALSE;
}
BOOL root = FALSE;
if (*ticks == 0) {
*ticks = GetTickCount();
root = TRUE;
}
do
{
sFileName = sBuf;
sFileName += wfd.cFileName;
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
/* Don't process "." and ".." items */
if (!wcscmp(wfd.cFileName, L".") || !wcscmp(wfd.cFileName, L".."))
continue;
++m_cFolders;
CountFolderAndFiles(hwndDlg, sFileName, ticks);
}
else
{
m_cFiles++;
ULARGE_INTEGER FileSize;
FileSize.u.LowPart = wfd.nFileSizeLow;
FileSize.u.HighPart = wfd.nFileSizeHigh;
m_DirSize.QuadPart += FileSize.QuadPart;
// Calculate size on disc
if (!GetPhysicalFileSize(sFileName.GetString(), &FileSize))
ERR("GetPhysicalFileSize failed for %ls\n", sFileName.GetString());
m_DirSizeOnDisc.QuadPart += FileSize.QuadPart;
}
if (GetTickCount() - *ticks > (DWORD) 300)
{
/* FIXME Using IsWindow is generally ill advised */
if (IsWindow(hwndDlg))
{
WCHAR wszBuf[100];
if (SH_FormatFileSizeWithBytes(&m_DirSize, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14011, wszBuf);
if (SH_FormatFileSizeWithBytes(&m_DirSizeOnDisc, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14012, wszBuf);
/* Display files and folders count */
WCHAR wszFormat[100];
LoadStringW(shell32_hInstance, IDS_FILE_FOLDER, wszFormat, _countof(wszFormat));
StringCchPrintfW(wszBuf, _countof(wszBuf), wszFormat, m_cFiles, m_cFolders);
SetDlgItemTextW(hwndDlg, 14027, wszBuf);
*ticks = GetTickCount();
}
else
break;
}
} while(FindNextFileW(hFind, &wfd));
if (root && IsWindow(hwndDlg))
{
WCHAR wszBuf[100];
if (SH_FormatFileSizeWithBytes(&m_DirSize, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14011, wszBuf);
if (SH_FormatFileSizeWithBytes(&m_DirSizeOnDisc, wszBuf, _countof(wszBuf)))
SetDlgItemTextW(hwndDlg, 14012, wszBuf);
/* Display files and folders count */
WCHAR wszFormat[100];
LoadStringW(shell32_hInstance, IDS_FILE_FOLDER, wszFormat, _countof(wszFormat));
StringCchPrintfW(wszBuf, _countof(wszBuf), wszFormat, m_cFiles, m_cFolders);
SetDlgItemTextW(hwndDlg, 14027, wszBuf);
}
FindClose(hFind);
return TRUE;
}