1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2023 - 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 "GitAdminDir.h"
33 #include "SmartHandle.h"
34 #include "Commands\Command.h"
35 #include "../version.h"
36 #include "I18NHelper.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"
45 #include "WindowsCredentialsStore.h"
46 #include "FirstStartWizard.h"
47 #include "AnimationManager.h"
48 #include "../TGitCache/CacheInterface.h"
49 #include "VersioncheckParser.h"
52 #define STRUCT_IOVEC_DEFINED
58 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
60 BEGIN_MESSAGE_MAP(CTortoiseProcApp
, CWinAppEx
)
61 ON_COMMAND(ID_HELP
, CWinAppEx::OnHelp
)
64 //////////////////////////////////////////////////////////////////////////
66 CTortoiseProcApp::CTortoiseProcApp()
68 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Constructor\n");
70 CCrashReport::Instance().AddUserInfoToReport(L
"CommandLine", GetCommandLine());
71 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": CommandLine: %s\n", GetCommandLine());
75 CGit::SetGit2CredentialCallback(CAppUtils::Git2GetUserPassword
);
76 CGit::SetGit2CertificateCheckCertificate(CAppUtils::Git2CertificateCheck
);
77 m_bLoadUserToolbars
= FALSE
;
81 CTortoiseProcApp::~CTortoiseProcApp()
84 git_libgit2_shutdown();
87 // The one and only CTortoiseProcApp object
88 CTortoiseProcApp theApp
;
90 CString g_sGroupingUUID
;
91 CString g_sGroupingIcon
;
92 bool g_bGroupingRemoveIcon
= false;
93 HWND
GetExplorerHWND()
95 return theApp
.GetExplorerHWND();
98 #if ENABLE_CRASHHANLDER && !_M_ARM64
99 CCrashReportTGit
crasher(L
"TortoiseGit " _T(APP_X64_STRING
), TGIT_VERMAJOR
, TGIT_VERMINOR
, TGIT_VERMICRO
, TGIT_VERBUILD
, TGIT_VERDATE
);
102 // CTortoiseProcApp initialization
104 BOOL
CTortoiseProcApp::InitInstance()
106 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": InitInstance\n");
108 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
109 CMFCButton::EnableWindowsTheming();
111 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
112 Gdiplus::GdiplusStartup(&m_gdiplusToken
, &gdiplusStartupInput
, nullptr);
114 //set the resource dll for the required language
115 CRegDWORD loc
= CRegDWORD(L
"Software\\TortoiseGit\\LanguageID", 1033);
118 CStringA langpath
= CStringA(CPathUtils::GetAppParentDirectory());
119 langpath
+= "Languages";
122 langDll
.Format(L
"%sLanguages\\TortoiseProc%ld.dll", static_cast<LPCWSTR
>(CPathUtils::GetAppParentDirectory()), langId
);
124 if (CI18NHelper::DoVersionStringsMatch(CPathUtils::GetVersionFromFile(langDll
), _T(STRPRODUCTVER
)))
126 HINSTANCE hInst
= LoadLibrary(langDll
);
129 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Load Language DLL %s\n", static_cast<LPCWSTR
>(langDll
));
130 AfxSetResourceHandle(hInst
);
135 DWORD lid
= SUBLANGID(langId
);
138 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
142 } while (langId
!= 0);
145 langStr
.Format(L
"%ld", langId
);
146 CCrashReport::Instance().AddUserInfoToReport(L
"LanguageID", langStr
);
148 free((void*)m_pszHelpFilePath
);
149 m_pszHelpFilePath
= _wcsdup(CPathUtils::GetAppDirectory() + L
"TortoiseGit_en.chm");
150 setlocale(LC_ALL
, "");
152 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Initializing UI components ...\n");
153 // InitCommonControls() is required on Windows XP if an application
154 // manifest specifies use of ComCtl32.dll version 6 or later to enable
155 // visual styles. Otherwise, any window creation will fail.
157 INITCOMMONCONTROLSEX used
= {
158 sizeof(INITCOMMONCONTROLSEX
),
159 ICC_ANIMATE_CLASS
| ICC_BAR_CLASSES
| ICC_COOL_CLASSES
| ICC_DATE_CLASSES
|
160 ICC_HOTKEY_CLASS
| ICC_INTERNET_CLASSES
| ICC_LISTVIEW_CLASSES
|
161 ICC_NATIVEFNTCTL_CLASS
| ICC_PAGESCROLLER_CLASS
| ICC_PROGRESS_CLASS
|
162 ICC_TAB_CLASSES
| ICC_TREEVIEW_CLASSES
| ICC_UPDOWN_CLASS
|
163 ICC_USEREX_CLASSES
| ICC_WIN95_CLASSES
165 InitCommonControlsEx(&used
);
167 AfxEnableControlContainer();
169 CWinAppEx::InitInstance();
170 SetRegistryKey(L
"TortoiseGit");
172 CHistoryCombo::m_nGitIconIndex
= SYS_IMAGE_LIST().AddIcon(CCommonAppUtils::LoadIconEx(IDI_GITCONFIG
, 0, 0));
173 AfxGetApp()->m_pszProfileName
= _wcsdup(L
"TortoiseProc"); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
175 CCmdLineParser
parser(AfxGetApp()->m_lpCmdLine
);
177 hWndExplorer
= nullptr;
178 CString sVal
= parser
.GetVal(L
"hwnd");
180 hWndExplorer
= reinterpret_cast<HWND
>(_wcstoui64(sVal
, nullptr, 16));
182 while (GetParent(hWndExplorer
))
183 hWndExplorer
= GetParent(hWndExplorer
);
184 if (!IsWindow(hWndExplorer
))
185 hWndExplorer
= nullptr;
187 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
189 if (CRegDWORD(L
"Software\\TortoiseGit\\Debug", FALSE
) == TRUE
)
190 AfxMessageBox(AfxGetApp()->m_lpCmdLine
, MB_OK
| MB_ICONINFORMATION
);
192 if (parser
.HasKey(L
"command") && wcscmp(parser
.GetVal(L
"command"), L
"firststart") == 0)
194 // CFirstStartWizard requires sOrigCWD to be set
195 DWORD len
= GetCurrentDirectory(0, nullptr);
198 auto originalCurrentDirectory
= std::make_unique
<wchar_t[]>(len
);
199 if (GetCurrentDirectory(len
, originalCurrentDirectory
.get()))
201 sOrigCWD
= originalCurrentDirectory
.get();
202 sOrigCWD
= CPathUtils::GetLongPathname(sOrigCWD
);
205 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), parser
.GetLongVal(L
"page"));
206 theApp
.m_pMainWnd
= &wizard
;
207 return (wizard
.DoModal() == ID_WIZFINISH
);
210 if (!g_Git
.CheckMsysGitDir())
212 UINT ret
= CMessageBox::Show(hWndExplorer
, IDS_PROC_NOMSYSGIT
, IDS_APPNAME
, 3, IDI_HAND
, IDS_PROC_SETMSYSGITPATH
, IDS_PROC_GOTOMSYSGITWEBSITE
, IDS_ABORTBUTTON
);
214 ShellExecute(hWndExplorer
, L
"open", GIT_FOR_WINDOWS_URL
, nullptr, nullptr, SW_SHOW
);
217 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), 2);
218 theApp
.m_pMainWnd
= &wizard
;
223 if (!CConfigureGitExe::CheckGitVersion(hWndExplorer
))
227 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Registering Crash Report ...\n");
228 CCrashReport::Instance().AddUserInfoToReport(L
"msysGitDir", CGit::ms_LastMsysGitDir
);
229 CString versionString
;
230 versionString
.Format(L
"%X", CGit::ms_LastMsysGitVersion
);
231 CCrashReport::Instance().AddUserInfoToReport(L
"msysGitVersion", versionString
);
232 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": msysGitVersion: %s\n", static_cast<LPCWSTR
>(versionString
));
233 if (CGit::ms_bCygwinGit
)
234 CCrashReport::Instance().AddUserInfoToReport(L
"CygwinHack", L
"true");
235 if (CGit::ms_bMsys2Git
)
236 CCrashReport::Instance().AddUserInfoToReport(L
"Msys2Hack", L
"true");
238 CCrashReport::Instance().AddUserInfoToReport(L
"Preview", _T(PREVIEW_INFO
));
239 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Preview: %s\n", _T(PREVIEW_INFO
));
241 if (CString hotfix
= CPathUtils::GetAppDirectory() + L
"hotfix.ini"; PathFileExists(hotfix
))
244 CVersioncheckParser versionparser
;
245 if (versionparser
.Load(hotfix
, err
))
247 auto version
= versionparser
.GetTortoiseGitVersion();
248 if (version
.major
== TGIT_VERMAJOR
&& version
.minor
== TGIT_VERMINOR
&& version
.micro
== TGIT_VERMICRO
&& version
.build
> TGIT_VERBUILD
)
250 CCrashReport::Instance().AddUserInfoToReport(L
"Hotfix", versionparser
.GetTortoiseGitVersion().version
);
251 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Hotfix: %s\n", static_cast<LPCWSTR
>(versionparser
.GetTortoiseGitVersion().version
));
258 if (parser
.HasKey(L
"urlhandler"))
260 CString url
= parser
.GetVal(L
"urlhandler");
261 if (CStringUtils::StartsWith(url
, L
"tgit://clone/"))
262 url
= url
.Mid(static_cast<int>(wcslen(L
"tgit://clone/")));
263 else if (CStringUtils::StartsWith(url
, L
"github-windows://openRepo/"))
265 url
= url
.Mid(static_cast<int>(wcslen(L
"github-windows://openRepo/")));
266 int questioMark
= url
.Find('?');
268 url
= url
.Left(questioMark
);
270 else if (CStringUtils::StartsWith(url
, L
"x-github-client://openRepo/")) {
271 url
= url
.Mid(static_cast<int>(wcslen(L
"x-github-client://openRepo/")));
272 int questioMark
= url
.Find('?');
274 url
= url
.Left(questioMark
);
276 else if (CStringUtils::StartsWith(url
, L
"smartgit://cloneRepo/"))
277 url
= url
.Mid(static_cast<int>(wcslen(L
"smartgit://cloneRepo/")));
278 else if (!CStringUtils::StartsWith(url
, L
"git://"))
280 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
284 newCmd
.Format(L
"/command:clone /url:\"%s\" /hasurlhandler", static_cast<LPCWSTR
>(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
);
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...
317 CString sPathArgument
= 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
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
"\\\\");
337 LPWSTR
*szArglist
= CommandLineToArgvW(cmdLine
, &nArgs
);
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
);
359 pathList
.LoadFromAsteriskSeparatedString(sPathArgument
);
360 if (!pathList
.IsEmpty())
361 cmdLinePath
= pathList
[0];
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);
373 auto originalCurrentDirectory
= std::make_unique
<wchar_t[]>(len
);
374 if (GetCurrentDirectory(len
, originalCurrentDirectory
.get()))
376 sOrigCWD
= originalCurrentDirectory
.get();
377 sOrigCWD
= CPathUtils::GetLongPathname(sOrigCWD
);
380 wchar_t pathbuf
[MAX_PATH
] = { 0 };
381 GetTortoiseGitTempPath(_countof(pathbuf
), 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()))
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
))
410 // implemented differently to TortoiseSVN atm
416 if (GitAdminDir::HasAdminDir(g_Git
.m_CurrentDir
, true, &wcroot
))
419 CStringA
wcRootA(wcroot
+ CPathUtils::GetAppDirectory());
420 if (!git_odb_hash(&oid
, wcRootA
.MakeLower(), wcRootA
.GetLength(), GIT_OBJECT_BLOB
))
423 git_oid_tostr(CStrBufA(hash
, GIT_OID_SHA1_HEXSIZE
, CStrBufA::SET_LENGTH
), GIT_OID_SHA1_HEXSIZE
+ 1, &oid
);
424 g_sGroupingUUID
= hash
;
426 ProjectProperties pp
;
428 CString icon
= pp
.sIcon
;
429 icon
.Replace('/', '\\');
431 g_bGroupingRemoveIcon
= true;
432 g_sGroupingIcon
= icon
;
438 CString sAppID
= GetTaskIDPerUUID(g_sGroupingUUID
).c_str();
439 InitializeJumpList(sAppID
);
440 EnsureGitLibrary(false);
446 // requires CWD to be set
447 CGit::m_LogEncode
= CAppUtils::GetLogOutputEncode();
449 // make sure all config files are read in order to check that none contains an error
450 g_Git
.GetConfigValue(L
"doesnot.exist");
452 catch (const char* msg
)
454 err
= CUnicodeUtils::GetUnicode(msg
);
459 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
)));
462 // open the config file with alternative editor
463 CAppUtils::LaunchAlternativeEditor(g_Git
.GetGitLocalConfig());
465 else if (choice
== 2)
467 // open the global config file with alternative editor
468 CAppUtils::LaunchAlternativeEditor(g_Git
.GetGitGlobalConfig());
474 // execute the requested command
475 CommandServer server
;
476 Command
* cmd
= server
.GetCommand(parser
.GetVal(L
"command"));
479 cmd
->SetExplorerHwnd(hWndExplorer
);
481 cmd
->SetParser(parser
);
482 cmd
->SetPaths(pathList
, cmdLinePath
);
484 retSuccess
= cmd
->Execute();
488 // Look for temporary files left around by TortoiseGit and
489 // remove them. But only delete 'old' files because some
490 // apps might still be needing the recent ones.
491 CTempFiles::Instance().DeleteOldTempFiles();
493 Animator::Instance().ShutDown();
495 // Since the dialog has been closed, return FALSE so that we exit the
496 // application, rather than start the application's message pump.
500 void CTortoiseProcApp::CheckUpgrade()
502 CRegString regVersion
= CRegString(L
"Software\\TortoiseGit\\CurrentVersion");
503 CString sVersion
= regVersion
;
504 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Current TGit Version %s vs. last used version %s\n", _T(STRPRODUCTVER
), static_cast<LPCWSTR
>(sVersion
));
505 if (sVersion
.Compare(_T(STRPRODUCTVER
))==0)
507 // we're starting the first time with a new version!
510 int pos
= sVersion
.Find('.');
513 lVersion
= (_wtol(sVersion
.Left(pos
)) << 24);
514 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 16);
515 pos
= sVersion
.Find('.', pos
+1);
516 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 8);
520 pos
= sVersion
.Find(',');
523 lVersion
= (_wtol(sVersion
.Left(pos
)) << 24);
524 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 16);
525 pos
= sVersion
.Find(',', pos
+1);
526 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 8);
531 if (CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2", TRUE
) != TRUE
)
533 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
)
534 CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2").removeValue();
537 if (CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2_mask").exists())
539 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
)
540 CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2_mask").removeValue();
543 CMessageBox::RemoveRegistryKey(L
"OldMsysgitVersionWarning");
545 CRegDWORD checkNewerWeekDay
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeekDay", 0);
546 if (!checkNewerWeekDay
.exists() || lVersion
<= ConvertVersionToInt(1, 8, 16))
548 std::random_device rd
;
549 std::mt19937
mt(rd());
550 std::uniform_int_distribution
<int> dist(0, 6);
551 checkNewerWeekDay
= dist(mt
);
554 // version specific updates
555 if (lVersion
<= ConvertVersionToInt(2, 9, 2))
557 if (auto inlineAdded
= CRegDWORD(L
"Software\\TortoiseGitMerge\\InlineAdded"); inlineAdded
.exists())
559 CRegDWORD(L
"Software\\TortoiseGitMerge\\Colors\\InlineAdded") = static_cast<DWORD
>(inlineAdded
);
560 inlineAdded
.removeValue();
562 if (auto inlineRemoved
= CRegDWORD(L
"Software\\TortoiseGitMerge\\InlineRemoved"); inlineRemoved
.exists())
564 CRegDWORD(L
"Software\\TortoiseGitMerge\\Colors\\InlineRemoved") = static_cast<DWORD
>(inlineRemoved
);
565 inlineRemoved
.removeValue();
569 if (lVersion
<= ConvertVersionToInt(2, 9, 1))
570 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\PatchDlgWidth").removeValue();
572 if (lVersion
<= ConvertVersionToInt(2, 4, 1))
574 CRegStdDWORD(L
"Software\\TortoiseGit\\CommitAskBeforeCancel").removeValue();
577 if (lVersion
<= ConvertVersionToInt(2, 4, 0))
579 CRegStdDWORD
commmitAskBeforeCancel(L
"Software\\TortoiseGit\\CommitAskBeforeCancel");
580 if (commmitAskBeforeCancel
.exists() && commmitAskBeforeCancel
!= IDYES
)
581 commmitAskBeforeCancel
= IDYES
;
584 if (lVersion
<= ConvertVersionToInt(2, 2, 1))
586 CString username
= CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username", L
"");
587 CString password
= CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password", L
"");
588 if (!username
.IsEmpty() && !password
.IsEmpty())
590 if (CWindowsCredentialsStore::SaveCredential(L
"TortoiseGit:SMTP-Credentials", username
, password
) == 0)
592 CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username").removeValue();
593 CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password").removeValue();
596 for (const CString
& setting
: { L
"SyncIn", L
"SyncOut" })
598 CRegDWORD
reg(L
"Software\\TortoiseGit\\StatusColumns\\" + setting
+ L
"loglistVersion", 0xff);
604 if (lVersion
<= ConvertVersionToInt(2, 1, 5))
606 // We updated GITSLC_COL_VERSION, but only significant changes were made for GitStatusList
607 // so, smoothly migrate GitLoglistBase settings
608 for (const CString
& setting
: { L
"log", L
"Blame", L
"Rebase", L
"reflog", L
"SyncIn", L
"SyncOut" })
610 CRegDWORD
reg(L
"Software\\TortoiseGit\\StatusColumns\\" + setting
+ L
"loglistVersion", 0xff);
616 if (lVersion
<= ConvertVersionToInt(1, 9, 0))
618 if (CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContent", TRUE
) == FALSE
)
620 CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContentMaxSize") = 0;
621 CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContent").removeValue();
625 if (lVersion
<= ConvertVersionToInt(1, 8, 8, 1))
627 CRegStdDWORD(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs").removeValue();
628 CRegStdString(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order").removeValue();
629 CRegStdString(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width").removeValue();
632 if (lVersion
<= ConvertVersionToInt(1, 8, 4, 1))
634 if (CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI", FALSE
) == TRUE
)
635 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType") = SEND_MAIL_MAPI
;
636 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI").removeValue();
639 if (lVersion
<= ConvertVersionToInt(1, 8, 2, 2))
641 // upgrade to 1.8.3: force recreation of all diff scripts.
642 CAppUtils::SetupDiffScripts(true, CString());
645 if (lVersion
<= ConvertVersionToInt(1, 8, 1))
647 if (CRegStdDWORD(L
"Software\\TortoiseGit\\LogTopoOrder", TRUE
) == FALSE
)
648 CRegStdDWORD(L
"Software\\TortoiseGit\\LogOrderBy") = 0;
650 // smoothly migrate broken msysgit path settings
651 CString oldmsysGitSetting
= CRegString(REG_MSYSGIT_PATH
);
652 oldmsysGitSetting
.TrimRight(L
'\\');
653 if (oldmsysGitSetting
.GetLength() > 4 && CStringUtils::EndsWith(oldmsysGitSetting
, L
"\\cmd"))
655 CString newPath
= oldmsysGitSetting
.Left(oldmsysGitSetting
.GetLength() - 3) + L
"bin";
656 if (PathFileExists(newPath
+ L
"\\git.exe"))
658 CRegString(REG_MSYSGIT_PATH
) = newPath
;
659 g_Git
.m_bInitialized
= FALSE
;
660 g_Git
.CheckMsysGitDir();
665 if (lVersion
<= ConvertVersionToInt(1, 4, 0))
667 CRegStdDWORD(L
"Software\\TortoiseGit\\OwnerdrawnMenus").removeValue();
670 if (lVersion
<= ConvertVersionToInt(1, 7, 6))
672 CoInitialize(nullptr);
675 CRegStdDWORD(L
"Software\\TortoiseGit\\ConvertBase").removeValue();
676 CRegStdDWORD(L
"Software\\TortoiseGit\\DiffProps").removeValue();
677 if (CRegStdDWORD(L
"Software\\TortoiseGit\\CheckNewer", TRUE
) == FALSE
)
678 CRegStdDWORD(L
"Software\\TortoiseGit\\VersionCheck") = FALSE
;
679 CRegStdDWORD(L
"Software\\TortoiseGit\\CheckNewer").removeValue();
682 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Setting up diff scripts ...\n");
683 CAppUtils::SetupDiffScripts(false, CString());
685 // set the current version so we don't come here again until the next update!
686 regVersion
= _T(STRPRODUCTVER
);
689 void CTortoiseProcApp::InitializeJumpList(const CString
& appid
)
691 // for Win7 : use a custom jump list
692 CoInitialize(nullptr);
694 DeleteJumpList(appid
);
695 DoInitializeJumpList(appid
);
699 void CTortoiseProcApp::DoInitializeJumpList(const CString
& appid
)
701 ATL::CComPtr
<ICustomDestinationList
> pcdl
;
702 HRESULT hr
= pcdl
.CoCreateInstance(CLSID_DestinationList
, nullptr, CLSCTX_INPROC_SERVER
);
706 hr
= pcdl
->SetAppID(appid
);
711 ATL::CComPtr
<IObjectArray
> poaRemoved
;
712 hr
= pcdl
->BeginList(&uMaxSlots
, IID_PPV_ARGS(&poaRemoved
));
716 ATL::CComPtr
<IObjectCollection
> poc
;
717 hr
= poc
.CoCreateInstance(CLSID_EnumerableObjectCollection
, nullptr, CLSCTX_INPROC_SERVER
);
721 CString sTemp
= CString(MAKEINTRESOURCE(IDS_MENUSETTINGS
));
722 CStringUtils::RemoveAccelerators(sTemp
);
724 ATL::CComPtr
<IShellLink
> psl
;
725 hr
= CreateShellLink(L
"/command:settings", static_cast<LPCWSTR
>(sTemp
), 18, &psl
);
729 sTemp
= CString(MAKEINTRESOURCE(IDS_MENUHELP
));
730 CStringUtils::RemoveAccelerators(sTemp
);
731 psl
.Release(); // Need to release the object before calling operator&()
732 hr
= CreateShellLink(L
"/command:help", static_cast<LPCWSTR
>(sTemp
), 17, &psl
);
737 ATL::CComPtr
<IObjectArray
> poa
;
738 hr
= poc
.QueryInterface(&poa
);
740 pcdl
->AppendCategory(static_cast<LPCWSTR
>(CString(MAKEINTRESOURCE(IDS_PROC_TASKS
))), poa
);
745 int CTortoiseProcApp::ExitInstance()
747 SYS_IMAGE_LIST().Cleanup();
748 Gdiplus::GdiplusShutdown(m_gdiplusToken
);
750 CWinAppEx::ExitInstance();
756 void CTortoiseProcApp::CheckForNewerVersion()
758 // check for newer versions
759 if (CRegDWORD(L
"Software\\TortoiseGit\\VersionCheck", TRUE
) != FALSE
)
765 if ((now
!= 0) && (localtime_s(&ptm
, &now
)==0))
768 // Check daily for new preview releases
769 CRegDWORD oldday
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerDay", DWORD(-1));
771 oldday
= ptm
.tm_yday
;
774 if (static_cast<DWORD
>(oldday
) != static_cast<DWORD
>(ptm
.tm_yday
))
776 oldday
= ptm
.tm_yday
;
779 // we don't calculate the real 'week of the year' here
780 // because just to decide if we should check for an update
781 // that's not needed.
782 week
= (ptm
.tm_yday
+ CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeekDay", 0)) / 7;
784 CRegDWORD oldweek
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeek", DWORD(-1));
786 oldweek
= week
; // first start of TortoiseProc, no update check needed
789 if (static_cast<DWORD
>(week
) != oldweek
)
793 CAppUtils::RunTortoiseGitProc(L
"/command:updatecheck", false, false);