4 * @brief Implementation file for Shell Options dialog.
11 #include "OptionsMgr.h"
12 #include "OptionsPanel.h"
13 #include "Constants.h"
14 #include "Environment.h"
21 /// Flags for enabling and mode of extension
22 #define CONTEXT_F_ENABLED 0x01
23 #define CONTEXT_F_ADVANCED 0x02
26 static LPCTSTR f_RegValueEnabled = _T("ContextMenuEnabled");
27 static LPCTSTR f_RegValuePath = _T("Executable");
29 static bool IsShellExtensionRegistered(bool peruser)
33 DWORD ulOptions = KEY_QUERY_VALUE;
35 auto Is64BitWindows = []() { BOOL f64 = FALSE; return IsWow64Process(GetCurrentProcess(), &f64) && f64; };
36 DWORD ulOptions = KEY_QUERY_VALUE | (Is64BitWindows() ? KEY_WOW64_64KEY : 0);
38 if (ERROR_SUCCESS == RegOpenKeyEx(peruser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, _T("Software\\Classes\\CLSID\\{4E716236-AA30-4C65-B225-D68BBA81E9C2}"), 0, ulOptions, &hKey))
46 static bool RegisterShellExtension(bool unregister, bool peruser)
48 TCHAR szSystem32[260] = { 0 };
49 TCHAR szSysWow64[260] = { 0 };
50 GetSystemDirectory(szSystem32, sizeof(szSystem32) / sizeof(szSystem32[0]));
51 GetSystemWow64Directory(szSysWow64, sizeof(szSysWow64) / sizeof(szSysWow64[0]));
53 String progpath = env::GetProgPath();
54 String regsvr32 = paths::ConcatPath(szSystem32, _T("regsvr32.exe"));
56 String options = (unregister ? _T("/s /u") : _T("/s"));
57 options += peruser ? _T(" /n /i:user") : _T("");
58 SHELLEXECUTEINFO sei = { sizeof(sei) };
60 sei.lpVerb = _T("runas");
63 args = options + _T(" \"") + paths::ConcatPath(progpath, _T("ShellExtensionX64.dll")) + _T("\"");
65 sei.lpFile = regsvr32.c_str();
66 sei.lpParameters = args.c_str();
69 regsvr32 = paths::ConcatPath(szSysWow64, _T("regsvr32.exe"));
70 args = options + _T("\"") + paths::ConcatPath(progpath, _T("ShellExtensionU.dll")) + _T("\"");
71 sei.lpFile = regsvr32.c_str();
72 sei.lpParameters = args.c_str();
73 return !!ShellExecuteEx(&sei);
77 args = options + _T(" \"") + paths::ConcatPath(progpath, _T("ShellExtensionU.dll")) + _T("\"");
78 sei.lpFile = regsvr32.c_str();
79 sei.lpParameters = args.c_str();
80 return !!ShellExecuteEx(&sei);
84 PropShell::PropShell(COptionsMgr *optionsMgr)
85 : OptionsPanel(optionsMgr, PropShell::IDD)
86 , m_bContextAdded(false)
87 , m_bContextAdvanced(false)
91 BOOL PropShell::OnInitDialog()
93 OptionsPanel::OnInitDialog();
96 #define BCM_SETSHIELD (0x1600/*BCM_FIRST*/ + 0x000C)
99 SendDlgItemMessage(IDC_REGISTER_SHELLEXTENSION, BCM_SETSHIELD, 0, TRUE);
100 SendDlgItemMessage(IDC_UNREGISTER_SHELLEXTENSION, BCM_SETSHIELD, 0, TRUE);
102 // Update shell extension checkboxes
104 GetContextRegValues();
105 AdvancedContextMenuCheck();
108 SetTimer(0, 1000, nullptr);
110 return TRUE; // return TRUE unless you set the focus to a control
113 void PropShell::DoDataExchange(CDataExchange* pDX)
115 CPropertyPage::DoDataExchange(pDX);
116 //{{AFX_DATA_MAP(PropShell)
117 DDX_Check(pDX, IDC_EXPLORER_CONTEXT, m_bContextAdded);
118 DDX_Check(pDX, IDC_EXPLORER_ADVANCED, m_bContextAdvanced);
122 BEGIN_MESSAGE_MAP(PropShell, OptionsPanel)
123 //{{AFX_MSG_MAP(PropShell)
124 ON_BN_CLICKED(IDC_EXPLORER_CONTEXT, OnAddToExplorer)
125 ON_BN_CLICKED(IDC_REGISTER_SHELLEXTENSION, OnRegisterShellExtension)
126 ON_BN_CLICKED(IDC_UNREGISTER_SHELLEXTENSION, OnUnregisterShellExtension)
127 ON_BN_CLICKED(IDC_REGISTER_SHELLEXTENSION_PERUSER, OnRegisterShellExtensionPerUser)
128 ON_BN_CLICKED(IDC_UNREGISTER_SHELLEXTENSION_PERUSER, OnUnregisterShellExtensionPerUser)
134 * @brief Reads options values from storage to UI.
136 void PropShell::ReadOptions()
138 GetContextRegValues();
142 * @brief Writes options values from UI to storage.
144 void PropShell::WriteOptions()
146 SaveMergePath(); // saves context menu settings as well
149 /// Get registry values for ShellExtension
150 void PropShell::GetContextRegValues()
154 retVal = reg.Open(HKEY_CURRENT_USER, RegDir);
155 if (retVal != ERROR_SUCCESS)
157 String msg = strutils::format(_T("Failed to open registry key HKCU/%s:\n\t%d : %s"),
158 RegDir, retVal, GetSysError(retVal));
163 // Read bitmask for shell extension settings
164 DWORD dwContextEnabled = reg.ReadDword(f_RegValueEnabled, 0);
166 if (dwContextEnabled & CONTEXT_F_ENABLED)
167 m_bContextAdded = true;
169 if (dwContextEnabled & CONTEXT_F_ADVANCED)
170 m_bContextAdvanced = true;
173 /// Set registry values for ShellExtension
174 void PropShell::OnAddToExplorer()
176 AdvancedContextMenuCheck();
180 /// Saves given path to registry for ShellExtension, and Context Menu settings
181 void PropShell::SaveMergePath()
183 TCHAR temp[MAX_PATH] = {0};
185 GetModuleFileName(AfxGetInstanceHandle(), temp, MAX_PATH);
188 retVal = reg.Open(HKEY_CURRENT_USER, RegDir);
189 if (retVal != ERROR_SUCCESS)
191 String msg = strutils::format(_T("Failed to open registry key HKCU/%s:\n\t%d : %s"),
192 RegDir, retVal, GetSysError(retVal));
197 // Save path to WinMerge(U).exe
198 retVal = reg.WriteString(f_RegValuePath, temp);
199 if (retVal != ERROR_SUCCESS)
201 String msg = strutils::format(_T("Failed to set registry value %s:\n\t%d : %s"),
202 f_RegValuePath, retVal, GetSysError(retVal));
206 // Determine bitmask for shell extension
207 DWORD dwContextEnabled = reg.ReadDword(f_RegValueEnabled, 0);
209 dwContextEnabled |= CONTEXT_F_ENABLED;
211 dwContextEnabled &= ~CONTEXT_F_ENABLED;
213 if (m_bContextAdvanced)
214 dwContextEnabled |= CONTEXT_F_ADVANCED;
216 dwContextEnabled &= ~CONTEXT_F_ADVANCED;
218 retVal = reg.WriteDword(f_RegValueEnabled, dwContextEnabled);
219 if (retVal != ERROR_SUCCESS)
221 String msg = strutils::format(_T("Failed to set registry value %s to %d:\n\t%d : %s"),
222 f_RegValueEnabled, dwContextEnabled, retVal, GetSysError(retVal));
227 /// Enable/Disable "Advanced menu" checkbox.
228 void PropShell::AdvancedContextMenuCheck()
230 if (!IsDlgButtonChecked(IDC_EXPLORER_CONTEXT))
232 CheckDlgButton(IDC_EXPLORER_ADVANCED, FALSE);
233 m_bContextAdvanced = false;
237 void PropShell::UpdateButtons()
239 bool registered = IsShellExtensionRegistered(false);
240 bool registeredPerUser = IsShellExtensionRegistered(true);
241 EnableDlgItem(IDC_EXPLORER_CONTEXT, registered || registeredPerUser);
242 EnableDlgItem(IDC_REGISTER_SHELLEXTENSION, !registered);
243 EnableDlgItem(IDC_UNREGISTER_SHELLEXTENSION, registered);
244 EnableDlgItem(IDC_REGISTER_SHELLEXTENSION_PERUSER, !registeredPerUser);
245 EnableDlgItem(IDC_UNREGISTER_SHELLEXTENSION_PERUSER, registeredPerUser);
246 EnableDlgItem(IDC_EXPLORER_ADVANCED,
247 (registered || registeredPerUser) && IsDlgButtonChecked(IDC_EXPLORER_CONTEXT));
250 void PropShell::OnRegisterShellExtension()
252 RegisterShellExtension(false, false);
255 void PropShell::OnUnregisterShellExtension()
257 RegisterShellExtension(true, false);
260 void PropShell::OnRegisterShellExtensionPerUser()
262 RegisterShellExtension(false, true);
265 void PropShell::OnUnregisterShellExtensionPerUser()
267 RegisterShellExtension(true, true);
270 void PropShell::OnTimer(UINT_PTR nIDEvent)