/* * Open With Context Menu extension * * Copyright 2007 Johannes Anderwald * Copyright 2016-2018 Katayama Hirofumi MZ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "precomp.h" WINE_DEFAULT_DEBUG_CHANNEL (fprop); /// Folder Options: /// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF} /// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210 /// Verbs: Open / RunAs /// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0 /// ShellFolder Attributes: 0x0 typedef struct { WCHAR FileExtension[30]; WCHAR FileDescription[100]; WCHAR ClassKey[MAX_PATH]; DWORD EditFlags; WCHAR AppName[64]; HICON hIconLarge; HICON hIconSmall; WCHAR ProgramPath[MAX_PATH]; } FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY; // uniquely-defined icon entry for Advanced Settings typedef struct ADVANCED_ICON { WCHAR szPath[MAX_PATH]; UINT nIconIndex; } ADVANCED_ICON; // predefined icon IDs (See CreateTreeImageList function below) #define I_CHECKED 0 #define I_UNCHECKED 1 #define I_CHECKED_DISABLED 2 #define I_UNCHECKED_DISABLED 3 #define I_RADIO_CHECKED 4 #define I_RADIO_UNCHECKED 5 #define I_RADIO_CHECKED_DISABLED 6 #define I_RADIO_UNCHECKED_DISABLED 7 #define PREDEFINED_ICON_COUNT 8 // definition of icon stock static ADVANCED_ICON * s_AdvancedIcons = NULL; static INT s_AdvancedIconCount = 0; static HIMAGELIST s_hImageList = NULL; static INT Advanced_FindIcon(LPCWSTR pszPath, UINT nIconIndex) { for (INT i = PREDEFINED_ICON_COUNT; i < s_AdvancedIconCount; ++i) { ADVANCED_ICON *pIcon = &s_AdvancedIcons[i]; if (pIcon->nIconIndex == nIconIndex && lstrcmpiW(pIcon->szPath, pszPath) == 0) { return i; // icon ID } } return -1; // not found } static INT Advanced_AddIcon(LPCWSTR pszPath, UINT nIconIndex) { ADVANCED_ICON *pAllocated; // return the ID if already existed INT nIconID = Advanced_FindIcon(pszPath, nIconIndex); if (nIconID != -1) return nIconID; // already exists // extract a small icon HICON hIconSmall = NULL; ExtractIconExW(pszPath, nIconIndex, NULL, &hIconSmall, 1); if (hIconSmall == NULL) return -1; // failure // resize s_AdvancedIcons size_t Size = (s_AdvancedIconCount + 1) * sizeof(ADVANCED_ICON); pAllocated = (ADVANCED_ICON *)realloc(s_AdvancedIcons, Size); if (pAllocated == NULL) return -1; // failure else s_AdvancedIcons = pAllocated; // save icon information ADVANCED_ICON *pIcon = &s_AdvancedIcons[s_AdvancedIconCount]; lstrcpynW(pIcon->szPath, pszPath, _countof(pIcon->szPath)); pIcon->nIconIndex = nIconIndex; // add the icon to the image list ImageList_AddIcon(s_hImageList, hIconSmall); // increment the counter nIconID = s_AdvancedIconCount; ++s_AdvancedIconCount; DestroyIcon(hIconSmall); return nIconID; // newly-added icon ID } // types of Advanced Setting entry typedef enum ADVANCED_ENTRY_TYPE { AETYPE_GROUP, AETYPE_CHECKBOX, AETYPE_RADIO, } ADVANCED_ENTRY_TYPE; // an entry info of Advanced Settings typedef struct ADVANCED_ENTRY { DWORD dwID; // entry ID DWORD dwParentID; // parent entry ID DWORD dwResourceID; // resource ID WCHAR szKeyName[64]; // entry key name DWORD dwType; // ADVANCED_ENTRY_TYPE WCHAR szText[MAX_PATH]; // text INT nIconID; // icon ID (See ADVANCED_ICON) HKEY hkeyRoot; // registry root key WCHAR szRegPath[MAX_PATH]; // registry path WCHAR szValueName[64]; // registry value name DWORD dwCheckedValue; // checked value DWORD dwUncheckedValue; // unchecked value DWORD dwDefaultValue; // defalut value BOOL bHasUncheckedValue; // If FALSE, UncheckedValue is invalid HTREEITEM hItem; // for TreeView BOOL bGrayed; // disabled? BOOL bChecked; // checked? } ADVANCED_ENTRY, *PADVANCED_ENTRY; // definition of advanced entries static ADVANCED_ENTRY * s_Advanced = NULL; static INT s_AdvancedCount = 0; static HBITMAP Create24BppBitmap(HDC hDC, INT cx, INT cy) { BITMAPINFO bi; LPVOID pvBits; ZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = cx; bi.bmiHeader.biHeight = cy; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 24; bi.bmiHeader.biCompression = BI_RGB; HBITMAP hbm = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &pvBits, NULL, 0); return hbm; } static HBITMAP BitmapFromIcon(HICON hIcon, INT cx, INT cy) { HDC hDC = CreateCompatibleDC(NULL); if (!hDC) return NULL; HBITMAP hbm = Create24BppBitmap(hDC, cx, cy); if (!hbm) { DeleteDC(hDC); return NULL; } HGDIOBJ hbmOld = SelectObject(hDC, hbm); { RECT rc = { 0, 0, cx, cy }; FillRect(hDC, &rc, HBRUSH(COLOR_3DFACE + 1)); if (hIcon) { DrawIconEx(hDC, 0, 0, hIcon, cx, cy, 0, NULL, DI_NORMAL); } } SelectObject(hDC, hbmOld); DeleteDC(hDC); return hbm; } static HBITMAP CreateCheckImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE) { INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon); if (hbm == NULL) return NULL; // failure RECT Rect, BoxRect; SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); BoxRect = Rect; InflateRect(&BoxRect, -1, -1); HGDIOBJ hbmOld = SelectObject(hDC, hbm); { UINT uState = DFCS_BUTTONCHECK | DFCS_FLAT | DFCS_MONO; if (bCheck) uState |= DFCS_CHECKED; if (!bEnabled) uState |= DFCS_INACTIVE; DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState); } SelectObject(hDC, hbmOld); return hbm; // success } static HBITMAP CreateCheckMask(HDC hDC) { INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL); if (hbm == NULL) return NULL; // failure RECT Rect, BoxRect; SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); BoxRect = Rect; InflateRect(&BoxRect, -1, -1); HGDIOBJ hbmOld = SelectObject(hDC, hbm); { FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH))); FillRect(hDC, &BoxRect, HBRUSH(GetStockObject(BLACK_BRUSH))); } SelectObject(hDC, hbmOld); return hbm; // success } static HBITMAP CreateRadioImage(HDC hDC, BOOL bCheck, BOOL bEnabled = TRUE) { INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); HBITMAP hbm = Create24BppBitmap(hDC, cxSmallIcon, cySmallIcon); if (hbm == NULL) return NULL; // failure RECT Rect, BoxRect; SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); BoxRect = Rect; InflateRect(&BoxRect, -1, -1); HGDIOBJ hbmOld = SelectObject(hDC, hbm); { UINT uState = DFCS_BUTTONRADIOIMAGE | DFCS_FLAT | DFCS_MONO; if (bCheck) uState |= DFCS_CHECKED; if (!bEnabled) uState |= DFCS_INACTIVE; DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState); } SelectObject(hDC, hbmOld); return hbm; // success } static HBITMAP CreateRadioMask(HDC hDC) { INT cxSmallIcon = GetSystemMetrics(SM_CXSMICON); INT cySmallIcon = GetSystemMetrics(SM_CYSMICON); HBITMAP hbm = CreateBitmap(cxSmallIcon, cySmallIcon, 1, 1, NULL); if (hbm == NULL) return NULL; // failure RECT Rect, BoxRect; SetRect(&Rect, 0, 0, cxSmallIcon, cySmallIcon); BoxRect = Rect; InflateRect(&BoxRect, -1, -1); HGDIOBJ hbmOld = SelectObject(hDC, hbm); { FillRect(hDC, &Rect, HBRUSH(GetStockObject(WHITE_BRUSH))); UINT uState = DFCS_BUTTONRADIOMASK | DFCS_FLAT | DFCS_MONO; DrawFrameControl(hDC, &BoxRect, DFC_BUTTON, uState); } SelectObject(hDC, hbmOld); return hbm; // success } static HIMAGELIST CreateTreeImageList(VOID) { HIMAGELIST hImageList; hImageList = ImageList_Create(16, 16, ILC_COLOR24 | ILC_MASK, 9, 1); if (hImageList == NULL) return NULL; // failure // free if existed if (s_AdvancedIcons) { free(s_AdvancedIcons); s_AdvancedIcons = NULL; } s_AdvancedIconCount = 0; // allocate now ADVANCED_ICON *pAllocated; size_t Size = PREDEFINED_ICON_COUNT * sizeof(ADVANCED_ICON); pAllocated = (ADVANCED_ICON *)calloc(1, Size); if (pAllocated == NULL) return NULL; // failure s_AdvancedIconCount = PREDEFINED_ICON_COUNT; s_AdvancedIcons = pAllocated; // add the predefined icons HDC hDC = CreateCompatibleDC(NULL); HBITMAP hbmMask = CreateCheckMask(hDC); HBITMAP hbmChecked, hbmUnchecked; hbmChecked = CreateCheckImage(hDC, TRUE); ImageList_Add(hImageList, hbmChecked, hbmMask); DeleteObject(hbmChecked); hbmUnchecked = CreateCheckImage(hDC, FALSE); ImageList_Add(hImageList, hbmUnchecked, hbmMask); DeleteObject(hbmUnchecked); hbmChecked = CreateCheckImage(hDC, TRUE, FALSE); ImageList_Add(hImageList, hbmChecked, hbmMask); DeleteObject(hbmChecked); hbmUnchecked = CreateCheckImage(hDC, FALSE, FALSE); ImageList_Add(hImageList, hbmUnchecked, hbmMask); DeleteObject(hbmUnchecked); DeleteObject(hbmMask); hbmMask = CreateRadioMask(hDC); hbmChecked = CreateRadioImage(hDC, TRUE); ImageList_Add(hImageList, hbmChecked, hbmMask); DeleteObject(hbmChecked); hbmUnchecked = CreateRadioImage(hDC, FALSE); ImageList_Add(hImageList, hbmUnchecked, hbmMask); DeleteObject(hbmUnchecked); hbmChecked = CreateRadioImage(hDC, TRUE, FALSE); ImageList_Add(hImageList, hbmChecked, hbmMask); DeleteObject(hbmChecked); hbmUnchecked = CreateRadioImage(hDC, FALSE, FALSE); ImageList_Add(hImageList, hbmUnchecked, hbmMask); DeleteObject(hbmUnchecked); DeleteObject(hbmMask); return hImageList; } static ADVANCED_ENTRY * Advanced_GetItem(DWORD dwID) { if (dwID == DWORD(-1)) return NULL; for (INT i = 0; i < s_AdvancedCount; ++i) { ADVANCED_ENTRY *pEntry = &s_Advanced[i]; if (pEntry->dwID == dwID) return pEntry; } return NULL; // failure } static INT Advanced_GetImage(ADVANCED_ENTRY *pEntry) { switch (pEntry->dwType) { case AETYPE_GROUP: return pEntry->nIconID; case AETYPE_CHECKBOX: if (pEntry->bGrayed) { if (pEntry->bChecked) return I_CHECKED_DISABLED; else return I_UNCHECKED_DISABLED; } else { if (pEntry->bChecked) return I_CHECKED; else return I_UNCHECKED; } case AETYPE_RADIO: if (pEntry->bGrayed) { if (pEntry->bChecked) return I_RADIO_CHECKED_DISABLED; else return I_RADIO_UNCHECKED_DISABLED; } else { if (pEntry->bChecked) return I_RADIO_CHECKED; else return I_RADIO_UNCHECKED; } } return -1; // failure } static VOID Advanced_InsertEntry(HWND hwndTreeView, ADVANCED_ENTRY *pEntry) { ADVANCED_ENTRY *pParent = Advanced_GetItem(pEntry->dwParentID); HTREEITEM hParent = TVI_ROOT; if (pParent) hParent = pParent->hItem; TV_INSERTSTRUCT Insertion; ZeroMemory(&Insertion, sizeof(Insertion)); Insertion.hParent = hParent; Insertion.hInsertAfter = TVI_LAST; Insertion.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; Insertion.item.pszText = pEntry->szText; INT iImage = Advanced_GetImage(pEntry); Insertion.item.iImage = Insertion.item.iSelectedImage = iImage; Insertion.item.lParam = pEntry->dwID; pEntry->hItem = TreeView_InsertItem(hwndTreeView, &Insertion); } static VOID Advanced_InsertAll(HWND hwndTreeView) { TreeView_DeleteAllItems(hwndTreeView); // insert the entries ADVANCED_ENTRY *pEntry; for (INT i = 0; i < s_AdvancedCount; ++i) { pEntry = &s_Advanced[i]; Advanced_InsertEntry(hwndTreeView, pEntry); } // expand all for (INT i = 0; i < s_AdvancedCount; ++i) { pEntry = &s_Advanced[i]; if (pEntry->dwType == AETYPE_GROUP) { TreeView_Expand(hwndTreeView, pEntry->hItem, TVE_EXPAND); } } } static BOOL Advanced_LoadTree(HKEY hKey, LPCWSTR pszKeyName, DWORD dwParentID) { DWORD dwIndex; WCHAR szKeyName[64], szText[MAX_PATH], *pch; DWORD Size, Value; ADVANCED_ENTRY *pAllocated; // resize s_Advanced Size = (s_AdvancedCount + 1) * sizeof(ADVANCED_ENTRY); pAllocated = (ADVANCED_ENTRY *)realloc(s_Advanced, Size); if (pAllocated == NULL) return FALSE; // failure else s_Advanced = pAllocated; ADVANCED_ENTRY *pEntry = &s_Advanced[s_AdvancedCount]; // dwID, dwParentID, szKeyName pEntry->dwID = s_AdvancedCount; pEntry->dwParentID = dwParentID; lstrcpynW(pEntry->szKeyName, pszKeyName, _countof(pEntry->szKeyName)); // Text, ResourceID pEntry->szText[0] = 0; pEntry->dwResourceID = 0; szText[0] = 0; Size = sizeof(szText); RegQueryValueExW(hKey, L"Text", NULL, NULL, LPBYTE(szText), &Size); if (szText[0] == L'@') { pch = wcsrchr(szText, L','); if (pch) { *pch = 0; dwIndex = abs(_wtoi(pch + 1)); pEntry->dwResourceID = dwIndex; } HINSTANCE hInst = LoadLibraryW(&szText[1]); LoadStringW(hInst, dwIndex, szText, _countof(szText)); FreeLibrary(hInst); } else { pEntry->dwResourceID = DWORD(-1); } lstrcpynW(pEntry->szText, szText, _countof(pEntry->szText)); // Type szText[0] = 0; RegQueryValueExW(hKey, L"Type", NULL, NULL, LPBYTE(szText), &Size); if (lstrcmpiW(szText, L"checkbox") == 0) pEntry->dwType = AETYPE_CHECKBOX; else if (lstrcmpiW(szText, L"radio") == 0) pEntry->dwType = AETYPE_RADIO; else if (lstrcmpiW(szText, L"group") == 0) pEntry->dwType = AETYPE_GROUP; else return FALSE; // failure pEntry->nIconID = -1; if (pEntry->dwType == AETYPE_GROUP) { // Bitmap (Icon) UINT nIconIndex = 0; Size = sizeof(szText); szText[0] = 0; RegQueryValueExW(hKey, L"Bitmap", NULL, NULL, LPBYTE(szText), &Size); WCHAR szExpanded[MAX_PATH]; ExpandEnvironmentStringsW(szText, szExpanded, _countof(szExpanded)); pch = wcsrchr(szExpanded, L','); if (pch) { *pch = 0; nIconIndex = abs(_wtoi(pch + 1)); } pEntry->nIconID = Advanced_AddIcon(szExpanded, nIconIndex); } if (pEntry->dwType == AETYPE_GROUP) { pEntry->hkeyRoot = NULL; pEntry->szRegPath[0] = 0; pEntry->szValueName[0] = 0; pEntry->dwCheckedValue = 0; pEntry->bHasUncheckedValue = FALSE; pEntry->dwUncheckedValue = 0; pEntry->dwDefaultValue = 0; pEntry->hItem = NULL; pEntry->bGrayed = FALSE; pEntry->bChecked = FALSE; } else { // HKeyRoot Value = DWORD(HKEY_CURRENT_USER); Size = sizeof(Value); RegQueryValueExW(hKey, L"HKeyRoot", NULL, NULL, LPBYTE(&Value), &Size); pEntry->hkeyRoot = HKEY(Value); // RegPath pEntry->szRegPath[0] = 0; Size = sizeof(szText); RegQueryValueExW(hKey, L"RegPath", NULL, NULL, LPBYTE(szText), &Size); lstrcpynW(pEntry->szRegPath, szText, _countof(pEntry->szRegPath)); // ValueName pEntry->szValueName[0] = 0; Size = sizeof(szText); RegQueryValueExW(hKey, L"ValueName", NULL, NULL, LPBYTE(szText), &Size); lstrcpynW(pEntry->szValueName, szText, _countof(pEntry->szValueName)); // CheckedValue Size = sizeof(Value); Value = 0x00000001; RegQueryValueExW(hKey, L"CheckedValue", NULL, NULL, LPBYTE(&Value), &Size); pEntry->dwCheckedValue = Value; // UncheckedValue Size = sizeof(Value); Value = 0x00000000; pEntry->bHasUncheckedValue = TRUE; if (RegQueryValueExW(hKey, L"UncheckedValue", NULL, NULL, LPBYTE(&Value), &Size) != ERROR_SUCCESS) { pEntry->bHasUncheckedValue = FALSE; } pEntry->dwUncheckedValue = Value; // DefaultValue Size = sizeof(Value); Value = 0x00000001; RegQueryValueExW(hKey, L"DefaultValue", NULL, NULL, LPBYTE(&Value), &Size); pEntry->dwDefaultValue = Value; // hItem pEntry->hItem = NULL; // bGrayed, bChecked HKEY hkeyTarget; Value = pEntry->dwDefaultValue; pEntry->bGrayed = TRUE; if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, KEY_READ, &hkeyTarget) == ERROR_SUCCESS) { Size = sizeof(Value); if (RegQueryValueExW(hkeyTarget, pEntry->szValueName, NULL, NULL, LPBYTE(&Value), &Size) == ERROR_SUCCESS) { pEntry->bGrayed = FALSE; } RegCloseKey(hkeyTarget); } pEntry->bChecked = (Value == pEntry->dwCheckedValue); } // Grayed (ReactOS extension) Size = sizeof(Value); Value = FALSE; RegQueryValueExW(hKey, L"Grayed", NULL, NULL, LPBYTE(&Value), &Size); if (!pEntry->bGrayed) pEntry->bGrayed = Value; BOOL bIsGroup = (pEntry->dwType == AETYPE_GROUP); dwParentID = pEntry->dwID; ++s_AdvancedCount; if (!bIsGroup) return TRUE; // success // load the children dwIndex = 0; while (RegEnumKeyW(hKey, dwIndex, szKeyName, _countof(szKeyName)) == ERROR_SUCCESS) { HKEY hkeyChild; if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, &hkeyChild) != ERROR_SUCCESS) { ++dwIndex; continue; // failure } Advanced_LoadTree(hkeyChild, szKeyName, dwParentID); RegCloseKey(hkeyChild); ++dwIndex; } return TRUE; // success } static BOOL Advanced_LoadAll(VOID) { static const WCHAR s_szAdvanced[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"; // free if already existed if (s_Advanced) { free(s_Advanced); s_Advanced = NULL; } s_AdvancedCount = 0; HKEY hKey; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, s_szAdvanced, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { return FALSE; // failure } // load the children WCHAR szKeyName[64]; DWORD dwIndex = 0; while (RegEnumKeyW(hKey, dwIndex, szKeyName, _countof(szKeyName)) == ERROR_SUCCESS) { HKEY hkeyChild; if (RegOpenKeyExW(hKey, szKeyName, 0, KEY_READ, &hkeyChild) != ERROR_SUCCESS) { ++dwIndex; continue; // failure } Advanced_LoadTree(hkeyChild, szKeyName, DWORD(-1)); RegCloseKey(hkeyChild); ++dwIndex; } RegCloseKey(hKey); return TRUE; // success } static int Advanced_Compare(const void *x, const void *y) { ADVANCED_ENTRY *pEntry1 = (ADVANCED_ENTRY *)x; ADVANCED_ENTRY *pEntry2 = (ADVANCED_ENTRY *)y; DWORD dwParentID1 = pEntry1->dwParentID; DWORD dwParentID2 = pEntry2->dwParentID; if (dwParentID1 == dwParentID2) return lstrcmpi(pEntry1->szText, pEntry2->szText); DWORD i, m, n; const UINT MAX_DEPTH = 32; ADVANCED_ENTRY *pArray1[MAX_DEPTH]; ADVANCED_ENTRY *pArray2[MAX_DEPTH]; // Make ancestor lists for (i = m = n = 0; i < MAX_DEPTH; ++i) { ADVANCED_ENTRY *pParent1 = Advanced_GetItem(dwParentID1); ADVANCED_ENTRY *pParent2 = Advanced_GetItem(dwParentID2); if (!pParent1 && !pParent2) break; if (pParent1) { pArray1[m++] = pParent1; dwParentID1 = pParent1->dwParentID; } if (pParent2) { pArray2[n++] = pParent2; dwParentID2 = pParent2->dwParentID; } } UINT k = min(m, n); for (i = 0; i < k; ++i) { INT nCompare = lstrcmpi(pArray1[m - i - 1]->szText, pArray2[n - i - 1]->szText); if (nCompare < 0) return -1; if (nCompare > 0) return 1; } if (m < n) return -1; if (m > n) return 1; return lstrcmpi(pEntry1->szText, pEntry2->szText); } static VOID Advanced_SortAll(VOID) { qsort(s_Advanced, s_AdvancedCount, sizeof(ADVANCED_ENTRY), Advanced_Compare); } EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); static VOID UpdateGeneralIcons(HWND hDlg) { HWND hwndTaskIcon, hwndFolderIcon, hwndClickIcon; HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL; LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL; // show task setting icon if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED) lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS); else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED) lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS); if (lpTaskIconName) { hTaskIcon = (HICON)LoadImage(shell32_hInstance, lpTaskIconName, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); if (hTaskIcon) { hwndTaskIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_TASKICON); if (hwndTaskIcon) { SendMessage(hwndTaskIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hTaskIcon); } } } // show Folder setting icons if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED) lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW); else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED) lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW); if (lpFolderIconName) { hFolderIcon = (HICON)LoadImage(shell32_hInstance, lpFolderIconName, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); if (hFolderIcon) { hwndFolderIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_FOLDERICON); if (hwndFolderIcon) { SendMessage(hwndFolderIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hFolderIcon); } } } // Show click setting icon if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED) lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN); else if(IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED) lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN); if (lpClickIconName) { hClickIcon = (HICON)LoadImage(shell32_hInstance, lpClickIconName, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); if (hClickIcon) { hwndClickIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_CLICKICON); if (hwndClickIcon) { SendMessage(hwndClickIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hClickIcon); } } } // Clean up if(hTaskIcon) DeleteObject(hTaskIcon); if(hFolderIcon) DeleteObject(hFolderIcon); if(hClickIcon) DeleteObject(hClickIcon); return; } INT_PTR CALLBACK FolderOptionsGeneralDlg( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { case WM_INITDIALOG: // FIXME break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_FOLDER_OPTIONS_COMMONTASKS: case IDC_FOLDER_OPTIONS_CLASSICFOLDERS: case IDC_FOLDER_OPTIONS_SAMEWINDOW: case IDC_FOLDER_OPTIONS_OWNWINDOW: case IDC_FOLDER_OPTIONS_SINGLECLICK: case IDC_FOLDER_OPTIONS_DOUBLECLICK: if (HIWORD(wParam) == BN_CLICKED) { UpdateGeneralIcons(hwndDlg); /* Enable the 'Apply' button */ PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } break; } break; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: break; case PSN_APPLY: break; } break; } case WM_DESTROY: break; default: return FALSE; } return FALSE; } static BOOL ViewDlg_OnInitDialog(HWND hwndDlg) { HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); s_hImageList = CreateTreeImageList(); TreeView_SetImageList(hwndTreeView, s_hImageList, TVSIL_NORMAL); Advanced_LoadAll(); Advanced_SortAll(); Advanced_InsertAll(hwndTreeView); return TRUE; // set focus } static BOOL ViewDlg_ToggleCheckItem(HWND hwndDlg, HTREEITEM hItem) { HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); // get the item TV_ITEM Item; INT i; ZeroMemory(&Item, sizeof(Item)); Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_PARAM; Item.hItem = hItem; if (!TreeView_GetItem(hwndTreeView, &Item)) return FALSE; // no such item ADVANCED_ENTRY *pEntry = Advanced_GetItem(Item.lParam); if (pEntry == NULL) return FALSE; // no such item if (pEntry->bGrayed) return FALSE; // disabled // toggle check mark Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; switch (pEntry->dwType) { case AETYPE_CHECKBOX: pEntry->bChecked = !pEntry->bChecked; break; case AETYPE_RADIO: // reset all the entries of the same parent for (i = 0; i < s_AdvancedCount; ++i) { ADVANCED_ENTRY *pEntry2 = &s_Advanced[i]; if (pEntry->dwParentID == pEntry2->dwParentID) { pEntry2->bChecked = FALSE; Item.hItem = pEntry2->hItem; INT iImage = Advanced_GetImage(pEntry2); Item.iImage = Item.iSelectedImage = iImage; TreeView_SetItem(hwndTreeView, &Item); } } pEntry->bChecked = TRUE; break; default: return FALSE; // failure } Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry); Item.hItem = hItem; TreeView_SetItem(hwndTreeView, &Item); // redraw the item RECT rcItem; TreeView_GetItemRect(hwndTreeView, hItem, &rcItem, FALSE); InvalidateRect(hwndTreeView, &rcItem, TRUE); return TRUE; // success } static VOID ViewDlg_OnTreeViewClick(HWND hwndDlg) { HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); // do hit test to get the clicked item TV_HITTESTINFO HitTest; ZeroMemory(&HitTest, sizeof(HitTest)); DWORD dwPos = GetMessagePos(); HitTest.pt.x = LOWORD(dwPos); HitTest.pt.y = HIWORD(dwPos); ScreenToClient(hwndTreeView, &HitTest.pt); HTREEITEM hItem = TreeView_HitTest(hwndTreeView, &HitTest); // toggle the check mark if possible if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) { // property sheet was changed PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } } static void ViewDlg_OnTreeViewKeyDown(HWND hwndDlg, TV_KEYDOWN *KeyDown) { HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); if (KeyDown->wVKey == VK_SPACE) { // [Space] key was pressed HTREEITEM hItem = TreeView_GetSelection(hwndTreeView); if (ViewDlg_ToggleCheckItem(hwndDlg, hItem)) { PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } } } static INT_PTR ViewDlg_OnTreeCustomDraw(HWND hwndDlg, NMTVCUSTOMDRAW *Draw) { NMCUSTOMDRAW& nmcd = Draw->nmcd; switch (nmcd.dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; // for CDDS_ITEMPREPAINT case CDDS_ITEMPREPAINT: if (!(nmcd.uItemState & CDIS_SELECTED)) // not selected { LPARAM lParam = nmcd.lItemlParam; ADVANCED_ENTRY *pEntry = Advanced_GetItem(lParam); if (pEntry && pEntry->bGrayed) // disabled { // draw as grayed Draw->clrText = GetSysColor(COLOR_GRAYTEXT); Draw->clrTextBk = GetSysColor(COLOR_WINDOW); return CDRF_NEWFONT; } } break; default: break; } return CDRF_DODEFAULT; } static VOID Advanced_RestoreDefaults(HWND hwndDlg) { HWND hwndTreeView = GetDlgItem(hwndDlg, 14003); for (INT i = 0; i < s_AdvancedCount; ++i) { // ignore if the type is group ADVANCED_ENTRY *pEntry = &s_Advanced[i]; if (pEntry->dwType == AETYPE_GROUP) continue; // set default value on registry HKEY hKey; if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, KEY_WRITE, &hKey) != ERROR_SUCCESS) { continue; } RegSetValueExW(hKey, pEntry->szValueName, 0, REG_DWORD, LPBYTE(pEntry->dwDefaultValue), sizeof(DWORD)); RegCloseKey(hKey); // update check status pEntry->bChecked = (pEntry->dwCheckedValue == pEntry->dwDefaultValue); // update the image TV_ITEM Item; ZeroMemory(&Item, sizeof(Item)); Item.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; Item.hItem = pEntry->hItem; Item.iImage = Item.iSelectedImage = Advanced_GetImage(pEntry); TreeView_SetItem(hwndTreeView, &Item); } PropSheet_Changed(GetParent(hwndDlg), hwndDlg); } /* FIXME: These macros should not be defined here */ #ifndef SSF_SHOWSUPERHIDDEN #define SSF_SHOWSUPERHIDDEN 0x00040000 #endif #ifndef SSF_SEPPROCESS #define SSF_SEPPROCESS 0x00080000 #endif static VOID ScanAdvancedSettings(SHELLSTATE *pSS, DWORD *pdwMask) { for (INT i = 0; i < s_AdvancedCount; ++i) { const ADVANCED_ENTRY *pEntry = &s_Advanced[i]; if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) continue; BOOL bChecked = pEntry->bChecked; // FIXME: Add more items if (lstrcmpiW(pEntry->szKeyName, L"SuperHidden") == 0) { pSS->fShowSuperHidden = !bChecked ? 1 : 0; *pdwMask |= SSF_SHOWSUPERHIDDEN; continue; } if (lstrcmpiW(pEntry->szKeyName, L"DesktopProcess") == 0) { pSS->fSepProcess = bChecked ? 1 : 0; *pdwMask |= SSF_SEPPROCESS; continue; } if (lstrcmpiW(pEntry->szKeyName, L"SHOWALL") == 0) { pSS->fShowAllObjects = !bChecked ? 1 : 0; *pdwMask |= SSF_SHOWALLOBJECTS; continue; } if (lstrcmpiW(pEntry->szKeyName, L"HideFileExt") == 0) { pSS->fShowExtensions = !bChecked ? 1 : 0; *pdwMask |= SSF_SHOWEXTENSIONS; continue; } if (lstrcmpiW(pEntry->szKeyName, L"ShowCompColor") == 0) { pSS->fShowCompColor = bChecked ? 1 : 0; *pdwMask |= SSF_SHOWCOMPCOLOR; continue; } if (lstrcmpiW(pEntry->szKeyName, L"ShowInfoTip") == 0) { pSS->fShowInfoTip = bChecked ? 1 : 0; *pdwMask |= SSF_SHOWINFOTIP; continue; } } } extern "C" VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet); static BOOL CALLBACK RefreshBrowsersCallback (HWND hWnd, LPARAM msg) { WCHAR ClassName[100]; if (GetClassName(hWnd, ClassName, 100)) { if (!wcscmp(ClassName, L"Progman") || !wcscmp(ClassName, L"CabinetWClass") || !wcscmp(ClassName, L"ExploreWClass")) { PostMessage(hWnd, WM_COMMAND, FCIDM_DESKBROWSER_REFRESH, 0); } } return TRUE; } static VOID ViewDlg_Apply(HWND hwndDlg) { for (INT i = 0; i < s_AdvancedCount; ++i) { // ignore the entry if the type is group or the entry is grayed ADVANCED_ENTRY *pEntry = &s_Advanced[i]; if (pEntry->dwType == AETYPE_GROUP || pEntry->bGrayed) continue; // open the registry key HKEY hkeyTarget; if (RegOpenKeyExW(HKEY(pEntry->hkeyRoot), pEntry->szRegPath, 0, KEY_WRITE, &hkeyTarget) != ERROR_SUCCESS) { continue; } // checked or unchecked? DWORD dwValue, dwSize; if (pEntry->bChecked) { dwValue = pEntry->dwCheckedValue; } else { if (pEntry->bHasUncheckedValue) { dwValue = pEntry->dwUncheckedValue; } else { // there is no unchecked value RegCloseKey(hkeyTarget); continue; // ignore } } // set the value dwSize = sizeof(dwValue); RegSetValueExW(hkeyTarget, pEntry->szValueName, 0, REG_DWORD, LPBYTE(&dwValue), dwSize); // close now RegCloseKey(hkeyTarget); } // scan advanced settings for user's settings DWORD dwMask = 0; SHELLSTATE ShellState; ZeroMemory(&ShellState, sizeof(ShellState)); ScanAdvancedSettings(&ShellState, &dwMask); // update user's settings SHGetSetSettings(&ShellState, dwMask, TRUE); // notify all SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0); EnumWindows(RefreshBrowsersCallback, NULL); } INT_PTR CALLBACK FolderOptionsViewDlg( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { INT_PTR Result; NMTVCUSTOMDRAW *Draw; switch(uMsg) { case WM_INITDIALOG: return ViewDlg_OnInitDialog(hwndDlg); case WM_COMMAND: switch (LOWORD(wParam)) { case 14004: // Restore Defaults Advanced_RestoreDefaults(hwndDlg); break; } break; case WM_NOTIFY: switch (LPNMHDR(lParam)->code) { case NM_CLICK: // clicked on treeview ViewDlg_OnTreeViewClick(hwndDlg); break; case NM_CUSTOMDRAW: // custom draw (for graying) Draw = (NMTVCUSTOMDRAW *)lParam; Result = ViewDlg_OnTreeCustomDraw(hwndDlg, Draw); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, Result); return Result; case TVN_KEYDOWN: // key is down ViewDlg_OnTreeViewKeyDown(hwndDlg, (TV_KEYDOWN *)lParam); break; case PSN_APPLY: // [Apply] is clicked ViewDlg_Apply(hwndDlg); break; default: break; } break; } return FALSE; } static VOID InitializeFileTypesListCtrlColumns(HWND hDlgCtrl) { RECT clientRect; LVCOLUMNW col; WCHAR szName[50]; DWORD dwStyle; int columnSize = 140; if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR))) { /* default to english */ wcscpy(szName, L"Extensions"); } /* make sure its null terminated */ szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0; GetClientRect(hDlgCtrl, &clientRect); ZeroMemory(&col, sizeof(LV_COLUMN)); columnSize = 140; //FIXME col.iSubItem = 0; col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; col.fmt = LVCFMT_FIXED_WIDTH; col.cx = columnSize | LVCFMT_LEFT; col.cchTextMax = wcslen(szName); col.pszText = szName; (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col); if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR))) { /* default to english */ wcscpy(szName, L"File Types"); ERR("Failed to load localized string!\n"); } col.iSubItem = 1; col.cx = clientRect.right - clientRect.left - columnSize; col.cchTextMax = wcslen(szName); col.pszText = szName; (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col); /* set full select style */ dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); dwStyle = dwStyle | LVS_EX_FULLROWSELECT; SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); } static BOOL DeleteExt(HWND hwndDlg, LPCWSTR pszExt) { if (*pszExt != L'.') return FALSE; // open ".ext" key HKEY hKey; if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return FALSE; // query "extfile" key name WCHAR szValue[64] = { 0 }; DWORD cbValue = sizeof(szValue); RegQueryValueExW(hKey, NULL, NULL, NULL, LPBYTE(szValue), &cbValue); RegCloseKey(hKey); // delete "extfile" key (if any) if (szValue[0]) SHDeleteKeyW(HKEY_CLASSES_ROOT, szValue); // delete ".ext" key return SHDeleteKeyW(HKEY_CLASSES_ROOT, pszExt) == ERROR_SUCCESS; } static inline HICON DoExtractIcon(PFOLDER_FILE_TYPE_ENTRY Entry, LPCWSTR IconPath, INT iIndex = 0, BOOL bSmall = FALSE) { HICON hIcon = NULL; if (iIndex < 0) { // A negative value will be interpreted as a negated resource ID. iIndex = -iIndex; INT cx, cy; HINSTANCE hDLL = LoadLibraryExW(IconPath, NULL, LOAD_LIBRARY_AS_DATAFILE); if (bSmall) { cx = GetSystemMetrics(SM_CXSMICON); cy = GetSystemMetrics(SM_CYSMICON); } else { cx = GetSystemMetrics(SM_CXICON); cy = GetSystemMetrics(SM_CYICON); } hIcon = HICON(LoadImageW(hDLL, MAKEINTRESOURCEW(iIndex), IMAGE_ICON, cx, cy, 0)); FreeLibrary(hDLL); } else { // A positive value is icon index. if (bSmall) ExtractIconExW(IconPath, iIndex, NULL, &hIcon, 1); else ExtractIconExW(IconPath, iIndex, &hIcon, NULL, 1); } return hIcon; } static void DoFileTypeIconLocation(PFOLDER_FILE_TYPE_ENTRY Entry, LPCWSTR IconLocation) { // Expand the REG_EXPAND_SZ string by environment variables WCHAR szLocation[MAX_PATH + 32]; if (!ExpandEnvironmentStringsW(IconLocation, szLocation, _countof(szLocation))) { return; } INT nIndex = PathParseIconLocationW(szLocation); Entry->hIconLarge = DoExtractIcon(Entry, szLocation, nIndex, FALSE); Entry->hIconSmall = DoExtractIcon(Entry, szLocation, nIndex, TRUE); } static BOOL GetFileTypeIconsEx(PFOLDER_FILE_TYPE_ENTRY Entry, LPCWSTR IconLocation) { Entry->hIconLarge = Entry->hIconSmall = NULL; if (lstrcmpiW(Entry->FileExtension, L".exe") == 0 || lstrcmpiW(Entry->FileExtension, L".scr") == 0) { // It's an executable Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE)); Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_EXE), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0)); } else if (lstrcmpW(IconLocation, L"%1") == 0) { return FALSE; // self icon } else { DoFileTypeIconLocation(Entry, IconLocation); } return Entry->hIconLarge && Entry->hIconSmall; } static BOOL GetFileTypeIconsByKey(HKEY hKey, PFOLDER_FILE_TYPE_ENTRY Entry) { Entry->hIconLarge = Entry->hIconSmall = NULL; // Open the "DefaultIcon" registry key HKEY hDefIconKey; LONG nResult = RegOpenKeyExW(hKey, L"DefaultIcon", 0, KEY_READ, &hDefIconKey); if (nResult != ERROR_SUCCESS) return FALSE; // Get the icon location WCHAR szLocation[MAX_PATH + 32] = { 0 }; DWORD dwSize = sizeof(szLocation); nResult = RegQueryValueExW(hDefIconKey, NULL, NULL, NULL, LPBYTE(szLocation), &dwSize); RegCloseKey(hDefIconKey); if (nResult != ERROR_SUCCESS || szLocation[0] == 0) return FALSE; return GetFileTypeIconsEx(Entry, szLocation); } static BOOL QueryFileDescription(LPCWSTR ProgramPath, LPWSTR pszName, INT cchName) { SHFILEINFOW FileInfo = { 0 }; if (SHGetFileInfoW(ProgramPath, 0, &FileInfo, sizeof(FileInfo), SHGFI_DISPLAYNAME)) { StringCchCopyW(pszName, cchName, FileInfo.szDisplayName); return TRUE; } return !!GetFileTitleW(ProgramPath, pszName, cchName); } static BOOL InsertFileType(HWND hListView, LPCWSTR szName, INT iItem, LPCWSTR szFile) { PFOLDER_FILE_TYPE_ENTRY Entry; HKEY hKey; LVITEMW lvItem; DWORD dwSize; DWORD dwType; if (szName[0] != L'.') { /* FIXME handle URL protocol handlers */ return FALSE; } // get imagelists of listview HIMAGELIST himlLarge = ListView_GetImageList(hListView, LVSIL_NORMAL); HIMAGELIST himlSmall = ListView_GetImageList(hListView, LVSIL_SMALL); /* allocate file type entry */ Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY)); if (!Entry) return FALSE; /* open key */ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { HeapFree(GetProcessHeap(), 0, Entry); return FALSE; } /* FIXME check for duplicates */ /* query for the default key */ dwSize = sizeof(Entry->ClassKey); if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS) { /* no link available */ Entry->ClassKey[0] = 0; } if (Entry->ClassKey[0]) { HKEY hTemp; /* try open linked key */ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS) { /* use linked key */ RegCloseKey(hKey); hKey = hTemp; } } /* read friendly type name */ if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS) { /* read file description */ dwSize = sizeof(Entry->FileDescription); Entry->FileDescription[0] = 0; /* read default key */ RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize); } /* Read the EditFlags value */ Entry->EditFlags = 0; if (!RegQueryValueExW(hKey, L"EditFlags", NULL, &dwType, NULL, &dwSize)) { if ((dwType == REG_DWORD || dwType == REG_BINARY) && dwSize == sizeof(DWORD)) RegQueryValueExW(hKey, L"EditFlags", NULL, NULL, (LPBYTE)&Entry->EditFlags, &dwSize); } /* convert extension to upper case */ wcscpy(Entry->FileExtension, szName); _wcsupr(Entry->FileExtension); /* get icon */ if (!GetFileTypeIconsByKey(hKey, Entry)) { // set default icon Entry->hIconLarge = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS)); INT cxSmall = GetSystemMetrics(SM_CXSMICON); INT cySmall = GetSystemMetrics(SM_CYSMICON); Entry->hIconSmall = HICON(LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPTIONS), IMAGE_ICON, cxSmall, cySmall, 0)); } /* close key */ RegCloseKey(hKey); // get program path and app name DWORD cch = _countof(Entry->ProgramPath); if (S_OK == AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_EXECUTABLE, Entry->FileExtension, NULL, Entry->ProgramPath, &cch)) { QueryFileDescription(Entry->ProgramPath, Entry->AppName, _countof(Entry->AppName)); } else { Entry->ProgramPath[0] = Entry->AppName[0] = 0; } // add icon to imagelist INT iLargeImage = -1, iSmallImage = -1; if (Entry->hIconLarge && Entry->hIconSmall) { iLargeImage = ImageList_AddIcon(himlLarge, Entry->hIconLarge); iSmallImage = ImageList_AddIcon(himlSmall, Entry->hIconSmall); ASSERT(iLargeImage == iSmallImage); } /* Do not add excluded entries */ if (Entry->EditFlags & 0x00000001) //FTA_Exclude { DestroyIcon(Entry->hIconLarge); DestroyIcon(Entry->hIconSmall); HeapFree(GetProcessHeap(), 0, Entry); return FALSE; } if (!Entry->FileDescription[0]) { /* construct default 'FileExtensionFile' by formatting the uppercase extension with IDS_FILE_EXT_TYPE, outputting something like a l18n 'INI File' */ StringCchPrintf(Entry->FileDescription, _countof(Entry->FileDescription), szFile, &Entry->FileExtension[1]); } ZeroMemory(&lvItem, sizeof(LVITEMW)); lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; lvItem.iSubItem = 0; lvItem.pszText = &Entry->FileExtension[1]; lvItem.iItem = iItem; lvItem.lParam = (LPARAM)Entry; lvItem.iImage = iSmallImage; SendMessageW(hListView, LVM_INSERTITEMW, 0, (LPARAM)&lvItem); ZeroMemory(&lvItem, sizeof(LVITEMW)); lvItem.mask = LVIF_TEXT; lvItem.pszText = Entry->FileDescription; lvItem.iItem = iItem; lvItem.iSubItem = 1; ListView_SetItem(hListView, &lvItem); return TRUE; } static int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2; int x; Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1; Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2; x = wcsicmp(Entry1->FileExtension, Entry2->FileExtension); if (x != 0) return x; return wcsicmp(Entry1->FileDescription, Entry2->FileDescription); } static PFOLDER_FILE_TYPE_ENTRY InitializeFileTypesListCtrl(HWND hwndDlg) { HWND hDlgCtrl; DWORD dwIndex = 0; WCHAR szName[50]; WCHAR szFile[100]; DWORD dwName; LVITEMW lvItem; INT iItem = 0; HIMAGELIST himlLarge, himlSmall; // create imagelists himlLarge = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 256, 20); himlSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 256, 20); // set imagelists to listview. hDlgCtrl = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW); ListView_SetImageList(hDlgCtrl, himlLarge, LVSIL_NORMAL); ListView_SetImageList(hDlgCtrl, himlSmall, LVSIL_SMALL); InitializeFileTypesListCtrlColumns(hDlgCtrl); szFile[0] = 0; if (!LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFile, _countof(szFile))) { /* default to english */ wcscpy(szFile, L"%s File"); } szFile[(_countof(szFile)) - 1] = 0; dwName = _countof(szName); while (RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { if (InsertFileType(hDlgCtrl, szName, iItem, szFile)) ++iItem; dwName = _countof(szName); } /* Leave if the list is empty */ if (iItem == 0) return NULL; /* sort list */ ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL); /* select first item */ ZeroMemory(&lvItem, sizeof(LVITEMW)); lvItem.mask = LVIF_STATE; lvItem.stateMask = (UINT)-1; lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; lvItem.iItem = 0; ListView_SetItem(hDlgCtrl, &lvItem); lvItem.mask = LVIF_PARAM; ListView_GetItem(hDlgCtrl, &lvItem); return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; } static inline PFOLDER_FILE_TYPE_ENTRY GetListViewEntry(HWND hListView, INT iItem = -1) { if (iItem == -1) { iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); if (iItem == -1) return NULL; } LV_ITEMW lvItem = { LVIF_PARAM, iItem }; if (ListView_GetItem(hListView, &lvItem)) return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; return NULL; } struct NEWEXT_DIALOG { HWND hwndDlg; HWND hwndLV; RECT rcDlg; BOOL bAdvanced; INT dy; WCHAR szExt[16]; WCHAR szFileType[64]; }; static VOID NewExtDlg_OnAdvanced(HWND hwndDlg, NEWEXT_DIALOG *pNewExt) { // If "Advanced" button was clicked, then we shrink or expand the dialog. WCHAR szText[64]; RECT rc, rc1, rc2; GetWindowRect(hwndDlg, &rc); rc.bottom = rc.top + (pNewExt->rcDlg.bottom - pNewExt->rcDlg.top); GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rc1); MapWindowPoints(NULL, hwndDlg, (POINT *)&rc1, 2); GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rc2); MapWindowPoints(NULL, hwndDlg, (POINT *)&rc2, 2); if (pNewExt->bAdvanced) { rc1.top += pNewExt->dy; rc1.bottom += pNewExt->dy; rc2.top += pNewExt->dy; rc2.bottom += pNewExt->dy; ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_SHOWNOACTIVATE); ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_SHOWNOACTIVATE); LoadStringW(shell32_hInstance, IDS_NEWEXT_ADVANCED_LEFT, szText, _countof(szText)); SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, szText); SetFocus(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX)); } else { rc1.top -= pNewExt->dy; rc1.bottom -= pNewExt->dy; rc2.top -= pNewExt->dy; rc2.bottom -= pNewExt->dy; ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_ASSOC), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), SW_HIDE); LoadStringW(shell32_hInstance, IDS_NEWEXT_ADVANCED_RIGHT, szText, _countof(szText)); SetDlgItemTextW(hwndDlg, IDC_NEWEXT_ADVANCED, szText); rc.bottom -= pNewExt->dy; LoadStringW(shell32_hInstance, IDS_NEWEXT_NEW, szText, _countof(szText)); SetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, szText); } HDWP hDWP = BeginDeferWindowPos(3); if (hDWP) hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDOK), NULL, rc1.left, rc1.top, rc1.right - rc1.left, rc1.bottom - rc1.top, SWP_NOACTIVATE | SWP_NOZORDER); if (hDWP) hDWP = DeferWindowPos(hDWP, GetDlgItem(hwndDlg, IDCANCEL), NULL, rc2.left, rc2.top, rc2.right - rc2.left, rc2.bottom - rc2.top, SWP_NOACTIVATE | SWP_NOZORDER); if (hDWP) hDWP = DeferWindowPos(hDWP, hwndDlg, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER); if (hDWP) EndDeferWindowPos(hDWP); } static BOOL NewExtDlg_OnInitDialog(HWND hwndDlg, NEWEXT_DIALOG *pNewExt) { WCHAR szText[64]; pNewExt->hwndDlg = hwndDlg; pNewExt->bAdvanced = FALSE; GetWindowRect(hwndDlg, &pNewExt->rcDlg); RECT rc1, rc2; GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_EDIT), &rc1); GetWindowRect(GetDlgItem(hwndDlg, IDC_NEWEXT_COMBOBOX), &rc2); pNewExt->dy = rc2.top - rc1.top; LoadStringW(shell32_hInstance, IDS_NEWEXT_NEW, szText, _countof(szText)); SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_ADDSTRING, 0, (LPARAM)szText); SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_COMBOBOX, CB_SETCURSEL, 0, 0); SendDlgItemMessageW(hwndDlg, IDC_NEWEXT_EDIT, EM_SETLIMITTEXT, _countof(pNewExt->szExt) - 1, 0); NewExtDlg_OnAdvanced(hwndDlg, pNewExt); return TRUE; } static void StringTrimW(LPWSTR pszText) { LPWSTR pch = pszText; while (iswspace(*pch)) pch++; LPWSTR pchFirst, pchLast; pchFirst = pchLast = pch; while (*pch && !iswspace(*pch)) { ++pch; pchLast = pch; } INT_PTR cch = pchLast - pchFirst; MoveMemory(pszText, pchFirst, cch * sizeof(WCHAR)); pszText[cch] = 0; } static BOOL NewExtDlg_OnOK(HWND hwndDlg, NEWEXT_DIALOG *pNewExt) { LV_FINDINFO find; INT iItem; GetDlgItemTextW(hwndDlg, IDC_NEWEXT_EDIT, pNewExt->szExt, _countof(pNewExt->szExt)); StringTrimW(pNewExt->szExt); CharUpperW(pNewExt->szExt); GetDlgItemTextW(hwndDlg, IDC_NEWEXT_COMBOBOX, pNewExt->szFileType, _countof(pNewExt->szFileType)); StringTrimW(pNewExt->szFileType); if (pNewExt->szExt[0] == 0) { WCHAR szText[128], szTitle[128]; LoadStringW(shell32_hInstance, IDS_NEWEXT_SPECIFY_EXT, szText, _countof(szText)); szText[_countof(szText) - 1] = 0; LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szTitle, _countof(szTitle)); szTitle[_countof(szTitle) - 1] = 0; MessageBoxW(hwndDlg, szText, szTitle, MB_ICONERROR); return FALSE; } ZeroMemory(&find, sizeof(find)); find.flags = LVFI_STRING; if (pNewExt->szExt[0] == L'.') { find.psz = &pNewExt->szExt[1]; } else { find.psz = pNewExt->szExt; } iItem = ListView_FindItem(pNewExt->hwndLV, -1, &find); if (iItem >= 0) { // already exists WCHAR szText[256], szFormat[256], szTitle[64], szFileType[64]; // get file type LV_ITEM item; ZeroMemory(&item, sizeof(item)); item.mask = LVIF_TEXT; item.pszText = szFileType; item.cchTextMax = _countof(szFileType); item.iItem = iItem; item.iSubItem = 1; ListView_GetItem(pNewExt->hwndLV, &item); // get text LoadStringW(shell32_hInstance, IDS_NEWEXT_ALREADY_ASSOC, szFormat, _countof(szFormat)); szText[_countof(szFormat) - 1] = 0; StringCchPrintfW(szText, _countof(szText), szFormat, find.psz, szFileType, find.psz, szFileType); // get title LoadStringW(shell32_hInstance, IDS_NEWEXT_EXT_IN_USE, szTitle, _countof(szTitle)); szTitle[_countof(szTitle) - 1] = 0; if (MessageBoxW(hwndDlg, szText, szTitle, MB_ICONWARNING | MB_YESNO) == IDNO) { return FALSE; } // Delete the extension CStringW strExt(L"."); strExt += find.psz; strExt.MakeLower(); DeleteExt(hwndDlg, strExt); // Delete the item ListView_DeleteItem(pNewExt->hwndLV, iItem); } EndDialog(hwndDlg, IDOK); return TRUE; } // IDD_NEWEXTENSION dialog INT_PTR CALLBACK NewExtensionDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static NEWEXT_DIALOG *s_pNewExt = NULL; switch (uMsg) { case WM_INITDIALOG: s_pNewExt = (NEWEXT_DIALOG *)lParam; NewExtDlg_OnInitDialog(hwndDlg, s_pNewExt); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: NewExtDlg_OnOK(hwndDlg, s_pNewExt); break; case IDCANCEL: EndDialog(hwndDlg, IDCANCEL); break; case IDC_NEWEXT_ADVANCED: s_pNewExt->bAdvanced = !s_pNewExt->bAdvanced; NewExtDlg_OnAdvanced(hwndDlg, s_pNewExt); break; } break; } return 0; } static BOOL FileTypesDlg_AddExt(HWND hwndDlg, LPCWSTR pszExt, LPCWSTR pszFileType) { DWORD dwValue = 1; HKEY hKey; WCHAR szKey[13]; // max. "ft4294967295" + "\0" LONG nResult; // Search the next "ft%06u" key name do { StringCchPrintfW(szKey, _countof(szKey), TEXT("ft%06u"), dwValue); nResult = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, 0, KEY_READ, &hKey); if (nResult != ERROR_SUCCESS) break; RegCloseKey(hKey); ++dwValue; } while (dwValue != 0); RegCloseKey(hKey); if (dwValue == 0) return FALSE; // Create new "ft%06u" key nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL); if (ERROR_SUCCESS != nResult) return FALSE; RegCloseKey(hKey); // Create the ".ext" key WCHAR szExt[16]; if (*pszExt == L'.') ++pszExt; StringCchPrintfW(szExt, _countof(szExt), TEXT(".%s"), pszExt); CharLowerW(szExt); nResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL); CharUpperW(szExt); if (ERROR_SUCCESS != nResult) return FALSE; // Set the default value of ".ext" to "ft%06u" DWORD dwSize = (lstrlen(szKey) + 1) * sizeof(WCHAR); RegSetValueExW(hKey, NULL, 0, REG_SZ, (BYTE *)szKey, dwSize); RegCloseKey(hKey); // Make up the file type name WCHAR szFile[100], szFileFormat[100]; LoadStringW(shell32_hInstance, IDS_FILE_EXT_TYPE, szFileFormat, _countof(szFileFormat)); szFile[_countof(szFileFormat) - 1] = 0; StringCchPrintfW(szFile, _countof(szFile), szFileFormat, &szExt[1]); // Insert an item to the listview HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW); INT iItem = ListView_GetItemCount(hListView); if (!InsertFileType(hListView, szExt, iItem, szFile)) return FALSE; LV_ITEM item; ZeroMemory(&item, sizeof(item)); item.mask = LVIF_STATE | LVIF_TEXT; item.iItem = iItem; item.state = LVIS_SELECTED | LVIS_FOCUSED; item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; item.pszText = &szExt[1]; ListView_SetItem(hListView, &item); item.pszText = szFile; item.iSubItem = 1; ListView_SetItem(hListView, &item); ListView_EnsureVisible(hListView, iItem, FALSE); return TRUE; } static BOOL FileTypesDlg_RemoveExt(HWND hwndDlg) { HWND hListView = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW); INT iItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED); if (iItem == -1) return FALSE; WCHAR szExt[20]; szExt[0] = L'.'; ListView_GetItemText(hListView, iItem, 0, &szExt[1], _countof(szExt) - 1); CharLowerW(szExt); DeleteExt(hwndDlg, szExt); ListView_DeleteItem(hListView, iItem); return TRUE; } static void FileTypesDlg_OnItemChanging(HWND hwndDlg, PFOLDER_FILE_TYPE_ENTRY pEntry) { WCHAR Buffer[255]; static HBITMAP s_hbmProgram = NULL; // format buffer and set groupbox text CStringW strFormat(MAKEINTRESOURCEW(IDS_FILE_DETAILS)); StringCchPrintfW(Buffer, _countof(Buffer), strFormat, &pEntry->FileExtension[1]); SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DETAILS_GROUPBOX, Buffer); // format buffer and set description strFormat.LoadString(IDS_FILE_DETAILSADV); StringCchPrintfW(Buffer, _countof(Buffer), strFormat, &pEntry->FileExtension[1], pEntry->FileDescription, pEntry->FileDescription); SetDlgItemTextW(hwndDlg, IDC_FILETYPES_DESCRIPTION, Buffer); // delete previous program image if (s_hbmProgram) { DeleteObject(s_hbmProgram); s_hbmProgram = NULL; } // set program image HICON hIconSm = NULL; ExtractIconExW(pEntry->ProgramPath, 0, NULL, &hIconSm, 1); s_hbmProgram = BitmapFromIcon(hIconSm, 16, 16); DestroyIcon(hIconSm); SendDlgItemMessageW(hwndDlg, IDC_FILETYPES_ICON, STM_SETIMAGE, IMAGE_BITMAP, LPARAM(s_hbmProgram)); // set program name if (pEntry->AppName[0]) SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, pEntry->AppName); else SetDlgItemTextW(hwndDlg, IDC_FILETYPES_APPNAME, L"ReactOS"); /* Enable the Delete button */ if (pEntry->EditFlags & 0x00000010) // FTA_NoRemove EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE); else EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), TRUE); } // IDD_FOLDER_OPTIONS_FILETYPES dialog INT_PTR CALLBACK FolderOptionsFileTypesDlg( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { LPNMLISTVIEW lppl; PFOLDER_FILE_TYPE_ENTRY pItem; OPENASINFO Info; NEWEXT_DIALOG newext; switch(uMsg) { case WM_INITDIALOG: pItem = InitializeFileTypesListCtrl(hwndDlg); /* Disable the Delete button if the listview is empty or the selected item should not be deleted by the user */ if (pItem == NULL || (pItem->EditFlags & 0x00000010)) // FTA_NoRemove EnableWindow(GetDlgItem(hwndDlg, IDC_FILETYPES_DELETE), FALSE); return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_FILETYPES_NEW: newext.hwndLV = GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW); if (IDOK == DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_NEWEXTENSION), hwndDlg, NewExtensionDlgProc, (LPARAM)&newext)) { FileTypesDlg_AddExt(hwndDlg, newext.szExt, newext.szFileType); } break; case IDC_FILETYPES_DELETE: { CStringW strRemoveExt(MAKEINTRESOURCEW(IDS_REMOVE_EXT)); CStringW strTitle(MAKEINTRESOURCEW(IDS_FILE_TYPES)); if (MessageBoxW(hwndDlg, strRemoveExt, strTitle, MB_ICONQUESTION | MB_YESNO) == IDYES) { FileTypesDlg_RemoveExt(hwndDlg); } } break; case IDC_FILETYPES_CHANGE: pItem = GetListViewEntry(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW)); if (pItem) { Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT; Info.pcszClass = pItem->FileExtension; SHOpenWithDialog(hwndDlg, &Info); } break; } break; case WM_NOTIFY: lppl = (LPNMLISTVIEW) lParam; switch (lppl->hdr.code) { case LVN_DELETEALLITEMS: return FALSE; // send LVN_DELETEITEM case LVN_DELETEITEM: pItem = GetListViewEntry(lppl->hdr.hwndFrom, lppl->iItem); if (pItem) { DestroyIcon(pItem->hIconLarge); DestroyIcon(pItem->hIconSmall); HeapFree(GetProcessHeap(), 0, pItem); } return FALSE; case LVN_ITEMCHANGING: pItem = GetListViewEntry(lppl->hdr.hwndFrom, lppl->iItem); if (!pItem) return TRUE; if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) { FileTypesDlg_OnItemChanging(hwndDlg, pItem); } break; case PSN_SETACTIVE: /* On page activation, set the focus to the listview */ SetFocus(GetDlgItem(hwndDlg, IDC_FILETYPES_LISTVIEW)); break; } break; } return FALSE; } static VOID ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst) { PROPSHEETHEADERW pinfo; HPROPSHEETPAGE hppages[3]; HPROPSHEETPAGE hpage; UINT num_pages = 0; WCHAR szOptions[100]; hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_GENERAL, FolderOptionsGeneralDlg, 0, NULL); if (hpage) hppages[num_pages++] = hpage; hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_VIEW, FolderOptionsViewDlg, 0, NULL); if (hpage) hppages[num_pages++] = hpage; hpage = SH_CreatePropertySheetPage(IDD_FOLDER_OPTIONS_FILETYPES, FolderOptionsFileTypesDlg, 0, NULL); if (hpage) hppages[num_pages++] = hpage; szOptions[0] = L'\0'; LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR)); szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0'; memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW)); pinfo.dwSize = sizeof(PROPSHEETHEADERW); pinfo.dwFlags = PSH_NOCONTEXTHELP; pinfo.nPages = num_pages; pinfo.phpage = hppages; pinfo.pszCaption = szOptions; PropertySheetW(&pinfo); } static VOID Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow) { switch(fOptions) { case 0: ShowFolderOptionsDialog(hWnd, hInst); break; case 1: // show taskbar options dialog FIXME("notify explorer to show taskbar options dialog"); //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0); break; default: FIXME("unrecognized options id %d\n", fOptions); } } /************************************************************************* * Options_RunDLL (SHELL32.@) */ EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) { Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); } /************************************************************************* * Options_RunDLLA (SHELL32.@) */ EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) { Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); } /************************************************************************* * Options_RunDLLW (SHELL32.@) */ EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow) { Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow); }