Disable unsupported commands
[TortoiseGit.git] / src / Utils / CommonAppUtils.cpp
blob86d36e509ed614bc09281131b7ac2f1ae28ac565
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013, 2015-2017 - TortoiseGit
4 // Copyright (C) 2003-2008,2010 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "..\Resources\LoglistCommonResource.h"
22 #include "CommonAppUtils.h"
23 #include "PathUtils.h"
24 #include "StringUtils.h"
25 #include "FormatMessageWrapper.h"
26 #include "registry.h"
27 #include "SelectFileFilter.h"
29 extern CString sOrigCWD;
30 extern CString g_sGroupingUUID;
32 bool CCommonAppUtils::LaunchApplication(const CString& sCommandLine, UINT idErrMessageFormat, bool bWaitForStartup, CString *cwd, bool uac)
34 CString theCWD = sOrigCWD;
35 if (cwd)
36 theCWD = *cwd;
38 if (uac)
40 CString file, param;
41 SHELLEXECUTEINFO shellinfo = { 0 };
42 shellinfo.cbSize = sizeof(shellinfo);
43 shellinfo.lpVerb = L"runas";
44 shellinfo.nShow = SW_SHOWNORMAL;
45 shellinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
46 shellinfo.lpDirectory = theCWD;
48 int pos = sCommandLine.Find('"');
49 if (pos == 0)
51 pos = sCommandLine.Find('"', 2);
52 if (pos > 1)
54 file = sCommandLine.Mid(1, pos - 1);
55 param = sCommandLine.Mid(pos + 1);
57 else
59 if (idErrMessageFormat != 0)
61 CString temp;
62 temp.Format(idErrMessageFormat, (LPCTSTR)CFormatMessageWrapper());
63 MessageBox(nullptr, temp, L"TortoiseGit", MB_OK | MB_ICONINFORMATION);
65 return false;
68 else
70 pos = sCommandLine.Find(' ', 1);
71 if (pos > 0)
73 file = sCommandLine.Mid(0, pos);
74 param = sCommandLine.Mid(pos + 1);
76 else
77 file = sCommandLine;
80 shellinfo.lpFile = file;
81 shellinfo.lpParameters = param;
83 if (!ShellExecuteEx(&shellinfo))
85 if (idErrMessageFormat != 0)
87 CString temp;
88 temp.Format(idErrMessageFormat, (LPCTSTR)CFormatMessageWrapper());
89 MessageBox(nullptr, temp, L"TortoiseGit", MB_OK | MB_ICONINFORMATION);
91 return false;
94 if (bWaitForStartup)
95 WaitForInputIdle(shellinfo.hProcess, 10000);
97 CloseHandle(shellinfo.hProcess);
99 return true;
102 STARTUPINFO startup = { 0 };
103 PROCESS_INFORMATION process = { 0 };
104 startup.cb = sizeof(startup);
106 CString cleanCommandLine(sCommandLine);
107 if (CreateProcess(nullptr, cleanCommandLine.GetBuffer(), nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, nullptr, theCWD, &startup, &process) == 0)
109 if (idErrMessageFormat)
111 CString temp;
112 temp.Format(idErrMessageFormat, (LPCTSTR)CFormatMessageWrapper());
113 MessageBox(nullptr, temp, L"TortoiseGit", MB_OK | MB_ICONINFORMATION);
115 return false;
118 AllowSetForegroundWindow(process.dwProcessId);
120 if (bWaitForStartup)
121 WaitForInputIdle(process.hProcess, 10000);
123 CloseHandle(process.hThread);
124 CloseHandle(process.hProcess);
126 return true;
129 bool CCommonAppUtils::RunTortoiseGitProc(const CString& sCommandLine, bool uac, bool includeGroupingUUID)
131 CString pathToExecutable = CPathUtils::GetAppDirectory() + L"TortoiseGitProc.exe";
132 CString sCmd;
133 sCmd.Format(L"\"%s\" %s", (LPCTSTR)pathToExecutable, (LPCTSTR)sCommandLine);
134 if (AfxGetMainWnd()->GetSafeHwnd() && (sCommandLine.Find(L"/hwnd:") < 0))
135 sCmd.AppendFormat(L" /hwnd:%p", (void*)AfxGetMainWnd()->GetSafeHwnd());
136 if (!g_sGroupingUUID.IsEmpty() && includeGroupingUUID)
138 sCmd += L" /groupuuid:\"";
139 sCmd += g_sGroupingUUID;
140 sCmd += L'"';
143 return LaunchApplication(sCmd, NULL, false, nullptr, uac);
146 bool CCommonAppUtils::IsAdminLogin()
148 SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
149 PSID administratorsGroup;
150 // Initialize SID.
151 if (!AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup))
152 return false;
153 SCOPE_EXIT { FreeSid(administratorsGroup); };
155 // Check whether the token is present in admin group.
156 BOOL isInAdminGroup = FALSE;
157 if (!CheckTokenMembership(nullptr, administratorsGroup, &isInAdminGroup))
158 return false;
160 return !!isInAdminGroup;
163 bool CCommonAppUtils::SetListCtrlBackgroundImage(HWND hListCtrl, UINT nID, int width /* = 128 */, int height /* = 128 */)
165 if ((((DWORD)CRegStdDWORD(L"Software\\TortoiseGit\\ShowListBackgroundImage", TRUE)) == FALSE))
166 return false;
167 ListView_SetTextBkColor(hListCtrl, CLR_NONE);
168 COLORREF bkColor = ListView_GetBkColor(hListCtrl);
169 // create a bitmap from the icon
170 HICON hIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(nID), IMAGE_ICON, width, height, LR_DEFAULTCOLOR);
171 if (!hIcon)
172 return false;
173 SCOPE_EXIT { DestroyIcon(hIcon); };
175 RECT rect = {0};
176 rect.right = width;
177 rect.bottom = height;
179 HWND desktop = ::GetDesktopWindow();
180 if (!desktop)
181 return false;
183 HDC screen_dev = ::GetDC(desktop);
184 if (!screen_dev)
185 return false;
186 SCOPE_EXIT { ::ReleaseDC(desktop, screen_dev); };
188 // Create a compatible DC
189 HDC dst_hdc = ::CreateCompatibleDC(screen_dev);
190 if (!dst_hdc)
191 return false;
192 SCOPE_EXIT { ::DeleteDC(dst_hdc); };
194 // Create a new bitmap of icon size
195 HBITMAP bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);
196 if (!bmp)
197 return false;
199 // Select it into the compatible DC
200 HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);
201 // Fill the background of the compatible DC with the given color
202 ::SetBkColor(dst_hdc, bkColor);
203 ::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, nullptr, 0, nullptr);
205 // Draw the icon into the compatible DC
206 ::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, nullptr, DI_NORMAL);
207 ::SelectObject(dst_hdc, old_dst_bmp);
209 LVBKIMAGE lv;
210 lv.ulFlags = LVBKIF_TYPE_WATERMARK;
211 lv.hbm = bmp;
212 lv.xOffsetPercent = 100;
213 lv.yOffsetPercent = 100;
214 ListView_SetBkImage(hListCtrl, &lv);
215 return true;
218 bool CCommonAppUtils::FileOpenSave(CString& path, int* filterindex, UINT title, UINT filterId, bool bOpen, HWND hwndOwner, LPCTSTR defaultExt, bool handleAsFile)
220 // Create a new common save file dialog
221 CComPtr<IFileDialog> pfd;
223 if (!SUCCEEDED(pfd.CoCreateInstance(bOpen ? CLSID_FileOpenDialog : CLSID_FileSaveDialog, nullptr, CLSCTX_INPROC_SERVER)))
224 return false;
226 // Set the dialog options
227 DWORD dwOptions;
228 if (!SUCCEEDED(pfd->GetOptions(&dwOptions)))
229 return false;
231 if (bOpen)
233 if (!SUCCEEDED(pfd->SetOptions(dwOptions | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST)))
234 return false;
236 else
238 if (!SUCCEEDED(pfd->SetOptions(dwOptions | FOS_OVERWRITEPROMPT | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST)))
239 return false;
241 if ((!PathIsDirectory(path) || handleAsFile) && !SUCCEEDED(pfd->SetFileName(CPathUtils::GetFileNameFromPath(path))))
242 return false;
244 // Set a title
245 if (title)
247 CString temp;
248 temp.LoadString(title);
249 CStringUtils::RemoveAccelerators(temp);
250 pfd->SetTitle(temp);
252 CComPtr<IShellItem> psiDefaultFolder;
253 if (filterId)
255 CSelectFileFilter fileFilter(filterId);
256 if (!SUCCEEDED(pfd->SetFileTypes(fileFilter.GetCount(), fileFilter)))
257 return false;
258 if (filterId == 1602 || filterId == 2501) // IDS_GITEXEFILEFILTER || IDS_PROGRAMSFILEFILTER
260 pfd->SetClientGuid({ 0x323ca4b0, 0x62df, 0x4a08, { 0xa5, 0x5, 0x58, 0xde, 0xa2, 0xb9, 0x2d, 0xcd } });
261 if (SUCCEEDED(SHCreateItemFromParsingName(CPathUtils::GetProgramsDirectory(), nullptr, IID_PPV_ARGS(&psiDefaultFolder))))
262 pfd->SetDefaultFolder(psiDefaultFolder);
264 else if (filterId == 1120) // IDS_PUTTYKEYFILEFILTER
266 pfd->SetClientGuid({ 0x271dbd3b, 0x50da, 0x4148, { 0x95, 0xfd, 0x64, 0x73, 0x69, 0xd1, 0x74, 0x2 } });
267 if (SUCCEEDED(SHCreateItemFromParsingName(CPathUtils::GetDocumentsDirectory(), nullptr, IID_PPV_ARGS(&psiDefaultFolder))))
268 pfd->SetDefaultFolder(psiDefaultFolder);
272 if (defaultExt && !SUCCEEDED(pfd->SetDefaultExtension(defaultExt)))
273 return false;
275 // set the default folder
276 CComPtr<IShellItem> psiFolder;
277 if (CStringUtils::StartsWith(path, L"\\") || path.Mid(1, 2) == L":\\")
279 CString dir = path;
280 if (!PathIsDirectory(dir) || handleAsFile)
282 if (PathRemoveFileSpec(dir.GetBuffer()))
283 dir.ReleaseBuffer();
284 else
285 dir.Empty();
287 if (!dir.IsEmpty() && SUCCEEDED(SHCreateItemFromParsingName(dir, nullptr, IID_PPV_ARGS(&psiFolder))))
288 pfd->SetFolder(psiFolder);
291 // Show the save/open file dialog
292 if (!SUCCEEDED(pfd->Show(hwndOwner)))
293 return false;
295 // Get the selection from the user
296 CComPtr<IShellItem> psiResult;
297 if (!SUCCEEDED(pfd->GetResult(&psiResult)))
298 return false;
300 PWSTR pszPath = nullptr;
301 if (!SUCCEEDED(psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath)))
302 return false;
304 path = CString(pszPath);
305 if (filterindex)
307 UINT fi = 0;
308 pfd->GetFileTypeIndex(&fi);
309 *filterindex = fi;
311 return true;
314 void CCommonAppUtils::SetCharFormat(CWnd* window, DWORD mask , DWORD effects, const std::vector<CHARRANGE>& positions)
316 CHARFORMAT2 format = {};
317 format.cbSize = sizeof(CHARFORMAT2);
318 format.dwMask = mask;
319 format.dwEffects = effects;
320 format.crTextColor = effects;
322 for (const auto& range : positions)
324 window->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);
325 window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
329 void CCommonAppUtils::SetCharFormat(CWnd* window, DWORD mask, DWORD effects )
331 CHARFORMAT2 format = {};
332 format.cbSize = sizeof(CHARFORMAT2);
333 format.dwMask = mask;
334 format.dwEffects = effects;
335 window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);