Use forward slashes in the includes for consistency and also remove double slashes
[TortoiseGit.git] / src / Utils / CommonAppUtils.cpp
blob55ecc859f4237fc02e338b535d6fd13af83d5c3f
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 (shellinfo.hProcess)
96 if (bWaitForStartup)
97 WaitForInputIdle(shellinfo.hProcess, 10000);
99 CloseHandle(shellinfo.hProcess);
102 return true;
105 STARTUPINFO startup = { 0 };
106 PROCESS_INFORMATION process = { 0 };
107 startup.cb = sizeof(startup);
109 CString cleanCommandLine(sCommandLine);
110 if (CreateProcess(nullptr, cleanCommandLine.GetBuffer(), nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, nullptr, theCWD, &startup, &process) == 0)
112 if (idErrMessageFormat)
114 CString temp;
115 temp.Format(idErrMessageFormat, (LPCTSTR)CFormatMessageWrapper());
116 MessageBox(nullptr, temp, L"TortoiseGit", MB_OK | MB_ICONINFORMATION);
118 return false;
121 AllowSetForegroundWindow(process.dwProcessId);
123 if (bWaitForStartup)
124 WaitForInputIdle(process.hProcess, 10000);
126 CloseHandle(process.hThread);
127 CloseHandle(process.hProcess);
129 return true;
132 bool CCommonAppUtils::RunTortoiseGitProc(const CString& sCommandLine, bool uac, bool includeGroupingUUID)
134 CString pathToExecutable = CPathUtils::GetAppDirectory() + L"TortoiseGitProc.exe";
135 CString sCmd;
136 sCmd.Format(L"\"%s\" %s", (LPCTSTR)pathToExecutable, (LPCTSTR)sCommandLine);
137 if (AfxGetMainWnd()->GetSafeHwnd() && (sCommandLine.Find(L"/hwnd:") < 0))
138 sCmd.AppendFormat(L" /hwnd:%p", (void*)AfxGetMainWnd()->GetSafeHwnd());
139 if (!g_sGroupingUUID.IsEmpty() && includeGroupingUUID)
141 sCmd += L" /groupuuid:\"";
142 sCmd += g_sGroupingUUID;
143 sCmd += L'"';
146 return LaunchApplication(sCmd, NULL, false, nullptr, uac);
149 bool CCommonAppUtils::IsAdminLogin()
151 SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
152 PSID administratorsGroup;
153 // Initialize SID.
154 if (!AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup))
155 return false;
156 SCOPE_EXIT { FreeSid(administratorsGroup); };
158 // Check whether the token is present in admin group.
159 BOOL isInAdminGroup = FALSE;
160 if (!CheckTokenMembership(nullptr, administratorsGroup, &isInAdminGroup))
161 return false;
163 return !!isInAdminGroup;
166 bool CCommonAppUtils::SetListCtrlBackgroundImage(HWND hListCtrl, UINT nID, int width /* = 128 */, int height /* = 128 */)
168 if ((((DWORD)CRegStdDWORD(L"Software\\TortoiseGit\\ShowListBackgroundImage", TRUE)) == FALSE))
169 return false;
170 ListView_SetTextBkColor(hListCtrl, CLR_NONE);
171 COLORREF bkColor = ListView_GetBkColor(hListCtrl);
172 // create a bitmap from the icon
173 HICON hIcon = (HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(nID), IMAGE_ICON, width, height, LR_DEFAULTCOLOR);
174 if (!hIcon)
175 return false;
176 SCOPE_EXIT { DestroyIcon(hIcon); };
178 RECT rect = {0};
179 rect.right = width;
180 rect.bottom = height;
182 HWND desktop = ::GetDesktopWindow();
183 if (!desktop)
184 return false;
186 HDC screen_dev = ::GetDC(desktop);
187 if (!screen_dev)
188 return false;
189 SCOPE_EXIT { ::ReleaseDC(desktop, screen_dev); };
191 // Create a compatible DC
192 HDC dst_hdc = ::CreateCompatibleDC(screen_dev);
193 if (!dst_hdc)
194 return false;
195 SCOPE_EXIT { ::DeleteDC(dst_hdc); };
197 // Create a new bitmap of icon size
198 HBITMAP bmp = ::CreateCompatibleBitmap(screen_dev, rect.right, rect.bottom);
199 if (!bmp)
200 return false;
202 // Select it into the compatible DC
203 HBITMAP old_dst_bmp = (HBITMAP)::SelectObject(dst_hdc, bmp);
204 // Fill the background of the compatible DC with the given color
205 ::SetBkColor(dst_hdc, bkColor);
206 ::ExtTextOut(dst_hdc, 0, 0, ETO_OPAQUE, &rect, nullptr, 0, nullptr);
208 // Draw the icon into the compatible DC
209 ::DrawIconEx(dst_hdc, 0, 0, hIcon, rect.right, rect.bottom, 0, nullptr, DI_NORMAL);
210 ::SelectObject(dst_hdc, old_dst_bmp);
212 LVBKIMAGE lv;
213 lv.ulFlags = LVBKIF_TYPE_WATERMARK;
214 lv.hbm = bmp;
215 lv.xOffsetPercent = 100;
216 lv.yOffsetPercent = 100;
217 ListView_SetBkImage(hListCtrl, &lv);
218 return true;
221 bool CCommonAppUtils::FileOpenSave(CString& path, int* filterindex, UINT title, UINT filterId, bool bOpen, HWND hwndOwner, LPCTSTR defaultExt, bool handleAsFile)
223 // Create a new common save file dialog
224 CComPtr<IFileDialog> pfd;
226 if (!SUCCEEDED(pfd.CoCreateInstance(bOpen ? CLSID_FileOpenDialog : CLSID_FileSaveDialog, nullptr, CLSCTX_INPROC_SERVER)))
227 return false;
229 // Set the dialog options
230 DWORD dwOptions;
231 if (!SUCCEEDED(pfd->GetOptions(&dwOptions)))
232 return false;
234 if (bOpen)
236 if (!SUCCEEDED(pfd->SetOptions(dwOptions | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST)))
237 return false;
239 else
241 if (!SUCCEEDED(pfd->SetOptions(dwOptions | FOS_OVERWRITEPROMPT | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST)))
242 return false;
244 if ((!PathIsDirectory(path) || handleAsFile) && !SUCCEEDED(pfd->SetFileName(CPathUtils::GetFileNameFromPath(path))))
245 return false;
247 // Set a title
248 if (title)
250 CString temp;
251 temp.LoadString(title);
252 CStringUtils::RemoveAccelerators(temp);
253 pfd->SetTitle(temp);
255 CComPtr<IShellItem> psiDefaultFolder;
256 if (filterId)
258 CSelectFileFilter fileFilter(filterId);
259 if (!SUCCEEDED(pfd->SetFileTypes(fileFilter.GetCount(), fileFilter)))
260 return false;
261 if (filterId == 1602 || filterId == 2501) // IDS_GITEXEFILEFILTER || IDS_PROGRAMSFILEFILTER
263 pfd->SetClientGuid({ 0x323ca4b0, 0x62df, 0x4a08, { 0xa5, 0x5, 0x58, 0xde, 0xa2, 0xb9, 0x2d, 0xcd } });
264 if (SUCCEEDED(SHCreateItemFromParsingName(CPathUtils::GetProgramsDirectory(), nullptr, IID_PPV_ARGS(&psiDefaultFolder))))
265 pfd->SetDefaultFolder(psiDefaultFolder);
267 else if (filterId == 1120) // IDS_PUTTYKEYFILEFILTER
269 pfd->SetClientGuid({ 0x271dbd3b, 0x50da, 0x4148, { 0x95, 0xfd, 0x64, 0x73, 0x69, 0xd1, 0x74, 0x2 } });
270 if (SUCCEEDED(SHCreateItemFromParsingName(CPathUtils::GetDocumentsDirectory(), nullptr, IID_PPV_ARGS(&psiDefaultFolder))))
271 pfd->SetDefaultFolder(psiDefaultFolder);
275 if (defaultExt && !SUCCEEDED(pfd->SetDefaultExtension(defaultExt)))
276 return false;
278 // set the default folder
279 CComPtr<IShellItem> psiFolder;
280 if (CStringUtils::StartsWith(path, L"\\") || path.Mid(1, 2) == L":\\")
282 CString dir = path;
283 if (!PathIsDirectory(dir) || handleAsFile)
285 if (PathRemoveFileSpec(dir.GetBuffer()))
286 dir.ReleaseBuffer();
287 else
288 dir.Empty();
290 if (!dir.IsEmpty() && SUCCEEDED(SHCreateItemFromParsingName(dir, nullptr, IID_PPV_ARGS(&psiFolder))))
291 pfd->SetFolder(psiFolder);
294 // Show the save/open file dialog
295 if (!SUCCEEDED(pfd->Show(hwndOwner)))
296 return false;
298 // Get the selection from the user
299 CComPtr<IShellItem> psiResult;
300 if (!SUCCEEDED(pfd->GetResult(&psiResult)))
301 return false;
303 PWSTR pszPath = nullptr;
304 if (!SUCCEEDED(psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath)))
305 return false;
307 path = CString(pszPath);
308 if (filterindex)
310 UINT fi = 0;
311 pfd->GetFileTypeIndex(&fi);
312 *filterindex = fi;
314 return true;
317 void CCommonAppUtils::SetCharFormat(CWnd* window, DWORD mask , DWORD effects, const std::vector<CHARRANGE>& positions)
319 CHARFORMAT2 format = {};
320 format.cbSize = sizeof(CHARFORMAT2);
321 format.dwMask = mask;
322 format.dwEffects = effects;
323 format.crTextColor = effects;
325 for (const auto& range : positions)
327 window->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);
328 window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);
332 void CCommonAppUtils::SetCharFormat(CWnd* window, DWORD mask, DWORD effects )
334 CHARFORMAT2 format = {};
335 format.cbSize = sizeof(CHARFORMAT2);
336 format.dwMask = mask;
337 format.dwEffects = effects;
338 window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);