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.
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"
49 #define STRUCT_IOVEC_DEFINED
55 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
57 BEGIN_MESSAGE_MAP(CTortoiseProcApp
, CWinAppEx
)
58 ON_COMMAND(ID_HELP
, CWinAppEx::OnHelp
)
61 //////////////////////////////////////////////////////////////////////////
63 CTortoiseProcApp::CTortoiseProcApp()
65 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Constructor\n");
67 CCrashReport::Instance().AddUserInfoToReport(L
"CommandLine", GetCommandLine());
71 CGit::SetGit2CredentialCallback(CAppUtils::Git2GetUserPassword
);
72 CGit::SetGit2CertificateCheckCertificate(CAppUtils::Git2CertificateCheck
);
73 m_bLoadUserToolbars
= FALSE
;
76 m_gdiplusToken
= NULL
;
77 #if defined (_WIN64) && _MSC_VER == 1800
82 CTortoiseProcApp::~CTortoiseProcApp()
85 git_libgit2_shutdown();
88 // The one and only CTortoiseProcApp object
89 CTortoiseProcApp theApp
;
91 CString g_sGroupingUUID
;
92 CString g_sGroupingIcon
;
93 bool g_bGroupingRemoveIcon
= false;
96 #if ENABLE_CRASHHANLDER
97 CCrashReportTGit
crasher(L
"TortoiseGit " _T(APP_X64_STRING
), TGIT_VERMAJOR
, TGIT_VERMINOR
, TGIT_VERMICRO
, TGIT_VERBUILD
, TGIT_VERDATE
);
100 // CTortoiseProcApp initialization
102 BOOL
CTortoiseProcApp::InitInstance()
104 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": InitInstance\n");
106 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows
));
107 CMFCButton::EnableWindowsTheming();
109 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
110 Gdiplus::GdiplusStartup(&m_gdiplusToken
, &gdiplusStartupInput
, nullptr);
112 //set the resource dll for the required language
113 CRegDWORD loc
= CRegDWORD(L
"Software\\TortoiseGit\\LanguageID", 1033);
116 CStringA langpath
= CStringA(CPathUtils::GetAppParentDirectory());
117 langpath
+= "Languages";
120 langDll
.Format(L
"%sLanguages\\TortoiseProc%ld.dll", (LPCTSTR
)CPathUtils::GetAppParentDirectory(), langId
);
122 CString sVer
= _T(STRPRODUCTVER
);
123 CString sFileVer
= CPathUtils::GetVersionFromFile(langDll
);
124 if (sFileVer
== sVer
)
126 HINSTANCE hInst
= LoadLibrary(langDll
);
129 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Load Language DLL %s\n", 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 TCHAR buf
[6] = { 0 };
149 wcscpy_s(buf
, L
"en");
151 // MFC uses a help file with the same name as the application by default,
152 // which means we have to change that default to our language specific help files
153 CString sHelppath
= CPathUtils::GetAppDirectory() + L
"TortoiseGit_en.chm";
154 free((void*)m_pszHelpFilePath
);
155 m_pszHelpFilePath
=_wcsdup(sHelppath
);
156 sHelppath
= CPathUtils::GetAppParentDirectory() + L
"Languages\\TortoiseGit_en.chm";
159 CString sLang
= L
"_";
160 if (GetLocaleInfo(MAKELCID(langId
, SORT_DEFAULT
), LOCALE_SISO639LANGNAME
, buf
, _countof(buf
)))
163 sHelppath
.Replace(L
"_en", sLang
);
164 if (PathFileExists(sHelppath
))
166 free((void*)m_pszHelpFilePath
);
167 m_pszHelpFilePath
=_wcsdup(sHelppath
);
171 sHelppath
.Replace(sLang
, L
"_en");
172 if (GetLocaleInfo(MAKELCID(langId
, SORT_DEFAULT
), LOCALE_SISO3166CTRYNAME
, buf
, _countof(buf
)))
176 sHelppath
.Replace(L
"_en", sLang
);
177 if (PathFileExists(sHelppath
))
179 free((void*)m_pszHelpFilePath
);
180 m_pszHelpFilePath
=_wcsdup(sHelppath
);
184 sHelppath
.Replace(sLang
, L
"_en");
186 DWORD lid
= SUBLANGID(langId
);
189 langId
= MAKELANGID(PRIMARYLANGID(langId
), lid
);
193 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Set Help Filename %s\n", m_pszHelpFilePath
);
194 setlocale(LC_ALL
, "");
196 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Initializing UI components ...\n");
197 // InitCommonControls() is required on Windows XP if an application
198 // manifest specifies use of ComCtl32.dll version 6 or later to enable
199 // visual styles. Otherwise, any window creation will fail.
201 INITCOMMONCONTROLSEX used
= {
202 sizeof(INITCOMMONCONTROLSEX
),
203 ICC_ANIMATE_CLASS
| ICC_BAR_CLASSES
| ICC_COOL_CLASSES
| ICC_DATE_CLASSES
|
204 ICC_HOTKEY_CLASS
| ICC_INTERNET_CLASSES
| ICC_LISTVIEW_CLASSES
|
205 ICC_NATIVEFNTCTL_CLASS
| ICC_PAGESCROLLER_CLASS
| ICC_PROGRESS_CLASS
|
206 ICC_TAB_CLASSES
| ICC_TREEVIEW_CLASSES
| ICC_UPDOWN_CLASS
|
207 ICC_USEREX_CLASSES
| ICC_WIN95_CLASSES
209 InitCommonControlsEx(&used
);
211 AfxEnableControlContainer();
213 CWinAppEx::InitInstance();
214 SetRegistryKey(L
"TortoiseGit");
216 CHistoryCombo::m_nGitIconIndex
= SYS_IMAGE_LIST().AddIcon((HICON
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG
), IMAGE_ICON
, 0, 0, LR_DEFAULTSIZE
));
217 AfxGetApp()->m_pszProfileName
= _wcsdup(L
"TortoiseProc"); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
219 CCmdLineParser
parser(AfxGetApp()->m_lpCmdLine
);
221 hWndExplorer
= nullptr;
222 CString sVal
= parser
.GetVal(L
"hwnd");
224 hWndExplorer
= (HWND
)_wcstoui64(sVal
, nullptr, 16);
226 while (GetParent(hWndExplorer
))
227 hWndExplorer
= GetParent(hWndExplorer
);
228 if (!IsWindow(hWndExplorer
))
229 hWndExplorer
= nullptr;
231 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
233 if (CRegDWORD(L
"Software\\TortoiseGit\\Debug", FALSE
) == TRUE
)
234 AfxMessageBox(AfxGetApp()->m_lpCmdLine
, MB_OK
| MB_ICONINFORMATION
);
236 if (parser
.HasKey(L
"command") && wcscmp(parser
.GetVal(L
"command"), L
"firststart") == 0)
238 // CFirstStartWizard requires sOrigCWD to be set
239 DWORD len
= GetCurrentDirectory(0, nullptr);
242 auto originalCurrentDirectory
= std::make_unique
<TCHAR
[]>(len
);
243 if (GetCurrentDirectory(len
, originalCurrentDirectory
.get()))
245 sOrigCWD
= originalCurrentDirectory
.get();
246 sOrigCWD
= CPathUtils::GetLongPathname(sOrigCWD
);
249 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), parser
.GetLongVal(L
"page"));
250 return (wizard
.DoModal() == ID_WIZFINISH
);
253 if (!g_Git
.CheckMsysGitDir())
255 UINT ret
= CMessageBox::Show(hWndExplorer
, IDS_PROC_NOMSYSGIT
, IDS_APPNAME
, 3, IDI_HAND
, IDS_PROC_SETMSYSGITPATH
, IDS_PROC_GOTOMSYSGITWEBSITE
, IDS_ABORTBUTTON
);
257 ShellExecute(hWndExplorer
, L
"open", GIT_FOR_WINDOWS_URL
, nullptr, nullptr, SW_SHOW
);
260 CFirstStartWizard
wizard(IDS_APPNAME
, CWnd::FromHandle(hWndExplorer
), 2);
265 if (!CConfigureGitExe::CheckGitVersion(hWndExplorer
))
269 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Registering Crash Report ...\n");
270 CCrashReport::Instance().AddUserInfoToReport(L
"msysGitDir", CGit::ms_LastMsysGitDir
);
271 CString versionString
;
272 versionString
.Format(L
"%X", CGit::ms_LastMsysGitVersion
);
273 CCrashReport::Instance().AddUserInfoToReport(L
"msysGitVersion", versionString
);
276 if (parser
.HasKey(L
"urlhandler"))
278 CString url
= parser
.GetVal(L
"urlhandler");
279 if (CStringUtils::StartsWith(url
, L
"tgit://clone/"))
280 url
= url
.Mid(13); // 21 = "tgit://clone/".GetLength()
281 else if (CStringUtils::StartsWith(url
, L
"github-windows://openRepo/"))
283 url
= url
.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
284 int questioMark
= url
.Find('?');
286 url
= url
.Left(questioMark
);
288 else if (CStringUtils::StartsWith(url
, L
"smartgit://cloneRepo/"))
289 url
= url
.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
292 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
296 newCmd
.Format(L
"/command:clone /url:\"%s\" /hasurlhandler", (LPCTSTR
)url
);
297 parser
= CCmdLineParser(newCmd
);
300 if (parser
.HasKey(L
"path") && parser
.HasKey(L
"pathfile"))
302 CMessageBox::Show(nullptr, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
306 CTGitPath cmdLinePath
;
307 CTGitPathList pathList
;
308 if (g_sGroupingUUID
.IsEmpty())
309 g_sGroupingUUID
= parser
.GetVal(L
"groupuuid");
310 if (parser
.HasKey(L
"pathfile"))
312 CString sPathfileArgument
= CPathUtils::GetLongPathname(parser
.GetVal(L
"pathfile"));
314 cmdLinePath
.SetFromUnknown(sPathfileArgument
);
315 if (pathList
.LoadFromFile(cmdLinePath
)==false)
316 return FALSE
; // no path specified!
317 if (parser
.HasKey(L
"deletepathfile"))
319 // We can delete the temporary path file, now that we've loaded it
320 ::DeleteFile(cmdLinePath
.GetWinPath());
322 // This was a path to a temporary file - it's got no meaning now, and
323 // anybody who uses it again is in for a problem...
329 CString sPathArgument
= CPathUtils::GetLongPathname(parser
.GetVal(L
"path"));
330 if (parser
.HasKey(L
"expaths"))
332 // an /expaths param means we're started via the buttons in our Win7 library
333 // and that means the value of /expaths is the current directory, and
334 // the selected paths are then added as additional parameters but without a key, only a value
336 // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
337 // we have to escape the backslashes first. Since we're only dealing with paths here, that's
339 // Without this, a command line like:
340 // /command:commit /expaths:"D:\" "D:\Utils"
341 // would fail because the "D:\" is treated as the backslash being the escape char for the quotation
342 // mark and we'd end up with:
343 // argv[1] = /command:commit
344 // argv[2] = /expaths:D:" D:\Utils
345 // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
346 CString cmdLine
= GetCommandLineW();
347 cmdLine
.Replace(L
"\\", L
"\\\\");
349 LPWSTR
*szArglist
= CommandLineToArgvW(cmdLine
, &nArgs
);
352 // argument 0 is the process path, so start with 1
353 for (int i
= 1; i
< nArgs
; ++i
)
355 if (szArglist
[i
][0] != '/')
357 if (!sPathArgument
.IsEmpty())
358 sPathArgument
+= '*';
359 sPathArgument
+= szArglist
[i
];
362 sPathArgument
.Replace(L
"\\\\", L
"\\");
364 LocalFree(szArglist
);
366 if (sPathArgument
.IsEmpty() && parser
.HasKey(L
"path"))
368 CMessageBox::Show(hWndExplorer
, IDS_ERR_INVALIDPATH
, IDS_APPNAME
, MB_ICONERROR
);
371 int asterisk
= sPathArgument
.Find('*');
372 cmdLinePath
.SetFromUnknown(asterisk
>= 0 ? sPathArgument
.Left(asterisk
) : sPathArgument
);
373 pathList
.LoadFromAsteriskSeparatedString(sPathArgument
);
376 if (pathList
.IsEmpty()) {
377 pathList
.AddPath(CTGitPath::CTGitPath(g_Git
.m_CurrentDir
));
380 // Set CWD to temporary dir, and restore it later
382 DWORD len
= GetCurrentDirectory(0, nullptr);
385 auto originalCurrentDirectory
= std::make_unique
<TCHAR
[]>(len
);
386 if (GetCurrentDirectory(len
, originalCurrentDirectory
.get()))
388 sOrigCWD
= originalCurrentDirectory
.get();
389 sOrigCWD
= CPathUtils::GetLongPathname(sOrigCWD
);
392 TCHAR pathbuf
[MAX_PATH
] = {0};
393 GetTortoiseGitTempPath(_countof(pathbuf
), pathbuf
);
394 SetCurrentDirectory(pathbuf
);
397 CheckForNewerVersion();
399 CAutoGeneralHandle TGitMutex
= ::CreateMutex(nullptr, FALSE
, L
"TortoiseGitProc.exe");
400 if (!g_Git
.SetCurrentDir(cmdLinePath
.GetWinPathString(), parser
.HasKey(L
"submodule") == TRUE
))
402 for (int i
= 0; i
< pathList
.GetCount(); ++i
)
403 if(g_Git
.SetCurrentDir(pathList
[i
].GetWinPath()))
406 if (parser
.HasKey(L
"pathfile") && parser
.HasKey(L
"submodule"))
407 g_Git
.SetCurrentDir(pathList
[0].GetWinPathString(), true);
409 if(!g_Git
.m_CurrentDir
.IsEmpty())
411 sOrigCWD
= g_Git
.m_CurrentDir
;
412 SetCurrentDirectory(g_Git
.m_CurrentDir
);
415 if (g_sGroupingUUID
.IsEmpty())
417 CRegStdDWORD groupSetting
= CRegStdDWORD(L
"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3);
418 switch (DWORD(groupSetting
))
422 // implemented differently to TortoiseSVN atm
428 if (GitAdminDir::HasAdminDir(g_Git
.m_CurrentDir
, true, &wcroot
))
431 CStringA
wcRootA(wcroot
+ CPathUtils::GetAppDirectory());
432 if (!git_odb_hash(&oid
, wcRootA
.MakeLower(), wcRootA
.GetLength(), GIT_OBJ_BLOB
))
435 git_oid_tostr(CStrBufA(hash
, GIT_OID_HEXSZ
, CStrBufA::SET_LENGTH
), GIT_OID_HEXSZ
+ 1, &oid
);
436 g_sGroupingUUID
= hash
;
438 ProjectProperties pp
;
440 CString icon
= pp
.sIcon
;
441 icon
.Replace('/', '\\');
443 g_bGroupingRemoveIcon
= true;
444 g_sGroupingIcon
= icon
;
450 CString sAppID
= GetTaskIDPerUUID(g_sGroupingUUID
).c_str();
451 InitializeJumpList(sAppID
);
452 EnsureGitLibrary(false);
458 // requires CWD to be set
459 CGit::m_LogEncode
= CAppUtils::GetLogOutputEncode();
461 // make sure all config files are read in order to check that none contains an error
462 g_Git
.GetConfigValue(L
"doesnot.exist");
471 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
)));
474 // open the config file with alternative editor
475 CAppUtils::LaunchAlternativeEditor(g_Git
.GetGitLocalConfig());
477 else if (choice
== 2)
479 // open the global config file with alternative editor
480 CAppUtils::LaunchAlternativeEditor(g_Git
.GetGitGlobalConfig());
486 // execute the requested command
487 CommandServer server
;
488 Command
* cmd
= server
.GetCommand(parser
.GetVal(L
"command"));
491 cmd
->SetExplorerHwnd(hWndExplorer
);
493 cmd
->SetParser(parser
);
494 cmd
->SetPaths(pathList
, cmdLinePath
);
496 retSuccess
= cmd
->Execute();
500 // Look for temporary files left around by TortoiseSVN and
501 // remove them. But only delete 'old' files because some
502 // apps might still be needing the recent ones.
504 DWORD len
= GetTortoiseGitTempPath(0, nullptr);
505 auto path
= std::make_unique
<TCHAR
[]>(len
+ 100);
506 len
= GetTortoiseGitTempPath (len
+ 100, path
.get());
509 CDirFileEnum
finder(path
.get());
511 ::GetSystemTimeAsFileTime(&systime_
);
512 __int64 systime
= (((_int64
)systime_
.dwHighDateTime
)<<32) | ((__int64
)systime_
.dwLowDateTime
);
515 while (finder
.NextFile(filepath
, &isDir
))
517 HANDLE hFile
= ::CreateFile(filepath
, GENERIC_READ
, FILE_SHARE_READ
, nullptr, OPEN_EXISTING
, isDir
? FILE_FLAG_BACKUP_SEMANTICS
: 0, nullptr);
518 if (hFile
!= INVALID_HANDLE_VALUE
)
520 FILETIME createtime_
;
521 if (::GetFileTime(hFile
, &createtime_
, nullptr, nullptr))
523 ::CloseHandle(hFile
);
524 __int64 createtime
= (((_int64
)createtime_
.dwHighDateTime
)<<32) | ((__int64
)createtime_
.dwLowDateTime
);
525 if ((createtime
+ 864000000000) < systime
) //only delete files older than a day
527 ::SetFileAttributes(filepath
, FILE_ATTRIBUTE_NORMAL
);
529 ::RemoveDirectory(filepath
);
531 ::DeleteFile(filepath
);
535 ::CloseHandle(hFile
);
541 // Since the dialog has been closed, return FALSE so that we exit the
542 // application, rather than start the application's message pump.
546 void CTortoiseProcApp::CheckUpgrade()
548 CRegString regVersion
= CRegString(L
"Software\\TortoiseGit\\CurrentVersion");
549 CString sVersion
= regVersion
;
550 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Current TGit Version %s\n", (LPCTSTR
)sVersion
);
551 if (sVersion
.Compare(_T(STRPRODUCTVER
))==0)
553 // we're starting the first time with a new version!
556 int pos
= sVersion
.Find('.');
559 lVersion
= (_wtol(sVersion
.Left(pos
)) << 24);
560 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 16);
561 pos
= sVersion
.Find('.', pos
+1);
562 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 8);
566 pos
= sVersion
.Find(',');
569 lVersion
= (_wtol(sVersion
.Left(pos
)) << 24);
570 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 16);
571 pos
= sVersion
.Find(',', pos
+1);
572 lVersion
|= (_wtol(sVersion
.Mid(pos
+ 1)) << 8);
577 if (CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2", TRUE
) != TRUE
)
579 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
)
580 CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2").removeValue();
583 if (CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2_mask").exists())
585 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
)
586 CRegStdDWORD(L
"Software\\TortoiseGit\\UseLibgit2_mask").removeValue();
589 CMessageBox::RemoveRegistryKey(L
"OldMsysgitVersionWarning");
591 CRegDWORD checkNewerWeekDay
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeekDay", 0);
592 if (!checkNewerWeekDay
.exists() || lVersion
<= 0x01081000)
594 std::random_device rd
;
595 std::mt19937
mt(rd());
596 std::uniform_int_distribution
<int> dist(0, 6);
597 checkNewerWeekDay
= dist(mt
);
600 // version specific updates
601 if (lVersion
<= 0x02040000)
603 CRegStdDWORD
commmitAskBeforeCancel(L
"Software\\TortoiseGit\\CommitAskBeforeCancel");
604 if (commmitAskBeforeCancel
.exists() && commmitAskBeforeCancel
!= IDYES
)
605 commmitAskBeforeCancel
= IDYES
;
608 if (lVersion
<= 0x02020100)
610 CString username
= CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username", L
"");
611 CString password
= CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password", L
"");
612 if (!username
.IsEmpty() && !password
.IsEmpty())
614 if (CWindowsCredentialsStore::SaveCredential(L
"TortoiseGit:SMTP-Credentials", username
, password
) == 0)
616 CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Username").removeValue();
617 CRegString(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\Password").removeValue();
620 for (const CString
& setting
: { L
"SyncIn", L
"SyncOut" })
622 CRegDWORD
reg(L
"Software\\TortoiseGit\\StatusColumns\\" + setting
+ L
"loglistVersion", 0xff);
628 if (lVersion
<= 0x02010500)
630 // We updated GITSLC_COL_VERSION, but only significant changes were made for GitStatusList
631 // so, smoothly migrate GitLoglistBase settings
632 for (const CString
& setting
: { L
"log", L
"Blame", L
"Rebase", L
"reflog", L
"SyncIn", L
"SyncOut" })
634 CRegDWORD
reg(L
"Software\\TortoiseGit\\StatusColumns\\" + setting
+ L
"loglistVersion", 0xff);
640 if (lVersion
<= 0x01090000)
642 if (CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContent", TRUE
) == FALSE
)
644 CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContentMaxSize") = 0;
645 CRegDWORD(L
"Software\\TortoiseGit\\TGitCacheCheckContent").removeValue();
649 if (lVersion
<= 0x01080801)
651 CRegStdDWORD(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs").removeValue();
652 CRegStdString(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order").removeValue();
653 CRegStdString(L
"Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width").removeValue();
656 if (lVersion
<= 0x01080401)
658 if (CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI", FALSE
) == TRUE
)
659 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType") = SEND_MAIL_MAPI
;
660 CRegStdDWORD(L
"Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI").removeValue();
663 if (lVersion
<= 0x01080202)
665 // upgrade to 1.8.3: force recreation of all diff scripts.
666 CAppUtils::SetupDiffScripts(true, CString());
669 if (lVersion
<= 0x01080100)
671 if (CRegStdDWORD(L
"Software\\TortoiseGit\\LogTopoOrder", TRUE
) == FALSE
)
672 CRegStdDWORD(L
"Software\\TortoiseGit\\LogOrderBy") = 0;
674 // smoothly migrate broken msysgit path settings
675 CString oldmsysGitSetting
= CRegString(REG_MSYSGIT_PATH
);
676 oldmsysGitSetting
.TrimRight(L
'\\');
677 if (oldmsysGitSetting
.GetLength() > 4 && CStringUtils::EndsWith(oldmsysGitSetting
, L
"\\cmd"))
679 CString newPath
= oldmsysGitSetting
.Mid(0, oldmsysGitSetting
.GetLength() - 3) + L
"bin";
680 if (PathFileExists(newPath
+ L
"\\git.exe"))
682 CRegString(REG_MSYSGIT_PATH
) = newPath
;
683 g_Git
.m_bInitialized
= FALSE
;
684 g_Git
.CheckMsysGitDir();
689 if (lVersion
<= 0x01040000)
691 CRegStdDWORD(L
"Software\\TortoiseGit\\OwnerdrawnMenus").removeValue();
694 if (lVersion
<= 0x01070600)
696 CoInitialize(nullptr);
699 CRegStdDWORD(L
"Software\\TortoiseGit\\ConvertBase").removeValue();
700 CRegStdDWORD(L
"Software\\TortoiseGit\\DiffProps").removeValue();
701 if (CRegStdDWORD(L
"Software\\TortoiseGit\\CheckNewer", TRUE
) == FALSE
)
702 CRegStdDWORD(L
"Software\\TortoiseGit\\VersionCheck") = FALSE
;
703 CRegStdDWORD(L
"Software\\TortoiseGit\\CheckNewer").removeValue();
706 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": Setting up diff scripts ...\n");
707 CAppUtils::SetupDiffScripts(false, CString());
709 // set the current version so we don't come here again until the next update!
710 regVersion
= _T(STRPRODUCTVER
);
713 void CTortoiseProcApp::InitializeJumpList(const CString
& appid
)
715 // for Win7 : use a custom jump list
716 CoInitialize(nullptr);
718 DeleteJumpList(appid
);
719 DoInitializeJumpList(appid
);
723 void CTortoiseProcApp::DoInitializeJumpList(const CString
& appid
)
725 ATL::CComPtr
<ICustomDestinationList
> pcdl
;
726 HRESULT hr
= pcdl
.CoCreateInstance(CLSID_DestinationList
, nullptr, CLSCTX_INPROC_SERVER
);
730 hr
= pcdl
->SetAppID(appid
);
735 ATL::CComPtr
<IObjectArray
> poaRemoved
;
736 hr
= pcdl
->BeginList(&uMaxSlots
, IID_PPV_ARGS(&poaRemoved
));
740 ATL::CComPtr
<IObjectCollection
> poc
;
741 hr
= poc
.CoCreateInstance(CLSID_EnumerableObjectCollection
, nullptr, CLSCTX_INPROC_SERVER
);
745 CString sTemp
= CString(MAKEINTRESOURCE(IDS_MENUSETTINGS
));
746 CStringUtils::RemoveAccelerators(sTemp
);
748 ATL::CComPtr
<IShellLink
> psl
;
749 hr
= CreateShellLink(L
"/command:settings", (LPCTSTR
)sTemp
, 20, &psl
);
753 sTemp
= CString(MAKEINTRESOURCE(IDS_MENUHELP
));
754 CStringUtils::RemoveAccelerators(sTemp
);
755 psl
.Release(); // Need to release the object before calling operator&()
756 hr
= CreateShellLink(L
"/command:help", (LPCTSTR
)sTemp
, 19, &psl
);
761 ATL::CComPtr
<IObjectArray
> poa
;
762 hr
= poc
.QueryInterface(&poa
);
764 pcdl
->AppendCategory((LPCTSTR
)CString(MAKEINTRESOURCE(IDS_PROC_TASKS
)), poa
);
769 int CTortoiseProcApp::ExitInstance()
771 SYS_IMAGE_LIST().Cleanup();
772 Gdiplus::GdiplusShutdown(m_gdiplusToken
);
774 CWinAppEx::ExitInstance();
780 void CTortoiseProcApp::CheckForNewerVersion()
782 // check for newer versions
783 if (CRegDWORD(L
"Software\\TortoiseGit\\VersionCheck", TRUE
) != FALSE
)
789 if ((now
!= 0) && (localtime_s(&ptm
, &now
)==0))
792 // Check daily for new preview releases
793 CRegDWORD oldday
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerDay", (DWORD
)-1);
794 if (((DWORD
)oldday
) == -1)
795 oldday
= ptm
.tm_yday
;
798 if ((DWORD
)oldday
!= (DWORD
)ptm
.tm_yday
)
800 oldday
= ptm
.tm_yday
;
803 // we don't calculate the real 'week of the year' here
804 // because just to decide if we should check for an update
805 // that's not needed.
806 week
= (ptm
.tm_yday
+ CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeekDay", 0)) / 7;
808 CRegDWORD oldweek
= CRegDWORD(L
"Software\\TortoiseGit\\CheckNewerWeek", (DWORD
)-1);
809 if (((DWORD
)oldweek
) == -1)
810 oldweek
= week
; // first start of TortoiseProc, no update check needed
813 if ((DWORD
)week
!= oldweek
)
817 CAppUtils::RunTortoiseGitProc(L
"/command:updatecheck", false, false);