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.
21 #include "..\Resources\LoglistCommonResource.h"
22 #include "CommonAppUtils.h"
23 #include "PathUtils.h"
24 #include "StringUtils.h"
25 #include "FormatMessageWrapper.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
;
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('"');
51 pos
= sCommandLine
.Find('"', 2);
54 file
= sCommandLine
.Mid(1, pos
- 1);
55 param
= sCommandLine
.Mid(pos
+ 1);
59 if (idErrMessageFormat
!= 0)
62 temp
.Format(idErrMessageFormat
, (LPCTSTR
)CFormatMessageWrapper());
63 MessageBox(nullptr, temp
, L
"TortoiseGit", MB_OK
| MB_ICONINFORMATION
);
70 pos
= sCommandLine
.Find(' ', 1);
73 file
= sCommandLine
.Mid(0, pos
);
74 param
= sCommandLine
.Mid(pos
+ 1);
80 shellinfo
.lpFile
= file
;
81 shellinfo
.lpParameters
= param
;
83 if (!ShellExecuteEx(&shellinfo
))
85 if (idErrMessageFormat
!= 0)
88 temp
.Format(idErrMessageFormat
, (LPCTSTR
)CFormatMessageWrapper());
89 MessageBox(nullptr, temp
, L
"TortoiseGit", MB_OK
| MB_ICONINFORMATION
);
95 WaitForInputIdle(shellinfo
.hProcess
, 10000);
97 CloseHandle(shellinfo
.hProcess
);
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
)
112 temp
.Format(idErrMessageFormat
, (LPCTSTR
)CFormatMessageWrapper());
113 MessageBox(nullptr, temp
, L
"TortoiseGit", MB_OK
| MB_ICONINFORMATION
);
118 AllowSetForegroundWindow(process
.dwProcessId
);
121 WaitForInputIdle(process
.hProcess
, 10000);
123 CloseHandle(process
.hThread
);
124 CloseHandle(process
.hProcess
);
129 bool CCommonAppUtils::RunTortoiseGitProc(const CString
& sCommandLine
, bool uac
, bool includeGroupingUUID
)
131 CString pathToExecutable
= CPathUtils::GetAppDirectory() + L
"TortoiseGitProc.exe";
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
;
143 return LaunchApplication(sCmd
, NULL
, false, nullptr, uac
);
146 bool CCommonAppUtils::IsAdminLogin()
148 SID_IDENTIFIER_AUTHORITY ntAuthority
= SECURITY_NT_AUTHORITY
;
149 PSID administratorsGroup
;
151 if (!AllocateAndInitializeSid(&ntAuthority
, 2, SECURITY_BUILTIN_DOMAIN_RID
, DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0, &administratorsGroup
))
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
))
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
))
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
);
173 SCOPE_EXIT
{ DestroyIcon(hIcon
); };
177 rect
.bottom
= height
;
179 HWND desktop
= ::GetDesktopWindow();
183 HDC screen_dev
= ::GetDC(desktop
);
186 SCOPE_EXIT
{ ::ReleaseDC(desktop
, screen_dev
); };
188 // Create a compatible DC
189 HDC dst_hdc
= ::CreateCompatibleDC(screen_dev
);
192 SCOPE_EXIT
{ ::DeleteDC(dst_hdc
); };
194 // Create a new bitmap of icon size
195 HBITMAP bmp
= ::CreateCompatibleBitmap(screen_dev
, rect
.right
, rect
.bottom
);
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
);
210 lv
.ulFlags
= LVBKIF_TYPE_WATERMARK
;
212 lv
.xOffsetPercent
= 100;
213 lv
.yOffsetPercent
= 100;
214 ListView_SetBkImage(hListCtrl
, &lv
);
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
)))
226 // Set the dialog options
228 if (!SUCCEEDED(pfd
->GetOptions(&dwOptions
)))
233 if (!SUCCEEDED(pfd
->SetOptions(dwOptions
| FOS_FILEMUSTEXIST
| FOS_FORCEFILESYSTEM
| FOS_PATHMUSTEXIST
)))
238 if (!SUCCEEDED(pfd
->SetOptions(dwOptions
| FOS_OVERWRITEPROMPT
| FOS_FORCEFILESYSTEM
| FOS_PATHMUSTEXIST
)))
241 if ((!PathIsDirectory(path
) || handleAsFile
) && !SUCCEEDED(pfd
->SetFileName(CPathUtils::GetFileNameFromPath(path
))))
248 temp
.LoadString(title
);
249 CStringUtils::RemoveAccelerators(temp
);
252 CComPtr
<IShellItem
> psiDefaultFolder
;
255 CSelectFileFilter
fileFilter(filterId
);
256 if (!SUCCEEDED(pfd
->SetFileTypes(fileFilter
.GetCount(), fileFilter
)))
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
)))
275 // set the default folder
276 CComPtr
<IShellItem
> psiFolder
;
277 if (CStringUtils::StartsWith(path
, L
"\\") || path
.Mid(1, 2) == L
":\\")
280 if (!PathIsDirectory(dir
) || handleAsFile
)
282 if (PathRemoveFileSpec(dir
.GetBuffer()))
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
)))
295 // Get the selection from the user
296 CComPtr
<IShellItem
> psiResult
;
297 if (!SUCCEEDED(pfd
->GetResult(&psiResult
)))
300 PWSTR pszPath
= nullptr;
301 if (!SUCCEEDED(psiResult
->GetDisplayName(SIGDN_FILESYSPATH
, &pszPath
)))
304 path
= CString(pszPath
);
308 pfd
->GetFileTypeIndex(&fi
);
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
);