Also check git.exe version when setting it up
[TortoiseGit.git] / src / TortoiseProc / TortoiseProc.cpp
blob802871e6f748c33a59723d12c31c532e2d853ee9
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2016 - 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 "SinglePropSheetDlg.h"
39 #include "Settings\setmainpage.h"
40 #include "ConfigureGitExe.h"
41 #include "Libraries.h"
42 #include "TaskbarUUID.h"
43 #include "ProjectProperties.h"
44 #include "HistoryCombo.h"
45 #include "gitindex.h"
46 #include <math.h>
47 #include <random>
48 #include "SendMail.h"
49 #include "WindowsCredentialsStore.h"
51 #define STRUCT_IOVEC_DEFINED
53 #ifdef _DEBUG
54 #define new DEBUG_NEW
55 #endif
57 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
59 BEGIN_MESSAGE_MAP(CTortoiseProcApp, CWinAppEx)
60 ON_COMMAND(ID_HELP, CWinAppEx::OnHelp)
61 END_MESSAGE_MAP()
63 //////////////////////////////////////////////////////////////////////////
65 CTortoiseProcApp::CTortoiseProcApp()
67 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Constructor\n");
68 SetDllDirectory(L"");
69 CCrashReport::Instance().AddUserInfoToReport(L"CommandLine", GetCommandLine());
70 EnableHtmlHelp();
71 CHooks::Create();
72 git_libgit2_init();
73 CGit::SetGit2CredentialCallback(CAppUtils::Git2GetUserPassword);
74 CGit::SetGit2CertificateCheckCertificate(CAppUtils::Git2CertificateCheck);
75 m_bLoadUserToolbars = FALSE;
76 m_bSaveState = FALSE;
77 retSuccess = false;
78 m_gdiplusToken = NULL;
79 #if defined (_WIN64) && _MSC_VER == 1800
80 _set_FMA3_enable(0);
81 #endif
84 CTortoiseProcApp::~CTortoiseProcApp()
86 CHooks::Destroy();
87 git_libgit2_shutdown();
90 // The one and only CTortoiseProcApp object
91 CTortoiseProcApp theApp;
92 CString sOrigCWD;
93 CString g_sGroupingUUID;
94 CString g_sGroupingIcon;
95 bool g_bGroupingRemoveIcon = false;
96 HWND hWndExplorer;
97 CGitIndexFileMap g_IndexFileMap;
99 #if ENABLE_CRASHHANLDER
100 CCrashReportTGit crasher(L"TortoiseGit " _T(APP_X64_STRING), TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE);
101 #endif
103 // CTortoiseProcApp initialization
105 BOOL CTortoiseProcApp::InitInstance()
107 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": InitInstance\n");
108 CheckUpgrade();
109 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
110 CMFCButton::EnableWindowsTheming();
112 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
113 Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, nullptr);
115 //set the resource dll for the required language
116 CRegDWORD loc = CRegDWORD(L"Software\\TortoiseGit\\LanguageID", 1033);
117 long langId = loc;
118 CString langDll;
119 CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory());
120 langpath += "Languages";
123 langDll.Format(L"%sLanguages\\TortoiseProc%ld.dll", (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);
125 CString sVer = _T(STRPRODUCTVER);
126 CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
127 if (sFileVer == sVer)
129 HINSTANCE hInst = LoadLibrary(langDll);
130 if (hInst)
132 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Load Language DLL %s\n", langDll);
133 AfxSetResourceHandle(hInst);
134 break;
138 DWORD lid = SUBLANGID(langId);
139 lid--;
140 if (lid > 0)
141 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
142 else
143 langId = 0;
145 } while (langId != 0);
147 CString langStr;
148 langStr.Format(L"%ld", langId);
149 CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr);
151 TCHAR buf[6] = { 0 };
152 wcscpy_s(buf, L"en");
153 langId = loc;
154 // MFC uses a help file with the same name as the application by default,
155 // which means we have to change that default to our language specific help files
156 CString sHelppath = CPathUtils::GetAppDirectory() + L"TortoiseGit_en.chm";
157 free((void*)m_pszHelpFilePath);
158 m_pszHelpFilePath=_wcsdup(sHelppath);
159 sHelppath = CPathUtils::GetAppParentDirectory() + L"Languages\\TortoiseGit_en.chm";
162 CString sLang = L"_";
163 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf)))
165 sLang += buf;
166 sHelppath.Replace(L"_en", sLang);
167 if (PathFileExists(sHelppath))
169 free((void*)m_pszHelpFilePath);
170 m_pszHelpFilePath=_wcsdup(sHelppath);
171 break;
174 sHelppath.Replace(sLang, L"_en");
175 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf)))
177 sLang += L'_';
178 sLang += buf;
179 sHelppath.Replace(L"_en", sLang);
180 if (PathFileExists(sHelppath))
182 free((void*)m_pszHelpFilePath);
183 m_pszHelpFilePath=_wcsdup(sHelppath);
184 break;
187 sHelppath.Replace(sLang, L"_en");
189 DWORD lid = SUBLANGID(langId);
190 lid--;
191 if (lid > 0)
192 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
193 else
194 langId = 0;
195 } while (langId);
196 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Set Help Filename %s\n", m_pszHelpFilePath);
197 setlocale(LC_ALL, "");
199 if (!g_Git.CheckMsysGitDir())
201 UINT ret = CMessageBox::Show(nullptr, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON);
202 if(ret == 2)
204 ShellExecute(nullptr, L"open", GIT_FOR_WINDOWS_URL, nullptr, nullptr, SW_SHOW);
206 else if(ret == 1)
208 // open settings dialog
209 CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROC_SETTINGS_TITLE)), new CSetMainPage(), this->GetMainWnd()).DoModal();
211 return FALSE;
213 if (!CConfigureGitExe::CheckGitVersion(hWndExplorer))
214 return FALSE;
217 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Registering Crash Report ...\n");
218 CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir);
219 CString versionString;
220 versionString.Format(L"%X", CGit::ms_LastMsysGitVersion);
221 CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString);
224 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Initializing UI components ...\n");
225 // InitCommonControls() is required on Windows XP if an application
226 // manifest specifies use of ComCtl32.dll version 6 or later to enable
227 // visual styles. Otherwise, any window creation will fail.
229 INITCOMMONCONTROLSEX used = {
230 sizeof(INITCOMMONCONTROLSEX),
231 ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES |
232 ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES |
233 ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
234 ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS |
235 ICC_USEREX_CLASSES | ICC_WIN95_CLASSES
237 InitCommonControlsEx(&used);
238 AfxOleInit();
239 AfxEnableControlContainer();
240 AfxInitRichEdit5();
241 CWinAppEx::InitInstance();
242 SetRegistryKey(L"TortoiseGit");
243 SYS_IMAGE_LIST();
244 CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
245 AfxGetApp()->m_pszProfileName = _wcsdup(L"TortoiseProc"); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
247 CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);
249 hWndExplorer = nullptr;
250 CString sVal = parser.GetVal(L"hwnd");
251 if (!sVal.IsEmpty())
252 hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);
254 while (GetParent(hWndExplorer))
255 hWndExplorer = GetParent(hWndExplorer);
256 if (!IsWindow(hWndExplorer))
257 hWndExplorer = nullptr;
259 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
260 // in a message box
261 if (CRegDWORD(L"Software\\TortoiseGit\\Debug", FALSE) == TRUE)
262 AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);
264 if (parser.HasKey(L"urlhandler"))
266 CString url = parser.GetVal(L"urlhandler");
267 if (CStringUtils::StartsWith(url, L"tgit://clone/"))
268 url = url.Mid(13); // 21 = "tgit://clone/".GetLength()
269 else if (CStringUtils::StartsWith(url, L"github-windows://openRepo/"))
271 url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
272 int questioMark = url.Find('?');
273 if (questioMark > 0)
274 url = url.Left(questioMark);
276 else if (CStringUtils::StartsWith(url, L"smartgit://cloneRepo/"))
277 url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
278 else
280 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
281 return FALSE;
283 CString newCmd;
284 newCmd.Format(L"/command:clone /url:\"%s\" /hasurlhandler", (LPCTSTR)url);
285 parser = CCmdLineParser(newCmd);
288 if (parser.HasKey(L"path") && parser.HasKey(L"pathfile"))
290 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
291 return FALSE;
294 CTGitPath cmdLinePath;
295 CTGitPathList pathList;
296 if (g_sGroupingUUID.IsEmpty())
297 g_sGroupingUUID = parser.GetVal(L"groupuuid");
298 if (parser.HasKey(L"pathfile"))
300 CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(L"pathfile"));
302 cmdLinePath.SetFromUnknown(sPathfileArgument);
303 if (pathList.LoadFromFile(cmdLinePath)==false)
304 return FALSE; // no path specified!
305 if (parser.HasKey(L"deletepathfile"))
307 // We can delete the temporary path file, now that we've loaded it
308 ::DeleteFile(cmdLinePath.GetWinPath());
310 // This was a path to a temporary file - it's got no meaning now, and
311 // anybody who uses it again is in for a problem...
312 cmdLinePath.Reset();
315 else
317 CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(L"path"));
318 if (parser.HasKey(L"expaths"))
320 // an /expaths param means we're started via the buttons in our Win7 library
321 // and that means the value of /expaths is the current directory, and
322 // the selected paths are then added as additional parameters but without a key, only a value
324 // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
325 // we have to escape the backslashes first. Since we're only dealing with paths here, that's
326 // a save bet.
327 // Without this, a command line like:
328 // /command:commit /expaths:"D:\" "D:\Utils"
329 // would fail because the "D:\" is treated as the backslash being the escape char for the quotation
330 // mark and we'd end up with:
331 // argv[1] = /command:commit
332 // argv[2] = /expaths:D:" D:\Utils
333 // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
334 CString cmdLine = GetCommandLineW();
335 cmdLine.Replace(L"\\", L"\\\\");
336 int nArgs = 0;
337 LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs);
338 if (szArglist)
340 // argument 0 is the process path, so start with 1
341 for (int i = 1; i < nArgs; ++i)
343 if (szArglist[i][0] != '/')
345 if (!sPathArgument.IsEmpty())
346 sPathArgument += '*';
347 sPathArgument += szArglist[i];
350 sPathArgument.Replace(L"\\\\", L"\\");
352 LocalFree(szArglist);
354 if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
356 CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
357 return FALSE;
359 int asterisk = sPathArgument.Find('*');
360 cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
361 pathList.LoadFromAsteriskSeparatedString(sPathArgument);
364 if (pathList.IsEmpty()) {
365 pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
368 // Set CWD to temporary dir, and restore it later
370 DWORD len = GetCurrentDirectory(0, nullptr);
371 if (len)
373 auto originalCurrentDirectory = std::make_unique<TCHAR[]>(len);
374 if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
376 sOrigCWD = originalCurrentDirectory.get();
377 sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
380 TCHAR pathbuf[MAX_PATH] = {0};
381 GetTortoiseGitTempPath(MAX_PATH, pathbuf);
382 SetCurrentDirectory(pathbuf);
385 CheckForNewerVersion();
387 CAutoGeneralHandle TGitMutex = ::CreateMutex(nullptr, FALSE, L"TortoiseGitProc.exe");
388 if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(L"submodule") == TRUE))
390 for (int i = 0; i < pathList.GetCount(); ++i)
391 if(g_Git.SetCurrentDir(pathList[i].GetWinPath()))
392 break;
394 if (parser.HasKey(L"pathfile") && parser.HasKey(L"submodule"))
395 g_Git.SetCurrentDir(pathList[0].GetWinPathString(), true);
397 if(!g_Git.m_CurrentDir.IsEmpty())
399 sOrigCWD = g_Git.m_CurrentDir;
400 SetCurrentDirectory(g_Git.m_CurrentDir);
403 if (g_sGroupingUUID.IsEmpty())
405 CRegStdDWORD groupSetting = CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3);
406 switch (DWORD(groupSetting))
408 case 1:
409 case 2:
410 // implemented differently to TortoiseSVN atm
411 break;
412 case 3:
413 case 4:
415 CString wcroot;
416 if (GitAdminDir::HasAdminDir(g_Git.m_CurrentDir, true, &wcroot))
418 git_oid oid;
419 CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory());
420 if (!git_odb_hash(&oid, wcRootA.MakeLower(), wcRootA.GetLength(), GIT_OBJ_BLOB))
422 CStringA hash;
423 git_oid_tostr(hash.GetBufferSetLength(GIT_OID_HEXSZ + 1), GIT_OID_HEXSZ + 1, &oid);
424 hash.ReleaseBuffer();
425 g_sGroupingUUID = hash;
427 ProjectProperties pp;
428 pp.ReadProps();
429 CString icon = pp.sIcon;
430 icon.Replace('/', '\\');
431 if (icon.IsEmpty())
432 g_bGroupingRemoveIcon = true;
433 g_sGroupingIcon = icon;
439 CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str();
440 InitializeJumpList(sAppID);
441 EnsureGitLibrary(false);
444 CString err;
447 // requires CWD to be set
448 CGit::m_LogEncode = CAppUtils::GetLogOutputEncode();
450 // make sure all config files are read in order to check that none contains an error
451 g_Git.GetConfigValue(L"doesnot.exist");
453 catch (char* msg)
455 err = CString(msg);
458 if (!err.IsEmpty())
460 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)));
461 if (choice == 1)
463 // open the config file with alternative editor
464 CAppUtils::LaunchAlternativeEditor(g_Git.GetGitLocalConfig());
466 else if (choice == 2)
468 // open the global config file with alternative editor
469 CAppUtils::LaunchAlternativeEditor(g_Git.GetGitGlobalConfig());
471 return FALSE;
475 // execute the requested command
476 CommandServer server;
477 Command* cmd = server.GetCommand(parser.GetVal(L"command"));
478 if (cmd)
480 cmd->SetExplorerHwnd(hWndExplorer);
482 cmd->SetParser(parser);
483 cmd->SetPaths(pathList, cmdLinePath);
485 retSuccess = cmd->Execute();
486 delete cmd;
489 // Look for temporary files left around by TortoiseSVN and
490 // remove them. But only delete 'old' files because some
491 // apps might still be needing the recent ones.
493 DWORD len = GetTortoiseGitTempPath(0, nullptr);
494 auto path = std::make_unique<TCHAR[]>(len + 100);
495 len = GetTortoiseGitTempPath (len + 100, path.get());
496 if (len != 0)
498 CDirFileEnum finder(path.get());
499 FILETIME systime_;
500 ::GetSystemTimeAsFileTime(&systime_);
501 __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime);
502 bool isDir;
503 CString filepath;
504 while (finder.NextFile(filepath, &isDir))
506 HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : 0, nullptr);
507 if (hFile != INVALID_HANDLE_VALUE)
509 FILETIME createtime_;
510 if (::GetFileTime(hFile, &createtime_, nullptr, nullptr))
512 ::CloseHandle(hFile);
513 __int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime);
514 if ((createtime + 864000000000) < systime) //only delete files older than a day
516 ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
517 if (isDir)
518 ::RemoveDirectory(filepath);
519 else
520 ::DeleteFile(filepath);
523 else
524 ::CloseHandle(hFile);
530 // Since the dialog has been closed, return FALSE so that we exit the
531 // application, rather than start the application's message pump.
532 return FALSE;
535 void CTortoiseProcApp::CheckUpgrade()
537 CRegString regVersion = CRegString(L"Software\\TortoiseGit\\CurrentVersion");
538 CString sVersion = regVersion;
539 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Current TGit Version %s\n", (LPCTSTR)sVersion);
540 if (sVersion.Compare(_T(STRPRODUCTVER))==0)
541 return;
542 // we're starting the first time with a new version!
544 LONG lVersion = 0;
545 int pos = sVersion.Find('.');
546 if (pos > 0)
548 lVersion = (_wtol(sVersion.Left(pos)) << 24);
549 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 16);
550 pos = sVersion.Find('.', pos+1);
551 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 8);
553 else
555 pos = sVersion.Find(',');
556 if (pos > 0)
558 lVersion = (_wtol(sVersion.Left(pos)) << 24);
559 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 16);
560 pos = sVersion.Find(',', pos+1);
561 lVersion |= (_wtol(sVersion.Mid(pos + 1)) << 8);
565 // generic cleanup
566 if (CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2", TRUE) != TRUE)
568 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)
569 CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2").removeValue();
572 if (CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2_mask").exists())
574 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)
575 CRegStdDWORD(L"Software\\TortoiseGit\\UseLibgit2_mask").removeValue();
578 CMessageBox::RemoveRegistryKey(L"OldMsysgitVersionWarning");
580 CRegDWORD checkNewerWeekDay = CRegDWORD(L"Software\\TortoiseGit\\CheckNewerWeekDay", 0);
581 if (!checkNewerWeekDay.exists() || lVersion <= 0x01081000)
583 std::random_device rd;
584 std::mt19937 mt(rd());
585 std::uniform_int_distribution<int> dist(0, 6);
586 checkNewerWeekDay = dist(mt);
589 // version specific updates
590 if (lVersion <= 0x02020100)
592 CString username = CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username", L"");
593 CString password = CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password", L"");
594 if (!username.IsEmpty() && !password.IsEmpty())
596 if (CWindowsCredentialsStore::SaveCredential(L"TortoiseGit:SMTP-Credentials", username, password) == 0)
598 CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username").removeValue();
599 CRegString(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password").removeValue();
602 for (const CString& setting : { L"SyncIn", L"SyncOut" })
604 CRegDWORD reg(L"Software\\TortoiseGit\\StatusColumns\\" + setting + L"loglistVersion", 0xff);
605 if ((DWORD)reg == 6)
606 reg.removeValue();
610 if (lVersion <= 0x02010500)
612 // We updated GITSLC_COL_VERSION, but only significant changes were made for GitStatusList
613 // so, smoothly migrate GitLoglistBase settings
614 for (const CString& setting : { L"log", L"Blame", L"Rebase", L"reflog", L"SyncIn", L"SyncOut" })
616 CRegDWORD reg(L"Software\\TortoiseGit\\StatusColumns\\" + setting + L"loglistVersion", 0xff);
617 if ((DWORD)reg == 5)
618 reg = 6;
622 if (lVersion <= 0x01090000)
624 if (CRegDWORD(L"Software\\TortoiseGit\\TGitCacheCheckContent", TRUE) == FALSE)
626 CRegDWORD(L"Software\\TortoiseGit\\TGitCacheCheckContentMaxSize") = 0;
627 CRegDWORD(L"Software\\TortoiseGit\\TGitCacheCheckContent").removeValue();
631 if (lVersion <= 0x01080801)
633 CRegStdDWORD(L"Software\\TortoiseGit\\StatusColumns\\BrowseRefs").removeValue();
634 CRegStdString(L"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order").removeValue();
635 CRegStdString(L"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width").removeValue();
638 if (lVersion <= 0x01080401)
640 if (CRegStdDWORD(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI", FALSE) == TRUE)
641 CRegStdDWORD(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType") = SEND_MAIL_MAPI;
642 CRegStdDWORD(L"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI").removeValue();
645 if (lVersion <= 0x01080202)
647 // upgrade to 1.8.3: force recreation of all diff scripts.
648 CAppUtils::SetupDiffScripts(true, CString());
651 if (lVersion <= 0x01080100)
653 if (CRegStdDWORD(L"Software\\TortoiseGit\\LogTopoOrder", TRUE) == FALSE)
654 CRegStdDWORD(L"Software\\TortoiseGit\\LogOrderBy") = 0;
656 // smoothly migrate broken msysgit path settings
657 CString oldmsysGitSetting = CRegString(REG_MSYSGIT_PATH);
658 oldmsysGitSetting.TrimRight(L'\\');
659 if (oldmsysGitSetting.GetLength() > 4 && CStringUtils::EndsWith(oldmsysGitSetting, L"\\cmd"))
661 CString newPath = oldmsysGitSetting.Mid(0, oldmsysGitSetting.GetLength() - 3) + L"bin";
662 if (PathFileExists(newPath + L"\\git.exe"))
664 CRegString(REG_MSYSGIT_PATH) = newPath;
665 g_Git.m_bInitialized = FALSE;
666 g_Git.CheckMsysGitDir();
671 if (lVersion <= 0x01040000)
673 CRegStdDWORD(L"Software\\TortoiseGit\\OwnerdrawnMenus").removeValue();
676 if (lVersion <= 0x01070600)
678 CoInitialize(nullptr);
679 EnsureGitLibrary();
680 CoUninitialize();
681 CRegStdDWORD(L"Software\\TortoiseGit\\ConvertBase").removeValue();
682 CRegStdDWORD(L"Software\\TortoiseGit\\DiffProps").removeValue();
683 if (CRegStdDWORD(L"Software\\TortoiseGit\\CheckNewer", TRUE) == FALSE)
684 CRegStdDWORD(L"Software\\TortoiseGit\\VersionCheck") = FALSE;
685 CRegStdDWORD(L"Software\\TortoiseGit\\CheckNewer").removeValue();
688 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Setting up diff scripts ...\n");
689 CAppUtils::SetupDiffScripts(false, CString());
691 // set the current version so we don't come here again until the next update!
692 regVersion = _T(STRPRODUCTVER);
695 void CTortoiseProcApp::InitializeJumpList(const CString& appid)
697 // for Win7 : use a custom jump list
698 CoInitialize(nullptr);
699 SetAppID(appid);
700 DeleteJumpList(appid);
701 DoInitializeJumpList(appid);
702 CoUninitialize();
705 void CTortoiseProcApp::DoInitializeJumpList(const CString& appid)
707 ATL::CComPtr<ICustomDestinationList> pcdl;
708 HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER);
709 if (FAILED(hr))
710 return;
712 hr = pcdl->SetAppID(appid);
713 if (FAILED(hr))
714 return;
716 UINT uMaxSlots;
717 ATL::CComPtr<IObjectArray> poaRemoved;
718 hr = pcdl->BeginList(&uMaxSlots, IID_PPV_ARGS(&poaRemoved));
719 if (FAILED(hr))
720 return;
722 ATL::CComPtr<IObjectCollection> poc;
723 hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr, CLSCTX_INPROC_SERVER);
724 if (FAILED(hr))
725 return;
727 CString sTemp = CString(MAKEINTRESOURCE(IDS_MENUSETTINGS));
728 CStringUtils::RemoveAccelerators(sTemp);
730 ATL::CComPtr<IShellLink> psl;
731 hr = CreateShellLink(L"/command:settings", (LPCTSTR)sTemp, 20, &psl);
732 if (SUCCEEDED(hr)) {
733 poc->AddObject(psl);
735 sTemp = CString(MAKEINTRESOURCE(IDS_MENUHELP));
736 CStringUtils::RemoveAccelerators(sTemp);
737 psl.Release(); // Need to release the object before calling operator&()
738 hr = CreateShellLink(L"/command:help", (LPCTSTR)sTemp, 19, &psl);
739 if (SUCCEEDED(hr)) {
740 poc->AddObject(psl);
743 ATL::CComPtr<IObjectArray> poa;
744 hr = poc.QueryInterface(&poa);
745 if (SUCCEEDED(hr)) {
746 pcdl->AppendCategory((LPCTSTR)CString(MAKEINTRESOURCE(IDS_PROC_TASKS)), poa);
747 pcdl->CommitList();
751 int CTortoiseProcApp::ExitInstance()
753 SYS_IMAGE_LIST().Cleanup();
754 Gdiplus::GdiplusShutdown(m_gdiplusToken);
756 CWinAppEx::ExitInstance();
757 if (retSuccess)
758 return 0;
759 return -1;
762 void CTortoiseProcApp::CheckForNewerVersion()
764 // check for newer versions
765 if (CRegDWORD(L"Software\\TortoiseGit\\VersionCheck", TRUE) != FALSE)
767 time_t now;
768 struct tm ptm;
770 time(&now);
771 if ((now != 0) && (localtime_s(&ptm, &now)==0))
773 #if PREVIEW
774 // Check daily for new preview releases
775 CRegDWORD oldday = CRegDWORD(L"Software\\TortoiseGit\\CheckNewerDay", (DWORD)-1);
776 if (((DWORD)oldday) == -1)
777 oldday = ptm.tm_yday;
778 else
780 if ((DWORD)oldday != (DWORD)ptm.tm_yday)
782 oldday = ptm.tm_yday;
783 #else
784 int week = 0;
785 // we don't calculate the real 'week of the year' here
786 // because just to decide if we should check for an update
787 // that's not needed.
788 week = (ptm.tm_yday + CRegDWORD(L"Software\\TortoiseGit\\CheckNewerWeekDay", 0)) / 7;
790 CRegDWORD oldweek = CRegDWORD(L"Software\\TortoiseGit\\CheckNewerWeek", (DWORD)-1);
791 if (((DWORD)oldweek) == -1)
792 oldweek = week; // first start of TortoiseProc, no update check needed
793 else
795 if ((DWORD)week != oldweek)
797 oldweek = week;
798 #endif
799 CAppUtils::RunTortoiseGitProc(L"/command:updatecheck", false, false);