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.
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()
66 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Constructor\n");
68 CCrashReport::Instance().AddUserInfoToReport(L
"CommandLine", GetCommandLine());
72 CGit::SetGit2CredentialCallback(CAppUtils::Git2GetUserPassword
);
73 CGit::SetGit2CertificateCheckCertificate(CAppUtils::Git2CertificateCheck
);
74 m_bLoadUserToolbars
= FALSE
;
77 m_gdiplusToken
= NULL
;
78 #if defined (_WIN64) && _MSC_VER == 1800
83 CTortoiseProcApp::~CTortoiseProcApp()
86 git_libgit2_shutdown();
89 // The one and only CTortoiseProcApp object
90 CTortoiseProcApp theApp
;
92 CString g_sGroupingUUID
;
93 CString g_sGroupingIcon
;
94 bool g_bGroupingRemoveIcon
= false;
97 #if ENABLE_CRASHHANLDER
98 CCrashReportTGit
crasher(L
"TortoiseGit " _T(APP_X64_STRING
), TGIT_VERMAJOR
, TGIT_VERMINOR
, TGIT_VERMICRO
, TGIT_VERBUILD
, TGIT_VERDATE
);
101 // CTortoiseProcApp initialization
103 BOOL
CTortoiseProcApp::InitInstance()
105 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": InitInstance\n");
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);
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
);
130 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Load Language DLL %s\n", (LPCTSTR
)langDll
);
131 AfxSetResourceHandle(hInst
);
136 DWORD lid
= SUBLANGID(langId
);
139 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
143 } while (langId
!= 0);
146 langStr
.Format(L
"%ld", langId
);
147 CCrashReport::Instance().AddUserInfoToReport(L
"LanguageID", langStr
);
149 TCHAR buf
[6] = { 0 };
150 wcscpy_s(buf
, L
"en");
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
)))
164 sHelppath
.Replace(L
"_en", sLang
);
165 if (PathFileExists(sHelppath
))
167 free((void*)m_pszHelpFilePath
);
168 m_pszHelpFilePath
=_wcsdup(sHelppath
);
172 sHelppath
.Replace(sLang
, L
"_en");
173 if (GetLocaleInfo(MAKELCID(langId
, SORT_DEFAULT
), LOCALE_SISO3166CTRYNAME
, buf
, _countof(buf
)))
177 sHelppath
.Replace(L
"_en", sLang
);
178 if (PathFileExists(sHelppath
))
180 free((void*)m_pszHelpFilePath
);
181 m_pszHelpFilePath
=_wcsdup(sHelppath
);
185 sHelppath
.Replace(sLang
, L
"_en");
187 DWORD lid
= SUBLANGID(langId
);
190 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
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
);
212 AfxEnableControlContainer();
214 CWinAppEx::InitInstance();
215 SetRegistryKey(L
"TortoiseGit");
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");
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
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);
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
);
258 ShellExecute(hWndExplorer
, L
"open", GIT_FOR_WINDOWS_URL
, nullptr, nullptr, SW_SHOW
);
261 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), 2);
266 if (!CConfigureGitExe::CheckGitVersion(hWndExplorer
))
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('?');
291 url
= url
.Left(questioMark
);
293 else if (CStringUtils::StartsWith(url
, L
"smartgit://cloneRepo/"))
294 url
= url
.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
297 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
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
);
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...
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
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
"\\\\");
354 LPWSTR
*szArglist
= CommandLineToArgvW(cmdLine
, &nArgs
);
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
);
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);
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()))
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
))
427 // implemented differently to TortoiseSVN atm
433 if (GitAdminDir::HasAdminDir(g_Git
.m_CurrentDir
, true, &wcroot
))
436 CStringA
wcRootA(wcroot
+ CPathUtils::GetAppDirectory());
437 if (!git_odb_hash(&oid
, wcRootA
.MakeLower(), wcRootA
.GetLength(), GIT_OBJ_BLOB
))
440 git_oid_tostr(CStrBufA(hash
, GIT_OID_HEXSZ
, CStrBufA::SET_LENGTH
), GIT_OID_HEXSZ
+ 1, &oid
);
441 g_sGroupingUUID
= hash
;
443 ProjectProperties pp
;
445 CString icon
= pp
.sIcon
;
446 icon
.Replace('/', '\\');
448 g_bGroupingRemoveIcon
= true;
449 g_sGroupingIcon
= icon
;
455 CString sAppID
= GetTaskIDPerUUID(g_sGroupingUUID
).c_str();
456 InitializeJumpList(sAppID
);
457 EnsureGitLibrary(false);
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");
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
)));
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());
491 // execute the requested command
492 CommandServer server
;
493 Command
* cmd
= server
.GetCommand(parser
.GetVal(L
"command"));
496 cmd
->SetExplorerHwnd(hWndExplorer
);
498 cmd
->SetParser(parser
);
499 cmd
->SetPaths(pathList
, cmdLinePath
);
501 retSuccess
= cmd
->Execute();
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());
514 CDirFileEnum
finder(path
.get());
516 ::GetSystemTimeAsFileTime(&systime_
);
517 __int64 systime
= (((_int64
)systime_
.dwHighDateTime
)<<32) | ((__int64
)systime_
.dwLowDateTime
);
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
);
534 ::RemoveDirectory(filepath
);
536 ::DeleteFile(filepath
);
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.
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)
560 // we're starting the first time with a new version!
563 int pos
= sVersion
.Find('.');
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);
573 pos
= sVersion
.Find(',');
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);
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);
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);
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);
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);
730 DeleteJumpList(appid
);
731 DoInitializeJumpList(appid
);
735 void CTortoiseProcApp::DoInitializeJumpList(const CString
& appid
)
737 ATL::CComPtr
<ICustomDestinationList
> pcdl
;
738 HRESULT hr
= pcdl
.CoCreateInstance(CLSID_DestinationList
, nullptr, CLSCTX_INPROC_SERVER
);
742 hr
= pcdl
->SetAppID(appid
);
747 ATL::CComPtr
<IObjectArray
> poaRemoved
;
748 hr
= pcdl
->BeginList(&uMaxSlots
, IID_PPV_ARGS(&poaRemoved
));
752 ATL::CComPtr
<IObjectCollection
> poc
;
753 hr
= poc
.CoCreateInstance(CLSID_EnumerableObjectCollection
, nullptr, CLSCTX_INPROC_SERVER
);
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
);
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
);
773 ATL::CComPtr
<IObjectArray
> poa
;
774 hr
= poc
.QueryInterface(&poa
);
776 pcdl
->AppendCategory((LPCTSTR
)CString(MAKEINTRESOURCE(IDS_PROC_TASKS
)), poa
);
781 int CTortoiseProcApp::ExitInstance()
783 SYS_IMAGE_LIST().Cleanup();
784 Gdiplus::GdiplusShutdown(m_gdiplusToken
);
786 CWinAppEx::ExitInstance();
792 void CTortoiseProcApp::CheckForNewerVersion()
794 // check for newer versions
795 if (CRegDWORD(L
"Software\\TortoiseGit\\VersionCheck", TRUE
) != FALSE
)
801 if ((now
!= 0) && (localtime_s(&ptm
, &now
)==0))
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
;
810 if ((DWORD
)oldday
!= (DWORD
)ptm
.tm_yday
)
812 oldday
= ptm
.tm_yday
;
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
825 if ((DWORD
)week
!= oldweek
)
829 CAppUtils::RunTortoiseGitProc(L
"/command:updatecheck", false, false);