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 for (INT i = 0; i < s_AdvancedCount; ++i) 363 { 364 ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 365 if (pEntry->dwID == dwID) 366 return pEntry; 367 } 368 return NULL; // failure 369 } 370 371 static INT 372 Advanced_GetImage(ADVANCED_ENTRY *pEntry) 373 { 374 switch (pEntry->dwType) 375 { 376 case AETYPE_GROUP: 377 return pEntry->nIconID; 378 379 case AETYPE_CHECKBOX: 380 if (pEntry->bGrayed) 381 { 382 if (pEntry->bChecked) 383 return I_CHECKED_DISABLED; 384 else 385 return I_UNCHECKED_DISABLED; 386 } 387 else 388 { 389 if (pEntry->bChecked) 390 return I_CHECKED; 391 else 392 return I_UNCHECKED; 393 } 394 395 case AETYPE_RADIO: 396 if (pEntry->bGrayed) 397 { 398 if (pEntry->bChecked) 399 return I_RADIO_CHECKED_DISABLED; 400 else 401 return I_RADIO_UNCHECKED_DISABLED; 402 } 403 else 404 { 405 if (pEntry->bChecked) 406 return I_RADIO_CHECKED; 407 else 408 return I_RADIO_UNCHECKED; 409 } 410 } 411 return -1; // failure 412 } 413 414 static VOID 415 Advanced_InsertEntry(HWND hwndTreeView, ADVANCED_ENTRY *pEntry) 416 { 417 ADVANCED_ENTRY *pParent = Advanced_GetItem(pEntry->dwParentID); 418 HTREEITEM hParent = TVI_ROOT; 419 if (pParent) 420 hParent = pParent->hItem; 421 422 TV_INSERTSTRUCT Insertion; 423 ZeroMemory(&Insertion, sizeof(Insertion)); 424 Insertion.hParent = hParent; 425 Insertion.hInsertAfter = TVI_LAST; 426 Insertion.item.mask = 427 TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; 428 Insertion.item.pszText = pEntry->szText; 429 430 INT iImage = Advanced_GetImage(pEntry); 431 Insertion.item.iImage = Insertion.item.iSelectedImage = iImage; 432 Insertion.item.lParam = pEntry->dwID; 433 pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion); 434 } 435 436 static VOID 437 Advanced_InsertAll(HWND hwndTreeView) 438 { 439 TreeView_DeleteAllItems(hwndTreeView); 440 441 // insert the entries 442 ADVANCED_ENTRY *pEntry; 443 for (INT i = 0; i < s_AdvancedCount; ++i) 444 { 445 pEntry = &s_Advanced[i]; 446 Advanced_InsertEntry(hwndTreeView, pEntry); 447 } 448 449 // expand all 450 for (INT i = 0; i < s_AdvancedCount; ++i) 451 { 452 pEntry = &s_Advanced[i]; 453 if (pEntry->dwType == AETYPE_GROUP) 454 { 455 TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND); 456 } 457 } 458 } 459 460 static BOOL 461 Advanced_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID) 462 { 463 DWORD dwIndex; 464 WCHAR szKeyName[64], szText[MAX_PATH], *pch; 465 DWORD Size, Value; 466 ADVANCED_ENTRY *pAllocated; 467 468 // resize s_Advanced 469 Size = (s_AdvancedCount + 1) * sizeof(ADVANCED_ENTRY); 470 pAllocated = (ADVANCED_ENTRY *)realloc(s_Advanced, Size); 471 if (pAllocated == NULL) 472 return FALSE; // failure 473 else 474 s_Advanced = pAllocated; 475 476 ADVANCED_ENTRY *pEntry = &s_Advanced[s_AdvancedCount]; 477 478 // dwID, dwParentID, szKeyName 479 pEntry->dwID = s_AdvancedCount; 480 pEntry->dwParentID = dwParentID; 481 lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName)); 482 483 // Text, ResourceID 484 pEntry->szText[0] = 0; 485 pEntry->dwResourceID = 0; 486 szText[0] = 0; 487 Size = sizeof(szText); 488 RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size); 489 if (szText[0] == L'@') 490 { 491 pch = wcsrchr(szText, L','); 492 if (pch) 493 { 494 *pch = 0; 495 dwIndex = abs(_wtoi(pch + 1)); 496 pEntry->dwResourceID = dwIndex; 497 } 498 HINSTANCE hInst = LoadLibraryW(&szText[1]); 499 LoadStringW(hInst, dwIndex, szText, _countof(szText)); 500 FreeLibrary(hInst); 501 } 502 else 503 { 504 pEntry->dwResourceID = DWORD(-1); 505 } 506 lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText)); 507 508 // Type 509 szText[0] = 0; 510 RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size); 511 if (lstrcmpiW(szText, L"checkbox") == 0) 512 pEntry->dwType = AETYPE_CHECKBOX; 513 else if (lstrcmpiW(szText, L"radio") == 0) 514 pEntry->dwType = AETYPE_RADIO; 515 else if (lstrcmpiW(szText, L"group") == 0) 516 pEntry->dwType = AETYPE_GROUP; 517 else 518 return FALSE; // failure 519 520 pEntry->nIconID = -1; 521 if (pEntry->dwType == AETYPE_GROUP) 522 { 523 // Bitmap (Icon) 524 UINT nIconIndex = 0; 525 Size = sizeof(szText); 526 szText[0] = 0; 527 RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size); 528 529 WCHAR szExpanded[MAX_PATH]; 530 ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded)); 531 pch = wcsrchr(szExpanded, L','); 532 if (pch) 533 { 534 *pch = 0; 535 nIconIndex = abs(_wtoi(pch + 1)); 536 } 537 pEntry->nIconID = Advanced_AddIcon(szExpanded, nIconIndex); 538 } 539 540 if (pEntry->dwType == AETYPE_GROUP) 541 { 542 pEntry->hkeyRoot = NULL; 543 pEntry->szRegPath[0] = 0; 544 pEntry->szValueName[0] = 0; 545 pEntry->dwCheckedValue = 0; 546 pEntry->bHasUncheckedValue = FALSE; 547 pEntry->dwUncheckedValue = 0; 548 pEntry->dwDefaultValue = 0; 549 pEntry->hItem = NULL; 550 pEntry->bGrayed = FALSE; 551 pEntry->bChecked = FALSE; 552 } 553 else 554 { 555 // HKeyRoot 556 Value = DWORD(HKEY_CURRENT_USER); 557 Size = sizeof(Value); 558 RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&Value), &Size); 559 pEntry->hkeyRoot = HKEY(Value); 560 561 // RegPath 562 pEntry->szRegPath[0] = 0; 563 Size = sizeof(szText); 564 RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size); 565 lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath)); 566 567 // ValueName 568 pEntry->szValueName[0] = 0; 569 Size = sizeof(szText); 570 RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size); 571 lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName)); 572 573 // CheckedValue 574 Size = sizeof(Value); 575 Value = 0x00000001; 576 RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size); 577 pEntry->dwCheckedValue = Value; 578 579 // UncheckedValue 580 Size = sizeof(Value); 581 Value = 0x00000000; 582 pEntry->bHasUncheckedValue = TRUE; 583 if (RegQueryValueExW(hKey, L"UncheckedValue", NULL, 584 NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS) 585 { 586 pEntry->bHasUncheckedValue = FALSE; 587 } 588 pEntry->dwUncheckedValue = Value; 589 590 // DefaultValue 591 Size = sizeof(Value); 592 Value = 0x00000001; 593 RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size); 594 pEntry->dwDefaultValue = Value; 595 596 // hItem 597 pEntry->hItem = NULL; 598 599 // bGrayed, bChecked 600 HKEY hkeyTarget; 601 Value = pEntry->dwDefaultValue; 602 pEntry->bGrayed = TRUE; 603 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 604 KEY_READ, &hkeyTarget) == ERROR_SUCCESS) 605 { 606 Size = sizeof(Value); 607 if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL, 608 LPBYTE(&Value), &Size) == ERROR_SUCCESS) 609 { 610 pEntry->bGrayed = FALSE; 611 } 612 RegCloseKey(hkeyTarget); 613 } 614 pEntry->bChecked = (Value == pEntry->dwCheckedValue); 615 } 616 617 // Grayed (ReactOS extension) 618 Size = sizeof(Value); 619 Value = FALSE; 620 RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size); 621 if (!pEntry->bGrayed) 622 pEntry->bGrayed = Value; 623 624 BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP); 625 dwParentID = pEntry->dwID; 626 ++s_AdvancedCount; 627 628 if (!bIsGroup) 629 return TRUE; // success 630 631 // load the children 632 dwIndex = 0; 633 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 634 _countof(szKeyName)) == ERROR_SUCCESS) 635 { 636 HKEY hkeyChild; 637 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 638 &hkeyChild) != ERROR_SUCCESS) 639 { 640 ++dwIndex; 641 continue; // failure 642 } 643 644 Advanced_LoadTree(hkeyChild, szKeyName, dwParentID); 645 RegCloseKey(hkeyChild); 646 647 ++dwIndex; 648 } 649 650 return TRUE; // success 651 } 652 653 static BOOL 654 Advanced_LoadAll(VOID) 655 { 656 static const WCHAR s_szAdvanced[] = 657 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"; 658 659 // free if already existed 660 if (s_Advanced) 661 { 662 free(s_Advanced); 663 s_Advanced = NULL; 664 } 665 s_AdvancedCount = 0; 666 667 HKEY hKey; 668 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0, 669 KEY_READ, &hKey) != ERROR_SUCCESS) 670 { 671 return FALSE; // failure 672 } 673 674 // load the children 675 WCHAR szKeyName[64]; 676 DWORD dwIndex = 0; 677 while (RegEnumKeyW(hKey, dwIndex, szKeyName, 678 _countof(szKeyName)) == ERROR_SUCCESS) 679 { 680 HKEY hkeyChild; 681 if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, 682 &hkeyChild) != ERROR_SUCCESS) 683 { 684 ++dwIndex; 685 continue; // failure 686 } 687 688 Advanced_LoadTree(hkeyChild, szKeyName, DWORD(-1)); 689 RegCloseKey(hkeyChild); 690 691 ++dwIndex; 692 } 693 694 RegCloseKey(hKey); 695 696 return TRUE; // success 697 } 698 699 static int 700 Advanced_Compare(const void *x, const void *y) 701 { 702 ADVANCED_ENTRY *pEntry1 = (ADVANCED_ENTRY *)x; 703 ADVANCED_ENTRY *pEntry2 = (ADVANCED_ENTRY *)y; 704 DWORD dwParentID1 = pEntry1->dwParentID; 705 DWORD dwParentID2 = pEntry2->dwParentID; 706 while (dwParentID1 != dwParentID2) 707 { 708 ADVANCED_ENTRY *pParent1 = Advanced_GetItem(dwParentID1); 709 ADVANCED_ENTRY *pParent2 = Advanced_GetItem(dwParentID2); 710 if (!pParent1 && !pParent2) 711 break; 712 if (!pParent1 && pParent2) 713 return -1; 714 if (pParent1 && !pParent2) 715 return 1; 716 INT nCompare = lstrcmpi(pParent1->szText, pParent2->szText); 717 if (nCompare) 718 return nCompare; 719 dwParentID1 = pParent1->dwParentID; 720 dwParentID2 = pParent2->dwParentID; 721 } 722 return lstrcmpi(pEntry1->szText, pEntry2->szText); 723 } 724 725 static VOID 726 Advanced_SortAll(VOID) 727 { 728 qsort(s_Advanced, s_AdvancedCount, sizeof(ADVANCED_ENTRY), Advanced_Compare); 729 } 730 731 EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); 732 733 static VOID 734 UpdateGeneralIcons(HWND hDlg) 735 { 736 HWND hwndTaskIcon, hwndFolderIcon, hwndClickIcon; 737 HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL; 738 LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL; 739 740 // show task setting icon 741 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED) 742 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS); 743 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED) 744 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS); 745 746 if (lpTaskIconName) 747 { 748 hTaskIcon = (HICON)LoadImage(shell32_hInstance, 749 lpTaskIconName, 750 IMAGE_ICON, 751 0, 752 0, 753 LR_DEFAULTCOLOR); 754 if (hTaskIcon) 755 { 756 hwndTaskIcon = GetDlgItem(hDlg, 757 IDC_FOLDER_OPTIONS_TASKICON); 758 if (hwndTaskIcon) 759 { 760 SendMessage(hwndTaskIcon, 761 STM_SETIMAGE, 762 IMAGE_ICON, 763 (LPARAM)hTaskIcon); 764 } 765 } 766 } 767 768 // show Folder setting icons 769 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED) 770 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW); 771 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED) 772 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW); 773 774 if (lpFolderIconName) 775 { 776 hFolderIcon = (HICON)LoadImage(shell32_hInstance, 777 lpFolderIconName, 778 IMAGE_ICON, 779 0, 780 0, 781 LR_DEFAULTCOLOR); 782 if (hFolderIcon) 783 { 784 hwndFolderIcon = GetDlgItem(hDlg, 785 IDC_FOLDER_OPTIONS_FOLDERICON); 786 if (hwndFolderIcon) 787 { 788 SendMessage(hwndFolderIcon, 789 STM_SETIMAGE, 790 IMAGE_ICON, 791 (LPARAM)hFolderIcon); 792 } 793 } 794 } 795 796 // Show click setting icon 797 if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED) 798 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN); 799 else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED) 800 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN); 801 802 if (lpClickIconName) 803 { 804 hClickIcon = (HICON)LoadImage(shell32_hInstance, 805 lpClickIconName, 806 IMAGE_ICON, 807 0, 808 0, 809 LR_DEFAULTCOLOR); 810 if (hClickIcon) 811 { 812 hwndClickIcon = GetDlgItem(hDlg, 813 IDC_FOLDER_OPTIONS_CLICKICON); 814 if (hwndClickIcon) 815 { 816 SendMessage(hwndClickIcon, 817 STM_SETIMAGE, 818 IMAGE_ICON, 819 (LPARAM)hClickIcon); 820 } 821 } 822 } 823 824 // Clean up 825 if(hTaskIcon) 826 DeleteObject(hTaskIcon); 827 if(hFolderIcon) 828 DeleteObject(hFolderIcon); 829 if(hClickIcon) 830 DeleteObject(hClickIcon); 831 832 return; 833 } 834 835 INT_PTR 836 CALLBACK 837 FolderOptionsGeneralDlg( 838 HWND hwndDlg, 839 UINT uMsg, 840 WPARAM wParam, 841 LPARAM lParam 842 ) 843 { 844 switch(uMsg) 845 { 846 case WM_INITDIALOG: 847 // FIXME 848 break; 849 850 case WM_COMMAND: 851 switch (LOWORD(wParam)) 852 { 853 case IDC_FOLDER_OPTIONS_COMMONTASKS: 854 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS: 855 case IDC_FOLDER_OPTIONS_SAMEWINDOW: 856 case IDC_FOLDER_OPTIONS_OWNWINDOW: 857 case IDC_FOLDER_OPTIONS_SINGLECLICK: 858 case IDC_FOLDER_OPTIONS_DOUBLECLICK: 859 if (HIWORD(wParam) == BN_CLICKED) 860 { 861 UpdateGeneralIcons(hwndDlg); 862 863 /* Enable the 'Apply' button */ 864 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 865 } 866 break; 867 } 868 break; 869 870 case WM_NOTIFY: 871 { 872 LPNMHDR pnmh = (LPNMHDR)lParam; 873 874 switch (pnmh->code) 875 { 876 case PSN_SETACTIVE: 877 break; 878 879 case PSN_APPLY: 880 break; 881 } 882 break; 883 } 884 885 case WM_DESTROY: 886 break; 887 888 default: 889 return FALSE; 890 } 891 return FALSE; 892 } 893 894 static BOOL 895 ViewDlg_OnInitDialog(HWND hwndDlg) 896 { 897 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 898 899 s_hImageList = CreateTreeImageList(); 900 TreeView_SetImageList(hwndTreeView, s_hImageList, TVSIL_NORMAL); 901 902 Advanced_LoadAll(); 903 Advanced_SortAll(); 904 Advanced_InsertAll(hwndTreeView); 905 906 return TRUE; // set focus 907 } 908 909 static BOOL 910 ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem) 911 { 912 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 913 914 // get the item 915 TV_ITEM Item; 916 INT i; 917 ZeroMemory(&Item, sizeof(Item)); 918 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM; 919 Item.hItem = hItem; 920 if (!TreeView_GetItem(hwndTreeView, &Item)) 921 return FALSE; // no such item 922 923 ADVANCED_ENTRY *pEntry = Advanced_GetItem(Item.lParam); 924 if (pEntry == NULL) 925 return FALSE; // no such item 926 if (pEntry->bGrayed) 927 return FALSE; // disabled 928 929 // toggle check mark 930 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 931 switch (pEntry->dwType) 932 { 933 case AETYPE_CHECKBOX: 934 pEntry->bChecked = !pEntry->bChecked; 935 break; 936 case AETYPE_RADIO: 937 // reset all the entries of the same parent 938 for (i = 0; i < s_AdvancedCount; ++i) 939 { 940 ADVANCED_ENTRY *pEntry2 = &s_Advanced[i]; 941 if (pEntry->dwParentID == pEntry2->dwParentID) 942 { 943 pEntry2->bChecked = FALSE; 944 945 Item.hItem = pEntry2->hItem; 946 INT iImage = Advanced_GetImage(pEntry2); 947 Item.iImage = Item.iSelectedImage = iImage; 948 TreeView_SetItem(hwndTreeView, &Item); 949 } 950 } 951 pEntry->bChecked = TRUE; 952 break; 953 default: 954 return FALSE; // failure 955 } 956 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry); 957 Item.hItem = hItem; 958 TreeView_SetItem(hwndTreeView, &Item); 959 960 // redraw the item 961 RECT rcItem; 962 TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE); 963 InvalidateRect(hwndTreeView, &rcItem, TRUE); 964 return TRUE; // success 965 } 966 967 static VOID 968 ViewDlg_OnTreeViewClick(HWND hwndDlg) 969 { 970 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 971 972 // do hit test to get the clicked item 973 TV_HITTESTINFO HitTest; 974 ZeroMemory(&HitTest, sizeof(HitTest)); 975 DWORD dwPos = GetMessagePos(); 976 HitTest.pt.x = LOWORD(dwPos); 977 HitTest.pt.y = HIWORD(dwPos); 978 ScreenToClient(hwndTreeView, &HitTest.pt); 979 HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest); 980 981 // toggle the check mark if possible 982 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 983 { 984 // property sheet was changed 985 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 986 } 987 } 988 989 static void 990 ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown) 991 { 992 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 993 994 if (KeyDown->wVKey == VK_SPACE) 995 { 996 // [Space] key was pressed 997 HTREEITEM hItem = TreeView_GetSelection(hwndTreeView); 998 if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) 999 { 1000 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1001 } 1002 } 1003 } 1004 1005 static INT_PTR 1006 ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw) 1007 { 1008 NMCUSTOMDRAW& nmcd = Draw->nmcd; 1009 switch (nmcd.dwDrawStage) 1010 { 1011 case CDDS_PREPAINT: 1012 return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT 1013 1014 case CDDS_ITEMPREPAINT: 1015 if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected 1016 { 1017 LPARAM lParam = nmcd.lItemlParam; 1018 ADVANCED_ENTRY *pEntry = Advanced_GetItem(lParam); 1019 if (pEntry && pEntry->bGrayed) // disabled 1020 { 1021 // draw as grayed 1022 Draw->clrText = GetSysColor(COLOR_GRAYTEXT); 1023 Draw->clrTextBk = GetSysColor(COLOR_WINDOW); 1024 return CDRF_NEWFONT; 1025 } 1026 } 1027 break; 1028 1029 default: 1030 break; 1031 } 1032 return CDRF_DODEFAULT; 1033 } 1034 1035 static VOID 1036 Advanced_RestoreDefaults(HWND hwndDlg) 1037 { 1038 HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); 1039 1040 for (INT i = 0; i < s_AdvancedCount; ++i) 1041 { 1042 // ignore if the type is group 1043 ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 1044 if (pEntry->dwType == AETYPE_GROUP) 1045 continue; 1046 1047 // set default value on registry 1048 HKEY hKey; 1049 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 1050 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) 1051 { 1052 continue; 1053 } 1054 RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD, 1055 LPBYTE(pEntry->dwDefaultValue), sizeof(DWORD)); 1056 RegCloseKey(hKey); 1057 1058 // update check status 1059 pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue); 1060 1061 // update the image 1062 TV_ITEM Item; 1063 ZeroMemory(&Item, sizeof(Item)); 1064 Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; 1065 Item.hItem = pEntry->hItem; 1066 Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry); 1067 TreeView_SetItem(hwndTreeView, &Item); 1068 } 1069 1070 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 1071 } 1072 1073 /* FIXME: These macros should not be defined here */ 1074 #ifndef SSF_SHOWSUPERHIDDEN 1075 #define SSF_SHOWSUPERHIDDEN 0x00040000 1076 #endif 1077 #ifndef SSF_SEPPROCESS 1078 #define SSF_SEPPROCESS 0x00080000 1079 #endif 1080 1081 static VOID 1082 ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask) 1083 { 1084 for (INT i = 0; i < s_AdvancedCount; ++i) 1085 { 1086 const ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 1087 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 1088 continue; 1089 1090 BOOL bChecked = pEntry->bChecked; 1091 1092 // FIXME: Add more items 1093 if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0) 1094 { 1095 pSS->fShowSuperHidden = !bChecked ? 1 : 0; 1096 *pdwMask |= SSF_SHOWSUPERHIDDEN; 1097 continue; 1098 } 1099 if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0) 1100 { 1101 pSS->fSepProcess = bChecked ? 1 : 0; 1102 *pdwMask |= SSF_SEPPROCESS; 1103 continue; 1104 } 1105 if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0) 1106 { 1107 pSS->fShowAllObjects = !bChecked ? 1 : 0; 1108 *pdwMask |= SSF_SHOWALLOBJECTS; 1109 continue; 1110 } 1111 if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0) 1112 { 1113 pSS->fShowExtensions = !bChecked ? 1 : 0; 1114 *pdwMask |= SSF_SHOWEXTENSIONS; 1115 continue; 1116 } 1117 if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0) 1118 { 1119 pSS->fShowCompColor = bChecked ? 1 : 0; 1120 *pdwMask |= SSF_SHOWCOMPCOLOR; 1121 continue; 1122 } 1123 if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0) 1124 { 1125 pSS->fShowInfoTip = bChecked ? 1 : 0; 1126 *pdwMask |= SSF_SHOWINFOTIP; 1127 continue; 1128 } 1129 } 1130 } 1131 1132 extern "C" 1133 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet); 1134 1135 static BOOL CALLBACK RefreshBrowsersCallback (HWND hWnd, LPARAM msg) 1136 { 1137 WCHAR ClassName[100]; 1138 if (GetClassName(hWnd, ClassName, 100)) 1139 { 1140 if (!wcscmp(ClassName, L"Progman") || 1141 !wcscmp(ClassName, L"CabinetWClass") || 1142 !wcscmp(ClassName, L"ExploreWClass")) 1143 { 1144 PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0); 1145 } 1146 } 1147 return TRUE; 1148 } 1149 1150 static VOID 1151 ViewDlg_Apply(HWND hwndDlg) 1152 { 1153 for (INT i = 0; i < s_AdvancedCount; ++i) 1154 { 1155 // ignore the entry if the type is group or the entry is grayed 1156 ADVANCED_ENTRY *pEntry = &s_Advanced[i]; 1157 if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) 1158 continue; 1159 1160 // open the registry key 1161 HKEY hkeyTarget; 1162 if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, 1163 KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS) 1164 { 1165 continue; 1166 } 1167 1168 // checked or unchecked? 1169 DWORD dwValue, dwSize; 1170 if (pEntry->bChecked) 1171 { 1172 dwValue = pEntry->dwCheckedValue; 1173 } 1174 else 1175 { 1176 if (pEntry->bHasUncheckedValue) 1177 { 1178 dwValue = pEntry->dwUncheckedValue; 1179 } 1180 else 1181 { 1182 // there is no unchecked value 1183 RegCloseKey(hkeyTarget); 1184 continue; // ignore 1185 } 1186 } 1187 1188 // set the value 1189 dwSize = sizeof(dwValue); 1190 RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD, 1191 LPBYTE(&dwValue), dwSize); 1192 1193 // close now 1194 RegCloseKey(hkeyTarget); 1195 } 1196 1197 // scan advanced settings for user's settings 1198 DWORD dwMask = 0; 1199 SHELLSTATE ShellState; 1200 ZeroMemory(&ShellState, sizeof(ShellState)); 1201 ScanAdvancedSettings(&ShellState, &dwMask); 1202 1203 // update user's settings 1204 SHGetSetSettings(&ShellState, dwMask, TRUE); 1205 1206 // notify all 1207 SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); 1208 1209 EnumWindows(RefreshBrowsersCallback, NULL); 1210 } 1211 1212 INT_PTR CALLBACK 1213 FolderOptionsViewDlg( 1214 HWND hwndDlg, 1215 UINT uMsg, 1216 WPARAM wParam, 1217 LPARAM lParam) 1218 { 1219 INT_PTR Result; 1220 NMTVCUSTOMDRAW *Draw; 1221 1222 switch(uMsg) 1223 { 1224 case WM_INITDIALOG: 1225 return ViewDlg_OnInitDialog(hwndDlg); 1226 case WM_COMMAND: 1227 switch (LOWORD(wParam)) 1228 { 1229 case 14004: // Restore Defaults 1230 Advanced_RestoreDefaults(hwndDlg); 1231 break; 1232 } 1233 break; 1234 case WM_NOTIFY: 1235 switch (LPNMHDR(lParam)->code) 1236 { 1237 case NM_CLICK: // clicked on treeview 1238 ViewDlg_OnTreeViewClick(hwndDlg); 1239 break; 1240 case NM_CUSTOMDRAW: // custom draw (for graying) 1241 Draw = (NMTVCUSTOMDRAW *)lParam; 1242 Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw); 1243 SetWindowLongPtr(hwndDlg, DWL_MSGRESULT, Result); 1244 return Result; 1245 case TVN_KEYDOWN: // key is down 1246 ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam); 1247 break; 1248 case PSN_APPLY: // [Apply] is clicked 1249 ViewDlg_Apply(hwndDlg); 1250 break; 1251 default: 1252 break; 1253 } 1254 break; 1255 } 1256 1257 return FALSE; 1258 } 1259 1260 static 1261 VOID 1262 InitializeFileTypesListCtrlColumns(HWND hDlgCtrl) 1263 { 1264 RECT clientRect; 1265 LVCOLUMNW col; 1266 WCHAR szName[50]; 1267 DWORD dwStyle; 1268 int columnSize = 140; 1269 1270 1271 if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR))) 1272 { 1273 /* default to english */ 1274 wcscpy(szName, L"Extensions"); 1275 } 1276 1277 /* make sure its null terminated */ 1278 szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0; 1279 1280 GetClientRect(hDlgCtrl, &clientRect); 1281 ZeroMemory(&col, sizeof(LV_COLUMN)); 1282 columnSize = 140; //FIXME 1283 col.iSubItem = 0; 1284 col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; 1285 col.fmt = LVCFMT_FIXED_WIDTH; 1286 col.cx = columnSize | LVCFMT_LEFT; 1287 col.cchTextMax = wcslen(szName); 1288 col.pszText = szName; 1289 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col); 1290 1291 if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR))) 1292 { 1293 /* default to english */ 1294 wcscpy(szName, L"File Types"); 1295 ERR("Failed to load localized string!\n"); 1296 } 1297 1298 col.iSubItem = 1; 1299 col.cx = clientRect.right - clientRect.left - columnSize; 1300 col.cchTextMax = wcslen(szName); 1301 col.pszText = szName; 1302 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col); 1303 1304 /* set full select style */ 1305 dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); 1306 dwStyle = dwStyle | LVS_EX_FULLROWSELECT; 1307 SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); 1308 } 1309 1310 INT 1311 FindItem(HWND hDlgCtrl, WCHAR * ItemName) 1312 { 1313 LVFINDINFOW findInfo; 1314 ZeroMemory(&findInfo, sizeof(LVFINDINFOW)); 1315 1316 findInfo.flags = LVFI_STRING; 1317 findInfo.psz = ItemName; 1318 return ListView_FindItem(hDlgCtrl, 0, &findInfo); 1319 } 1320 1321 static 1322 VOID 1323 InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile) 1324 { 1325 PFOLDER_FILE_TYPE_ENTRY Entry; 1326 HKEY hKey; 1327 LVITEMW lvItem; 1328 DWORD dwSize; 1329 DWORD dwType; 1330 1331 if (szName[0] != L'.') 1332 { 1333 /* FIXME handle URL protocol handlers */ 1334 return; 1335 } 1336 1337 /* allocate file type entry */ 1338 Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY)); 1339 1340 if (!Entry) 1341 return; 1342 1343 /* open key */ 1344 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 1345 { 1346 HeapFree(GetProcessHeap(), 0, Entry); 1347 return; 1348 } 1349 1350 /* FIXME check for duplicates */ 1351 1352 /* query for the default key */ 1353 dwSize = sizeof(Entry->ClassKey); 1354 if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS) 1355 { 1356 /* no link available */ 1357 Entry->ClassKey[0] = 0; 1358 } 1359 1360 if (Entry->ClassKey[0]) 1361 { 1362 HKEY hTemp; 1363 /* try open linked key */ 1364 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS) 1365 { 1366 /* use linked key */ 1367 RegCloseKey(hKey); 1368 hKey = hTemp; 1369 } 1370 } 1371 1372 /* read friendly type name */ 1373 if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS) 1374 { 1375 /* read file description */ 1376 dwSize = sizeof(Entry->FileDescription); 1377 Entry->FileDescription[0] = 0; 1378 1379 /* read default key */ 1380 RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize); 1381 } 1382 1383 /* Read the EditFlags value */ 1384 Entry->EditFlags = 0; 1385 if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize)) 1386 { 1387 if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD)) 1388 RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize); 1389 } 1390 1391 /* close key */ 1392 RegCloseKey(hKey); 1393 1394 /* Do not add excluded entries */ 1395 if (Entry->EditFlags & 0x00000001) //FTA_Exclude 1396 { 1397 HeapFree(GetProcessHeap(), 0, Entry); 1398 return; 1399 } 1400 1401 /* convert extension to upper case */ 1402 wcscpy(Entry->FileExtension, szName); 1403 _wcsupr(Entry->FileExtension); 1404 1405 if (!Entry->FileDescription[0]) 1406 { 1407 /* construct default 'FileExtensionFile' by formatting the uppercase extension 1408 with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */ 1409 1410 StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]); 1411 } 1412 1413 ZeroMemory(&lvItem, sizeof(LVITEMW)); 1414 lvItem.mask = LVIF_TEXT | LVIF_PARAM; 1415 lvItem.iSubItem = 0; 1416 lvItem.pszText = &Entry->FileExtension[1]; 1417 lvItem.iItem = *iItem; 1418 lvItem.lParam = (LPARAM)Entry; 1419 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem); 1420 1421 ZeroMemory(&lvItem, sizeof(LVITEMW)); 1422 lvItem.mask = LVIF_TEXT; 1423 lvItem.pszText = Entry->FileDescription; 1424 lvItem.iItem = *iItem; 1425 lvItem.iSubItem = 1; 1426 ListView_SetItem(hDlgCtrl, &lvItem); 1427 1428 (*iItem)++; 1429 } 1430 1431 static 1432 int 1433 CALLBACK 1434 ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 1435 { 1436 PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2; 1437 int x; 1438 1439 Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1; 1440 Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2; 1441 1442 x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension); 1443 if (x != 0) 1444 return x; 1445 1446 return wcsicmp(Entry1->FileDescription, Entry2->FileDescription); 1447 } 1448 1449 static 1450 PFOLDER_FILE_TYPE_ENTRY 1451 InitializeFileTypesListCtrl(HWND hwndDlg) 1452 { 1453 HWND hDlgCtrl; 1454 DWORD dwIndex = 0; 1455 WCHAR szName[50]; 1456 WCHAR szFile[100]; 1457 DWORD dwName; 1458 LVITEMW lvItem; 1459 INT iItem = 0; 1460 1461 hDlgCtrl = GetDlgItem(hwndDlg, 14000); 1462 InitializeFileTypesListCtrlColumns(hDlgCtrl); 1463 1464 szFile[0] = 0; 1465 if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile))) 1466 { 1467 /* default to english */ 1468 wcscpy(szFile, L"%s File"); 1469 } 1470 szFile[(_countof(szFile)) - 1] = 0; 1471 1472 dwName = _countof(szName); 1473 1474 while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) 1475 { 1476 InsertFileType(hDlgCtrl, szName, &iItem, szFile); 1477 dwName = _countof(szName); 1478 } 1479 1480 /* Leave if the list is empty */ 1481 if (iItem == 0) 1482 return NULL; 1483 1484 /* sort list */ 1485 ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL); 1486 1487 /* select first item */ 1488 ZeroMemory(&lvItem, sizeof(LVITEMW)); 1489 lvItem.mask = LVIF_STATE; 1490 lvItem.stateMask = (UINT)-1; 1491 lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; 1492 lvItem.iItem = 0; 1493 ListView_SetItem(hDlgCtrl, &lvItem); 1494 1495 lvItem.mask = LVIF_PARAM; 1496 ListView_GetItem(hDlgCtrl, &lvItem); 1497 1498 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; 1499 } 1500 1501 static 1502 PFOLDER_FILE_TYPE_ENTRY 1503 FindSelectedItem( 1504 HWND hDlgCtrl) 1505 { 1506 UINT Count, Index; 1507 LVITEMW lvItem; 1508 1509 Count = ListView_GetItemCount(hDlgCtrl); 1510 1511 for (Index = 0; Index < Count; Index++) 1512 { 1513 ZeroMemory(&lvItem, sizeof(LVITEM)); 1514 lvItem.mask = LVIF_PARAM | LVIF_STATE; 1515 lvItem.iItem = Index; 1516 lvItem.stateMask = (UINT) - 1; 1517 1518 if (ListView_GetItem(hDlgCtrl, &lvItem)) 1519 { 1520 if (lvItem.state & LVIS_SELECTED) 1521 return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; 1522 } 1523 } 1524 1525 return NULL; 1526 } 1527 1528 INT_PTR 1529 CALLBACK 1530 FolderOptionsFileTypesDlg( 1531 HWND hwndDlg, 1532 UINT uMsg, 1533 WPARAM wParam, 1534 LPARAM lParam) 1535 { 1536 LPNMLISTVIEW lppl; 1537 LVITEMW lvItem; 1538 WCHAR Buffer[255], FormatBuffer[255]; 1539 PFOLDER_FILE_TYPE_ENTRY pItem; 1540 OPENASINFO Info; 1541 1542 switch(uMsg) 1543 { 1544 case WM_INITDIALOG: 1545 pItem = InitializeFileTypesListCtrl(hwndDlg); 1546 1547 /* Disable the Delete button if the listview is empty or 1548 the selected item should not be deleted by the user */ 1549 if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove 1550 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); 1551 return TRUE; 1552 1553 case WM_COMMAND: 1554 switch(LOWORD(wParam)) 1555 { 1556 case 14006: 1557 pItem = FindSelectedItem(GetDlgItem(hwndDlg, 14000)); 1558 if (pItem) 1559 { 1560 Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT; 1561 Info.pcszClass = pItem->FileExtension; 1562 SHOpenWithDialog(hwndDlg, &Info); 1563 } 1564 break; 1565 } 1566 break; 1567 1568 case WM_NOTIFY: 1569 lppl = (LPNMLISTVIEW) lParam; 1570 1571 if (lppl->hdr.code == LVN_ITEMCHANGING) 1572 { 1573 ZeroMemory(&lvItem, sizeof(LVITEM)); 1574 lvItem.mask = LVIF_PARAM; 1575 lvItem.iItem = lppl->iItem; 1576 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem)) 1577 return TRUE; 1578 1579 pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; 1580 if (!pItem) 1581 return TRUE; 1582 1583 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) 1584 { 1585 /* new focused item */ 1586 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR))) 1587 { 1588 /* use default english format string */ 1589 wcscpy(FormatBuffer, L"Details for '%s' extension"); 1590 } 1591 1592 /* format buffer */ 1593 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]); 1594 /* update dialog */ 1595 SetDlgItemTextW(hwndDlg, 14003, Buffer); 1596 1597 if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR))) 1598 { 1599 /* use default english format string */ 1600 wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced."); 1601 } 1602 /* format buffer */ 1603 swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]); 1604 /* update dialog */ 1605 SetDlgItemTextW(hwndDlg, 14007, Buffer); 1606 1607 /* Enable the Delete button */ 1608 if (pItem->EditFlags & 0x00000010) // FTA_NoRemove 1609 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); 1610 else 1611 EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE); 1612 } 1613 } 1614 else if (lppl->hdr.code == PSN_SETACTIVE) 1615 { 1616 /* On page activation, set the focus to the listview */ 1617 SetFocus(GetDlgItem(hwndDlg, 14000)); 1618 } 1619 break; 1620 } 1621 1622 return FALSE; 1623 } 1624 1625 static 1626 VOID 1627 ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst) 1628 { 1629 PROPSHEETHEADERW pinfo; 1630 HPROPSHEETPAGE hppages[3]; 1631 HPROPSHEETPAGE hpage; 1632 UINT num_pages = 0; 1633 WCHAR szOptions[100]; 1634 1635 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL); 1636 if (hpage) 1637 hppages[num_pages++] = hpage; 1638 1639 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL); 1640 if (hpage) 1641 hppages[num_pages++] = hpage; 1642 1643 hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL); 1644 if (hpage) 1645 hppages[num_pages++] = hpage; 1646 1647 szOptions[0] = L'\0'; 1648 LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR)); 1649 szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0'; 1650 1651 memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW)); 1652 pinfo.dwSize = sizeof(PROPSHEETHEADERW); 1653 pinfo.dwFlags = PSH_NOCONTEXTHELP; 1654 pinfo.nPages = num_pages; 1655 pinfo.phpage = hppages; 1656 pinfo.pszCaption = szOptions; 1657 1658 PropertySheetW(&pinfo); 1659 } 1660 1661 static 1662 VOID 1663 Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow) 1664 { 1665 switch(fOptions) 1666 { 1667 case 0: 1668 ShowFolderOptionsDialog(hWnd, hInst); 1669 break; 1670 case 1: 1671 // show taskbar options dialog 1672 FIXME("notify explorer to show taskbar options dialog"); 1673 //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0); 1674 break; 1675 default: 1676 FIXME("unrecognized options id %d\n", fOptions); 1677 } 1678 } 1679 1680 /************************************************************************* 1681 * Options_RunDLL (SHELL32.@) 1682 */ 1683 EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) 1684 { 1685 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); 1686 } 1687 1688 /************************************************************************* 1689 * Options_RunDLLA (SHELL32.@) 1690 */ 1691 EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) 1692 { 1693 Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); 1694 } 1695 1696 /************************************************************************* 1697 * Options_RunDLLW (SHELL32.@) 1698 */ 1699 EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow) 1700 { 1701 Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow); 1702 } 1703