1 /*
2  * ReactOS Explorer
3  *
4  * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5  *                  2015 Robert Naumann <gonzomdx@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 Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #include "precomp.h"
23 
24 #define I_UNCHECKED 1
25 #define I_CHECKED   2
26 
27 // TODO: Windows Explorer appears to be calling NewLinkHere / ConfigStartMenu directly for both items.
28 VOID OnAddStartMenuItems(HWND hDlg)
29 {
30     WCHAR szPath[MAX_PATH];
31 
32     if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, szPath)))
33     {
34         WCHAR szCommand[MAX_PATH] = L"appwiz.cpl,NewLinkHere ";
35         if (SUCCEEDED(StringCchCatW(szCommand, _countof(szCommand), szPath)))
36             ShellExecuteW(hDlg, L"open", L"rundll32.exe", szCommand, NULL, SW_SHOWNORMAL);
37     }
38 }
39 
40 VOID OnRemoveStartmenuItems(HWND hDlg)
41 {
42     ShellExecuteW(hDlg, L"open", L"rundll32.exe", L"appwiz.cpl,ConfigStartMenu", NULL, SW_SHOWNORMAL);
43 }
44 
45 VOID OnAdvancedStartMenuItems()
46 {
47     WCHAR szPath[MAX_PATH];
48 
49     if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_STARTMENU, NULL, 0, szPath)))
50     {
51         ShellExecuteW(NULL, L"explore", szPath, NULL, NULL, SW_SHOWNORMAL);
52     }
53 }
54 
55 static BOOL RecentHasShortcut(HWND hwnd)
56 {
57     WCHAR szPath[MAX_PATH];
58     if (FAILED(SHGetFolderPathW(hwnd, CSIDL_RECENT | CSIDL_FLAG_CREATE, NULL, 0, szPath)))
59         return FALSE;
60 
61     // Find shortcut files in Recent
62     WIN32_FIND_DATAW find;
63     PathAppendW(szPath, L"*.lnk");
64     HANDLE hFind = FindFirstFileW(szPath, &find);
65     if (hFind == INVALID_HANDLE_VALUE)
66         return FALSE;
67 
68     FindClose(hFind);
69     return TRUE;
70 }
71 
72 static VOID OnClearRecentItems(HWND hwnd)
73 {
74     SHAddToRecentDocs(SHARD_PIDL, NULL);
75     EnableWindow(GetDlgItem(hwnd, IDC_CLASSICSTART_CLEAR), RecentHasShortcut(hwnd));
76 }
77 
78 struct CUSTOMIZE_ENTRY;
79 typedef DWORD (CALLBACK *FN_CUSTOMIZE_READ)(const CUSTOMIZE_ENTRY *entry);
80 typedef BOOL (CALLBACK *FN_CUSTOMIZE_WRITE)(const CUSTOMIZE_ENTRY *entry, DWORD dwValue);
81 
82 struct CUSTOMIZE_ENTRY
83 {
84     LPARAM id;
85     LPCWSTR name;
86     BOOL bDefaultValue;
87     RESTRICTIONS policy1, policy2;
88 };
89 
90 static const CUSTOMIZE_ENTRY s_CustomizeEntries[] =
91 {
92     {
93         IDS_ADVANCED_DISPLAY_ADMINTOOLS, L"StartMenuAdminTools", TRUE,
94     },
95     {
96         IDS_ADVANCED_DISPLAY_FAVORITES, L"StartMenuFavorites", FALSE,
97         REST_NOFAVORITESMENU
98     },
99     {
100         IDS_ADVANCED_DISPLAY_LOG_OFF, L"StartMenuLogoff", FALSE,
101         REST_STARTMENULOGOFF
102     },
103     {
104         IDS_ADVANCED_DISPLAY_RUN, L"StartMenuRun", TRUE,
105         REST_NORUN
106     },
107     {
108         IDS_ADVANCED_EXPAND_MY_DOCUMENTS, L"CascadeMyDocuments", FALSE,
109         REST_NOSMMYDOCS
110     },
111     {
112         IDS_ADVANCED_EXPAND_MY_PICTURES, L"CascadeMyPictures", FALSE,
113         REST_NOSMMYPICS
114     },
115     {
116         IDS_ADVANCED_EXPAND_CONTROL_PANEL, L"CascadeControlPanel", FALSE,
117         REST_NOSETFOLDERS, REST_NOCONTROLPANEL,
118     },
119     {
120         IDS_ADVANCED_EXPAND_PRINTERS, L"CascadePrinters", FALSE,
121         REST_NOSETFOLDERS
122     },
123     {
124         IDS_ADVANCED_EXPAND_NET_CONNECTIONS, L"CascadeNetworkConnections", FALSE,
125         REST_NOSETFOLDERS, REST_NONETWORKCONNECTIONS
126     },
127 };
128 
129 static VOID AddCustomizeItem(HWND hTreeView, const CUSTOMIZE_ENTRY *entry)
130 {
131     if (SHRestricted(entry->policy1) || SHRestricted(entry->policy2))
132     {
133         TRACE("%p: Restricted\n", entry->id);
134         return; // Restricted. Don't show
135     }
136 
137     TV_INSERTSTRUCT Insert = { TVI_ROOT, TVI_LAST };
138     Insert.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
139 
140     WCHAR szText[MAX_PATH];
141     LoadStringW(GetModuleHandleW(L"shell32.dll"), entry->id, szText, _countof(szText));
142     Insert.item.pszText = szText;
143     Insert.item.lParam = entry->id;
144     Insert.item.stateMask = TVIS_STATEIMAGEMASK;
145     BOOL bChecked = GetAdvancedBool(entry->name, entry->bDefaultValue);
146     Insert.item.state = INDEXTOSTATEIMAGEMASK(bChecked ? I_CHECKED : I_UNCHECKED);
147     TRACE("%p: %d\n", entry->id, bChecked);
148     TreeView_InsertItem(hTreeView, &Insert);
149 }
150 
151 static void CustomizeClassic_OnInitDialog(HWND hwnd)
152 {
153     EnableWindow(GetDlgItem(hwnd, IDC_CLASSICSTART_CLEAR), RecentHasShortcut(hwnd));
154 
155     HWND hTreeView = GetDlgItem(hwnd, IDC_CLASSICSTART_SETTINGS);
156 
157     DWORD_PTR style = GetWindowLongPtrW(hTreeView, GWL_STYLE);
158     SetWindowLongPtrW(hTreeView, GWL_STYLE, style | TVS_CHECKBOXES);
159 
160     for (auto& entry : s_CustomizeEntries)
161     {
162         AddCustomizeItem(hTreeView, &entry);
163     }
164 }
165 
166 static BOOL CustomizeClassic_OnOK(HWND hwnd)
167 {
168     HWND hTreeView = GetDlgItem(hwnd, IDC_CLASSICSTART_SETTINGS);
169 
170     for (HTREEITEM hItem = TreeView_GetFirstVisible(hTreeView);
171          hItem != NULL;
172          hItem = TreeView_GetNextVisible(hTreeView, hItem))
173     {
174         TV_ITEM item = { TVIF_PARAM | TVIF_STATE };
175         item.hItem = hItem;
176         item.stateMask = TVIS_STATEIMAGEMASK;
177         TreeView_GetItem(hTreeView, &item);
178 
179         BOOL bChecked = !!(item.state & INDEXTOSTATEIMAGEMASK(I_CHECKED));
180         for (auto& entry : s_CustomizeEntries)
181         {
182             if (SHRestricted(entry.policy1) || SHRestricted(entry.policy2))
183                 continue;
184 
185             if (item.lParam == entry.id)
186             {
187                 TRACE("%p: %d\n", item.lParam, bChecked);
188                 SetAdvancedDword(entry.name, bChecked);
189                 break;
190             }
191         }
192     }
193 
194     SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)L"TraySettings",
195                         SMTO_ABORTIFHUNG, 200, NULL);
196     return TRUE;
197 }
198 
199 INT_PTR CALLBACK CustomizeClassicProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
200 {
201     switch (Message)
202     {
203         case WM_INITDIALOG:
204             CustomizeClassic_OnInitDialog(hwnd);
205             return TRUE;
206         case WM_COMMAND:
207             switch (LOWORD(wParam))
208             {
209                 case IDC_CLASSICSTART_ADD:
210                     OnAddStartMenuItems(hwnd);
211                     break;
212                 case IDC_CLASSICSTART_REMOVE:
213                     OnRemoveStartmenuItems(hwnd);
214                     break;
215                 case IDC_CLASSICSTART_ADVANCED:
216                     OnAdvancedStartMenuItems();
217                     break;
218                 case IDC_CLASSICSTART_CLEAR:
219                     OnClearRecentItems(hwnd);
220                     break;
221                 case IDOK:
222                     if (CustomizeClassic_OnOK(hwnd))
223                     {
224                         EndDialog(hwnd, IDOK);
225                     }
226                     break;
227                 case IDCANCEL:
228                     EndDialog(hwnd, IDCANCEL);
229                     break;
230             }
231             break;
232         default:
233             return FALSE;
234     }
235     return TRUE;
236 }
237 
238 VOID ShowCustomizeClassic(HINSTANCE hInst, HWND hExplorer)
239 {
240     DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_CLASSICSTART_CUSTOMIZE), hExplorer, CustomizeClassicProc);
241 }
242