Add start and pre commit hooks
[TortoiseGit.git] / src / TortoiseProc / TortoiseProc.cpp
blobfb58c8971a53321c973d13f4bb3f23cfff702e72
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - 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 "SoundUtils.h"
43 #include "ProjectProperties.h"
45 #define STRUCT_IOVEC_DEFINED
47 #ifdef _DEBUG
48 #define new DEBUG_NEW
49 #endif
51 #pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
53 BEGIN_MESSAGE_MAP(CTortoiseProcApp, CWinAppEx)
54 ON_COMMAND(ID_HELP, CWinAppEx::OnHelp)
55 END_MESSAGE_MAP()
57 //////////////////////////////////////////////////////////////////////////
59 CTortoiseProcApp::CTortoiseProcApp()
61 SetDllDirectory(L"");
62 // prevent from inheriting %GIT_DIR% from parent process by resetting it,
63 // use MSVC function instead of Windows API because MSVC runtime caches environment variables
64 _tputenv(_T("GIT_DIR="));
65 CCrashReport::Instance().AddUserInfoToReport(L"CommandLine", GetCommandLine());
66 EnableHtmlHelp();
67 SYS_IMAGE_LIST();
68 CHooks::Create();
69 m_bLoadUserToolbars = FALSE;
70 m_bSaveState = FALSE;
71 retSuccess = false;
72 m_gdiplusToken = NULL;
75 CTortoiseProcApp::~CTortoiseProcApp()
77 CHooks::Destroy();
78 SYS_IMAGE_LIST().Cleanup();
81 // The one and only CTortoiseProcApp object
82 CTortoiseProcApp theApp;
83 CString sOrigCWD;
84 CString g_sGroupingUUID;
85 CString g_sGroupingIcon;
86 bool g_bGroupingRemoveIcon = false;
87 HWND hWndExplorer;
89 #if ENABLE_CRASHHANLDER
90 CCrashReportTGit crasher(L"TortoiseGit " _T(APP_X64_STRING), TGIT_VERMAJOR, TGIT_VERMINOR, TGIT_VERMICRO, TGIT_VERBUILD, TGIT_VERDATE);
91 #endif
93 // CTortoiseProcApp initialization
95 BOOL CTortoiseProcApp::InitInstance()
97 CheckUpgrade();
98 CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
99 CMFCButton::EnableWindowsTheming();
100 CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));
102 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
103 Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL);
105 //set the resource dll for the required language
106 CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
107 long langId = loc;
109 CString langStr;
110 langStr.Format(_T("%ld"), langId);
111 CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr);
113 CString langDll;
114 CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory());
115 langpath += "Languages";
116 HINSTANCE hInst = NULL;
119 langDll.Format(_T("%sLanguages\\TortoiseProc%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);
121 hInst = LoadLibrary(langDll);
123 CString sVer = _T(STRPRODUCTVER);
124 CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
125 if (sFileVer.Compare(sVer)!=0)
127 FreeLibrary(hInst);
128 hInst = NULL;
130 if (hInst != NULL)
132 AfxSetResourceHandle(hInst);
134 else
136 DWORD lid = SUBLANGID(langId);
137 lid--;
138 if (lid > 0)
140 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
142 else
143 langId = 0;
145 } while ((hInst == NULL) && (langId != 0));
146 TCHAR buf[6] = { 0 };
147 _tcscpy_s(buf, _T("en"));
148 langId = loc;
149 // MFC uses a help file with the same name as the application by default,
150 // which means we have to change that default to our language specific help files
151 CString sHelppath = CPathUtils::GetAppDirectory() + _T("TortoiseGit_en.chm");
152 free((void*)m_pszHelpFilePath);
153 m_pszHelpFilePath=_tcsdup(sHelppath);
154 sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGit_en.chm");
157 CString sLang = _T("_");
158 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf)))
160 sLang += buf;
161 sHelppath.Replace(_T("_en"), sLang);
162 if (PathFileExists(sHelppath))
164 free((void*)m_pszHelpFilePath);
165 m_pszHelpFilePath=_tcsdup(sHelppath);
166 break;
169 sHelppath.Replace(sLang, _T("_en"));
170 if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf)))
172 sLang += _T("_");
173 sLang += buf;
174 sHelppath.Replace(_T("_en"), sLang);
175 if (PathFileExists(sHelppath))
177 free((void*)m_pszHelpFilePath);
178 m_pszHelpFilePath=_tcsdup(sHelppath);
179 break;
182 sHelppath.Replace(sLang, _T("_en"));
184 DWORD lid = SUBLANGID(langId);
185 lid--;
186 if (lid > 0)
188 langId = MAKELANGID(PRIMARYLANGID(langId), lid);
190 else
191 langId = 0;
192 } while (langId);
193 setlocale(LC_ALL, "");
195 if (!g_Git.CheckMsysGitDir())
197 UINT ret = CMessageBox::Show(NULL, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON);
198 if(ret == 2)
200 ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW);
202 else if(ret == 1)
204 // open settings dialog
205 CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROC_SETTINGS_TITLE)), new CSetMainPage(), this->GetMainWnd()).DoModal();
207 return FALSE;
209 if (CAppUtils::GetMsysgitVersion() < 0x01070a00)
211 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);
212 if (ret == 1)
214 CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
215 ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW);
216 return FALSE;
218 else if (ret == 2)
220 CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
221 return FALSE;
226 CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir);
227 CString versionString;
228 versionString.Format(_T("%d"), CGit::ms_LastMsysGitVersion);
229 CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString);
232 // InitCommonControls() is required on Windows XP if an application
233 // manifest specifies use of ComCtl32.dll version 6 or later to enable
234 // visual styles. Otherwise, any window creation will fail.
236 INITCOMMONCONTROLSEX used = {
237 sizeof(INITCOMMONCONTROLSEX),
238 ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES |
239 ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES |
240 ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
241 ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS |
242 ICC_USEREX_CLASSES | ICC_WIN95_CLASSES
244 InitCommonControlsEx(&used);
245 AfxOleInit();
246 AfxEnableControlContainer();
247 AfxInitRichEdit5();
248 CWinAppEx::InitInstance();
249 SetRegistryKey(_T("TortoiseGit"));
250 AfxGetApp()->m_pszProfileName = _tcsdup(_T("TortoiseProc")); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions
252 CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);
254 hWndExplorer = NULL;
255 CString sVal = parser.GetVal(_T("hwnd"));
256 if (!sVal.IsEmpty())
257 hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);
259 while (GetParent(hWndExplorer)!=NULL)
260 hWndExplorer = GetParent(hWndExplorer);
261 if (!IsWindow(hWndExplorer))
263 hWndExplorer = NULL;
266 // if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
267 // in a message box
268 if (CRegDWORD(_T("Software\\TortoiseGit\\Debug"), FALSE)==TRUE)
269 AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);
271 if (parser.HasKey(_T("urlhandler")))
273 CString url = parser.GetVal(_T("urlhandler"));
274 if (url.Find(_T("tgit://clone/")) == 0)
276 url = url.Mid(13); // 21 = "tgit://clone/".GetLength()
278 else if (url.Find(_T("github-windows://openRepo/")) == 0)
280 url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
281 int questioMark = url.Find('?');
282 if (questioMark > 0)
283 url = url.Left(questioMark);
285 else if (url.Find(_T("smartgit://cloneRepo/")) == 0)
287 url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
289 else
291 CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
292 return FALSE;
294 CString newCmd;
295 newCmd.Format(_T("/command:clone /url:\"%s\" /hasurlhandler"), url);
296 parser = CCmdLineParser(newCmd);
299 if ( parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile")))
301 CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
302 return FALSE;
305 CTGitPath cmdLinePath;
306 CTGitPathList pathList;
307 if (g_sGroupingUUID.IsEmpty())
308 g_sGroupingUUID = parser.GetVal(L"groupuuid");
309 if ( parser.HasKey(_T("pathfile")) )
312 CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile")));
314 cmdLinePath.SetFromUnknown(sPathfileArgument);
315 if (pathList.LoadFromFile(cmdLinePath)==false)
316 return FALSE; // no path specified!
317 if ( parser.HasKey(_T("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...
324 cmdLinePath.Reset();
327 else
330 CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path")));
331 if (parser.HasKey(_T("expaths")))
333 // an /expaths param means we're started via the buttons in our Win7 library
334 // and that means the value of /expaths is the current directory, and
335 // the selected paths are then added as additional parameters but without a key, only a value
337 // because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
338 // we have to escape the backslashes first. Since we're only dealing with paths here, that's
339 // a save bet.
340 // Without this, a command line like:
341 // /command:commit /expaths:"D:\" "D:\Utils"
342 // would fail because the "D:\" is treated as the backslash being the escape char for the quotation
343 // mark and we'd end up with:
344 // argv[1] = /command:commit
345 // argv[2] = /expaths:D:" D:\Utils
346 // See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
347 CString cmdLine = GetCommandLineW();
348 cmdLine.Replace(L"\\", L"\\\\");
349 int nArgs = 0;
350 LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs);
351 if (szArglist)
353 // argument 0 is the process path, so start with 1
354 for (int i = 1; i < nArgs; ++i)
356 if (szArglist[i][0] != '/')
358 if (!sPathArgument.IsEmpty())
359 sPathArgument += '*';
360 sPathArgument += szArglist[i];
363 sPathArgument.Replace(L"\\\\", L"\\");
365 LocalFree(szArglist);
367 if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
369 CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
370 return FALSE;
372 int asterisk = sPathArgument.Find('*');
373 cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
374 pathList.LoadFromAsteriskSeparatedString(sPathArgument);
377 if (pathList.IsEmpty()) {
378 pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
381 // Set CWD to temporary dir, and restore it later
383 DWORD len = GetCurrentDirectory(0, NULL);
384 if (len)
386 std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);
387 if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
389 sOrigCWD = originalCurrentDirectory.get();
390 sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
393 TCHAR pathbuf[MAX_PATH] = {0};
394 GetTortoiseGitTempPath(MAX_PATH, pathbuf);
395 SetCurrentDirectory(pathbuf);
398 CheckForNewerVersion();
400 CAutoGeneralHandle TGitMutex = ::CreateMutex(NULL, FALSE, _T("TortoiseGitProc.exe"));
401 if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(_T("submodule")) == TRUE))
403 for (int i = 0; i < pathList.GetCount(); ++i)
404 if(g_Git.SetCurrentDir(pathList[i].GetWinPath()))
405 break;
408 if(!g_Git.m_CurrentDir.IsEmpty())
410 sOrigCWD = g_Git.m_CurrentDir;
411 SetCurrentDirectory(g_Git.m_CurrentDir);
414 if (g_sGroupingUUID.IsEmpty())
416 CRegStdDWORD groupSetting = CRegStdDWORD(_T("Software\\TortoiseGit\\GroupTaskbarIconsPerRepo"), 3);
417 switch (DWORD(groupSetting))
419 case 1:
420 case 2:
421 // implemented differently to TortoiseSVN atm
422 break;
423 case 3:
424 case 4:
426 CString wcroot;
427 if (g_GitAdminDir.HasAdminDir(g_Git.m_CurrentDir, true, &wcroot))
429 git_oid oid;
430 CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory());
431 if (!git_odb_hash(&oid, wcRootA, wcRootA.GetLength(), GIT_OBJ_BLOB))
433 CStringA hash;
434 git_oid_tostr(hash.GetBufferSetLength(GIT_OID_HEXSZ + 1), GIT_OID_HEXSZ + 1, &oid);
435 hash.ReleaseBuffer();
436 g_sGroupingUUID = hash;
438 ProjectProperties pp;
439 pp.ReadProps();
440 CString icon = pp.sIcon;
441 icon.Replace('/', '\\');
442 if (icon.IsEmpty())
443 g_bGroupingRemoveIcon = true;
444 g_sGroupingIcon = icon;
450 CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str();
451 InitializeJumpList(sAppID);
452 EnsureGitLibrary(false);
455 CString err;
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(_T("doesnot.exist"));
464 catch (char* msg)
466 err = CString(msg);
469 if (!err.IsEmpty())
471 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)));
472 if (choice == 1)
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());
482 return FALSE;
486 // execute the requested command
487 CommandServer server;
488 Command * cmd = server.GetCommand(parser.GetVal(_T("command")));
489 if (cmd)
491 cmd->SetExplorerHwnd(hWndExplorer);
493 cmd->SetParser(parser);
494 cmd->SetPaths(pathList, cmdLinePath);
496 retSuccess = cmd->Execute();
497 delete cmd;
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, NULL);
505 std::unique_ptr<TCHAR[]> path(new TCHAR[len + 100]);
506 len = GetTortoiseGitTempPath (len + 100, path.get());
507 if (len != 0)
509 CDirFileEnum finder(path.get());
510 FILETIME systime_;
511 ::GetSystemTimeAsFileTime(&systime_);
512 __int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime);
513 bool isDir;
514 CString filepath;
515 while (finder.NextFile(filepath, &isDir))
517 HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : NULL, NULL);
518 if (hFile != INVALID_HANDLE_VALUE)
520 FILETIME createtime_;
521 if (::GetFileTime(hFile, &createtime_, NULL, NULL))
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);
528 if (isDir)
529 ::RemoveDirectory(filepath);
530 else
531 ::DeleteFile(filepath);
534 else
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.
543 return FALSE;
546 void CTortoiseProcApp::CheckUpgrade()
548 CRegString regVersion = CRegString(_T("Software\\TortoiseGit\\CurrentVersion"));
549 CString sVersion = regVersion;
550 if (sVersion.Compare(_T(STRPRODUCTVER))==0)
551 return;
552 // we're starting the first time with a new version!
554 LONG lVersion = 0;
555 int pos = sVersion.Find('.');
556 if (pos > 0)
558 lVersion = (_ttol(sVersion.Left(pos))<<24);
559 lVersion |= (_ttol(sVersion.Mid(pos+1))<<16);
560 pos = sVersion.Find('.', pos+1);
561 lVersion |= (_ttol(sVersion.Mid(pos+1))<<8);
563 else
565 pos = sVersion.Find(',');
566 if (pos > 0)
568 lVersion = (_ttol(sVersion.Left(pos))<<24);
569 lVersion |= (_ttol(sVersion.Mid(pos+1))<<16);
570 pos = sVersion.Find(',', pos+1);
571 lVersion |= (_ttol(sVersion.Mid(pos+1))<<8);
575 // generic cleanup
576 if (CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2"), TRUE) != TRUE)
578 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)
579 CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2")).removeValue();
582 if (CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2_mask")).exists())
584 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)
585 CRegStdDWORD(_T("Software\\TortoiseGit\\UseLibgit2_mask")).removeValue();
588 // version specific updates
589 if (lVersion <= 0x01080802)
591 CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\CleanTypeDlgWindowPlacement")).removeValue();
594 if (lVersion <= 0x01080801)
596 CRegStdDWORD(_T("Software\\TortoiseGit\\StatusColumns\\BrowseRefs")).removeValue();
597 CRegStdString(_T("Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Order")).removeValue();
598 CRegStdString(_T("Software\\TortoiseGit\\StatusColumns\\BrowseRefs_Width")).removeValue();
601 if (lVersion <= 0x01080401)
603 if (CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI"), FALSE) == TRUE)
604 CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\DeliveryType")) = 1;
605 CRegStdDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\SendMail\\UseMAPI")).removeValue();
608 if (lVersion <= 0x01080202)
610 CSoundUtils::RegisterTGitSounds();
611 // upgrade to 1.8.3: force recreation of all diff scripts.
612 CAppUtils::SetupDiffScripts(true, CString());
615 if (lVersion <= 0x01080100)
617 if (CRegStdDWORD(_T("Software\\TortoiseGit\\LogTopoOrder"), TRUE) == FALSE)
618 CRegStdDWORD(_T("Software\\TortoiseGit\\LogOrderBy")) = 0;
620 // smoothly migrate broken msysgit path settings
621 CString oldmsysGitSetting = CRegString(REG_MSYSGIT_PATH);
622 oldmsysGitSetting.TrimRight(_T("\\"));
623 CString right = oldmsysGitSetting.Right(4);
624 if (oldmsysGitSetting.GetLength() > 4 && oldmsysGitSetting.Right(4) == _T("\\cmd"))
626 CString newPath = oldmsysGitSetting.Mid(0, oldmsysGitSetting.GetLength() - 3) + _T("bin");
627 if (PathFileExists(newPath + _T("\\git.exe")))
629 CRegString(REG_MSYSGIT_PATH) = newPath;
630 g_Git.m_bInitialized = FALSE;
631 g_Git.CheckMsysGitDir();
636 if (lVersion <= 0x01040000)
638 CRegStdDWORD(_T("Software\\TortoiseGit\\OwnerdrawnMenus")).removeValue();
641 if (lVersion <= 0x01070600)
643 CoInitialize(NULL);
644 EnsureGitLibrary();
645 CoUninitialize();
646 CRegStdDWORD(_T("Software\\TortoiseGit\\ConvertBase")).removeValue();
647 CRegStdDWORD(_T("Software\\TortoiseGit\\DiffProps")).removeValue();
648 if (CRegStdDWORD(_T("Software\\TortoiseGit\\CheckNewer"), TRUE) == FALSE)
649 CRegStdDWORD(_T("Software\\TortoiseGit\\VersionCheck")) = FALSE;
650 CRegStdDWORD(_T("Software\\TortoiseGit\\CheckNewer")).removeValue();
653 CAppUtils::SetupDiffScripts(false, CString());
655 // set the current version so we don't come here again until the next update!
656 regVersion = _T(STRPRODUCTVER);
659 void CTortoiseProcApp::InitializeJumpList(const CString& appid)
661 // for Win7 : use a custom jump list
662 CoInitialize(NULL);
663 SetAppID(appid);
664 DeleteJumpList(appid);
665 DoInitializeJumpList(appid);
666 CoUninitialize();
669 void CTortoiseProcApp::DoInitializeJumpList(const CString& appid)
671 ATL::CComPtr<ICustomDestinationList> pcdl;
672 HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER);
673 if (FAILED(hr))
674 return;
676 hr = pcdl->SetAppID(appid);
677 if (FAILED(hr))
678 return;
680 UINT uMaxSlots;
681 ATL::CComPtr<IObjectArray> poaRemoved;
682 hr = pcdl->BeginList(&uMaxSlots, IID_PPV_ARGS(&poaRemoved));
683 if (FAILED(hr))
684 return;
686 ATL::CComPtr<IObjectCollection> poc;
687 hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC_SERVER);
688 if (FAILED(hr))
689 return;
691 CString sTemp = CString(MAKEINTRESOURCE(IDS_MENUSETTINGS));
692 CStringUtils::RemoveAccelerators(sTemp);
694 ATL::CComPtr<IShellLink> psl;
695 hr = CreateShellLink(_T("/command:settings"), (LPCTSTR)sTemp, 20, &psl);
696 if (SUCCEEDED(hr)) {
697 poc->AddObject(psl);
699 sTemp = CString(MAKEINTRESOURCE(IDS_MENUHELP));
700 CStringUtils::RemoveAccelerators(sTemp);
701 psl.Release(); // Need to release the object before calling operator&()
702 hr = CreateShellLink(_T("/command:help"), (LPCTSTR)sTemp, 19, &psl);
703 if (SUCCEEDED(hr)) {
704 poc->AddObject(psl);
707 ATL::CComPtr<IObjectArray> poa;
708 hr = poc.QueryInterface(&poa);
709 if (SUCCEEDED(hr)) {
710 pcdl->AppendCategory((LPCTSTR)CString(MAKEINTRESOURCE(IDS_PROC_TASKS)), poa);
711 pcdl->CommitList();
715 int CTortoiseProcApp::ExitInstance()
717 Gdiplus::GdiplusShutdown(m_gdiplusToken);
719 CWinAppEx::ExitInstance();
720 if (retSuccess)
721 return 0;
722 return -1;
725 void CTortoiseProcApp::CheckForNewerVersion()
727 // check for newer versions
728 if (CRegDWORD(_T("Software\\TortoiseGit\\VersionCheck"), TRUE) != FALSE)
730 time_t now;
731 struct tm ptm;
733 time(&now);
734 if ((now != 0) && (localtime_s(&ptm, &now)==0))
736 #if PREVIEW
737 // Check daily for new preview releases
738 CRegDWORD oldday = CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerDay"), (DWORD)-1);
739 if (((DWORD)oldday) == -1)
740 oldday = ptm.tm_yday;
741 else
743 if ((DWORD)oldday != (DWORD)ptm.tm_yday)
745 oldday = ptm.tm_yday;
746 #else
747 int week = 0;
748 // we don't calculate the real 'week of the year' here
749 // because just to decide if we should check for an update
750 // that's not needed.
751 week = ptm.tm_yday / 7;
753 CRegDWORD oldweek = CRegDWORD(_T("Software\\TortoiseGit\\CheckNewerWeek"), (DWORD)-1);
754 if (((DWORD)oldweek) == -1)
755 oldweek = week; // first start of TortoiseProc, no update check needed
756 else
758 if ((DWORD)week != oldweek)
760 oldweek = week;
761 #endif
762 CAppUtils::RunTortoiseGitProc(_T("/command:updatecheck"), false, false);