1 /* 2 * Provides default file shell extension 3 * 4 * Copyright 2005 Johannes Anderwald 5 * Copyright 2012 Rafal Harabien 6 * 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. 11 * 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. 16 * 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 20 */ 21 22 #include "precomp.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(shell); 25 26 EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath); 27 28 BOOL CFileVersionInfo::Load(LPCWSTR pwszPath) 29 { 30 ULONG cbInfo = GetFileVersionInfoSizeW(pwszPath, NULL); 31 if (!cbInfo) 32 { 33 WARN("GetFileVersionInfoSize %ls failed\n", pwszPath); 34 return FALSE; 35 } 36 37 m_pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbInfo); 38 if (!m_pInfo) 39 { 40 ERR("HeapAlloc failed bytes %x\n", cbInfo); 41 return FALSE; 42 } 43 44 if (!GetFileVersionInfoW(pwszPath, 0, cbInfo, m_pInfo)) 45 { 46 ERR("GetFileVersionInfoW failed\n"); 47 return FALSE; 48 } 49 50 LPLANGANDCODEPAGE lpLangCode; 51 UINT cBytes; 52 if (!VerQueryValueW(m_pInfo, L"\\VarFileInfo\\Translation", (LPVOID *)&lpLangCode, &cBytes) || cBytes < sizeof(LANGANDCODEPAGE)) 53 { 54 ERR("VerQueryValueW failed\n"); 55 return FALSE; 56 } 57 58 /* FIXME: find language from current locale / if not available, 59 * default to english 60 * for now default to first available language 61 */ 62 m_wLang = lpLangCode->wLang; 63 m_wCode = lpLangCode->wCode; 64 TRACE("Lang %hx Code %hu\n", m_wLang, m_wCode); 65 66 return TRUE; 67 } 68 69 LPCWSTR CFileVersionInfo::GetString(LPCWSTR pwszName) 70 { 71 if (!m_pInfo) 72 return NULL; 73 74 WCHAR wszBuf[256]; 75 swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\%s", m_wLang, m_wCode, pwszName); 76 77 /* Query string in version block */ 78 LPCWSTR pwszResult = NULL; 79 UINT cBytes = 0; 80 if (!VerQueryValueW(m_pInfo, wszBuf, (LPVOID *)&pwszResult, &cBytes)) 81 pwszResult = NULL; 82 83 if (!m_wLang && !m_wCode) 84 { 85 /* Try US English */ 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)) 88 pwszResult = NULL; 89 } 90 91 if (!pwszResult) 92 ERR("VerQueryValueW %ls failed\n", pwszName); 93 else 94 TRACE("%ls: %ls\n", pwszName, pwszResult); 95 96 return pwszResult; 97 } 98 99 VS_FIXEDFILEINFO *CFileVersionInfo::GetFixedInfo() 100 { 101 if (!m_pInfo) 102 return NULL; 103 104 VS_FIXEDFILEINFO *pInfo; 105 UINT cBytes; 106 if (!VerQueryValueW(m_pInfo, L"\\", (PVOID*)&pInfo, &cBytes)) 107 return NULL; 108 return pInfo; 109 } 110 111 LPCWSTR CFileVersionInfo::GetLangName() 112 { 113 if (!m_pInfo) 114 return NULL; 115 116 if (!m_wszLang[0]) 117 { 118 if (!VerLanguageNameW(m_wLang, m_wszLang, _countof(m_wszLang))) 119 ERR("VerLanguageNameW failed\n"); 120 } 121 122 return m_wszLang; 123 } 124 125 UINT 126 SH_FormatInteger(LONGLONG Num, LPWSTR pwszResult, UINT cchResultMax) 127 { 128 // Print the number in uniform mode 129 WCHAR wszNumber[24]; 130 swprintf(wszNumber, L"%I64u", Num); 131 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)); 136 137 // Initialize format for printing the number in bytes 138 NUMBERFMTW nf; 139 ZeroMemory(&nf, sizeof(nf)); 140 nf.lpDecimalSep = wszDecimalSep; 141 nf.lpThousandSep = wszThousandSep; 142 143 // Get system string for groups separator 144 WCHAR wszGrouping[12]; 145 INT cchGrouping = GetLocaleInfoW(LOCALE_USER_DEFAULT, 146 LOCALE_SGROUPING, 147 wszGrouping, 148 _countof(wszGrouping)); 149 150 // Convert grouping specs from string to integer 151 for (INT i = 0; i < cchGrouping; i++) 152 { 153 WCHAR wch = wszGrouping[i]; 154 155 if (wch >= L'0' && wch <= L'9') 156 nf.Grouping = nf.Grouping * 10 + (wch - L'0'); 157 else if (wch != L';') 158 break; 159 } 160 161 if ((nf.Grouping % 10) == 0) 162 nf.Grouping /= 10; 163 else 164 nf.Grouping *= 10; 165 166 // Format the number 167 INT cchResult = GetNumberFormatW(LOCALE_USER_DEFAULT, 168 0, 169 wszNumber, 170 &nf, 171 pwszResult, 172 cchResultMax); 173 174 if (!cchResult) 175 return 0; 176 177 // GetNumberFormatW returns number of characters including UNICODE_NULL 178 return cchResult - 1; 179 } 180 181 UINT 182 SH_FormatByteSize(LONGLONG cbSize, LPWSTR pwszResult, UINT cchResultMax) 183 { 184 /* Write formated bytes count */ 185 INT cchWritten = SH_FormatInteger(cbSize, pwszResult, cchResultMax); 186 if (!cchWritten) 187 return 0; 188 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; 195 196 return cchResultMax - cchRemaining; 197 } 198 199 /************************************************************************* 200 * 201 * SH_FormatFileSizeWithBytes 202 * 203 * Format a size in bytes to string. 204 * 205 * lpQwSize = Pointer to 64bit large integer to format 206 * pszBuf = Buffer to fill with output string 207 * cchBuf = size of pszBuf in characters 208 * 209 */ 210 211 LPWSTR 212 SH_FormatFileSizeWithBytes(const PULARGE_INTEGER lpQwSize, LPWSTR pwszResult, UINT cchResultMax) 213 { 214 /* Format bytes in KBs, MBs etc */ 215 if (StrFormatByteSizeW(lpQwSize->QuadPart, pwszResult, cchResultMax) == NULL) 216 return NULL; 217 218 /* If there is less bytes than 1KB, we have nothing to do */ 219 if (lpQwSize->QuadPart < 1024) 220 return pwszResult; 221 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); 227 228 /* Write formated bytes count */ 229 cchWritten = SH_FormatByteSize(lpQwSize->QuadPart, pwszEnd, cchRemaining); 230 pwszEnd += cchWritten; 231 cchRemaining -= cchWritten; 232 233 /* Copy ")" to the buffer */ 234 StringCchCopyW(pwszEnd, cchRemaining, L")"); 235 236 return pwszResult; 237 } 238 239 /************************************************************************* 240 * 241 * SH_CreatePropertySheetPage [Internal] 242 * 243 * creates a property sheet page from a resource id 244 * 245 */ 246 247 HPROPSHEETPAGE 248 SH_CreatePropertySheetPage(WORD wDialogId, DLGPROC pfnDlgProc, LPARAM lParam, LPCWSTR pwszTitle) 249 { 250 PROPSHEETPAGEW Page; 251 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; 260 261 if (pwszTitle) 262 Page.dwFlags |= PSP_USETITLE; 263 264 return CreatePropertySheetPageW(&Page); 265 } 266 267 VOID 268 CFileDefExt::InitOpensWithField(HWND hwndDlg) 269 { 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); 275 276 if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS) 277 { 278 bUnknownApp = FALSE; 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) 282 { 283 /* Get path from command line */ 284 ExpandEnvironmentStringsW(wszPath, wszBuf, _countof(wszBuf)); 285 PathRemoveArgs(wszBuf); 286 PathUnquoteSpacesW(wszBuf); 287 PathSearchAndQualify(wszBuf, wszPath, _countof(wszPath)); 288 289 HICON hIcon; 290 if (ExtractIconExW(wszPath, 0, NULL, &hIcon, 1)) 291 { 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); 297 298 rcIcon.right = rcIcon.left + GetSystemMetrics(SM_CXSMICON); 299 rcIcon.bottom = rcIcon.top + GetSystemMetrics(SM_CYSMICON); 300 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, 308 SWP_NOZORDER); 309 SendMessageW(hIconCtrl, STM_SETICON, (WPARAM)hIcon, 0); 310 } else 311 ERR("Failed to extract icon\n"); 312 313 if (PathFileExistsW(wszPath)) 314 { 315 /* Get file description */ 316 CFileVersionInfo VerInfo; 317 VerInfo.Load(wszPath); 318 LPCWSTR pwszDescr = VerInfo.GetString(L"FileDescription"); 319 if (pwszDescr) 320 SetDlgItemTextW(hwndDlg, 14007, pwszDescr); 321 else 322 { 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); 328 } 329 } 330 else 331 bUnknownApp = TRUE; 332 } else 333 WARN("RegGetValueW %ls failed\n", wszBuf); 334 } else 335 WARN("RegGetValueW %ls failed\n", pwszExt); 336 337 if (bUnknownApp) 338 { 339 /* Unknown application */ 340 LoadStringW(shell32_hInstance, IDS_UNKNOWN_APP, wszBuf, _countof(wszBuf)); 341 SetDlgItemTextW(hwndDlg, 14007, wszBuf); 342 } 343 } 344 345 /************************************************************************* 346 * 347 * SH_FileGeneralFileType [Internal] 348 * 349 * retrieves file extension description from registry and sets it in dialog 350 * 351 * TODO: retrieve file extension default icon and load it 352 * find executable name from registry, retrieve description from executable 353 */ 354 355 BOOL 356 CFileDefExt::InitFileType(HWND hwndDlg) 357 { 358 TRACE("path %s\n", debugstr_w(m_wszPath)); 359 360 HWND hDlgCtrl = GetDlgItem(hwndDlg, 14005); 361 if (hDlgCtrl == NULL) 362 return FALSE; 363 364 /* Get file information */ 365 SHFILEINFOW fi; 366 if (!SHGetFileInfoW(m_wszPath, 0, &fi, sizeof(fi), SHGFI_TYPENAME|SHGFI_ICON)) 367 { 368 ERR("SHGetFileInfoW failed for %ls (%lu)\n", m_wszPath, GetLastError()); 369 fi.szTypeName[0] = L'\0'; 370 fi.hIcon = NULL; 371 } 372 373 LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); 374 if (pwszExt[0]) 375 { 376 WCHAR wszBuf[256]; 377 378 if (!fi.szTypeName[0]) 379 { 380 /* The file type is unknown, so default to string "FileExtension File" */ 381 size_t cchRemaining = 0; 382 LPWSTR pwszEnd = NULL; 383 384 StringCchPrintfExW(wszBuf, _countof(wszBuf), &pwszEnd, &cchRemaining, 0, L"%s ", pwszExt + 1); 385 SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)cchRemaining, (LPARAM)pwszEnd); 386 387 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf); 388 } 389 else 390 { 391 /* Update file type */ 392 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s (%s)", fi.szTypeName, pwszExt); 393 SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wszBuf); 394 } 395 } 396 397 /* Update file icon */ 398 if (fi.hIcon) 399 SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)fi.hIcon, 0); 400 else 401 ERR("No icon %ls\n", m_wszPath); 402 403 return TRUE; 404 } 405 406 /************************************************************************* 407 * 408 * CFileDefExt::InitFilePath [Internal] 409 * 410 * sets file path string and filename string 411 * 412 */ 413 414 BOOL 415 CFileDefExt::InitFilePath(HWND hwndDlg) 416 { 417 /* Find the filename */ 418 WCHAR *pwszFilename = PathFindFileNameW(m_wszPath); 419 420 if (pwszFilename > m_wszPath) 421 { 422 /* Location field */ 423 WCHAR wszLocation[MAX_PATH]; 424 StringCchCopyNW(wszLocation, _countof(wszLocation), m_wszPath, pwszFilename - m_wszPath); 425 PathRemoveBackslashW(wszLocation); 426 427 SetDlgItemTextW(hwndDlg, 14009, wszLocation); 428 } 429 430 /* Filename field */ 431 SetDlgItemTextW(hwndDlg, 14001, pwszFilename); 432 433 return TRUE; 434 } 435 436 /************************************************************************* 437 * 438 * CFileDefExt::GetFileTimeString [Internal] 439 * 440 * formats a given LPFILETIME struct into readable user format 441 */ 442 443 BOOL 444 CFileDefExt::GetFileTimeString(LPFILETIME lpFileTime, LPWSTR pwszResult, UINT cchResult) 445 { 446 FILETIME ft; 447 SYSTEMTIME st; 448 449 if (!FileTimeToLocalFileTime(lpFileTime, &ft) || !FileTimeToSystemTime(&ft, &st)) 450 return FALSE; 451 452 size_t cchRemaining = cchResult; 453 LPWSTR pwszEnd = pwszResult; 454 int cchWritten = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, pwszEnd, cchRemaining); 455 if (cchWritten) 456 --cchWritten; // GetDateFormatW returns count with terminating zero 457 else 458 ERR("GetDateFormatW failed\n"); 459 cchRemaining -= cchWritten; 460 pwszEnd += cchWritten; 461 462 StringCchCopyExW(pwszEnd, cchRemaining, L", ", &pwszEnd, &cchRemaining, 0); 463 464 cchWritten = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, pwszEnd, cchRemaining); 465 if (cchWritten) 466 --cchWritten; // GetTimeFormatW returns count with terminating zero 467 else 468 ERR("GetTimeFormatW failed\n"); 469 TRACE("result %s\n", debugstr_w(pwszResult)); 470 return TRUE; 471 } 472 473 /************************************************************************* 474 * 475 * CFileDefExt::InitFileAttr [Internal] 476 * 477 * retrieves file information from file and sets in dialog 478 * 479 */ 480 481 BOOL 482 CFileDefExt::InitFileAttr(HWND hwndDlg) 483 { 484 BOOL Success; 485 WIN32_FIND_DATAW FileInfo; // WIN32_FILE_ATTRIBUTE_DATA 486 WCHAR wszBuf[MAX_PATH]; 487 488 TRACE("InitFileAttr %ls\n", m_wszPath); 489 490 /* 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). 497 * 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. 509 * 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. 514 */ 515 516 Success = GetFileAttributesExW(m_wszPath, 517 GetFileExInfoStandard, 518 (LPWIN32_FILE_ATTRIBUTE_DATA)&FileInfo); 519 if (!Success) 520 { 521 HANDLE hFind = FindFirstFileW(m_wszPath, &FileInfo); 522 Success = (hFind != INVALID_HANDLE_VALUE); 523 if (Success) 524 FindClose(hFind); 525 } 526 527 if (Success) 528 { 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); 536 537 /* Update creation time */ 538 if (GetFileTimeString(&FileInfo.ftCreationTime, wszBuf, _countof(wszBuf))) 539 SetDlgItemTextW(hwndDlg, 14015, wszBuf); 540 541 /* For files display last access and last write time */ 542 if (!m_bDir) 543 { 544 if (GetFileTimeString(&FileInfo.ftLastAccessTime, wszBuf, _countof(wszBuf))) 545 SetDlgItemTextW(hwndDlg, 14019, wszBuf); 546 547 if (GetFileTimeString(&FileInfo.ftLastWriteTime, wszBuf, _countof(wszBuf))) 548 SetDlgItemTextW(hwndDlg, 14017, wszBuf); 549 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); 556 } 557 } 558 559 if (m_bDir) 560 { 561 /* For directories files have to be counted */ 562 563 _CountFolderAndFilesData *data = static_cast<_CountFolderAndFilesData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_CountFolderAndFilesData))); 564 data->This = this; 565 data->pwszBuf = static_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * MAX_PATH)); 566 data->cchBufMax = MAX_PATH; 567 data->hwndDlg = hwndDlg; 568 this->AddRef(); 569 StringCchCopyW(data->pwszBuf, MAX_PATH, m_wszPath); 570 571 SHCreateThread(CFileDefExt::_CountFolderAndFilesThreadProc, data, NULL, NULL); 572 573 /* Update size field */ 574 if (SH_FormatFileSizeWithBytes(&m_DirSize, wszBuf, _countof(wszBuf))) 575 SetDlgItemTextW(hwndDlg, 14011, wszBuf); 576 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); 582 } 583 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); 586 587 return TRUE; 588 } 589 590 /************************************************************************* 591 * 592 * CFileDefExt::InitGeneralPage [Internal] 593 * 594 * sets all file general properties in dialog 595 */ 596 597 BOOL 598 CFileDefExt::InitGeneralPage(HWND hwndDlg) 599 { 600 /* Set general text properties filename filelocation and icon */ 601 InitFilePath(hwndDlg); 602 603 /* Set file type and icon */ 604 InitFileType(hwndDlg); 605 606 /* Set open with application */ 607 if (!m_bDir) 608 { 609 if (!PathIsExeW(m_wszPath)) 610 InitOpensWithField(hwndDlg); 611 else 612 { 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); 617 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 ); 626 627 LPCWSTR pwszDescr = m_VerInfo.GetString(L"FileDescription"); 628 if (pwszDescr) 629 SetDlgItemTextW(hwndDlg, 14007, pwszDescr); 630 else 631 { 632 StringCbCopyW(wszBuf, sizeof(wszBuf), PathFindFileNameW(m_wszPath)); 633 PathRemoveExtension(wszBuf); 634 SetDlgItemTextW(hwndDlg, 14007, wszBuf); 635 } 636 } 637 } 638 639 /* Set file created/modfied/accessed time, size and attributes */ 640 InitFileAttr(hwndDlg); 641 642 return TRUE; 643 } 644 645 /************************************************************************* 646 * 647 * CFileDefExt::GeneralPageProc 648 * 649 * wnd proc of 'General' property sheet page 650 * 651 */ 652 653 INT_PTR CALLBACK 654 CFileDefExt::GeneralPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 655 { 656 CFileDefExt *pFileDefExt = reinterpret_cast<CFileDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 657 switch (uMsg) 658 { 659 case WM_INITDIALOG: 660 { 661 LPPROPSHEETPAGEW ppsp = (LPPROPSHEETPAGEW)lParam; 662 663 if (ppsp == NULL || !ppsp->lParam) 664 break; 665 666 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg, lParam, ppsp->lParam); 667 668 pFileDefExt = reinterpret_cast<CFileDefExt *>(ppsp->lParam); 669 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pFileDefExt); 670 pFileDefExt->InitGeneralPage(hwndDlg); 671 break; 672 } 673 case WM_COMMAND: 674 if (LOWORD(wParam) == 14024) /* Opens With - Change */ 675 { 676 OPENASINFO oainfo; 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)); 681 } 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 */ 685 { 686 if (HIWORD(wParam) == EN_CHANGE) 687 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 688 } 689 break; 690 case WM_NOTIFY: 691 { 692 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam; 693 if (lppsn->hdr.code == PSN_APPLY) 694 { 695 /* Update attributes first */ 696 DWORD dwAttr = GetFileAttributesW(pFileDefExt->m_wszPath); 697 if (dwAttr) 698 { 699 dwAttr &= ~(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE); 700 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; 707 708 if (!SetFileAttributesW(pFileDefExt->m_wszPath, dwAttr)) 709 ERR("SetFileAttributesW failed\n"); 710 } 711 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)) 718 { 719 if (!MoveFileW(pFileDefExt->m_wszPath, wszBuf)) 720 ERR("MoveFileW failed\n"); 721 } 722 723 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); 724 return TRUE; 725 } 726 break; 727 } 728 case PSM_QUERYSIBLINGS: 729 { 730 // reset icon 731 HWND hIconCtrl = GetDlgItem(hwndDlg, 14025); 732 HICON hIcon = (HICON)SendMessageW(hIconCtrl, STM_GETICON, 0, 0); 733 DestroyIcon(hIcon); 734 hIcon = NULL; 735 SendMessageW(hIconCtrl, STM_SETICON, (WPARAM)hIcon, 0); 736 737 // refresh the page 738 pFileDefExt->InitGeneralPage(hwndDlg); 739 return FALSE; // continue 740 } 741 default: 742 break; 743 } 744 745 return FALSE; 746 } 747 748 /************************************************************************* 749 * 750 * CFileDefExt::InitVersionPage [Internal] 751 * 752 * sets all file version properties in dialog 753 */ 754 755 BOOL 756 CFileDefExt::InitVersionPage(HWND hwndDlg) 757 { 758 /* Get fixed info */ 759 VS_FIXEDFILEINFO *pInfo = m_VerInfo.GetFixedInfo(); 760 if (pInfo) 761 { 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); 769 } 770 771 /* Update labels */ 772 SetVersionLabel(hwndDlg, 14003, L"FileDescription"); 773 SetVersionLabel(hwndDlg, 14005, L"LegalCopyright"); 774 775 /* Add items to listbox */ 776 AddVersionString(hwndDlg, L"CompanyName"); 777 LPCWSTR pwszLang = m_VerInfo.GetLangName(); 778 if (pwszLang) 779 { 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); 783 } 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"); 789 790 /* Attach file version to dialog window */ 791 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)this); 792 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); 799 800 return TRUE; 801 } 802 803 /************************************************************************* 804 * 805 * CFileDefExt::SetVersionLabel [Internal] 806 * 807 * retrieves a version string and uses it to set label text 808 */ 809 810 BOOL 811 CFileDefExt::SetVersionLabel(HWND hwndDlg, DWORD idCtrl, LPCWSTR pwszName) 812 { 813 if (hwndDlg == NULL || pwszName == NULL) 814 return FALSE; 815 816 LPCWSTR pwszValue = m_VerInfo.GetString(pwszName); 817 if (pwszValue) 818 { 819 /* file description property */ 820 TRACE("%s :: %s\n", debugstr_w(pwszName), debugstr_w(pwszValue)); 821 SetDlgItemTextW(hwndDlg, idCtrl, pwszValue); 822 return TRUE; 823 } 824 825 return FALSE; 826 } 827 828 /************************************************************************* 829 * 830 * CFileDefExt::AddVersionString [Internal] 831 * 832 * retrieves a version string and adds it to listbox 833 */ 834 835 BOOL 836 CFileDefExt::AddVersionString(HWND hwndDlg, LPCWSTR pwszName) 837 { 838 TRACE("pwszName %s, hwndDlg %p\n", debugstr_w(pwszName), hwndDlg); 839 840 if (hwndDlg == NULL || pwszName == NULL) 841 return FALSE; 842 843 LPCWSTR pwszValue = m_VerInfo.GetString(pwszName); 844 if (pwszValue) 845 { 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); 851 return TRUE; 852 } 853 854 return FALSE; 855 } 856 857 /************************************************************************* 858 * 859 * CFileDefExt::VersionPageProc 860 * 861 * wnd proc of 'Version' property sheet page 862 */ 863 864 INT_PTR CALLBACK 865 CFileDefExt::VersionPageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 866 { 867 switch (uMsg) 868 { 869 case WM_INITDIALOG: 870 { 871 LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam; 872 873 if (ppsp == NULL || !ppsp->lParam) 874 break; 875 876 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam); 877 878 CFileDefExt *pFileDefExt = reinterpret_cast<CFileDefExt *>(ppsp->lParam); 879 return pFileDefExt->InitVersionPage(hwndDlg); 880 } 881 case WM_COMMAND: 882 if (LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_SELCHANGE) 883 { 884 HWND hDlgCtrl = (HWND)lParam; 885 886 LRESULT Index = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL); 887 if (Index == LB_ERR) 888 break; 889 890 LPCWSTR pwszData = (LPCWSTR)SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)Index, (LPARAM)NULL); 891 if (pwszData == NULL) 892 break; 893 894 TRACE("hDlgCtrl %x string %s\n", hDlgCtrl, debugstr_w(pwszData)); 895 SetDlgItemTextW(hwndDlg, 14010, pwszData); 896 897 return TRUE; 898 } 899 break; 900 case WM_DESTROY: 901 break; 902 case PSM_QUERYSIBLINGS: 903 return FALSE; // continue 904 default: 905 break; 906 } 907 908 return FALSE; 909 } 910 911 /*************************************************************************/ 912 /* Folder Customize */ 913 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"; 918 919 // IDD_FOLDER_CUSTOMIZE 920 INT_PTR CALLBACK 921 CFileDefExt::FolderCustomizePageProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 922 { 923 CFileDefExt *pFileDefExt = reinterpret_cast<CFileDefExt *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 924 switch (uMsg) 925 { 926 case WM_INITDIALOG: 927 { 928 LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam; 929 930 if (ppsp == NULL || !ppsp->lParam) 931 break; 932 933 TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam); 934 935 pFileDefExt = reinterpret_cast<CFileDefExt *>(ppsp->lParam); 936 return pFileDefExt->InitFolderCustomizePage(hwndDlg); 937 } 938 939 case WM_COMMAND: 940 switch (LOWORD(wParam)) 941 { 942 case IDC_FOLDERCUST_CHANGE_ICON: 943 pFileDefExt->OnFolderCustChangeIcon(hwndDlg); 944 break; 945 946 case IDC_FOLDERCUST_CHOOSE_PIC: 947 // TODO: 948 break; 949 950 case IDC_FOLDERCUST_RESTORE_DEFAULTS: 951 // TODO: 952 break; 953 } 954 break; 955 956 case WM_NOTIFY: 957 { 958 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam; 959 if (lppsn->hdr.code == PSN_APPLY) 960 { 961 // apply or not 962 if (pFileDefExt->OnFolderCustApply(hwndDlg)) 963 { 964 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); 965 } 966 else 967 { 968 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); 969 } 970 return TRUE; 971 } 972 break; 973 } 974 975 case PSM_QUERYSIBLINGS: 976 return FALSE; // continue 977 978 case WM_DESTROY: 979 pFileDefExt->OnFolderCustDestroy(hwndDlg); 980 break; 981 982 default: 983 break; 984 } 985 986 return FALSE; 987 } 988 989 // IDD_FOLDER_CUSTOMIZE WM_DESTROY 990 void CFileDefExt::OnFolderCustDestroy(HWND hwndDlg) 991 { 992 ::DestroyIcon(m_hFolderIcon); 993 m_hFolderIcon = NULL; 994 995 /* Detach the object from dialog window */ 996 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)0); 997 } 998 999 void CFileDefExt::UpdateFolderIcon(HWND hwndDlg) 1000 { 1001 // destroy icon if any 1002 if (m_hFolderIcon) 1003 { 1004 ::DestroyIcon(m_hFolderIcon); 1005 m_hFolderIcon = NULL; 1006 } 1007 1008 // create the icon 1009 if (m_szFolderIconPath[0] == 0 && m_nFolderIconIndex == 0) 1010 { 1011 m_hFolderIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER)); 1012 } 1013 else 1014 { 1015 ExtractIconExW(m_szFolderIconPath, m_nFolderIconIndex, &m_hFolderIcon, NULL, 1); 1016 } 1017 1018 // set icon 1019 SendDlgItemMessageW(hwndDlg, IDC_FOLDERCUST_ICON, STM_SETICON, (WPARAM)m_hFolderIcon, 0); 1020 } 1021 1022 // IDD_FOLDER_CUSTOMIZE WM_INITDIALOG 1023 BOOL CFileDefExt::InitFolderCustomizePage(HWND hwndDlg) 1024 { 1025 /* Attach the object to dialog window */ 1026 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)this); 1027 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); 1032 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"); 1037 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)) 1043 { 1044 m_nFolderIconIndex = GetPrivateProfileIntW(s_szShellClassInfo, s_szIconIndex, 0, szIniFile); 1045 } 1046 else if (GetPrivateProfileStringW(s_szShellClassInfo, s_szIconResource, NULL, 1047 m_szFolderIconPath, _countof(m_szFolderIconPath), szIniFile)) 1048 { 1049 m_nFolderIconIndex = PathParseIconLocationW(m_szFolderIconPath); 1050 } 1051 1052 // update icon 1053 UpdateFolderIcon(hwndDlg); 1054 1055 return TRUE; 1056 } 1057 1058 // IDD_FOLDER_CUSTOMIZE IDC_FOLDERCUST_CHANGE_ICON 1059 void CFileDefExt::OnFolderCustChangeIcon(HWND hwndDlg) 1060 { 1061 WCHAR szPath[MAX_PATH]; 1062 INT nIconIndex; 1063 1064 // m_szFolderIconPath, m_nFolderIconIndex --> szPath, nIconIndex 1065 if (m_szFolderIconPath[0]) 1066 { 1067 StringCchCopyW(szPath, _countof(szPath), m_szFolderIconPath); 1068 nIconIndex = m_nFolderIconIndex; 1069 } 1070 else 1071 { 1072 szPath[0] = 0; 1073 nIconIndex = 0; 1074 } 1075 1076 // let the user choose the icon 1077 if (PickIconDlg(hwndDlg, szPath, _countof(szPath), &nIconIndex)) 1078 { 1079 // changed 1080 m_bFolderIconIsSet = TRUE; 1081 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1082 1083 // update 1084 StringCchCopyW(m_szFolderIconPath, _countof(m_szFolderIconPath), szPath); 1085 m_nFolderIconIndex = nIconIndex; 1086 UpdateFolderIcon(hwndDlg); 1087 } 1088 } 1089 1090 // IDD_FOLDER_CUSTOMIZE PSN_APPLY 1091 BOOL CFileDefExt::OnFolderCustApply(HWND hwndDlg) 1092 { 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"); 1097 1098 if (m_bFolderIconIsSet) // it is set! 1099 { 1100 DWORD attrs; 1101 1102 // change folder attributes (-S -R) 1103 attrs = GetFileAttributesW(m_wszPath); 1104 attrs &= ~(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY); 1105 SetFileAttributesW(m_wszPath, attrs); 1106 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); 1111 1112 if (m_szFolderIconPath[0]) 1113 { 1114 // write IconFile and IconIndex 1115 WritePrivateProfileStringW(s_szShellClassInfo, s_szIconFile, m_szFolderIconPath, szIniFile); 1116 1117 WCHAR szInt[32]; 1118 StringCchPrintfW(szInt, _countof(szInt), L"%d", m_nFolderIconIndex); 1119 WritePrivateProfileStringW(s_szShellClassInfo, s_szIconIndex, szInt, szIniFile); 1120 1121 // flush! 1122 WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); 1123 } 1124 else 1125 { 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); 1130 1131 // flush! 1132 WritePrivateProfileStringW(NULL, NULL, NULL, szIniFile); 1133 } 1134 1135 // change desktop.ini attributes (+S +H) 1136 attrs = GetFileAttributesW(szIniFile); 1137 attrs |= FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; 1138 SetFileAttributesW(szIniFile, attrs); 1139 1140 // change folder attributes (+R) 1141 attrs = GetFileAttributesW(m_wszPath); 1142 attrs |= FILE_ATTRIBUTE_READONLY; 1143 SetFileAttributesW(m_wszPath, attrs); 1144 1145 // notify to the siblings 1146 PropSheet_QuerySiblings(GetParent(hwndDlg), 0, 0); 1147 1148 // done! 1149 m_bFolderIconIsSet = FALSE; 1150 } 1151 1152 return TRUE; 1153 } 1154 1155 /*****************************************************************************/ 1156 1157 CFileDefExt::CFileDefExt(): 1158 m_bDir(FALSE), m_cFiles(0), m_cFolders(0) 1159 { 1160 m_wszPath[0] = L'\0'; 1161 m_DirSize.QuadPart = 0ull; 1162 1163 m_szFolderIconPath[0] = 0; 1164 m_nFolderIconIndex = 0; 1165 m_hFolderIcon = NULL; 1166 m_bFolderIconIsSet = FALSE; 1167 } 1168 1169 CFileDefExt::~CFileDefExt() 1170 { 1171 1172 } 1173 1174 HRESULT WINAPI 1175 CFileDefExt::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pDataObj, HKEY hkeyProgID) 1176 { 1177 FORMATETC format; 1178 STGMEDIUM stgm; 1179 HRESULT hr; 1180 1181 TRACE("%p %p %p %p\n", this, pidlFolder, pDataObj, hkeyProgID); 1182 1183 if (!pDataObj) 1184 return E_FAIL; 1185 1186 format.cfFormat = CF_HDROP; 1187 format.ptd = NULL; 1188 format.dwAspect = DVASPECT_CONTENT; 1189 format.lindex = -1; 1190 format.tymed = TYMED_HGLOBAL; 1191 1192 hr = pDataObj->GetData(&format, &stgm); 1193 if (FAILED(hr)) 1194 return hr; 1195 1196 if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, m_wszPath, _countof(m_wszPath))) 1197 { 1198 ERR("DragQueryFileW failed\n"); 1199 ReleaseStgMedium(&stgm); 1200 return E_FAIL; 1201 } 1202 1203 ReleaseStgMedium(&stgm); 1204 1205 TRACE("File properties %ls\n", m_wszPath); 1206 m_bDir = PathIsDirectoryW(m_wszPath) ? TRUE : FALSE; 1207 if (!m_bDir) 1208 m_VerInfo.Load(m_wszPath); 1209 1210 return S_OK; 1211 } 1212 1213 HRESULT WINAPI 1214 CFileDefExt::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 1215 { 1216 UNIMPLEMENTED; 1217 return E_NOTIMPL; 1218 } 1219 1220 HRESULT WINAPI 1221 CFileDefExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 1222 { 1223 UNIMPLEMENTED; 1224 return E_NOTIMPL; 1225 } 1226 1227 HRESULT WINAPI 1228 CFileDefExt::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) 1229 { 1230 UNIMPLEMENTED; 1231 return E_NOTIMPL; 1232 } 1233 1234 HRESULT WINAPI 1235 CFileDefExt::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) 1236 { 1237 HPROPSHEETPAGE hPage; 1238 WORD wResId = m_bDir ? IDD_FOLDER_PROPERTIES : IDD_FILE_PROPERTIES; 1239 1240 hPage = SH_CreatePropertySheetPage(wResId, 1241 GeneralPageProc, 1242 (LPARAM)this, 1243 NULL); 1244 if (hPage) 1245 pfnAddPage(hPage, lParam); 1246 1247 if (!m_bDir && GetFileVersionInfoSizeW(m_wszPath, NULL)) 1248 { 1249 hPage = SH_CreatePropertySheetPage(IDD_FILE_VERSION, 1250 VersionPageProc, 1251 (LPARAM)this, 1252 NULL); 1253 if (hPage) 1254 pfnAddPage(hPage, lParam); 1255 } 1256 1257 if (m_bDir) 1258 { 1259 hPage = SH_CreatePropertySheetPage(IDD_FOLDER_CUSTOMIZE, 1260 FolderCustomizePageProc, 1261 (LPARAM)this, 1262 NULL); 1263 if (hPage) 1264 pfnAddPage(hPage, lParam); 1265 } 1266 1267 return S_OK; 1268 } 1269 1270 HRESULT WINAPI 1271 CFileDefExt::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) 1272 { 1273 UNIMPLEMENTED; 1274 return E_NOTIMPL; 1275 } 1276 1277 HRESULT WINAPI 1278 CFileDefExt::SetSite(IUnknown *punk) 1279 { 1280 UNIMPLEMENTED; 1281 return E_NOTIMPL; 1282 } 1283 1284 HRESULT WINAPI 1285 CFileDefExt::GetSite(REFIID iid, void **ppvSite) 1286 { 1287 UNIMPLEMENTED; 1288 return E_NOTIMPL; 1289 } 1290 1291 DWORD WINAPI 1292 CFileDefExt::_CountFolderAndFilesThreadProc(LPVOID lpParameter) 1293 { 1294 _CountFolderAndFilesData *data = static_cast<_CountFolderAndFilesData*>(lpParameter); 1295 DWORD ticks = 0; 1296 data->This->CountFolderAndFiles(data->hwndDlg, data->pwszBuf, data->cchBufMax, &ticks); 1297 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); 1302 1303 return 0; 1304 } 1305 1306 BOOL 1307 CFileDefExt::CountFolderAndFiles(HWND hwndDlg, LPWSTR pwszBuf, UINT cchBufMax, DWORD *ticks) 1308 { 1309 /* Find filename position */ 1310 UINT cchBuf = wcslen(pwszBuf); 1311 WCHAR *pwszFilename = pwszBuf + cchBuf; 1312 size_t cchFilenameMax = cchBufMax - cchBuf; 1313 if (!cchFilenameMax) 1314 return FALSE; 1315 *(pwszFilename++) = '\\'; 1316 --cchFilenameMax; 1317 1318 /* Find all files, FIXME: shouldn't be "*"? */ 1319 StringCchCopyW(pwszFilename, cchFilenameMax, L"*"); 1320 1321 WIN32_FIND_DATAW wfd; 1322 HANDLE hFind = FindFirstFileW(pwszBuf, &wfd); 1323 if (hFind == INVALID_HANDLE_VALUE) 1324 { 1325 ERR("FindFirstFileW %ls failed\n", pwszBuf); 1326 return FALSE; 1327 } 1328 1329 BOOL root = FALSE; 1330 if (*ticks == 0) { 1331 *ticks = GetTickCount(); 1332 root = TRUE; 1333 } 1334 1335 do 1336 { 1337 if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1338 { 1339 /* Don't process "." and ".." items */ 1340 if (!wcscmp(wfd.cFileName, L".") || !wcscmp(wfd.cFileName, L"..")) 1341 continue; 1342 1343 ++m_cFolders; 1344 1345 StringCchCopyW(pwszFilename, cchFilenameMax, wfd.cFileName); 1346 CountFolderAndFiles(hwndDlg, pwszBuf, cchBufMax, ticks); 1347 } 1348 else 1349 { 1350 m_cFiles++; 1351 1352 ULARGE_INTEGER FileSize; 1353 FileSize.u.LowPart = wfd.nFileSizeLow; 1354 FileSize.u.HighPart = wfd.nFileSizeHigh; 1355 m_DirSize.QuadPart += FileSize.QuadPart; 1356 } 1357 if (GetTickCount() - *ticks > (DWORD) 300) 1358 { 1359 /* FIXME Using IsWindow is generally ill advised */ 1360 if (IsWindow(hwndDlg)) 1361 { 1362 WCHAR wszBuf[MAX_PATH]; 1363 1364 if (SH_FormatFileSizeWithBytes(&m_DirSize, wszBuf, _countof(wszBuf))) 1365 SetDlgItemTextW(hwndDlg, 14011, wszBuf); 1366 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(); 1373 } 1374 else 1375 break; 1376 } 1377 } while(FindNextFileW(hFind, &wfd)); 1378 1379 if (root && IsWindow(hwndDlg)) 1380 { 1381 WCHAR wszBuf[MAX_PATH]; 1382 1383 if (SH_FormatFileSizeWithBytes(&m_DirSize, wszBuf, _countof(wszBuf))) 1384 SetDlgItemTextW(hwndDlg, 14011, wszBuf); 1385 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); 1391 } 1392 1393 FindClose(hFind); 1394 return TRUE; 1395 } 1396