1 /* 2 * Open With Context Menu extension 3 * 4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org> 5 * Copyright 2016-2017 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 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 (fprop); 25 26 /// Folder Options: 27 /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF} 28 /// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210 29 /// Verbs: Open / RunAs 30 /// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0 31 32 /// ShellFolder Attributes: 0x0 33 34 typedef struct 35 { 36 WCHAR FileExtension[30]; 37 WCHAR FileDescription[100]; 38 WCHAR ClassKey[MAX_PATH]; 39 DWORD EditFlags; 40 } FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY; 41 42 // uniquely-defined icon entry for Advanced Settings 43 typedef struct ADVANCED_ICON 44 { 45 WCHAR szPath[MAX_PATH]; 46 UINT nIconIndex; 47 } ADVANCED_ICON; 48 49 // predefined icon IDs (See CreateTreeImageList function below) 50 #define I_CHECKED 0 51 #define I_UNCHECKED 1 52 #define I_CHECKED_DISABLED 2 53 #define I_UNCHECKED_DISABLED 3 54 #define I_RADIO_CHECKED 4 55 #define I_RADIO_UNCHECKED 5 56 #define I_RADIO_CHECKED_DISABLED 6 57 #define I_RADIO_UNCHECKED_DISABLED 7 58 59 #define PREDEFINED_ICON_COUNT 8 60 61 // definition of icon stock 62 static ADVANCED_ICON * s_AdvancedIcons = NULL; 63 static INT s_AdvancedIconCount = 0; 64 static HIMAGELIST s_hImageList = NULL; 65 66 static INT 67 Advanced_FindIcon(LPCWSTR pszPath, UINT nIconIndex) 68 { 69 for (INT i = PREDEFINED_ICON_COUNT; i < s_AdvancedIconCount; ++i) 70 { 71 ADVANCED_ICON *pIcon = &s_AdvancedIcons[i]; 72 if (pIcon->nIconIndex == nIconIndex && 73 lstrcmpiW(pIcon->szPath, pszPath) == 0) 74 { 75 return i; // icon ID 76 } 77 } 78 return -1; // not found 79 } 80 81 static INT 82 Advanced_AddIcon(LPCWSTR pszPath, UINT nIconIndex) 83 { 84 ADVANCED_ICON *pAllocated; 85 86 // return the ID if already existed 87 INT nIconID = Advanced_FindIcon(pszPath, nIconIndex); 88 if (nIconID != -1) 89 return nIconID; // already exists 90 91 // extract a small icon 92 HICON hIconSmall = NULL; 93 ExtractIconExW(pszPath, nIconIndex, NULL, &hIconSmall, 1); 94 if (hIconSmall == NULL) 95 return -1; // failure 96 97 // resize s_AdvancedIcons 98 size_t Size = (s_AdvancedIconCount + 1) * sizeof(ADVANCED_ICON); 99 pAllocated = (ADVANCED_ICON *)realloc(s_AdvancedIcons, Size); 100 if (pAllocated == NULL) 101 return -1; // failure 102 else 103 s_AdvancedIcons = pAllocated; 104 105 // save icon information 106 ADVANCED_ICON *pIcon = &s_AdvancedIcons[s_AdvancedIconCount]; 107 lstrcpynW(pIcon->szPath, pszPath, _countof(pIcon->szPath)); 108 pIcon->nIconIndex = nIconIndex; 109 110 // add the icon to the image list 111 ImageList_AddIcon(s_hImageList, hIconSmall); 112 113 // increment the counter 114 nIconID = s_AdvancedIconCount; 115 ++s_AdvancedIconCount; 116 117 DestroyIcon(hIconSmall); 118 119 return nIconID; // newly-added icon ID 120 } 121 122 // types of Advanced Setting entry 123 typedef enum ADVANCED_ENTRY_TYPE 124 { 125 AETYPE_GROUP, 126 AETYPE_CHECKBOX, 127 AETYPE_RADIO, 128 } ADVANCED_ENTRY_TYPE; 129 130 // an entry info of Advanced Settings 131 typedef struct ADVANCED_ENTRY 132 { 133 DWORD dwID; // entry ID 134 DWORD dwParentID; // parent entry ID 135 DWORD dwResourceID; // resource ID 136 WCHAR szKeyName[64]; // entry key name 137 DWORD dwType; // ADVANCED_ENTRY_TYPE 138 WCHAR szText[MAX_PATH]; // text 139 INT nIconID; // icon ID (See ADVANCED_ICON) 140 141 HKEY hkeyRoot; // registry root key 142 WCHAR szRegPath[MAX_PATH]; // registry path 143 WCHAR szValueName[64]; // registry value name 144 145 DWORD dwCheckedValue; // checked value 146 DWORD dwUncheckedValue; // unchecked value 147 DWORD dwDefaultValue; // defalut value 148 BOOL bHasUncheckedValue; // If FALSE, UncheckedValue is invalid 149 150 HTREEITEM hItem; // for TreeView 151 BOOL bGrayed; // disabled? 152 BOOL bChecked; // checked? 153 } ADVANCED_ENTRY, *PADVANCED_ENTRY; 154 155 // definition of advanced entries 156 static ADVANCED_ENTRY * s_Advanced = NULL; 157 static INT s_AdvancedCount = 0; 158 159 static HBITMAP 160 Create24BppBitmap(HDC hDC, INT cx, INT cy) 161 { 162 BITMAPINFO bi; 163 LPVOID pvBits; 164 165 ZeroMemory(&bi, sizeof(bi)); 166 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 167 bi.bmiHeader.biWidth = cx; 168 bi.bmiHeader.biHeight = cy; 169 bi.bmiHeader.biPlanes = 1; 170 bi.bmiHeader.biBitCount = 24; 171 bi.bmiHeader.biCompression = BI_RGB; 172 173 HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0); 174 return hbm; 175 } 176 177 static HBITMAP 178 CreateCheckImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE) 179 { 180 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); 181 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); 182 183 HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon); 184 if (hbm == NULL) 185 return NULL; // failure 186 187 RECT Rect, BoxRect; 188 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); 189 BoxRect = Rect; 190 InflateRect(&BoxRect, -1, -1); 191 192 HGDIOBJ hbmOld = SelectObject(hDC, hbm); 193 { 194 UINT uState = DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_MONO; 195 if (bCheck) 196 uState |= DFCS_CHECKED; 197 if (!bEnabled) 198 uState |= DFCS_INACTIVE; 199 DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState); 200 } 201 SelectObject(hDC, hbmOld); 202 203 return hbm; // success 204 } 205 206 static HBITMAP 207 CreateCheckMask(HDC hDC) 208 { 209 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); 210 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); 211 212 HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL); 213 if (hbm == NULL) 214 return NULL; // failure 215 216 RECT Rect, BoxRect; 217 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); 218 BoxRect = Rect; 219 InflateRect(&BoxRect, -1, -1); 220 221 HGDIOBJ hbmOld = SelectObject(hDC, hbm); 222 { 223 FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH))); 224 FillRect(hDC, &BoxRect, HBRUSH(GetStockObject(BLACK_BRUSH))); 225 } 226 SelectObject(hDC, hbmOld); 227 228 return hbm; // success 229 } 230 231 static HBITMAP 232 CreateRadioImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE) 233 { 234 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); 235 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); 236 237 HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon); 238 if (hbm == NULL) 239 return NULL; // failure 240 241 RECT Rect, BoxRect; 242 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); 243 BoxRect = Rect; 244 InflateRect(&BoxRect, -1, -1); 245 246 HGDIOBJ hbmOld = SelectObject(hDC, hbm); 247 { 248 UINT uState = DFCS_BUTTONRADIOIMAGE | DFCS_FLAT | DFCS_MONO; 249 if (bCheck) 250 uState |= DFCS_CHECKED; 251 if (!bEnabled) 252 uState |= DFCS_INACTIVE; 253 DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState); 254 } 255 SelectObject(hDC, hbmOld); 256 257 return hbm; // success 258 } 259 260 static HBITMAP 261 CreateRadioMask(HDC hDC) 262 { 263 INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); 264 INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); 265 266 HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL); 267 if (hbm == NULL) 268 return NULL; // failure 269 270 RECT Rect, BoxRect; 271 SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); 272 BoxRect = Rect; 273 InflateRect(&BoxRect, -1, -1); 274 275 HGDIOBJ hbmOld = SelectObject(hDC, hbm); 276 { 277 FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH))); 278 UINT uState = DFCS_BUTTONRADIOMASK | DFCS_FLAT | DFCS_MONO; 279 DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState); 280 } 281 SelectObject(hDC, hbmOld); 282 283 return hbm; // success 284 } 285 286 static HIMAGELIST 287 CreateTreeImageList(VOID) 288 { 289 HIMAGELIST hImageList; 290 hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 9, 1); 291 if (hImageList == NULL) 292 return NULL; // failure 293 294 // free if existed 295 if (s_AdvancedIcons) 296 { 297 free(s_AdvancedIcons); 298 s_AdvancedIcons = NULL; 299 } 300 s_AdvancedIconCount = 0; 301 302 // allocate now 303 ADVANCED_ICON *pAllocated; 304 size_t Size = PREDEFINED_ICON_COUNT * sizeof(ADVANCED_ICON); 305 pAllocated = (ADVANCED_ICON *)calloc(1, Size); 306 if (pAllocated == NULL) 307 return NULL; // failure 308 309 s_AdvancedIconCount = PREDEFINED_ICON_COUNT; 310 s_AdvancedIcons = pAllocated; 311 312 // add the predefined icons 313 314 HDC hDC = CreateCompatibleDC(NULL); 315 HBITMAP hbmMask = CreateCheckMask(hDC); 316 317 HBITMAP hbmChecked, hbmUnchecked; 318 319 hbmChecked = CreateCheckImage(hDC, TRUE); 320 ImageList_Add(hImageList, hbmChecked, hbmMask); 321 DeleteObject(hbmChecked); 322 323 hbmUnchecked = CreateCheckImage(hDC, FALSE); 324 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 325 DeleteObject(hbmUnchecked); 326 327 hbmChecked = CreateCheckImage(hDC, TRUE, FALSE); 328 ImageList_Add(hImageList, hbmChecked, hbmMask); 329 DeleteObject(hbmChecked); 330 331 hbmUnchecked = CreateCheckImage(hDC, FALSE, FALSE); 332 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 333 DeleteObject(hbmUnchecked); 334 335 DeleteObject(hbmMask); 336 hbmMask = CreateRadioMask(hDC); 337 338 hbmChecked = CreateRadioImage(hDC, TRUE); 339 ImageList_Add(hImageList, hbmChecked, hbmMask); 340 DeleteObject(hbmChecked); 341 342 hbmUnchecked = CreateRadioImage(hDC, FALSE); 343 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 344 DeleteObject(hbmUnchecked); 345 346 hbmChecked = CreateRadioImage(hDC, TRUE, FALSE); 347 ImageList_Add(hImageList, hbmChecked, hbmMask); 348 DeleteObject(hbmChecked); 349 350 hbmUnchecked = CreateRadioImage(hDC, FALSE, FALSE); 351 ImageList_Add(hImageList, hbmUnchecked, hbmMask); 352 DeleteObject(hbmUnchecked); 353 354 DeleteObject(hbmMask); 355 356 return hImageList; 357 } 358 359 static ADVANCED_ENTRY * 360 Advanced_GetItem(DWORD dwID) 361 { 362 if (dwID == DWORD(-1)) 363 return NULL; 364 365 for (INT i = 0; i < s_AdvancedCount; ++i) 366 { 367 ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 368 if (pEntry->dwID == dwID) 369 return pEntry; 370 } 371 return NULL; // failure 372 } 373 374 static INT 375 Advanced_GetImage(ADVANCED_ENTRY *pEntry) 376 { 377 switch (pEntry->dwType) 378 { 379 case AETYPE_GROUP: 380 return pEntry->nIconID; 381 382 case AETYPE_CHECKBOX: 383 if (pEntry->bGrayed) 384 { 385 if (pEntry->bChecked) 386 return I_CHECKED_DISABLED; 387 else 388 return I_UNCHECKED_DISABLED; 389 } 390 else 391 { 392 if (pEntry->bChecked) 393 return I_CHECKED; 394 else 395 return I_UNCHECKED; 396 } 397 398 case AETYPE_RADIO: 399 if (pEntry->bGrayed) 400 { 401 if (pEntry->bChecked) 402 return I_RADIO_CHECKED_DISABLED; 403 else 404 return I_RADIO_UNCHECKED_DISABLED; 405 } 406 else 407 { 408 if (pEntry->bChecked) 409 return I_RADIO_CHECKED; 410 else 411 return I_RADIO_UNCHECKED; 412 } 413 } 414 return -1; // failure 415 } 416 417 static VOID 418 Advanced_InsertEntry(HWND hwndTreeView, ADVANCED_ENTRY *pEntry) 419 { 420 ADVANCED_ENTRY *pParent = Advanced_GetItem(pEntry->dwParentID); 421 HTREEITEM hParent = TVI_ROOT; 422 if (pParent) 423 hParent = pParent->hItem; 424 425 TV_INSERTSTRUCT Insertion; 426 ZeroMemory(&Insertion, sizeof(Insertion)); 427 Insertion.hParent = hParent; 428 Insertion.hInsertAfter = TVI_LAST; 429 Insertion.item.mask = 430 TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; 431 Insertion.item.pszText = pEntry->szText; 432 433 INT iImage = Advanced_GetImage(pEntry); 434 Insertion.item.iImage = Insertion.item.iSelectedImage = iImage; 435 Insertion.item.lParam = pEntry->dwID; 436 pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion); 437 } 438 439 static VOID 440 Advanced_InsertAll(HWND hwndTreeView) 441 { 442 TreeView_DeleteAllItems(hwndTreeView); 443 444 // insert the entries 445 ADVANCED_ENTRY *pEntry; 446 for (INT i = 0; i < s_AdvancedCount; ++i) 447 { 448 pEntry = &s_Advanced[i]; 449 Advanced_InsertEntry(hwndTreeView, pEntry); 450 } 451 452 // expand all 453 for (INT i = 0; i < s_AdvancedCount; ++i) 454 { 455 pEntry = &s_Advanced[i]; 456 if (pEntry->dwType == AETYPE_GROUP) 457 { 458 TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND); 459 } 460 } 461 } 462 463 static BOOL 464 Advanced_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID) 465 { 466 DWORD dwIndex; 467 WCHAR szKeyName[64], szText[MAX_PATH], *pch; 468 DWORD Size, Value; 469 ADVANCED_ENTRY *pAllocated; 470 471 // resize s_Advanced 472 Size = (s_AdvancedCount + 1) * sizeof(ADVANCED_ENTRY); 473 pAllocated = (ADVANCED_ENTRY *)realloc(s_Advanced, Size); 474 if (pAllocated == NULL) 475 return FALSE; // failure 476 else 477 s_Advanced = pAllocated; 478 479 ADVANCED_ENTRY *pEntry = &s_Advanced[s_AdvancedCount]; 480 481 // dwID, dwParentID, szKeyName 482 pEntry->dwID = s_AdvancedCount; 483 pEntry->dwParentID = dwParentID; 484 lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName)); 485 486 // Text, ResourceID 487 pEntry->szText[0] = 0; 488 pEntry->dwResourceID = 0; 489 szText[0] = 0; 490 Size = sizeof(szText); 491 RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size); 492 if (szText[0] == L'@') 493 { 494 pch = wcsrchr(szText, L','); 495 if (pch) 496 { 497 *pch = 0; 498 dwIndex = abs(_wtoi(pch + 1)); 499 pEntry->dwResourceID = dwIndex; 500 } 501 HINSTANCE hInst = LoadLibraryW(&szText[1]); 502 LoadStringW(hInst, dwIndex, szText, _countof(szText)); 503 FreeLibrary(hInst); 504 } 505 else 506 { 507 pEntry->dwResourceID = DWORD(-1); 508 } 509 lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText)); 510 511 // Type 512 szText[0] = 0; 513 RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size); 514 if (lstrcmpiW(szText, L"checkbox") == 0) 515 pEntry->dwType = AETYPE_CHECKBOX; 516 else if (lstrcmpiW(szText, L"radio") == 0) 517 pEntry->dwType = AETYPE_RADIO; 518 else if (lstrcmpiW(szText, L"group") == 0) 519 pEntry->dwType = AETYPE_GROUP; 520 else 521 return FALSE; // failure 522 523 pEntry->nIconID = -1; 524 if (pEntry->dwType == AETYPE_GROUP) 525 { 526 // Bitmap (Icon) 527 UINT nIconIndex = 0; 528 Size = sizeof(szText); 529 szText[0] = 0; 530 RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size); 531 532 WCHAR szExpanded[MAX_PATH]; 533 ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded)); 534 pch = wcsrchr(szExpanded, L','); 535 if (pch) 536 { 537 *pch = 0; 538 nIconIndex = abs(_wtoi(pch + 1)); 539 } 540 pEntry->nIconID = Advanced_AddIcon(szExpanded, nIconIndex); 541 } 542 543 if (pEntry->dwType == AETYPE_GROUP) 544 { 545 pEntry->hkeyRoot = NULL; 546 pEntry->szRegPath[0] = 0; 547 pEntry->szValueName[0] = 0; 548 pEntry->dwCheckedValue = 0; 549 pEntry->bHasUncheckedValue = FALSE; 550 pEntry->dwUncheckedValue = 0; 551 pEntry->dwDefaultValue = 0; 552 pEntry->hItem = NULL; 553 pEntry->bGrayed = FALSE; 554 pEntry->bChecked = FALSE; 555 } 556 else 557 { 558 // HKeyRoot 559 Value = DWORD(HKEY_CURRENT_USER); 560 Size = sizeof(Value); 561 RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&Value), &Size); 562 pEntry->hkeyRoot = HKEY(Value); 563 564 // RegPath 565 pEntry->szRegPath[0] = 0; 566 Size = sizeof(szText); 567 RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size); 568 lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath)); 569 570 // ValueName 571 pEntry->szValueName[0] = 0; 572 Size = sizeof(szText); 573 RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size); 574 lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName)); 575 576 // CheckedValue 577 Size = sizeof(Value); 578 Value = 0x00000001; 579 RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size); 580 pEntry->dwCheckedValue = Value; 581 582 // UncheckedValue 583 Size = sizeof(Value); 584 Value = 0x00000000; 585 pEntry->bHasUncheckedValue = TRUE; 586 if (RegQueryValueExW(hKey, L"UncheckedValue", NULL, 587 NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS) 588 { 589 pEntry->bHasUncheckedValue = FALSE; 590 } 591 pEntry->dwUncheckedValue = Value; 592 593 // DefaultValue 594 Size = sizeof(Value); 595 Value = 0x00000001; 596 RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size); 597 pEntry->dwDefaultValue = Value; 598 599 // hItem 600 pEntry->hItem = NULL; 601 602 // bGrayed, bChecked 603 HKEY hkeyTarget; 604 Value = pEntry->dwDefaultValue; 605 pEntry->bGrayed = TRUE; 606 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 607 KEY_READ, &hkeyTarget) == ERROR_SUCCESS) 608 { 609 Size = sizeof(Value); 610 if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL, 611 LPBYTE(&Value), &Size) == ERROR_SUCCESS) 612 { 613 pEntry->bGrayed = FALSE; 614 } 615 RegCloseKey(hkeyTarget); 616 } 617 pEntry->bChecked = (Value == pEntry->dwCheckedValue); 618 } 619 620 // Grayed (ReactOS extension) 621 Size = sizeof(Value); 622 Value = FALSE; 623 RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size); 624 if (!pEntry->bGrayed) 625 pEntry->bGrayed = Value; 626 627 BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP); 628 dwParentID = pEntry->dwID; 629 ++s_AdvancedCount; 630 631 if (!bIsGroup) 632 return TRUE; // success 633 634 // load the children 635 dwIndex = 0; 636 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 637 _countof(szKeyName)) == ERROR_SUCCESS) 638 { 639 HKEY hkeyChild; 640 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 641 &hkeyChild) != ERROR_SUCCESS) 642 { 643 ++dwIndex; 644 continue; // failure 645 } 646 647 Advanced_LoadTree(hkeyChild, szKeyName, dwParentID); 648 RegCloseKey(hkeyChild); 649 650 ++dwIndex; 651 } 652 653 return TRUE; // success 654 } 655 656 static BOOL 657 Advanced_LoadAll(VOID) 658 { 659 static const WCHAR s_szAdvanced[] = 660 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"; 661 662 // free if already existed 663 if (s_Advanced) 664 { 665 free(s_Advanced); 666 s_Advanced = NULL; 667 } 668 s_AdvancedCount = 0; 669 670 HKEY hKey; 671 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0, 672 KEY_READ, &hKey) != ERROR_SUCCESS) 673 { 674 return FALSE; // failure 675 } 676 677 // load the children 678 WCHAR szKeyName[64]; 679 DWORD dwIndex = 0; 680 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 681 _countof(szKeyName)) == ERROR_SUCCESS) 682 { 683 HKEY hkeyChild; 684 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 685 &hkeyChild) != ERROR_SUCCESS) 686 { 687 ++dwIndex; 688 continue; // failure 689 } 690 691 Advanced_LoadTree(hkeyChild, szKeyName, DWORD(-1)); 692 RegCloseKey(hkeyChild); 693 694 ++dwIndex; 695 } 696 697 RegCloseKey(hKey); 698 699 return TRUE; // success 700 } 701 702 static int 703 Advanced_Compare(const void *x, const void *y) 704 { 705 ADVANCED_ENTRY *pEntry1 = (ADVANCED_ENTRY *)x; 706 ADVANCED_ENTRY *pEntry2 = (ADVANCED_ENTRY *)y; 707 708 DWORD dwParentID1 = pEntry1->dwParentID; 709 DWORD dwParentID2 = pEntry2->dwParentID; 710 711 if (dwParentID1 == dwParentID2) 712 return lstrcmpi(pEntry1->szText, pEntry2->szText); 713 714 DWORD i, m, n; 715 const UINT MAX_DEPTH = 32; 716 ADVANCED_ENTRY *pArray1[MAX_DEPTH]; 717 ADVANCED_ENTRY *pArray2[MAX_DEPTH]; 718 719 // Make ancestor lists 720 for (i = m = n = 0; i < MAX_DEPTH; ++i) 721 { 722 ADVANCED_ENTRY *pParent1 = Advanced_GetItem(dwParentID1); 723 ADVANCED_ENTRY *pParent2 = Advanced_GetItem(dwParentID2); 724 if (!pParent1 && !pParent2) 725 break; 726 727 if (pParent1) 728 { 729 pArray1[m++] = pParent1; 730 dwParentID1 = pParent1->dwParentID; 731 } 732 if (pParent2) 733 { 734 pArray2[n++] = pParent2; 735 dwParentID2 = pParent2->dwParentID; 736 } 737 } 738 739 UINT k = min(m, n); 740 for (i = 0; i < k; ++i) 741 { 742 INT nCompare = lstrcmpi(pArray1[m - i - 1]->szText, pArray2[n - i - 1]->szText); 743 if (nCompare < 0) 744 return -1; 745 if (nCompare > 0) 746 return 1; 747 } 748 749 if (m < n) 750 return -1; 751 if (m > n) 752 return 1; 753 return lstrcmpi(pEntry1->szText, pEntry2->szText); 754 } 755 756 static VOID 757 Advanced_SortAll(VOID) 758 { 759 qsort(s_Advanced, s_AdvancedCount, sizeof(ADVANCED_ENTRY), Advanced_Compare); 760 } 761 762 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); 763 764 static VOID 765 UpdateGeneralIcons(HWND hDlg) 766 { 767 HWND hwndTaskIcon, hwndFolderIcon, hwndClickIcon; 768 HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL; 769 LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL; 770 771 // show task setting icon 772 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED) 773 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS); 774 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED) 775 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS); 776 777 if (lpTaskIconName) 778 { 779 hTaskIcon = (HICON)LoadImage(shell32_hInstance, 780 lpTaskIconName, 781 IMAGE_ICON, 782 0, 783 0, 784 LR_DEFAULTCOLOR); 785 if (hTaskIcon) 786 { 787 hwndTaskIcon = GetDlgItem(hDlg, 788 IDC_FOLDER_OPTIONS_TASKICON); 789 if (hwndTaskIcon) 790 { 791 SendMessage(hwndTaskIcon, 792 STM_SETIMAGE, 793 IMAGE_ICON, 794 (LPARAM)hTaskIcon); 795 } 796 } 797 } 798 799 // show Folder setting icons 800 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED) 801 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW); 802 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED) 803 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW); 804 805 if (lpFolderIconName) 806 { 807 hFolderIcon = (HICON)LoadImage(shell32_hInstance, 808 lpFolderIconName, 809 IMAGE_ICON, 810 0, 811 0, 812 LR_DEFAULTCOLOR); 813 if (hFolderIcon) 814 { 815 hwndFolderIcon = GetDlgItem(hDlg, 816 IDC_FOLDER_OPTIONS_FOLDERICON); 817 if (hwndFolderIcon) 818 { 819 SendMessage(hwndFolderIcon, 820 STM_SETIMAGE, 821 IMAGE_ICON, 822 (LPARAM)hFolderIcon); 823 } 824 } 825 } 826 827 // Show click setting icon 828 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED) 829 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN); 830 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED) 831 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN); 832 833 if (lpClickIconName) 834 { 835 hClickIcon = (HICON)LoadImage(shell32_hInstance, 836 lpClickIconName, 837 IMAGE_ICON, 838 0, 839 0, 840 LR_DEFAULTCOLOR); 841 if (hClickIcon) 842 { 843 hwndClickIcon = GetDlgItem(hDlg, 844 IDC_FOLDER_OPTIONS_CLICKICON); 845 if (hwndClickIcon) 846 { 847 SendMessage(hwndClickIcon, 848 STM_SETIMAGE, 849 IMAGE_ICON, 850 (LPARAM)hClickIcon); 851 } 852 } 853 } 854 855 // Clean up 856 if(hTaskIcon) 857 DeleteObject(hTaskIcon); 858 if(hFolderIcon) 859 DeleteObject(hFolderIcon); 860 if(hClickIcon) 861 DeleteObject(hClickIcon); 862 863 return; 864 } 865 866 INT_PTR 867 CALLBACK 868 FolderOptionsGeneralDlg( 869 HWND hwndDlg, 870 UINT uMsg, 871 WPARAM wParam, 872 LPARAM lParam 873 ) 874 { 875 switch(uMsg) 876 { 877 case WM_INITDIALOG: 878 // FIXME 879 break; 880 881 case WM_COMMAND: 882 switch (LOWORD(wParam)) 883 { 884 case IDC_FOLDER_OPTIONS_COMMONTASKS: 885 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS: 886 case IDC_FOLDER_OPTIONS_SAMEWINDOW: 887 case IDC_FOLDER_OPTIONS_OWNWINDOW: 888 case IDC_FOLDER_OPTIONS_SINGLECLICK: 889 case IDC_FOLDER_OPTIONS_DOUBLECLICK: 890 if (HIWORD(wParam) == BN_CLICKED) 891 { 892 UpdateGeneralIcons(hwndDlg); 893 894 /* Enable the 'Apply' button */ 895 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 896 } 897 break; 898 } 899 break; 900 901 case WM_NOTIFY: 902 { 903 LPNMHDR pnmh = (LPNMHDR)lParam; 904 905 switch (pnmh->code) 906 { 907 case PSN_SETACTIVE: 908 break; 909 910 case PSN_APPLY: 911 break; 912 } 913 break; 914 } 915 916 case WM_DESTROY: 917 break; 918 919 default: 920 return FALSE; 921 } 922 return FALSE; 923 } 924 925 static BOOL 926 ViewDlg_OnInitDialog(HWND hwndDlg) 927 { 928 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 929 930 s_hImageList = CreateTreeImageList(); 931 TreeView_SetImageList(hwndTreeView, s_hImageList, TVSIL_NORMAL); 932 933 Advanced_LoadAll(); 934 Advanced_SortAll(); 935 Advanced_InsertAll(hwndTreeView); 936 937 return TRUE; // set focus 938 } 939 940 static BOOL 941 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem) 942 { 943 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 944 945 // get the item 946 TV_ITEM Item; 947 INT i; 948 ZeroMemory(&Item, sizeof(Item)); 949 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM; 950 Item.hItem = hItem; 951 if (!TreeView_GetItem(hwndTreeView, &Item)) 952 return FALSE; // no such item 953 954 ADVANCED_ENTRY *pEntry = Advanced_GetItem(Item.lParam); 955 if (pEntry == NULL) 956 return FALSE; // no such item 957 if (pEntry->bGrayed) 958 return FALSE; // disabled 959 960 // toggle check mark 961 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 962 switch (pEntry->dwType) 963 { 964 case AETYPE_CHECKBOX: 965 pEntry->bChecked = !pEntry->bChecked; 966 break; 967 case AETYPE_RADIO: 968 // reset all the entries of the same parent 969 for (i = 0; i < s_AdvancedCount; ++i) 970 { 971 ADVANCED_ENTRY *pEntry2 = &s_Advanced[i]; 972 if (pEntry->dwParentID == pEntry2->dwParentID) 973 { 974 pEntry2->bChecked = FALSE; 975 976 Item.hItem = pEntry2->hItem; 977 INT iImage = Advanced_GetImage(pEntry2); 978 Item.iImage = Item.iSelectedImage = iImage; 979 TreeView_SetItem(hwndTreeView, &Item); 980 } 981 } 982 pEntry->bChecked = TRUE; 983 break; 984 default: 985 return FALSE; // failure 986 } 987 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry); 988 Item.hItem = hItem; 989 TreeView_SetItem(hwndTreeView, &Item); 990 991 // redraw the item 992 RECT rcItem; 993 TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE); 994 InvalidateRect(hwndTreeView, &rcItem, TRUE); 995 return TRUE; // success 996 } 997 998 static VOID 999 ViewDlg_OnTreeViewClick(HWND hwndDlg) 1000 { 1001 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 1002 1003 // do hit test to get the clicked item 1004 TV_HITTESTINFO HitTest; 1005 ZeroMemory(&HitTest, sizeof(HitTest)); 1006 DWORD dwPos = GetMessagePos(); 1007 HitTest.pt.x = LOWORD(dwPos); 1008 HitTest.pt.y = HIWORD(dwPos); 1009 ScreenToClient(hwndTreeView, &HitTest.pt); 1010 HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest); 1011 1012 // toggle the check mark if possible 1013 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 1014 { 1015 // property sheet was changed 1016 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1017 } 1018 } 1019 1020 static void 1021 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown) 1022 { 1023 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 1024 1025 if (KeyDown->wVKey == VK_SPACE) 1026 { 1027 // [Space] key was pressed 1028 HTREEITEM hItem = TreeView_GetSelection(hwndTreeView); 1029 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 1030 { 1031 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1032 } 1033 } 1034 } 1035 1036 static INT_PTR 1037 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw) 1038 { 1039 NMCUSTOMDRAW& nmcd = Draw->nmcd; 1040 switch (nmcd.dwDrawStage) 1041 { 1042 case CDDS_PREPAINT: 1043 return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT 1044 1045 case CDDS_ITEMPREPAINT: 1046 if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected 1047 { 1048 LPARAM lParam = nmcd.lItemlParam; 1049 ADVANCED_ENTRY *pEntry = Advanced_GetItem(lParam); 1050 if (pEntry && pEntry->bGrayed) // disabled 1051 { 1052 // draw as grayed 1053 Draw->clrText = GetSysColor(COLOR_GRAYTEXT); 1054 Draw->clrTextBk = GetSysColor(COLOR_WINDOW); 1055 return CDRF_NEWFONT; 1056 } 1057 } 1058 break; 1059 1060 default: 1061 break; 1062 } 1063 return CDRF_DODEFAULT; 1064 } 1065 1066 static VOID 1067 Advanced_RestoreDefaults(HWND hwndDlg) 1068 { 1069 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 1070 1071 for (INT i = 0; i < s_AdvancedCount; ++i) 1072 { 1073 // ignore if the type is group 1074 ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 1075 if (pEntry->dwType == AETYPE_GROUP) 1076 continue; 1077 1078 // set default value on registry 1079 HKEY hKey; 1080 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 1081 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) 1082 { 1083 continue; 1084 } 1085 RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD, 1086 LPBYTE(pEntry->dwDefaultValue), sizeof(DWORD)); 1087 RegCloseKey(hKey); 1088 1089 // update check status 1090 pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue); 1091 1092 // update the image 1093 TV_ITEM Item; 1094 ZeroMemory(&Item, sizeof(Item)); 1095 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 1096 Item.hItem = pEntry->hItem; 1097 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry); 1098 TreeView_SetItem(hwndTreeView, &Item); 1099 } 1100 1101 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1102 } 1103 1104 /* FIXME: These macros should not be defined here */ 1105 #ifndef SSF_SHOWSUPERHIDDEN 1106 #define SSF_SHOWSUPERHIDDEN 0x00040000 1107 #endif 1108 #ifndef SSF_SEPPROCESS 1109 #define SSF_SEPPROCESS 0x00080000 1110 #endif 1111 1112 static VOID 1113 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask) 1114 { 1115 for (INT i = 0; i < s_AdvancedCount; ++i) 1116 { 1117 const ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 1118 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 1119 continue; 1120 1121 BOOL bChecked = pEntry->bChecked; 1122 1123 // FIXME: Add more items 1124 if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0) 1125 { 1126 pSS->fShowSuperHidden = !bChecked ? 1 : 0; 1127 *pdwMask |= SSF_SHOWSUPERHIDDEN; 1128 continue; 1129 } 1130 if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0) 1131 { 1132 pSS->fSepProcess = bChecked ? 1 : 0; 1133 *pdwMask |= SSF_SEPPROCESS; 1134 continue; 1135 } 1136 if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0) 1137 { 1138 pSS->fShowAllObjects = !bChecked ? 1 : 0; 1139 *pdwMask |= SSF_SHOWALLOBJECTS; 1140 continue; 1141 } 1142 if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0) 1143 { 1144 pSS->fShowExtensions = !bChecked ? 1 : 0; 1145 *pdwMask |= SSF_SHOWEXTENSIONS; 1146 continue; 1147 } 1148 if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0) 1149 { 1150 pSS->fShowCompColor = bChecked ? 1 : 0; 1151 *pdwMask |= SSF_SHOWCOMPCOLOR; 1152 continue; 1153 } 1154 if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0) 1155 { 1156 pSS->fShowInfoTip = bChecked ? 1 : 0; 1157 *pdwMask |= SSF_SHOWINFOTIP; 1158 continue; 1159 } 1160 } 1161 } 1162 1163 extern "C" 1164 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet); 1165 1166 static BOOL CALLBACK RefreshBrowsersCallback (HWND hWnd, LPARAM msg) 1167 { 1168 WCHAR ClassName[100]; 1169 if (GetClassName(hWnd, ClassName, 100)) 1170 { 1171 if (!wcscmp(ClassName, L"Progman") || 1172 !wcscmp(ClassName, L"CabinetWClass") || 1173 !wcscmp(ClassName, L"ExploreWClass")) 1174 { 1175 PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0); 1176 } 1177 } 1178 return TRUE; 1179 } 1180 1181 static VOID 1182 ViewDlg_Apply(HWND hwndDlg) 1183 { 1184 for (INT i = 0; i < s_AdvancedCount; ++i) 1185 { 1186 // ignore the entry if the type is group or the entry is grayed 1187 ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 1188 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 1189 continue; 1190 1191 // open the registry key 1192 HKEY hkeyTarget; 1193 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 1194 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS) 1195 { 1196 continue; 1197 } 1198 1199 // checked or unchecked? 1200 DWORD dwValue, dwSize; 1201 if (pEntry->bChecked) 1202 { 1203 dwValue = pEntry->dwCheckedValue; 1204 } 1205 else 1206 { 1207 if (pEntry->bHasUncheckedValue) 1208 { 1209 dwValue = pEntry->dwUncheckedValue; 1210 } 1211 else 1212 { 1213 // there is no unchecked value 1214 RegCloseKey(hkeyTarget); 1215 continue; // ignore 1216 } 1217 } 1218 1219 // set the value 1220 dwSize = sizeof(dwValue); 1221 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD, 1222 LPBYTE(&dwValue), dwSize); 1223 1224 // close now 1225 RegCloseKey(hkeyTarget); 1226 } 1227 1228 // scan advanced settings for user's settings 1229 DWORD dwMask = 0; 1230 SHELLSTATE ShellState; 1231 ZeroMemory(&ShellState, sizeof(ShellState)); 1232 ScanAdvancedSettings(&ShellState, &dwMask); 1233 1234 // update user's settings 1235 SHGetSetSettings(&ShellState, dwMask, TRUE); 1236 1237 // notify all 1238 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); 1239 1240 EnumWindows(RefreshBrowsersCallback, NULL); 1241 } 1242 1243 INT_PTR CALLBACK 1244 FolderOptionsViewDlg( 1245 HWND hwndDlg, 1246 UINT uMsg, 1247 WPARAM wParam, 1248 LPARAM lParam) 1249 { 1250 INT_PTR Result; 1251 NMTVCUSTOMDRAW *Draw; 1252 1253 switch(uMsg) 1254 { 1255 case WM_INITDIALOG: 1256 return ViewDlg_OnInitDialog(hwndDlg); 1257 case WM_COMMAND: 1258 switch (LOWORD(wParam)) 1259 { 1260 case 14004: // Restore Defaults 1261 Advanced_RestoreDefaults(hwndDlg); 1262 break; 1263 } 1264 break; 1265 case WM_NOTIFY: 1266 switch (LPNMHDR(lParam)->code) 1267 { 1268 case NM_CLICK: // clicked on treeview 1269 ViewDlg_OnTreeViewClick(hwndDlg); 1270 break; 1271 case NM_CUSTOMDRAW: // custom draw (for graying) 1272 Draw = (NMTVCUSTOMDRAW *)lParam; 1273 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw); 1274 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); 1275 return Result; 1276 case TVN_KEYDOWN: // key is down 1277 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam); 1278 break; 1279 case PSN_APPLY: // [Apply] is clicked 1280 ViewDlg_Apply(hwndDlg); 1281 break; 1282 default: 1283 break; 1284 } 1285 break; 1286 } 1287 1288 return FALSE; 1289 } 1290 1291 static 1292 VOID 1293 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl) 1294 { 1295 RECT clientRect; 1296 LVCOLUMNW col; 1297 WCHAR szName[50]; 1298 DWORD dwStyle; 1299 int columnSize = 140; 1300 1301 1302 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR))) 1303 { 1304 /* default to english */ 1305 wcscpy(szName, L"Extensions"); 1306 } 1307 1308 /* make sure its null terminated */ 1309 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0; 1310 1311 GetClientRect(hDlgCtrl, &clientRect); 1312 ZeroMemory(&col, sizeof(LV_COLUMN)); 1313 columnSize = 140; //FIXME 1314 col.iSubItem = 0; 1315 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; 1316 col.fmt = LVCFMT_FIXED_WIDTH; 1317 col.cx = columnSize | LVCFMT_LEFT; 1318 col.cchTextMax = wcslen(szName); 1319 col.pszText = szName; 1320 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col); 1321 1322 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR))) 1323 { 1324 /* default to english */ 1325 wcscpy(szName, L"File Types"); 1326 ERR("Failed to load localized string!\n"); 1327 } 1328 1329 col.iSubItem = 1; 1330 col.cx = clientRect.right - clientRect.left - columnSize; 1331 col.cchTextMax = wcslen(szName); 1332 col.pszText = szName; 1333 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col); 1334 1335 /* set full select style */ 1336 dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 1337 dwStyle = dwStyle | LVS_EX_FULLROWSELECT; 1338 SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); 1339 } 1340 1341 INT 1342 FindItem(HWND hDlgCtrl, WCHAR * ItemName) 1343 { 1344 LVFINDINFOW findInfo; 1345 ZeroMemory(&findInfo, sizeof(LVFINDINFOW)); 1346 1347 findInfo.flags = LVFI_STRING; 1348 findInfo.psz = ItemName; 1349 return ListView_FindItem(hDlgCtrl, 0, &findInfo); 1350 } 1351 1352 static 1353 VOID 1354 InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile) 1355 { 1356 PFOLDER_FILE_TYPE_ENTRY Entry; 1357 HKEY hKey; 1358 LVITEMW lvItem; 1359 DWORD dwSize; 1360 DWORD dwType; 1361 1362 if (szName[0] != L'.') 1363 { 1364 /* FIXME handle URL protocol handlers */ 1365 return; 1366 } 1367 1368 /* allocate file type entry */ 1369 Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY)); 1370 1371 if (!Entry) 1372 return; 1373 1374 /* open key */ 1375 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 1376 { 1377 HeapFree(GetProcessHeap(), 0, Entry); 1378 return; 1379 } 1380 1381 /* FIXME check for duplicates */ 1382 1383 /* query for the default key */ 1384 dwSize = sizeof(Entry->ClassKey); 1385 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS) 1386 { 1387 /* no link available */ 1388 Entry->ClassKey[0] = 0; 1389 } 1390 1391 if (Entry->ClassKey[0]) 1392 { 1393 HKEY hTemp; 1394 /* try open linked key */ 1395 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS) 1396 { 1397 /* use linked key */ 1398 RegCloseKey(hKey); 1399 hKey = hTemp; 1400 } 1401 } 1402 1403 /* read friendly type name */ 1404 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS) 1405 { 1406 /* read file description */ 1407 dwSize = sizeof(Entry->FileDescription); 1408 Entry->FileDescription[0] = 0; 1409 1410 /* read default key */ 1411 RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize); 1412 } 1413 1414 /* Read the EditFlags value */ 1415 Entry->EditFlags = 0; 1416 if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize)) 1417 { 1418 if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD)) 1419 RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize); 1420 } 1421 1422 /* close key */ 1423 RegCloseKey(hKey); 1424 1425 /* Do not add excluded entries */ 1426 if (Entry->EditFlags & 0x00000001) //FTA_Exclude 1427 { 1428 HeapFree(GetProcessHeap(), 0, Entry); 1429 return; 1430 } 1431 1432 /* convert extension to upper case */ 1433 wcscpy(Entry->FileExtension, szName); 1434 _wcsupr(Entry->FileExtension); 1435 1436 if (!Entry->FileDescription[0]) 1437 { 1438 /* construct default 'FileExtensionFile' by formatting the uppercase extension 1439 with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */ 1440 1441 StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]); 1442 } 1443 1444 ZeroMemory(&lvItem, sizeof(LVITEMW)); 1445 lvItem.mask = LVIF_TEXT | LVIF_PARAM; 1446 lvItem.iSubItem = 0; 1447 lvItem.pszText = &Entry->FileExtension[1]; 1448 lvItem.iItem = *iItem; 1449 lvItem.lParam = (LPARAM)Entry; 1450 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem); 1451 1452 ZeroMemory(&lvItem, sizeof(LVITEMW)); 1453 lvItem.mask = LVIF_TEXT; 1454 lvItem.pszText = Entry->FileDescription; 1455 lvItem.iItem = *iItem; 1456 lvItem.iSubItem = 1; 1457 ListView_SetItem(hDlgCtrl, &lvItem); 1458 1459 (*iItem)++; 1460 } 1461 1462 static 1463 int 1464 CALLBACK 1465 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 1466 { 1467 PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2; 1468 int x; 1469 1470 Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1; 1471 Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2; 1472 1473 x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension); 1474 if (x != 0) 1475 return x; 1476 1477 return wcsicmp(Entry1->FileDescription, Entry2->FileDescription); 1478 } 1479 1480 static 1481 PFOLDER_FILE_TYPE_ENTRY 1482 InitializeFileTypesListCtrl(HWND hwndDlg) 1483 { 1484 HWND hDlgCtrl; 1485 DWORD dwIndex = 0; 1486 WCHAR szName[50]; 1487 WCHAR szFile[100]; 1488 DWORD dwName; 1489 LVITEMW lvItem; 1490 INT iItem = 0; 1491 1492 hDlgCtrl = GetDlgItem(hwndDlg, 14000); 1493 InitializeFileTypesListCtrlColumns(hDlgCtrl); 1494 1495 szFile[0] = 0; 1496 if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile))) 1497 { 1498 /* default to english */ 1499 wcscpy(szFile, L"%s File"); 1500 } 1501 szFile[(_countof(szFile)) - 1] = 0; 1502 1503 dwName = _countof(szName); 1504 1505 while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) 1506 { 1507 InsertFileType(hDlgCtrl, szName, &iItem, szFile); 1508 dwName = _countof(szName); 1509 } 1510 1511 /* Leave if the list is empty */ 1512 if (iItem == 0) 1513 return NULL; 1514 1515 /* sort list */ 1516 ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL); 1517 1518 /* select first item */ 1519 ZeroMemory(&lvItem, sizeof(LVITEMW)); 1520 lvItem.mask = LVIF_STATE; 1521 lvItem.stateMask = (UINT)-1; 1522 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; 1523 lvItem.iItem = 0; 1524 ListView_SetItem(hDlgCtrl, &lvItem); 1525 1526 lvItem.mask = LVIF_PARAM; 1527 ListView_GetItem(hDlgCtrl, &lvItem); 1528 1529 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; 1530 } 1531 1532 static 1533 PFOLDER_FILE_TYPE_ENTRY 1534 FindSelectedItem( 1535 HWND hDlgCtrl) 1536 { 1537 UINT Count, Index; 1538 LVITEMW lvItem; 1539 1540 Count = ListView_GetItemCount(hDlgCtrl); 1541 1542 for (Index = 0; Index < Count; Index++) 1543 { 1544 ZeroMemory(&lvItem, sizeof(LVITEM)); 1545 lvItem.mask = LVIF_PARAM | LVIF_STATE; 1546 lvItem.iItem = Index; 1547 lvItem.stateMask = (UINT) - 1; 1548 1549 if (ListView_GetItem(hDlgCtrl, &lvItem)) 1550 { 1551 if (lvItem.state & LVIS_SELECTED) 1552 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; 1553 } 1554 } 1555 1556 return NULL; 1557 } 1558 1559 INT_PTR 1560 CALLBACK 1561 FolderOptionsFileTypesDlg( 1562 HWND hwndDlg, 1563 UINT uMsg, 1564 WPARAM wParam, 1565 LPARAM lParam) 1566 { 1567 LPNMLISTVIEW lppl; 1568 LVITEMW lvItem; 1569 WCHAR Buffer[255], FormatBuffer[255]; 1570 PFOLDER_FILE_TYPE_ENTRY pItem; 1571 OPENASINFO Info; 1572 1573 switch(uMsg) 1574 { 1575 case WM_INITDIALOG: 1576 pItem = InitializeFileTypesListCtrl(hwndDlg); 1577 1578 /* Disable the Delete button if the listview is empty or 1579 the selected item should not be deleted by the user */ 1580 if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove 1581 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); 1582 return TRUE; 1583 1584 case WM_COMMAND: 1585 switch(LOWORD(wParam)) 1586 { 1587 case 14006: 1588 pItem = FindSelectedItem(GetDlgItem(hwndDlg, 14000)); 1589 if (pItem) 1590 { 1591 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT; 1592 Info.pcszClass = pItem->FileExtension; 1593 SHOpenWithDialog(hwndDlg, &Info); 1594 } 1595 break; 1596 } 1597 break; 1598 1599 case WM_NOTIFY: 1600 lppl = (LPNMLISTVIEW) lParam; 1601 1602 if (lppl->hdr.code == LVN_ITEMCHANGING) 1603 { 1604 ZeroMemory(&lvItem, sizeof(LVITEM)); 1605 lvItem.mask = LVIF_PARAM; 1606 lvItem.iItem = lppl->iItem; 1607 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem)) 1608 return TRUE; 1609 1610 pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; 1611 if (!pItem) 1612 return TRUE; 1613 1614 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) 1615 { 1616 /* new focused item */ 1617 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR))) 1618 { 1619 /* use default english format string */ 1620 wcscpy(FormatBuffer, L"Details for '%s' extension"); 1621 } 1622 1623 /* format buffer */ 1624 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]); 1625 /* update dialog */ 1626 SetDlgItemTextW(hwndDlg, 14003, Buffer); 1627 1628 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR))) 1629 { 1630 /* use default english format string */ 1631 wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced."); 1632 } 1633 /* format buffer */ 1634 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]); 1635 /* update dialog */ 1636 SetDlgItemTextW(hwndDlg, 14007, Buffer); 1637 1638 /* Enable the Delete button */ 1639 if (pItem->EditFlags & 0x00000010) // FTA_NoRemove 1640 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); 1641 else 1642 EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE); 1643 } 1644 } 1645 else if (lppl->hdr.code == PSN_SETACTIVE) 1646 { 1647 /* On page activation, set the focus to the listview */ 1648 SetFocus(GetDlgItem(hwndDlg, 14000)); 1649 } 1650 break; 1651 } 1652 1653 return FALSE; 1654 } 1655 1656 static 1657 VOID 1658 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst) 1659 { 1660 PROPSHEETHEADERW pinfo; 1661 HPROPSHEETPAGE hppages[3]; 1662 HPROPSHEETPAGE hpage; 1663 UINT num_pages = 0; 1664 WCHAR szOptions[100]; 1665 1666 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL); 1667 if (hpage) 1668 hppages[num_pages++] = hpage; 1669 1670 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL); 1671 if (hpage) 1672 hppages[num_pages++] = hpage; 1673 1674 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL); 1675 if (hpage) 1676 hppages[num_pages++] = hpage; 1677 1678 szOptions[0] = L'\0'; 1679 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR)); 1680 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0'; 1681 1682 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW)); 1683 pinfo.dwSize = sizeof(PROPSHEETHEADERW); 1684 pinfo.dwFlags = PSH_NOCONTEXTHELP; 1685 pinfo.nPages = num_pages; 1686 pinfo.phpage = hppages; 1687 pinfo.pszCaption = szOptions; 1688 1689 PropertySheetW(&pinfo); 1690 } 1691 1692 static 1693 VOID 1694 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow) 1695 { 1696 switch(fOptions) 1697 { 1698 case 0: 1699 ShowFolderOptionsDialog(hWnd, hInst); 1700 break; 1701 case 1: 1702 // show taskbar options dialog 1703 FIXME("notify explorer to show taskbar options dialog"); 1704 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0); 1705 break; 1706 default: 1707 FIXME("unrecognized options id %d\n", fOptions); 1708 } 1709 } 1710 1711 /************************************************************************* 1712 * Options_RunDLL (SHELL32.@) 1713 */ 1714 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) 1715 { 1716 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); 1717 } 1718 1719 /************************************************************************* 1720 * Options_RunDLLA (SHELL32.@) 1721 */ 1722 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) 1723 { 1724 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); 1725 } 1726 1727 /************************************************************************* 1728 * Options_RunDLLW (SHELL32.@) 1729 */ 1730 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow) 1731 { 1732 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow); 1733 } 1734