Use forward slashes in the includes for consistency and also remove double slashes
[TortoiseGit.git] / src / TortoiseProc / TortoiseProc.cpp
blob512aa1e45b23e69ef8d99452efd252d4102e28b4
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2017 - 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.
20 #include "stdafx.h"
21 #include "TortoiseProc.h"
22 #include "SysImageList.h"
23 #include "../Utils/CrashReport.h"
24 #include "CmdLineParser.h"
25 #include "Hooks.h"
26 #include "AppUtils.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"
33 #include "Git.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"
43 #include <math.h>
44 #include <random>
45 #include "SendMail.h"
46 #include "WindowsCredentialsStore.h"
47 #include "FirstStartWizard.h"
48 #include "AnimationManager.h"
50 #define STRUCT_IOVEC_DEFINED
52 #ifdef _DEBUG
53 #define new DEBUG_NEW
54 #endif
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)
60 END_MESSAGE_MAP()
62 //////////////////////////////////////////////////////////////////////////
64 CTortoiseProcApp::CTortoiseProcApp()
66 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Constructor\n");
67 SetDllDirectory(L"");
68 CCrashReport::Instance().AddUserInfoToReport(L"CommandLine", GetCommandLine());
69 EnableHtmlHelp();
70 CHooks::Create();
71 git_libgit2_init();
72 CGit::SetGit2CredentialCallback(CAppUtils::Git2GetUserPassword);
73 CGit::SetGit2CertificateCheckCertificate(CAppUtils::Git2CertificateCheck);
74 m_bLoadUserToolbars = FALSE;
75 m_bSaveState = FALSE;
76 retSuccess = false;
77 m_gdiplusToken = NULL;
78 #if defined (_WIN64) && _MSC_VER == 1800
79 _set_FMA3_enable(0);
80 #endif
83 CTortoiseProcApp::~CTortoiseProcApp()
85 CHooks::Destroy();
86 git_libgit2_shutdown();
89 // The one and only CTortoiseProcApp object
90 CTortoiseProcApp theApp;
91 CString sOrigCWD;
92 CString g_sGroupingUUID;
93 CString g_sGroupingIcon;
94 bool g_bGroupingRemoveIcon = false;
95 HWND hWndExplorer;
97 #if ENABLE_CRASHHANLDER
98 CCrashReportTGit crasher(L"TortoiseGit " _T(APP_X64_STRING), TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE);
99 #endif
101 // CTortoiseProcApp initialization
103 BOOL CTortoiseProcApp::InitInstance()
105 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": InitInstance\n");
106 CheckUpgrade();
107 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
108 CMFCButton::EnableWindowsTheming();
110 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
111 Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, nullptr);
113 //set the resource dll for the required language
114 CRegDWORD loc = CRegDWORD(L"Software\\TortoiseGit\\LanguageID", 1033);
115 long langId = loc;
116 CString langDll;
117 CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory());
118 langpath += "Languages";
121 langDll.Format(L"%sLanguages\\TortoiseProc%ld.dll", (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);
123 CString sVer = _T(STRPRODUCTVER);
124 CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
125 if (sFileVer == sVer)
127 HINSTANCE hInst = LoadLibrary(langDll);
128 if (hInst)
130 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Load Language DLL %s\n", (LPCTSTR)langDll);
131 AfxSetResourceHandle(hInst);
132 break;
136 DWORD lid = SUBLANGID(langId);
137 lid--;
138 if (lid > 0)
139 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
140 else
141 langId = 0;
143 } while (langId != 0);
145 CString langStr;
146 langStr.Format(L"%ld", langId);
147 CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr);
149 TCHAR buf[6] = { 0 };
150 wcscpy_s(buf, L"en");
151 langId = loc;
152 // MFC uses a help file with the same name as the application by default,
153 // which means we have to change that default to our language specific help files
154 CString sHelppath = CPathUtils::GetAppDirectory() + L"TortoiseGit_en.chm";
155 free((void*)m_pszHelpFilePath);
156 m_pszHelpFilePath=_wcsdup(sHelppath);
157 sHelppath = CPathUtils::GetAppParentDirectory() + L"Languages\\TortoiseGit_en.chm";
160 CString sLang = L"_";
161 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf)))
163 sLang += buf;
164 sHelppath.Replace(L"_en", sLang);
165 if (PathFileExists(sHelppath))
167 free((void*)m_pszHelpFilePath);
168 m_pszHelpFilePath=_wcsdup(sHelppath);
169 break;
172 sHelppath.Replace(sLang, L"_en");
173 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf)))
175 sLang += L'_';
176 sLang += buf;
177 sHelppath.Replace(L"_en", sLang);
178 if (PathFileExists(sHelppath))
180 free((void*)m_pszHelpFilePath);
181 m_pszHelpFilePath=_wcsdup(sHelppath);
182 break;
185 sHelppath.Replace(sLang, L"_en");
187 DWORD lid = SUBLANGID(langId);
188 lid--;
189 if (lid > 0)
190 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
191 else
192 langId = 0;
193 } while (langId);
194 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Set Help Filename %s\n", m_pszHelpFilePath);
195 setlocale(LC_ALL, "");
197 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Initializing UI components ...\n");
198 // InitCommonControls() is required on Windows XP if an application
199 // manifest specifies use of ComCtl32.dll version 6 or later to enable
200 // visual styles. Otherwise, any window creation will fail.
202 INITCOMMONCONTROLSEX used = {
203 sizeof(INITCOMMONCONTROLSEX),
204 ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES |
205 ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES |
206 ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
207 ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS |
208 ICC_USEREX_CLASSES | ICC_WIN95_CLASSES
210 InitCommonControlsEx(&used);
211 AfxOleInit();
212 AfxEnableControlContainer();
213 AfxInitRichEdit5();
214 CWinAppEx::InitInstance();
215 SetRegistryKey(L"TortoiseGit");
216 SYS_IMAGE_LIST();
217 CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
218 AfxGetApp()->m_pszProfileName = _wcsdup(L"TortoiseProc"); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
220 CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);
222 hWndExplorer = nullptr;
223 CString sVal = parser.GetVal(L"hwnd");
224 if (!sVal.IsEmpty())
225 hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);
227 while (GetParent(hWndExplorer))
228 hWndExplorer = GetParent(hWndExplorer);
229 if (!IsWindow(hWndExplorer))
230 hWndExplorer = nullptr;
232 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
233 // in a message box
234 if (CRegDWORD(L"Software\\TortoiseGit\\Debug", FALSE) == TRUE)
235 AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);
237 if (parser.HasKey(L"command") && wcscmp(parser.GetVal(L"command"), L"firststart") == 0)
239 // CFirstStartWizard requires sOrigCWD to be set
240 DWORD len = GetCurrentDirectory(0, nullptr);
241 if (len)
243 auto originalCurrentDirectory = std::make_unique<TCHAR[]>(len);
244 if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
246 sOrigCWD = originalCurrentDirectory.get();
247 sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
250 CFirstStartWizard wizard(IDS_APPNAME, CWnd::FromHandle(hWndExplorer), parser.GetLongVal(L"page"));
251 return (wizard.DoModal() == ID_WIZFINISH);
254 if (!g_Git.CheckMsysGitDir())
256 UINT ret = CMessageBox::Show(hWndExplorer, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON);
257 if (ret == 2)
258 ShellExecute(hWndExplorer, L"open", GIT_FOR_WINDOWS_URL, nullptr, nullptr, SW_SHOW);
259 else if (ret == 1)
261 CFirstStartWizard wizard(IDS_APPNAME, CWnd::FromHandle(hWndExplorer), 2);
262 wizard.DoModal();
264 return FALSE;
266 if (!CConfigureGitExe::CheckGitVersion(hWndExplorer))
267 return FALSE;
270 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Registering Crash Report ...\n");
271 CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir);
272 CString versionString;
273 versionString.Format(L"%X", CGit::ms_LastMsysGitVersion);
274 CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString);
275 if (CGit::ms_bCygwinGit)
276 CCrashReport::Instance().AddUserInfoToReport(L"CygwinHack", L"true");
277 if (CGit::ms_bMsys2Git)
278 CCrashReport::Instance().AddUserInfoToReport(L"Msys2Hack", L"true");
281 if (parser.HasKey(L"urlhandler"))
283 CString url = parser.GetVal(L"urlhandler");
284 if (CStringUtils::StartsWith(url, L"tgit://clone/"))
285 url = url.Mid(13); // 21 = "tgit://clone/".GetLength()
286 else if (CStringUtils::StartsWith(url, L"github-windows://openRepo/"))
288 url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
289 int questioMark = url.Find('?');
290 if (questioMark > 0)
291 url = url.Left(questioMark);
293 else if (CStringUtils::StartsWith(url, L"smartgit://cloneRepo/"))
294 url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
295 else
297 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
298 return FALSE;
300 CString newCmd;
301 newCmd.Format(L"/command:clone /url:\"%s\" /hasurlhandler", (LPCTSTR)url);
302 parser = CCmdLineParser(newCmd);
305 if (parser.HasKey(L"path") && parser.HasKey(L"pathfile"))
307 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
308 return FALSE;
311 CTGitPath cmdLinePath;
312 CTGitPathList pathList;
313 if (g_sGroupingUUID.IsEmpty())
314 g_sGroupingUUID = parser.GetVal(L"groupuuid");
315 if (parser.HasKey(L"pathfile"))
317 CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(L"pathfile"));
319 cmdLinePath.SetFromUnknown(sPathfileArgument);
320 if (pathList.LoadFromFile(cmdLinePath)==false)
321 return FALSE; // no path specified!
322 if (parser.HasKey(L"deletepathfile"))
324 // We can delete the temporary path file, now that we've loaded it
325 ::DeleteFile(cmdLinePath.GetWinPath());
327 // This was a path to a temporary file - it's got no meaning now, and
328 // anybody who uses it again is in for a problem...
329 cmdLinePath.Reset();
332 else
334 CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(L"path"));
335 if (parser.HasKey(L"expaths"))
337 // an /expaths param means we're started via the buttons in our Win7 library
338 // and that means the value of /expaths is the current directory, and
339 // the selected paths are then added as additional parameters but without a key, only a value
341 // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
342 // we have to escape the backslashes first. Since we're only dealing with paths here, that's
343 // a save bet.
344 // Without this, a command line like:
345 // /command:commit /expaths:"D:\" "D:\Utils"
346 // would fail because the "D:\" is treated as the backslash being the escape char for the quotation
347 // mark and we'd end up with:
348 // argv[1] = /command:commit
349 // argv[2] = /expaths:D:" D:\Utils
350 // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
351 CString cmdLine = GetCommandLineW();
352 cmdLine.Replace(L"\\", L"\\\\");
353 int nArgs = 0;
354 LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs);
355 if (szArglist)
357 // argument 0 is the process path, so start with 1
358 for (int i = 1; i < nArgs; ++i)
360 if (szArglist[i][0] != '/')
362 if (!sPathArgument.IsEmpty())
363 sPathArgument += '*';
364 sPathArgument += szArglist[i];
367 sPathArgument.Replace(L"\\\\", L"\\");
369 LocalFree(szArglist);
371 if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
373 CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
374 return FALSE;
376 int asterisk = sPathArgument.Find('*');
377 cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
378 pathList.LoadFromAsteriskSeparatedString(sPathArgument);
381 if (pathList.IsEmpty()) {
382 pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
385 // Set CWD to temporary dir, and restore it later
387 DWORD len = GetCurrentDirectory(0, nullptr);
388 if (len)
390 auto originalCurrentDirectory = std::make_unique<TCHAR[]>(len);
391 if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
393 sOrigCWD = originalCurrentDirectory.get();
394 sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
397 TCHAR pathbuf[MAX_PATH] = {0};
398 GetTortoiseGitTempPath(_countof(pathbuf), pathbuf);
399 SetCurrentDirectory(pathbuf);
402 CheckForNewerVersion();
404 CAutoGeneralHandle TGitMutex = ::CreateMutex(nullptr, FALSE, L"TortoiseGitProc.exe");
405 if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(L"submodule") == TRUE))
407 for (int i = 0; i < pathList.GetCount(); ++i)
408 if(g_Git.SetCurrentDir(pathList[i].GetWinPath()))
409 break;
411 if (parser.HasKey(L"pathfile") && parser.HasKey(L"submodule"))
412 g_Git.SetCurrentDir(pathList[0].GetWinPathString(), true);
414 if(!g_Git.m_CurrentDir.IsEmpty())
416 sOrigCWD = g_Git.m_CurrentDir;
417 SetCurrentDirectory(g_Git.m_CurrentDir);
420 if (g_sGroupingUUID.IsEmpty())
422 CRegStdDWORD groupSetting = CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3);
423 switch (DWORD(groupSetting))
425 case 1:
426 case 2:
427 // implemented differently to TortoiseSVN atm
428 break;
429 case 3:
430 case 4:
432 CString wcroot;
433 if (GitAdminDir::HasAdminDir(g_Git.m_CurrentDir, true, &wcroot))
435 git_oid oid;
436 CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory());
437 if (!git_odb_hash(&oid, wcRootA.MakeLower(), wcRootA.GetLength(), GIT_OBJ_BLOB))
439 CStringA hash;
440 git_oid_tostr(CStrBufA(hash, GIT_OID_HEXSZ, CStrBufA::SET_LENGTH), GIT_OID_HEXSZ + 1, &oid);
441 g_sGroupingUUID = hash;
443 ProjectProperties pp;
444 pp.ReadProps();
445 CString icon = pp.sIcon;
446 icon.Replace('/', '\\');
447 if (icon.IsEmpty())
448 g_bGroupingRemoveIcon = true;
449 g_sGroupingIcon = icon;
455 CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str();
456 InitializeJumpList(sAppID);
457 EnsureGitLibrary(false);
460 CString err;
463 // requires CWD to be set
464 CGit::m_LogEncode = CAppUtils::GetLogOutputEncode();
466 // make sure all config files are read in order to check that none contains an error
467 g_Git.GetConfigValue(L"doesnot.exist");
469 catch (char* msg)
471 err = CString(msg);
474 if (!err.IsEmpty())
476 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)));
477 if (choice == 1)
479 // open the config file with alternative editor
480 CAppUtils::LaunchAlternativeEditor(g_Git.GetGitLocalConfig());
482 else if (choice == 2)
484 // open the global config file with alternative editor
485 CAppUtils::LaunchAlternativeEditor(g_Git.GetGitGlobalConfig());
487 return FALSE;
491 // execute the requested command
492 CommandServer server;
493 Command* cmd = server.GetCommand(parser.GetVal(L"command"));
494 if (cmd)
496 cmd->SetExplorerHwnd(hWndExplorer);
498 cmd->SetParser(parser);
499 cmd->SetPaths(pathList, cmdLinePath);
501 retSuccess = cmd->Execute();
502 delete cmd;
505 // Look for temporary files left around by TortoiseSVN and
506 // remove them. But only delete 'old' files because some
507 // apps might still be needing the recent ones.
509 DWORD len = GetTortoiseGitTempPath(0, nullptr);
510 auto path = std::make_unique<TCHAR[]>(len + 100);
511 len = GetTortoiseGitTempPath (len + 100, path.get());
512 if (len != 0)
514 CDirFileEnum finder(path.get());
515 FILETIME systime_;
516 ::GetSystemTimeAsFileTime(&systime_);
517 __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime);
518 bool isDir;
519 CString filepath;
520 while (finder.NextFile(filepath, &isDir))
522 HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : 0, nullptr);
523 if (hFile != INVALID_HANDLE_VALUE)
525 FILETIME createtime_;
526 if (::GetFileTime(hFile, &createtime_, nullptr, nullptr))
528 ::CloseHandle(hFile);
529 __int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime);
530 if ((createtime + 864000000000) < systime) //only delete files older than a day
532 ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
533 if (isDir)
534 ::RemoveDirectory(filepath);
535 else
536 ::DeleteFile(filepath);
539 else
540 ::CloseHandle(hFile);
546 Animator::Instance().ShutDown();
548 // Since the dialog has been closed, return FALSE so that we exit the
549 // application, rather than start the application's message pump.
550 return FALSE;
553 void CTortoiseProcApp::CheckUpgrade()
555 CRegString regVersion = CRegString(L"Software\\TortoiseGit\\CurrentVersion");
556 CString sVersion = regVersion;
557 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Current TGit Version %s\n", (LPCTSTR)sVersion);
558 if (sVersion.Compare(_T(STRPRODUCTVER))==0)
559 return;
560 // we're starting the first time with a new version!
562 LONG lVersion = 0;
563 int pos = sVersion.Find('.');
564 if (pos > 0)
566 lVersion = (_wtol(sVersion.Left(pos)) << 24);
567 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 16);
568 pos = sVersion.Find('.', pos+1);
569 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 8);
571 else
573 pos = sVersion.Find(',');
574 if (pos > 0)
576 lVersion = (_wtol(sVersion.Left(pos)) << 24);
577 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 16);
578 pos = sVersion.Find(',', pos+1);
579 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 8);
583 // generic cleanup
584 if (CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2", TRUE) != TRUE)
586 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)
587 CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2").removeValue();
590 if (CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2_mask").exists())
592 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)
593 CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2_mask").removeValue();
596 CMessageBox::RemoveRegistryKey(L"OldMsysgitVersionWarning");
598 CRegDWORD checkNewerWeekDay = CRegDWORD(L"Software\\TortoiseGit\\CheckNewerWeekDay", 0);
599 if (!checkNewerWeekDay.exists() || lVersion <= 0x01081000)
601 std::random_device rd;
602 std::mt19937 mt(rd());
603 std::uniform_int_distribution<int> dist(0, 6);
604 checkNewerWeekDay = dist(mt);
607 // version specific updates
608 if (lVersion <= 0x02040100)
610 CRegStdDWORD(L"Software\\TortoiseGit\\CommitAskBeforeCancel").removeValue();
613 if (lVersion <= 0x02040000)
615 CRegStdDWORD commmitAskBeforeCancel(L"Software\\TortoiseGit\\CommitAskBeforeCancel");
616 if (commmitAskBeforeCancel.exists() && commmitAskBeforeCancel != IDYES)
617 commmitAskBeforeCancel = IDYES;
620 if (lVersion <= 0x02020100)
622 CString username = CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username", L"");
623 CString password = CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password", L"");
624 if (!username.IsEmpty() && !password.IsEmpty())
626 if (CWindowsCredentialsStore::SaveCredential(L"TortoiseGit:SMTP-Credentials", username, password) == 0)
628 CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username").removeValue();
629 CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password").removeValue();
632 for (const CString& setting : { L"SyncIn", L"SyncOut" })
634 CRegDWORD reg(L"Software\\TortoiseGit\\StatusColumns\\" + setting + L"loglistVersion", 0xff);
635 if ((DWORD)reg == 6)
636 reg.removeValue();
640 if (lVersion <= 0x02010500)
642 // We updated GITSLC_COL_VERSION, but only significant changes were made for GitStatusList
643 // so, smoothly migrate GitLoglistBase settings
644 for (const CString& setting : { L"log", L"Blame", L"Rebase", L"reflog", L"SyncIn", L"SyncOut" })
646 CRegDWORD reg(L"Software\\TortoiseGit\\StatusColumns\\" + setting + L"loglistVersion", 0xff);
647 if ((DWORD)reg == 5)
648 reg = 6;
652 if (lVersion <= 0x01090000)
654 if (CRegDWORD(L"Software\\TortoiseGit\\TGitCacheCheckContent", TRUE) == FALSE)
656 CRegDWORD(L"Software\\TortoiseGit\\TGitCacheCheckContentMaxSize") = 0;
657 CRegDWORD(L"Software\\TortoiseGit\\TGitCacheCheckContent").removeValue();
661 if (lVersion <= 0x01080801)
663 CRegStdDWORD(L"Software\\TortoiseGit\\StatusColumns\\BrowseRefs").removeValue();
664 CRegStdString(L"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order").removeValue();
665 CRegStdString(L"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width").removeValue();
668 if (lVersion <= 0x01080401)
670 if (CRegStdDWORD(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI", FALSE) == TRUE)
671 CRegStdDWORD(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType") = SEND_MAIL_MAPI;
672 CRegStdDWORD(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI").removeValue();
675 if (lVersion <= 0x01080202)
677 // upgrade to 1.8.3: force recreation of all diff scripts.
678 CAppUtils::SetupDiffScripts(true, CString());
681 if (lVersion <= 0x01080100)
683 if (CRegStdDWORD(L"Software\\TortoiseGit\\LogTopoOrder", TRUE) == FALSE)
684 CRegStdDWORD(L"Software\\TortoiseGit\\LogOrderBy") = 0;
686 // smoothly migrate broken msysgit path settings
687 CString oldmsysGitSetting = CRegString(REG_MSYSGIT_PATH);
688 oldmsysGitSetting.TrimRight(L'\\');
689 if (oldmsysGitSetting.GetLength() > 4 && CStringUtils::EndsWith(oldmsysGitSetting, L"\\cmd"))
691 CString newPath = oldmsysGitSetting.Mid(0, oldmsysGitSetting.GetLength() - 3) + L"bin";
692 if (PathFileExists(newPath + L"\\git.exe"))
694 CRegString(REG_MSYSGIT_PATH) = newPath;
695 g_Git.m_bInitialized = FALSE;
696 g_Git.CheckMsysGitDir();
701 if (lVersion <= 0x01040000)
703 CRegStdDWORD(L"Software\\TortoiseGit\\OwnerdrawnMenus").removeValue();
706 if (lVersion <= 0x01070600)
708 CoInitialize(nullptr);
709 EnsureGitLibrary();
710 CoUninitialize();
711 CRegStdDWORD(L"Software\\TortoiseGit\\ConvertBase").removeValue();
712 CRegStdDWORD(L"Software\\TortoiseGit\\DiffProps").removeValue();
713 if (CRegStdDWORD(L"Software\\TortoiseGit\\CheckNewer", TRUE) == FALSE)
714 CRegStdDWORD(L"Software\\TortoiseGit\\VersionCheck") = FALSE;
715 CRegStdDWORD(L"Software\\TortoiseGit\\CheckNewer").removeValue();
718 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Setting up diff scripts ...\n");
719 CAppUtils::SetupDiffScripts(false, CString());
721 // set the current version so we don't come here again until the next update!
722 regVersion = _T(STRPRODUCTVER);
725 void CTortoiseProcApp::InitializeJumpList(const CString& appid)
727 // for Win7 : use a custom jump list
728 CoInitialize(nullptr);
729 SetAppID(appid);
730 DeleteJumpList(appid);
731 DoInitializeJumpList(appid);
732 CoUninitialize();
735 void CTortoiseProcApp::DoInitializeJumpList(const CString& appid)
737 ATL::CComPtr<ICustomDestinationList> pcdl;
738 HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER);
739 if (FAILED(hr))
740 return;
742 hr = pcdl->SetAppID(appid);
743 if (FAILED(hr))
744 return;
746 UINT uMaxSlots;
747 ATL::CComPtr<IObjectArray> poaRemoved;
748 hr = pcdl->BeginList(&uMaxSlots, IID_PPV_ARGS(&poaRemoved));
749 if (FAILED(hr))
750 return;
752 ATL::CComPtr<IObjectCollection> poc;
753 hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr, CLSCTX_INPROC_SERVER);
754 if (FAILED(hr))
755 return;
757 CString sTemp = CString(MAKEINTRESOURCE(IDS_MENUSETTINGS));
758 CStringUtils::RemoveAccelerators(sTemp);
760 ATL::CComPtr<IShellLink> psl;
761 hr = CreateShellLink(L"/command:settings", (LPCTSTR)sTemp, 20, &psl);
762 if (SUCCEEDED(hr)) {
763 poc->AddObject(psl);
765 sTemp = CString(MAKEINTRESOURCE(IDS_MENUHELP));
766 CStringUtils::RemoveAccelerators(sTemp);
767 psl.Release(); // Need to release the object before calling operator&()
768 hr = CreateShellLink(L"/command:help", (LPCTSTR)sTemp, 19, &psl);
769 if (SUCCEEDED(hr)) {
770 poc->AddObject(psl);
773 ATL::CComPtr<IObjectArray> poa;
774 hr = poc.QueryInterface(&poa);
775 if (SUCCEEDED(hr)) {
776 pcdl->AppendCategory((LPCTSTR)CString(MAKEINTRESOURCE(IDS_PROC_TASKS)), poa);
777 pcdl->CommitList();
781 int CTortoiseProcApp::ExitInstance()
783 SYS_IMAGE_LIST().Cleanup();
784 Gdiplus::GdiplusShutdown(m_gdiplusToken);
786 CWinAppEx::ExitInstance();
787 if (retSuccess)
788 return 0;
789 return -1;
792 void CTortoiseProcApp::CheckForNewerVersion()
794 // check for newer versions
795 if (CRegDWORD(L"Software\\TortoiseGit\\VersionCheck", TRUE) != FALSE)
797 time_t now;
798 struct tm ptm;
800 time(&now);
801 if ((now != 0) && (localtime_s(&ptm, &now)==0))
803 #if PREVIEW
804 // Check daily for new preview releases
805 CRegDWORD oldday = CRegDWORD(L"Software\\TortoiseGit\\CheckNewerDay", (DWORD)-1);
806 if (((DWORD)oldday) == -1)
807 oldday = ptm.tm_yday;
808 else
810 if ((DWORD)oldday != (DWORD)ptm.tm_yday)
812 oldday = ptm.tm_yday;
813 #else
814 int week = 0;
815 // we don't calculate the real 'week of the year' here
816 // because just to decide if we should check for an update
817 // that's not needed.
818 week = (ptm.tm_yday + CRegDWORD(L"Software\\TortoiseGit\\CheckNewerWeekDay", 0)) / 7;
820 CRegDWORD oldweek = CRegDWORD(L"Software\\TortoiseGit\\CheckNewerWeek", (DWORD)-1);
821 if (((DWORD)oldweek) == -1)
822 oldweek = week; // first start of TortoiseProc, no update check needed
823 else
825 if ((DWORD)week != oldweek)
827 oldweek = week;
828 #endif
829 CAppUtils::RunTortoiseGitProc(L"/command:updatecheck", false, false);