Do not use GitAdminDir objects
[TortoiseGit.git] / src / TortoiseProc / TortoiseProc.cpp
blob25c7079bd675e29d7716961737ba4db29e5de650
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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 "Libraries.h"
41 #include "TaskbarUUID.h"
42 #include "ProjectProperties.h"
43 #include "HistoryCombo.h"
44 #include "gitindex.h"
45 #include <math.h>
47 #define STRUCT_IOVEC_DEFINED
49 #ifdef _DEBUG
50 #define new DEBUG_NEW
51 #endif
53 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
55 BEGIN_MESSAGE_MAP(CTortoiseProcApp, CWinAppEx)
56 ON_COMMAND(ID_HELP, CWinAppEx::OnHelp)
57 END_MESSAGE_MAP()
59 //////////////////////////////////////////////////////////////////////////
61 CTortoiseProcApp::CTortoiseProcApp()
63 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Constructor\n"));
64 SetDllDirectory(L"");
65 // prevent from inheriting %GIT_DIR% from parent process by resetting it,
66 // use MSVC function instead of Windows API because MSVC runtime caches environment variables
67 _tputenv(_T("GIT_DIR="));
68 CCrashReport::Instance().AddUserInfoToReport(L"CommandLine", GetCommandLine());
69 EnableHtmlHelp();
70 SYS_IMAGE_LIST();
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 SYS_IMAGE_LIST().Cleanup();
88 git_libgit2_shutdown();
91 // The one and only CTortoiseProcApp object
92 CTortoiseProcApp theApp;
93 CString sOrigCWD;
94 CString g_sGroupingUUID;
95 CString g_sGroupingIcon;
96 bool g_bGroupingRemoveIcon = false;
97 HWND hWndExplorer;
98 CGitIndexFileMap g_IndexFileMap;
100 #if ENABLE_CRASHHANLDER
101 CCrashReportTGit crasher(L"TortoiseGit " _T(APP_X64_STRING), TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE);
102 #endif
104 // CTortoiseProcApp initialization
106 BOOL CTortoiseProcApp::InitInstance()
108 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": InitInstance\n"));
109 CheckUpgrade();
110 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
111 CMFCButton::EnableWindowsTheming();
112 CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
114 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
115 Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL);
117 //set the resource dll for the required language
118 CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
119 long langId = loc;
121 CString langStr;
122 langStr.Format(_T("%ld"), langId);
123 CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr);
125 CString langDll;
126 CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory());
127 langpath += "Languages";
130 langDll.Format(_T("%sLanguages\\TortoiseProc%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);
132 CString sVer = _T(STRPRODUCTVER);
133 CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
134 if (sFileVer == sVer)
136 HINSTANCE hInst = LoadLibrary(langDll);
137 if (hInst != NULL)
139 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Load Language DLL %s\n"), langDll);
140 AfxSetResourceHandle(hInst);
141 break;
145 DWORD lid = SUBLANGID(langId);
146 lid--;
147 if (lid > 0)
149 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
151 else
152 langId = 0;
154 } while (langId != 0);
155 TCHAR buf[6] = { 0 };
156 _tcscpy_s(buf, _T("en"));
157 langId = loc;
158 // MFC uses a help file with the same name as the application by default,
159 // which means we have to change that default to our language specific help files
160 CString sHelppath = CPathUtils::GetAppDirectory() + _T("TortoiseGit_en.chm");
161 free((void*)m_pszHelpFilePath);
162 m_pszHelpFilePath=_tcsdup(sHelppath);
163 sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGit_en.chm");
166 CString sLang = _T("_");
167 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf)))
169 sLang += buf;
170 sHelppath.Replace(_T("_en"), sLang);
171 if (PathFileExists(sHelppath))
173 free((void*)m_pszHelpFilePath);
174 m_pszHelpFilePath=_tcsdup(sHelppath);
175 break;
178 sHelppath.Replace(sLang, _T("_en"));
179 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf)))
181 sLang += _T("_");
182 sLang += buf;
183 sHelppath.Replace(_T("_en"), sLang);
184 if (PathFileExists(sHelppath))
186 free((void*)m_pszHelpFilePath);
187 m_pszHelpFilePath=_tcsdup(sHelppath);
188 break;
191 sHelppath.Replace(sLang, _T("_en"));
193 DWORD lid = SUBLANGID(langId);
194 lid--;
195 if (lid > 0)
197 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
199 else
200 langId = 0;
201 } while (langId);
202 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Set Help Filename %s\n"), m_pszHelpFilePath);
203 setlocale(LC_ALL, "");
205 if (!g_Git.CheckMsysGitDir())
207 UINT ret = CMessageBox::Show(NULL, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON);
208 if(ret == 2)
210 ShellExecute(NULL, _T("open"), _T("https://msysgit.github.io/"), NULL, NULL, SW_SHOW);
212 else if(ret == 1)
214 // open settings dialog
215 CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROC_SETTINGS_TITLE)), new CSetMainPage(), this->GetMainWnd()).DoModal();
217 return FALSE;
219 if (CAppUtils::GetMsysgitVersion() < 0x01090500)
221 int ret = CMessageBox::ShowCheck(NULL, IDS_PROC_OLDMSYSGIT, IDS_APPNAME, 1, IDI_EXCLAMATION, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON, IDS_IGNOREBUTTON, _T("OldMsysgitVersionWarning"), IDS_PROC_NOTSHOWAGAINIGNORE);
222 if (ret == 1)
224 CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
225 ShellExecute(NULL, _T("open"), _T("https://msysgit.github.io/"), NULL, NULL, SW_SHOW);
226 return FALSE;
228 else if (ret == 2)
230 CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
231 return FALSE;
236 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Registering Crash Report ...\n"));
237 CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir);
238 CString versionString;
239 versionString.Format(_T("%d"), CGit::ms_LastMsysGitVersion);
240 CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString);
243 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Initializing UI components ...\n"));
244 // InitCommonControls() is required on Windows XP if an application
245 // manifest specifies use of ComCtl32.dll version 6 or later to enable
246 // visual styles. Otherwise, any window creation will fail.
248 INITCOMMONCONTROLSEX used = {
249 sizeof(INITCOMMONCONTROLSEX),
250 ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES |
251 ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES |
252 ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
253 ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS |
254 ICC_USEREX_CLASSES | ICC_WIN95_CLASSES
256 InitCommonControlsEx(&used);
257 AfxOleInit();
258 AfxEnableControlContainer();
259 AfxInitRichEdit5();
260 CWinAppEx::InitInstance();
261 SetRegistryKey(_T("TortoiseGit"));
262 AfxGetApp()->m_pszProfileName = _tcsdup(_T("TortoiseProc")); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
264 CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);
266 hWndExplorer = NULL;
267 CString sVal = parser.GetVal(_T("hwnd"));
268 if (!sVal.IsEmpty())
269 hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);
271 while (GetParent(hWndExplorer)!=NULL)
272 hWndExplorer = GetParent(hWndExplorer);
273 if (!IsWindow(hWndExplorer))
275 hWndExplorer = NULL;
278 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
279 // in a message box
280 if (CRegDWORD(_T("Software\\TortoiseGit\\Debug"), FALSE)==TRUE)
281 AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);
283 if (parser.HasKey(_T("urlhandler")))
285 CString url = parser.GetVal(_T("urlhandler"));
286 if (url.Find(_T("tgit://clone/")) == 0)
288 url = url.Mid(13); // 21 = "tgit://clone/".GetLength()
290 else if (url.Find(_T("github-windows://openRepo/")) == 0)
292 url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
293 int questioMark = url.Find('?');
294 if (questioMark > 0)
295 url = url.Left(questioMark);
297 else if (url.Find(_T("smartgit://cloneRepo/")) == 0)
299 url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
301 else
303 CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
304 return FALSE;
306 CString newCmd;
307 newCmd.Format(_T("/command:clone /url:\"%s\" /hasurlhandler"), url);
308 parser = CCmdLineParser(newCmd);
311 if ( parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile")))
313 CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
314 return FALSE;
317 CTGitPath cmdLinePath;
318 CTGitPathList pathList;
319 if (g_sGroupingUUID.IsEmpty())
320 g_sGroupingUUID = parser.GetVal(L"groupuuid");
321 if ( parser.HasKey(_T("pathfile")) )
324 CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile")));
326 cmdLinePath.SetFromUnknown(sPathfileArgument);
327 if (pathList.LoadFromFile(cmdLinePath)==false)
328 return FALSE; // no path specified!
329 if ( parser.HasKey(_T("deletepathfile")) )
331 // We can delete the temporary path file, now that we've loaded it
332 ::DeleteFile(cmdLinePath.GetWinPath());
334 // This was a path to a temporary file - it's got no meaning now, and
335 // anybody who uses it again is in for a problem...
336 cmdLinePath.Reset();
339 else
342 CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path")));
343 if (parser.HasKey(_T("expaths")))
345 // an /expaths param means we're started via the buttons in our Win7 library
346 // and that means the value of /expaths is the current directory, and
347 // the selected paths are then added as additional parameters but without a key, only a value
349 // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
350 // we have to escape the backslashes first. Since we're only dealing with paths here, that's
351 // a save bet.
352 // Without this, a command line like:
353 // /command:commit /expaths:"D:\" "D:\Utils"
354 // would fail because the "D:\" is treated as the backslash being the escape char for the quotation
355 // mark and we'd end up with:
356 // argv[1] = /command:commit
357 // argv[2] = /expaths:D:" D:\Utils
358 // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
359 CString cmdLine = GetCommandLineW();
360 cmdLine.Replace(L"\\", L"\\\\");
361 int nArgs = 0;
362 LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs);
363 if (szArglist)
365 // argument 0 is the process path, so start with 1
366 for (int i = 1; i < nArgs; ++i)
368 if (szArglist[i][0] != '/')
370 if (!sPathArgument.IsEmpty())
371 sPathArgument += '*';
372 sPathArgument += szArglist[i];
375 sPathArgument.Replace(L"\\\\", L"\\");
377 LocalFree(szArglist);
379 if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
381 CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
382 return FALSE;
384 int asterisk = sPathArgument.Find('*');
385 cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
386 pathList.LoadFromAsteriskSeparatedString(sPathArgument);
389 if (pathList.IsEmpty()) {
390 pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
393 // Set CWD to temporary dir, and restore it later
395 DWORD len = GetCurrentDirectory(0, NULL);
396 if (len)
398 std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);
399 if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
401 sOrigCWD = originalCurrentDirectory.get();
402 sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
405 TCHAR pathbuf[MAX_PATH] = {0};
406 GetTortoiseGitTempPath(MAX_PATH, pathbuf);
407 SetCurrentDirectory(pathbuf);
410 CheckForNewerVersion();
412 CAutoGeneralHandle TGitMutex = ::CreateMutex(NULL, FALSE, _T("TortoiseGitProc.exe"));
413 if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(_T("submodule")) == TRUE))
415 for (int i = 0; i < pathList.GetCount(); ++i)
416 if(g_Git.SetCurrentDir(pathList[i].GetWinPath()))
417 break;
420 if(!g_Git.m_CurrentDir.IsEmpty())
422 sOrigCWD = g_Git.m_CurrentDir;
423 SetCurrentDirectory(g_Git.m_CurrentDir);
426 if (g_sGroupingUUID.IsEmpty())
428 CRegStdDWORD groupSetting = CRegStdDWORD(_T("Software\\TortoiseGit\\GroupTaskbarIconsPerRepo"), 3);
429 switch (DWORD(groupSetting))
431 case 1:
432 case 2:
433 // implemented differently to TortoiseSVN atm
434 break;
435 case 3:
436 case 4:
438 CString wcroot;
439 if (GitAdminDir::HasAdminDir(g_Git.m_CurrentDir, true, &wcroot))
441 git_oid oid;
442 CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory());
443 if (!git_odb_hash(&oid, wcRootA, wcRootA.GetLength(), GIT_OBJ_BLOB))
445 CStringA hash;
446 git_oid_tostr(hash.GetBufferSetLength(GIT_OID_HEXSZ + 1), GIT_OID_HEXSZ + 1, &oid);
447 hash.ReleaseBuffer();
448 g_sGroupingUUID = hash;
450 ProjectProperties pp;
451 pp.ReadProps();
452 CString icon = pp.sIcon;
453 icon.Replace('/', '\\');
454 if (icon.IsEmpty())
455 g_bGroupingRemoveIcon = true;
456 g_sGroupingIcon = icon;
462 CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str();
463 InitializeJumpList(sAppID);
464 EnsureGitLibrary(false);
467 CString err;
470 // requires CWD to be set
471 CGit::m_LogEncode = CAppUtils::GetLogOutputEncode();
473 // make sure all config files are read in order to check that none contains an error
474 g_Git.GetConfigValue(_T("doesnot.exist"));
476 catch (char* msg)
478 err = CString(msg);
481 if (!err.IsEmpty())
483 UINT choice = CMessageBox::Show(hWndExplorer, err, _T("TortoiseGit"), 1, IDI_ERROR, CString(MAKEINTRESOURCE(IDS_PROC_EDITLOCALGITCONFIG)), CString(MAKEINTRESOURCE(IDS_PROC_EDITGLOBALGITCONFIG)), CString(MAKEINTRESOURCE(IDS_ABORTBUTTON)));
484 if (choice == 1)
486 // open the config file with alternative editor
487 CAppUtils::LaunchAlternativeEditor(g_Git.GetGitLocalConfig());
489 else if (choice == 2)
491 // open the global config file with alternative editor
492 CAppUtils::LaunchAlternativeEditor(g_Git.GetGitGlobalConfig());
494 return FALSE;
498 // execute the requested command
499 CommandServer server;
500 Command * cmd = server.GetCommand(parser.GetVal(_T("command")));
501 if (cmd)
503 cmd->SetExplorerHwnd(hWndExplorer);
505 cmd->SetParser(parser);
506 cmd->SetPaths(pathList, cmdLinePath);
508 retSuccess = cmd->Execute();
509 delete cmd;
512 // Look for temporary files left around by TortoiseSVN and
513 // remove them. But only delete 'old' files because some
514 // apps might still be needing the recent ones.
516 DWORD len = GetTortoiseGitTempPath(0, NULL);
517 std::unique_ptr<TCHAR[]> path(new TCHAR[len + 100]);
518 len = GetTortoiseGitTempPath (len + 100, path.get());
519 if (len != 0)
521 CDirFileEnum finder(path.get());
522 FILETIME systime_;
523 ::GetSystemTimeAsFileTime(&systime_);
524 __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime);
525 bool isDir;
526 CString filepath;
527 while (finder.NextFile(filepath, &isDir))
529 HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : NULL, NULL);
530 if (hFile != INVALID_HANDLE_VALUE)
532 FILETIME createtime_;
533 if (::GetFileTime(hFile, &createtime_, NULL, NULL))
535 ::CloseHandle(hFile);
536 __int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime);
537 if ((createtime + 864000000000) < systime) //only delete files older than a day
539 ::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
540 if (isDir)
541 ::RemoveDirectory(filepath);
542 else
543 ::DeleteFile(filepath);
546 else
547 ::CloseHandle(hFile);
553 // Since the dialog has been closed, return FALSE so that we exit the
554 // application, rather than start the application's message pump.
555 return FALSE;
558 void CTortoiseProcApp::CheckUpgrade()
560 CRegString regVersion = CRegString(_T("Software\\TortoiseGit\\CurrentVersion"));
561 CString sVersion = regVersion;
562 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Current TGit Version %s\n"), sVersion);
563 if (sVersion.Compare(_T(STRPRODUCTVER))==0)
564 return;
565 // we're starting the first time with a new version!
567 LONG lVersion = 0;
568 int pos = sVersion.Find('.');
569 if (pos > 0)
571 lVersion = (_ttol(sVersion.Left(pos))<<24);
572 lVersion |= (_ttol(sVersion.Mid(pos+1))<<16);
573 pos = sVersion.Find('.', pos+1);
574 lVersion |= (_ttol(sVersion.Mid(pos+1))<<8);
576 else
578 pos = sVersion.Find(',');
579 if (pos > 0)
581 lVersion = (_ttol(sVersion.Left(pos))<<24);
582 lVersion |= (_ttol(sVersion.Mid(pos+1))<<16);
583 pos = sVersion.Find(',', pos+1);
584 lVersion |= (_ttol(sVersion.Mid(pos+1))<<8);
588 // generic cleanup
589 if (CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2"), TRUE) != TRUE)
591 if (CMessageBox::Show(nullptr, _T("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)?"), _T("TortoiseGit"), MB_ICONQUESTION | MB_YESNO) == IDYES)
592 CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2")).removeValue();
595 if (CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2_mask")).exists())
597 if (CMessageBox::Show(nullptr, _T("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)?"), _T("TortoiseGit"), MB_ICONQUESTION | MB_YESNO) == IDYES)
598 CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2_mask")).removeValue();
601 CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning"));
603 srand((unsigned)time(0));
604 CRegDWORD checkNewerWeekDay = CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerWeekDay"), 0);
605 checkNewerWeekDay = rand() % 7;
607 // version specific updates
608 if (lVersion <= 0x01080802)
610 CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\CleanTypeDlgWindowPlacement")).removeValue();
613 if (lVersion <= 0x01080801)
615 CRegStdDWORD(_T("Software\\TortoiseGit\\StatusColumns\\BrowseRefs")).removeValue();
616 CRegStdString(_T("Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order")).removeValue();
617 CRegStdString(_T("Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width")).removeValue();
620 if (lVersion <= 0x01080401)
622 if (CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI"), FALSE) == TRUE)
623 CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType")) = 1;
624 CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI")).removeValue();
627 if (lVersion <= 0x01080202)
629 // upgrade to 1.8.3: force recreation of all diff scripts.
630 CAppUtils::SetupDiffScripts(true, CString());
633 if (lVersion <= 0x01080100)
635 if (CRegStdDWORD(_T("Software\\TortoiseGit\\LogTopoOrder"), TRUE) == FALSE)
636 CRegStdDWORD(_T("Software\\TortoiseGit\\LogOrderBy")) = 0;
638 // smoothly migrate broken msysgit path settings
639 CString oldmsysGitSetting = CRegString(REG_MSYSGIT_PATH);
640 oldmsysGitSetting.TrimRight(_T("\\"));
641 CString right = oldmsysGitSetting.Right(4);
642 if (oldmsysGitSetting.GetLength() > 4 && oldmsysGitSetting.Right(4) == _T("\\cmd"))
644 CString newPath = oldmsysGitSetting.Mid(0, oldmsysGitSetting.GetLength() - 3) + _T("bin");
645 if (PathFileExists(newPath + _T("\\git.exe")))
647 CRegString(REG_MSYSGIT_PATH) = newPath;
648 g_Git.m_bInitialized = FALSE;
649 g_Git.CheckMsysGitDir();
654 if (lVersion <= 0x01040000)
656 CRegStdDWORD(_T("Software\\TortoiseGit\\OwnerdrawnMenus")).removeValue();
659 if (lVersion <= 0x01070600)
661 CoInitialize(NULL);
662 EnsureGitLibrary();
663 CoUninitialize();
664 CRegStdDWORD(_T("Software\\TortoiseGit\\ConvertBase")).removeValue();
665 CRegStdDWORD(_T("Software\\TortoiseGit\\DiffProps")).removeValue();
666 if (CRegStdDWORD(_T("Software\\TortoiseGit\\CheckNewer"), TRUE) == FALSE)
667 CRegStdDWORD(_T("Software\\TortoiseGit\\VersionCheck")) = FALSE;
668 CRegStdDWORD(_T("Software\\TortoiseGit\\CheckNewer")).removeValue();
671 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Setting up diff scripts ...\n"));
672 CAppUtils::SetupDiffScripts(false, CString());
674 // set the current version so we don't come here again until the next update!
675 regVersion = _T(STRPRODUCTVER);
678 void CTortoiseProcApp::InitializeJumpList(const CString& appid)
680 // for Win7 : use a custom jump list
681 CoInitialize(NULL);
682 SetAppID(appid);
683 DeleteJumpList(appid);
684 DoInitializeJumpList(appid);
685 CoUninitialize();
688 void CTortoiseProcApp::DoInitializeJumpList(const CString& appid)
690 ATL::CComPtr<ICustomDestinationList> pcdl;
691 HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER);
692 if (FAILED(hr))
693 return;
695 hr = pcdl->SetAppID(appid);
696 if (FAILED(hr))
697 return;
699 UINT uMaxSlots;
700 ATL::CComPtr<IObjectArray> poaRemoved;
701 hr = pcdl->BeginList(&uMaxSlots, IID_PPV_ARGS(&poaRemoved));
702 if (FAILED(hr))
703 return;
705 ATL::CComPtr<IObjectCollection> poc;
706 hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER);
707 if (FAILED(hr))
708 return;
710 CString sTemp = CString(MAKEINTRESOURCE(IDS_MENUSETTINGS));
711 CStringUtils::RemoveAccelerators(sTemp);
713 ATL::CComPtr<IShellLink> psl;
714 hr = CreateShellLink(_T("/command:settings"), (LPCTSTR)sTemp, 20, &psl);
715 if (SUCCEEDED(hr)) {
716 poc->AddObject(psl);
718 sTemp = CString(MAKEINTRESOURCE(IDS_MENUHELP));
719 CStringUtils::RemoveAccelerators(sTemp);
720 psl.Release(); // Need to release the object before calling operator&()
721 hr = CreateShellLink(_T("/command:help"), (LPCTSTR)sTemp, 19, &psl);
722 if (SUCCEEDED(hr)) {
723 poc->AddObject(psl);
726 ATL::CComPtr<IObjectArray> poa;
727 hr = poc.QueryInterface(&poa);
728 if (SUCCEEDED(hr)) {
729 pcdl->AppendCategory((LPCTSTR)CString(MAKEINTRESOURCE(IDS_PROC_TASKS)), poa);
730 pcdl->CommitList();
734 int CTortoiseProcApp::ExitInstance()
736 Gdiplus::GdiplusShutdown(m_gdiplusToken);
738 CWinAppEx::ExitInstance();
739 if (retSuccess)
740 return 0;
741 return -1;
744 void CTortoiseProcApp::CheckForNewerVersion()
746 // check for newer versions
747 if (CRegDWORD(_T("Software\\TortoiseGit\\VersionCheck"), TRUE) != FALSE)
749 time_t now;
750 struct tm ptm;
752 time(&now);
753 if ((now != 0) && (localtime_s(&ptm, &now)==0))
755 #if PREVIEW
756 // Check daily for new preview releases
757 CRegDWORD oldday = CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerDay"), (DWORD)-1);
758 if (((DWORD)oldday) == -1)
759 oldday = ptm.tm_yday;
760 else
762 if ((DWORD)oldday != (DWORD)ptm.tm_yday)
764 oldday = ptm.tm_yday;
765 #else
766 int week = 0;
767 // we don't calculate the real 'week of the year' here
768 // because just to decide if we should check for an update
769 // that's not needed.
770 week = (ptm.tm_yday + CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerWeekDay"), 0)) / 7;
772 CRegDWORD oldweek = CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerWeek"), (DWORD)-1);
773 if (((DWORD)oldweek) == -1)
774 oldweek = week; // first start of TortoiseProc, no update check needed
775 else
777 if ((DWORD)week != oldweek)
779 oldweek = week;
780 #endif
781 CAppUtils::RunTortoiseGitProc(_T("/command:updatecheck"), false, false);