1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2018 - TortoiseGit
4 // Copyright (C) 2003-2008, 2012-2014 - 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 "TortoiseProc.h"
22 #include "SysImageList.h"
23 #include "../Utils/CrashReport.h"
24 #include "CmdLineParser.h"
27 #include "PathUtils.h"
28 #include "StringUtils.h"
29 #include "UnicodeUtils.h"
30 #include "MessageBox.h"
31 #include "DirFileEnum.h"
32 #include "GitAdminDir.h"
34 #include "SmartHandle.h"
35 #include "Commands\Command.h"
36 #include "../version.h"
37 #include "JumpListHelpers.h"
38 #include "ConfigureGitExe.h"
39 #include "Libraries.h"
40 #include "TaskbarUUID.h"
41 #include "ProjectProperties.h"
42 #include "HistoryCombo.h"
46 #include "WindowsCredentialsStore.h"
47 #include "FirstStartWizard.h"
48 #include "AnimationManager.h"
50 #define STRUCT_IOVEC_DEFINED
56 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
58 BEGIN_MESSAGE_MAP(CTortoiseProcApp
, CWinAppEx
)
59 ON_COMMAND(ID_HELP
, CWinAppEx::OnHelp
)
62 //////////////////////////////////////////////////////////////////////////
64 CTortoiseProcApp::CTortoiseProcApp()
65 : hWndExplorer(nullptr)
67 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Constructor\n");
69 CCrashReport::Instance().AddUserInfoToReport(L
"CommandLine", GetCommandLine());
73 CGit::SetGit2CredentialCallback(CAppUtils::Git2GetUserPassword
);
74 CGit::SetGit2CertificateCheckCertificate(CAppUtils::Git2CertificateCheck
);
75 m_bLoadUserToolbars
= FALSE
;
78 m_gdiplusToken
= NULL
;
79 #if defined (_WIN64) && _MSC_VER == 1800
84 CTortoiseProcApp::~CTortoiseProcApp()
87 git_libgit2_shutdown();
90 // The one and only CTortoiseProcApp object
91 CTortoiseProcApp theApp
;
93 CString g_sGroupingUUID
;
94 CString g_sGroupingIcon
;
95 bool g_bGroupingRemoveIcon
= false;
96 HWND
GetExplorerHWND()
98 return theApp
.GetExplorerHWND();
101 #if ENABLE_CRASHHANLDER
102 CCrashReportTGit
crasher(L
"TortoiseGit " _T(APP_X64_STRING
), TGIT_VERMAJOR
, TGIT_VERMINOR
, TGIT_VERMICRO
, TGIT_VERBUILD
, TGIT_VERDATE
);
105 // CTortoiseProcApp initialization
107 BOOL
CTortoiseProcApp::InitInstance()
109 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": InitInstance\n");
111 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
112 CMFCButton::EnableWindowsTheming();
114 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
115 Gdiplus::GdiplusStartup(&m_gdiplusToken
, &gdiplusStartupInput
, nullptr);
117 //set the resource dll for the required language
118 CRegDWORD loc
= CRegDWORD(L
"Software\\TortoiseGit\\LanguageID", 1033);
121 CStringA langpath
= CStringA(CPathUtils::GetAppParentDirectory());
122 langpath
+= "Languages";
125 langDll
.Format(L
"%sLanguages\\TortoiseProc%ld.dll", (LPCTSTR
)CPathUtils::GetAppParentDirectory(), langId
);
127 CString sVer
= _T(STRPRODUCTVER
);
128 CString sFileVer
= CPathUtils::GetVersionFromFile(langDll
);
129 if (sFileVer
== sVer
)
131 HINSTANCE hInst
= LoadLibrary(langDll
);
134 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Load Language DLL %s\n", (LPCTSTR
)langDll
);
135 AfxSetResourceHandle(hInst
);
140 DWORD lid
= SUBLANGID(langId
);
143 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
147 } while (langId
!= 0);
150 langStr
.Format(L
"%ld", langId
);
151 CCrashReport::Instance().AddUserInfoToReport(L
"LanguageID", langStr
);
153 TCHAR buf
[6] = { 0 };
154 wcscpy_s(buf
, L
"en");
156 // MFC uses a help file with the same name as the application by default,
157 // which means we have to change that default to our language specific help files
158 CString sHelppath
= CPathUtils::GetAppDirectory() + L
"TortoiseGit_en.chm";
159 free((void*)m_pszHelpFilePath
);
160 m_pszHelpFilePath
=_wcsdup(sHelppath
);
161 sHelppath
= CPathUtils::GetAppParentDirectory() + L
"Languages\\TortoiseGit_en.chm";
164 CString sLang
= L
"_";
165 if (GetLocaleInfo(MAKELCID(langId
, SORT_DEFAULT
), LOCALE_SISO639LANGNAME
, buf
, _countof(buf
)))
168 sHelppath
.Replace(L
"_en", sLang
);
169 if (PathFileExists(sHelppath
))
171 free((void*)m_pszHelpFilePath
);
172 m_pszHelpFilePath
=_wcsdup(sHelppath
);
176 sHelppath
.Replace(sLang
, L
"_en");
177 if (GetLocaleInfo(MAKELCID(langId
, SORT_DEFAULT
), LOCALE_SISO3166CTRYNAME
, buf
, _countof(buf
)))
181 sHelppath
.Replace(L
"_en", sLang
);
182 if (PathFileExists(sHelppath
))
184 free((void*)m_pszHelpFilePath
);
185 m_pszHelpFilePath
=_wcsdup(sHelppath
);
189 sHelppath
.Replace(sLang
, L
"_en");
191 DWORD lid
= SUBLANGID(langId
);
194 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
198 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Set Help Filename %s\n", m_pszHelpFilePath
);
199 setlocale(LC_ALL
, "");
201 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Initializing UI components ...\n");
202 // InitCommonControls() is required on Windows XP if an application
203 // manifest specifies use of ComCtl32.dll version 6 or later to enable
204 // visual styles. Otherwise, any window creation will fail.
206 INITCOMMONCONTROLSEX used
= {
207 sizeof(INITCOMMONCONTROLSEX
),
208 ICC_ANIMATE_CLASS
| ICC_BAR_CLASSES
| ICC_COOL_CLASSES
| ICC_DATE_CLASSES
|
209 ICC_HOTKEY_CLASS
| ICC_INTERNET_CLASSES
| ICC_LISTVIEW_CLASSES
|
210 ICC_NATIVEFNTCTL_CLASS
| ICC_PAGESCROLLER_CLASS
| ICC_PROGRESS_CLASS
|
211 ICC_TAB_CLASSES
| ICC_TREEVIEW_CLASSES
| ICC_UPDOWN_CLASS
|
212 ICC_USEREX_CLASSES
| ICC_WIN95_CLASSES
214 InitCommonControlsEx(&used
);
216 AfxEnableControlContainer();
218 CWinAppEx::InitInstance();
219 SetRegistryKey(L
"TortoiseGit");
221 CHistoryCombo::m_nGitIconIndex
= SYS_IMAGE_LIST().AddIcon(CCommonAppUtils::LoadIconEx(IDI_GITCONFIG
, 0, 0));
222 AfxGetApp()->m_pszProfileName
= _wcsdup(L
"TortoiseProc"); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
224 CCmdLineParser
parser(AfxGetApp()->m_lpCmdLine
);
226 hWndExplorer
= nullptr;
227 CString sVal
= parser
.GetVal(L
"hwnd");
229 hWndExplorer
= (HWND
)_wcstoui64(sVal
, nullptr, 16);
231 while (GetParent(hWndExplorer
))
232 hWndExplorer
= GetParent(hWndExplorer
);
233 if (!IsWindow(hWndExplorer
))
234 hWndExplorer
= nullptr;
236 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
238 if (CRegDWORD(L
"Software\\TortoiseGit\\Debug", FALSE
) == TRUE
)
239 AfxMessageBox(AfxGetApp()->m_lpCmdLine
, MB_OK
| MB_ICONINFORMATION
);
241 if (parser
.HasKey(L
"command") && wcscmp(parser
.GetVal(L
"command"), L
"firststart") == 0)
243 // CFirstStartWizard requires sOrigCWD to be set
244 DWORD len
= GetCurrentDirectory(0, nullptr);
247 auto originalCurrentDirectory
= std::make_unique
<TCHAR
[]>(len
);
248 if (GetCurrentDirectory(len
, originalCurrentDirectory
.get()))
250 sOrigCWD
= originalCurrentDirectory
.get();
251 sOrigCWD
= CPathUtils::GetLongPathname(sOrigCWD
);
254 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), parser
.GetLongVal(L
"page"));
255 theApp
.m_pMainWnd
= &wizard
;
256 return (wizard
.DoModal() == ID_WIZFINISH
);
259 if (!g_Git
.CheckMsysGitDir())
261 UINT ret
= CMessageBox::Show(hWndExplorer
, IDS_PROC_NOMSYSGIT
, IDS_APPNAME
, 3, IDI_HAND
, IDS_PROC_SETMSYSGITPATH
, IDS_PROC_GOTOMSYSGITWEBSITE
, IDS_ABORTBUTTON
);
263 ShellExecute(hWndExplorer
, L
"open", GIT_FOR_WINDOWS_URL
, nullptr, nullptr, SW_SHOW
);
266 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), 2);
267 theApp
.m_pMainWnd
= &wizard
;
272 if (!CConfigureGitExe::CheckGitVersion(hWndExplorer
))
276 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Registering Crash Report ...\n");
277 CCrashReport::Instance().AddUserInfoToReport(L
"msysGitDir", CGit::ms_LastMsysGitDir
);
278 CString versionString
;
279 versionString
.Format(L
"%X", CGit::ms_LastMsysGitVersion
);
280 CCrashReport::Instance().AddUserInfoToReport(L
"msysGitVersion", versionString
);
281 if (CGit::ms_bCygwinGit
)
282 CCrashReport::Instance().AddUserInfoToReport(L
"CygwinHack", L
"true");
283 if (CGit::ms_bMsys2Git
)
284 CCrashReport::Instance().AddUserInfoToReport(L
"Msys2Hack", L
"true");
287 if (parser
.HasKey(L
"urlhandler"))
289 CString url
= parser
.GetVal(L
"urlhandler");
290 if (CStringUtils::StartsWith(url
, L
"tgit://clone/"))
291 url
= url
.Mid((int)wcslen(L
"tgit://clone/"));
292 else if (CStringUtils::StartsWith(url
, L
"github-windows://openRepo/"))
294 url
= url
.Mid((int)wcslen(L
"github-windows://openRepo/"));
295 int questioMark
= url
.Find('?');
297 url
= url
.Left(questioMark
);
299 else if (CStringUtils::StartsWith(url
, L
"x-github-client://openRepo/")) {
300 url
= url
.Mid((int)wcslen(L
"x-github-client://openRepo/"));
301 int questioMark
= url
.Find('?');
303 url
= url
.Left(questioMark
);
305 else if (CStringUtils::StartsWith(url
, L
"smartgit://cloneRepo/"))
306 url
= url
.Mid((int)wcslen(L
"smartgit://cloneRepo/"));
309 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
313 newCmd
.Format(L
"/command:clone /url:\"%s\" /hasurlhandler", (LPCTSTR
)url
);
314 parser
= CCmdLineParser(newCmd
);
317 if (parser
.HasKey(L
"path") && parser
.HasKey(L
"pathfile"))
319 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
323 CTGitPath cmdLinePath
;
324 CTGitPathList pathList
;
325 if (g_sGroupingUUID
.IsEmpty())
326 g_sGroupingUUID
= parser
.GetVal(L
"groupuuid");
327 if (parser
.HasKey(L
"pathfile"))
329 CString sPathfileArgument
= CPathUtils::GetLongPathname(parser
.GetVal(L
"pathfile"));
331 cmdLinePath
.SetFromUnknown(sPathfileArgument
);
332 if (pathList
.LoadFromFile(cmdLinePath
)==false)
333 return FALSE
; // no path specified!
334 if (parser
.HasKey(L
"deletepathfile"))
336 // We can delete the temporary path file, now that we've loaded it
337 ::DeleteFile(cmdLinePath
.GetWinPath());
339 // This was a path to a temporary file - it's got no meaning now, and
340 // anybody who uses it again is in for a problem...
346 CString sPathArgument
= CPathUtils::GetLongPathname(parser
.GetVal(L
"path"));
347 if (parser
.HasKey(L
"expaths"))
349 // an /expaths param means we're started via the buttons in our Win7 library
350 // and that means the value of /expaths is the current directory, and
351 // the selected paths are then added as additional parameters but without a key, only a value
353 // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
354 // we have to escape the backslashes first. Since we're only dealing with paths here, that's
356 // Without this, a command line like:
357 // /command:commit /expaths:"D:\" "D:\Utils"
358 // would fail because the "D:\" is treated as the backslash being the escape char for the quotation
359 // mark and we'd end up with:
360 // argv[1] = /command:commit
361 // argv[2] = /expaths:D:" D:\Utils
362 // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
363 CString cmdLine
= GetCommandLineW();
364 cmdLine
.Replace(L
"\\", L
"\\\\");
366 LPWSTR
*szArglist
= CommandLineToArgvW(cmdLine
, &nArgs
);
369 // argument 0 is the process path, so start with 1
370 for (int i
= 1; i
< nArgs
; ++i
)
372 if (szArglist
[i
][0] != '/')
374 if (!sPathArgument
.IsEmpty())
375 sPathArgument
+= '*';
376 sPathArgument
+= szArglist
[i
];
379 sPathArgument
.Replace(L
"\\\\", L
"\\");
381 LocalFree(szArglist
);
383 if (sPathArgument
.IsEmpty() && parser
.HasKey(L
"path"))
385 CMessageBox::Show(hWndExplorer
, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
388 int asterisk
= sPathArgument
.Find('*');
389 cmdLinePath
.SetFromUnknown(asterisk
>= 0 ? sPathArgument
.Left(asterisk
) : sPathArgument
);
390 pathList
.LoadFromAsteriskSeparatedString(sPathArgument
);
393 if (pathList
.IsEmpty()) {
394 pathList
.AddPath(CTGitPath::CTGitPath(g_Git
.m_CurrentDir
));
397 // Set CWD to temporary dir, and restore it later
399 DWORD len
= GetCurrentDirectory(0, nullptr);
402 auto originalCurrentDirectory
= std::make_unique
<TCHAR
[]>(len
);
403 if (GetCurrentDirectory(len
, originalCurrentDirectory
.get()))
405 sOrigCWD
= originalCurrentDirectory
.get();
406 sOrigCWD
= CPathUtils::GetLongPathname(sOrigCWD
);
409 TCHAR pathbuf
[MAX_PATH
] = {0};
410 GetTortoiseGitTempPath(_countof(pathbuf
), pathbuf
);
411 SetCurrentDirectory(pathbuf
);
414 CheckForNewerVersion();
416 CAutoGeneralHandle TGitMutex
= ::CreateMutex(nullptr, FALSE
, L
"TortoiseGitProc.exe");
417 if (!g_Git
.SetCurrentDir(cmdLinePath
.GetWinPathString(), parser
.HasKey(L
"submodule") == TRUE
))
419 for (int i
= 0; i
< pathList
.GetCount(); ++i
)
420 if(g_Git
.SetCurrentDir(pathList
[i
].GetWinPath()))
423 if (parser
.HasKey(L
"pathfile") && parser
.HasKey(L
"submodule"))
424 g_Git
.SetCurrentDir(pathList
[0].GetWinPathString(), true);
426 if(!g_Git
.m_CurrentDir
.IsEmpty())
428 sOrigCWD
= g_Git
.m_CurrentDir
;
429 SetCurrentDirectory(g_Git
.m_CurrentDir
);
432 if (g_sGroupingUUID
.IsEmpty())
434 CRegStdDWORD groupSetting
= CRegStdDWORD(L
"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3);
435 switch (DWORD(groupSetting
))
439 // implemented differently to TortoiseSVN atm
445 if (GitAdminDir::HasAdminDir(g_Git
.m_CurrentDir
, true, &wcroot
))
448 CStringA
wcRootA(wcroot
+ CPathUtils::GetAppDirectory());
449 if (!git_odb_hash(&oid
, wcRootA
.MakeLower(), wcRootA
.GetLength(), GIT_OBJ_BLOB
))
452 git_oid_tostr(CStrBufA(hash
, GIT_OID_HEXSZ
, CStrBufA::SET_LENGTH
), GIT_OID_HEXSZ
+ 1, &oid
);
453 g_sGroupingUUID
= hash
;
455 ProjectProperties pp
;
457 CString icon
= pp
.sIcon
;
458 icon
.Replace('/', '\\');
460 g_bGroupingRemoveIcon
= true;
461 g_sGroupingIcon
= icon
;
467 CString sAppID
= GetTaskIDPerUUID(g_sGroupingUUID
).c_str();
468 InitializeJumpList(sAppID
);
469 EnsureGitLibrary(false);
475 // requires CWD to be set
476 CGit::m_LogEncode
= CAppUtils::GetLogOutputEncode();
478 // make sure all config files are read in order to check that none contains an error
479 g_Git
.GetConfigValue(L
"doesnot.exist");
488 UINT choice
= CMessageBox::Show(hWndExplorer
, err
, L
"TortoiseGit", 1, IDI_ERROR
, CString(MAKEINTRESOURCE(IDS_PROC_EDITLOCALGITCONFIG
)), CString(MAKEINTRESOURCE(IDS_PROC_EDITGLOBALGITCONFIG
)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON
)));
491 // open the config file with alternative editor
492 CAppUtils::LaunchAlternativeEditor(g_Git
.GetGitLocalConfig());
494 else if (choice
== 2)
496 // open the global config file with alternative editor
497 CAppUtils::LaunchAlternativeEditor(g_Git
.GetGitGlobalConfig());
503 // execute the requested command
504 CommandServer server
;
505 Command
* cmd
= server
.GetCommand(parser
.GetVal(L
"command"));
508 cmd
->SetExplorerHwnd(hWndExplorer
);
510 cmd
->SetParser(parser
);
511 cmd
->SetPaths(pathList
, cmdLinePath
);
513 retSuccess
= cmd
->Execute();
517 // Look for temporary files left around by TortoiseSVN and
518 // remove them. But only delete 'old' files because some
519 // apps might still be needing the recent ones.
521 DWORD len
= GetTortoiseGitTempPath(0, nullptr);
522 auto path
= std::make_unique
<TCHAR
[]>(len
+ 100);
523 len
= GetTortoiseGitTempPath (len
+ 100, path
.get());
526 CDirFileEnum
finder(path
.get());
528 ::GetSystemTimeAsFileTime(&systime_
);
529 __int64 systime
= (((_int64
)systime_
.dwHighDateTime
)<<32) | ((__int64
)systime_
.dwLowDateTime
);
532 while (finder
.NextFile(filepath
, &isDir
))
534 HANDLE hFile
= ::CreateFile(filepath
, GENERIC_READ
, FILE_SHARE_READ
, nullptr, OPEN_EXISTING
, isDir
? FILE_FLAG_BACKUP_SEMANTICS
: 0, nullptr);
535 if (hFile
!= INVALID_HANDLE_VALUE
)
537 FILETIME createtime_
;
538 if (::GetFileTime(hFile
, &createtime_
, nullptr, nullptr))
540 ::CloseHandle(hFile
);
541 __int64 createtime
= (((_int64
)createtime_
.dwHighDateTime
)<<32) | ((__int64
)createtime_
.dwLowDateTime
);
542 if ((createtime
+ 864000000000) < systime
) //only delete files older than a day
544 ::SetFileAttributes(filepath
, FILE_ATTRIBUTE_NORMAL
);
546 ::RemoveDirectory(filepath
);
548 ::DeleteFile(filepath
);
552 ::CloseHandle(hFile
);
558 Animator::Instance().ShutDown();
560 // Since the dialog has been closed, return FALSE so that we exit the
561 // application, rather than start the application's message pump.
565 void CTortoiseProcApp::CheckUpgrade()
567 CRegString regVersion
= CRegString(L
"Software\\TortoiseGit\\CurrentVersion");
568 CString sVersion
= regVersion
;
569 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Current TGit Version %s\n", (LPCTSTR
)sVersion
);
570 if (sVersion
.Compare(_T(STRPRODUCTVER
))==0)
572 // we're starting the first time with a new version!
575 int pos
= sVersion
.Find('.');
578 lVersion
= (_wtol(sVersion
.Left(pos
)) << 24);
579 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 16);
580 pos
= sVersion
.Find('.', pos
+1);
581 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 8);
585 pos
= sVersion
.Find(',');
588 lVersion
= (_wtol(sVersion
.Left(pos
)) << 24);
589 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 16);
590 pos
= sVersion
.Find(',', pos
+1);
591 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 8);
596 if (CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2", TRUE
) != TRUE
)
598 if (CMessageBox::Show(nullptr, L
"You have disabled the usage of libgit2 in TortoiseGit.\n\nThis might be the case in order to resolve an issue in an older TortoiseGit version.\n\nDo you want to restore the default value (i.e., enable it)?", L
"TortoiseGit", MB_ICONQUESTION
| MB_YESNO
) == IDYES
)
599 CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2").removeValue();
602 if (CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2_mask").exists())
604 if (CMessageBox::Show(nullptr, L
"You have a non-default setting of UseLibgit2_mask in your registry.\n\nThis might be the case in order to resolve an issue in an older TortoiseGit version.\n\nDo you want to restore the default value (i.e., remove custom setting from registry)?", L
"TortoiseGit", MB_ICONQUESTION
| MB_YESNO
) == IDYES
)
605 CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2_mask").removeValue();
608 CMessageBox::RemoveRegistryKey(L
"OldMsysgitVersionWarning");
610 CRegDWORD checkNewerWeekDay
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeekDay", 0);
611 if (!checkNewerWeekDay
.exists() || lVersion
<= ConvertVersionToInt(1, 8, 16))
613 std::random_device rd
;
614 std::mt19937
mt(rd());
615 std::uniform_int_distribution
<int> dist(0, 6);
616 checkNewerWeekDay
= dist(mt
);
619 // version specific updates
620 if (lVersion
<= ConvertVersionToInt(2, 4, 1))
622 CRegStdDWORD(L
"Software\\TortoiseGit\\CommitAskBeforeCancel").removeValue();
625 if (lVersion
<= ConvertVersionToInt(2, 4, 0))
627 CRegStdDWORD
commmitAskBeforeCancel(L
"Software\\TortoiseGit\\CommitAskBeforeCancel");
628 if (commmitAskBeforeCancel
.exists() && commmitAskBeforeCancel
!= IDYES
)
629 commmitAskBeforeCancel
= IDYES
;
632 if (lVersion
<= ConvertVersionToInt(2, 2, 1))
634 CString username
= CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username", L
"");
635 CString password
= CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password", L
"");
636 if (!username
.IsEmpty() && !password
.IsEmpty())
638 if (CWindowsCredentialsStore::SaveCredential(L
"TortoiseGit:SMTP-Credentials", username
, password
) == 0)
640 CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username").removeValue();
641 CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password").removeValue();
644 for (const CString
& setting
: { L
"SyncIn", L
"SyncOut" })
646 CRegDWORD
reg(L
"Software\\TortoiseGit\\StatusColumns\\" + setting
+ L
"loglistVersion", 0xff);
652 if (lVersion
<= ConvertVersionToInt(2, 1, 5))
654 // We updated GITSLC_COL_VERSION, but only significant changes were made for GitStatusList
655 // so, smoothly migrate GitLoglistBase settings
656 for (const CString
& setting
: { L
"log", L
"Blame", L
"Rebase", L
"reflog", L
"SyncIn", L
"SyncOut" })
658 CRegDWORD
reg(L
"Software\\TortoiseGit\\StatusColumns\\" + setting
+ L
"loglistVersion", 0xff);
664 if (lVersion
<= ConvertVersionToInt(1, 9, 0))
666 if (CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContent", TRUE
) == FALSE
)
668 CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContentMaxSize") = 0;
669 CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContent").removeValue();
673 if (lVersion
<= ConvertVersionToInt(1, 8, 8, 1))
675 CRegStdDWORD(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs").removeValue();
676 CRegStdString(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order").removeValue();
677 CRegStdString(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width").removeValue();
680 if (lVersion
<= ConvertVersionToInt(1, 8, 4, 1))
682 if (CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI", FALSE
) == TRUE
)
683 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType") = SEND_MAIL_MAPI
;
684 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI").removeValue();
687 if (lVersion
<= ConvertVersionToInt(1, 8, 2, 2))
689 // upgrade to 1.8.3: force recreation of all diff scripts.
690 CAppUtils::SetupDiffScripts(true, CString());
693 if (lVersion
<= ConvertVersionToInt(1, 8, 1))
695 if (CRegStdDWORD(L
"Software\\TortoiseGit\\LogTopoOrder", TRUE
) == FALSE
)
696 CRegStdDWORD(L
"Software\\TortoiseGit\\LogOrderBy") = 0;
698 // smoothly migrate broken msysgit path settings
699 CString oldmsysGitSetting
= CRegString(REG_MSYSGIT_PATH
);
700 oldmsysGitSetting
.TrimRight(L
'\\');
701 if (oldmsysGitSetting
.GetLength() > 4 && CStringUtils::EndsWith(oldmsysGitSetting
, L
"\\cmd"))
703 CString newPath
= oldmsysGitSetting
.Left(oldmsysGitSetting
.GetLength() - 3) + L
"bin";
704 if (PathFileExists(newPath
+ L
"\\git.exe"))
706 CRegString(REG_MSYSGIT_PATH
) = newPath
;
707 g_Git
.m_bInitialized
= FALSE
;
708 g_Git
.CheckMsysGitDir();
713 if (lVersion
<= ConvertVersionToInt(1, 4, 0))
715 CRegStdDWORD(L
"Software\\TortoiseGit\\OwnerdrawnMenus").removeValue();
718 if (lVersion
<= ConvertVersionToInt(1, 7, 6))
720 CoInitialize(nullptr);
723 CRegStdDWORD(L
"Software\\TortoiseGit\\ConvertBase").removeValue();
724 CRegStdDWORD(L
"Software\\TortoiseGit\\DiffProps").removeValue();
725 if (CRegStdDWORD(L
"Software\\TortoiseGit\\CheckNewer", TRUE
) == FALSE
)
726 CRegStdDWORD(L
"Software\\TortoiseGit\\VersionCheck") = FALSE
;
727 CRegStdDWORD(L
"Software\\TortoiseGit\\CheckNewer").removeValue();
730 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Setting up diff scripts ...\n");
731 CAppUtils::SetupDiffScripts(false, CString());
733 // set the current version so we don't come here again until the next update!
734 regVersion
= _T(STRPRODUCTVER
);
737 void CTortoiseProcApp::InitializeJumpList(const CString
& appid
)
739 // for Win7 : use a custom jump list
740 CoInitialize(nullptr);
742 DeleteJumpList(appid
);
743 DoInitializeJumpList(appid
);
747 void CTortoiseProcApp::DoInitializeJumpList(const CString
& appid
)
749 ATL::CComPtr
<ICustomDestinationList
> pcdl
;
750 HRESULT hr
= pcdl
.CoCreateInstance(CLSID_DestinationList
, nullptr, CLSCTX_INPROC_SERVER
);
754 hr
= pcdl
->SetAppID(appid
);
759 ATL::CComPtr
<IObjectArray
> poaRemoved
;
760 hr
= pcdl
->BeginList(&uMaxSlots
, IID_PPV_ARGS(&poaRemoved
));
764 ATL::CComPtr
<IObjectCollection
> poc
;
765 hr
= poc
.CoCreateInstance(CLSID_EnumerableObjectCollection
, nullptr, CLSCTX_INPROC_SERVER
);
769 CString sTemp
= CString(MAKEINTRESOURCE(IDS_MENUSETTINGS
));
770 CStringUtils::RemoveAccelerators(sTemp
);
772 ATL::CComPtr
<IShellLink
> psl
;
773 hr
= CreateShellLink(L
"/command:settings", (LPCTSTR
)sTemp
, 20, &psl
);
777 sTemp
= CString(MAKEINTRESOURCE(IDS_MENUHELP
));
778 CStringUtils::RemoveAccelerators(sTemp
);
779 psl
.Release(); // Need to release the object before calling operator&()
780 hr
= CreateShellLink(L
"/command:help", (LPCTSTR
)sTemp
, 19, &psl
);
785 ATL::CComPtr
<IObjectArray
> poa
;
786 hr
= poc
.QueryInterface(&poa
);
788 pcdl
->AppendCategory((LPCTSTR
)CString(MAKEINTRESOURCE(IDS_PROC_TASKS
)), poa
);
793 int CTortoiseProcApp::ExitInstance()
795 SYS_IMAGE_LIST().Cleanup();
796 Gdiplus::GdiplusShutdown(m_gdiplusToken
);
798 CWinAppEx::ExitInstance();
804 void CTortoiseProcApp::CheckForNewerVersion()
806 // check for newer versions
807 if (CRegDWORD(L
"Software\\TortoiseGit\\VersionCheck", TRUE
) != FALSE
)
813 if ((now
!= 0) && (localtime_s(&ptm
, &now
)==0))
816 // Check daily for new preview releases
817 CRegDWORD oldday
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerDay", (DWORD
)-1);
818 if (((DWORD
)oldday
) == -1)
819 oldday
= ptm
.tm_yday
;
822 if ((DWORD
)oldday
!= (DWORD
)ptm
.tm_yday
)
824 oldday
= ptm
.tm_yday
;
827 // we don't calculate the real 'week of the year' here
828 // because just to decide if we should check for an update
829 // that's not needed.
830 week
= (ptm
.tm_yday
+ CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeekDay", 0)) / 7;
832 CRegDWORD oldweek
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeek", (DWORD
)-1);
833 if (((DWORD
)oldweek
) == -1)
834 oldweek
= week
; // first start of TortoiseProc, no update check needed
837 if ((DWORD
)week
!= oldweek
)
841 CAppUtils::RunTortoiseGitProc(L
"/command:updatecheck", false, false);