Beispiel #1
0
BOOL CTortoiseGitBlameApp::InitInstance()
{
    {
        DWORD len = GetCurrentDirectory(0, NULL);
        if (len)
        {
            std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);
            if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
            {
                sOrigCWD = originalCurrentDirectory.get();
                sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
            }
        }
    }

    //set the resource dll for the required language
    CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
    long langId = loc;
    CString langDll;
    HINSTANCE hInst = NULL;
    do
    {
        langDll.Format(_T("%sLanguages\\TortoiseGitBlame%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);

        hInst = LoadLibrary(langDll);
        CString sVer = _T(STRPRODUCTVER);
        CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
        if (sFileVer.Compare(sVer)!=0)
        {
            FreeLibrary(hInst);
            hInst = NULL;
        }
        if (hInst != NULL)
            AfxSetResourceHandle(hInst);
        else
        {
            DWORD lid = SUBLANGID(langId);
            lid--;
            if (lid > 0)
            {
                langId = MAKELANGID(PRIMARYLANGID(langId), lid);
            }
            else
                langId = 0;
        }
    } while ((hInst == NULL) && (langId != 0));
    TCHAR buf[6] = { 0 };
    _tcscpy_s(buf, _T("en"));
    langId = loc;
    CString sHelppath;
    sHelppath = this->m_pszHelpFilePath;
    sHelppath = sHelppath.MakeLower();
    sHelppath.Replace(_T(".chm"), _T("_en.chm"));
    free((void*)m_pszHelpFilePath);
    m_pszHelpFilePath=_tcsdup(sHelppath);
    sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGitBlame_en.chm");
    do
    {
        GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf));
        CString sLang = _T("_");
        sLang += buf;
        sHelppath.Replace(_T("_en"), sLang);
        if (PathFileExists(sHelppath))
        {
            free((void*)m_pszHelpFilePath);
            m_pszHelpFilePath=_tcsdup(sHelppath);
            break;
        }
        sHelppath.Replace(sLang, _T("_en"));
        GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf));
        sLang += _T("_");
        sLang += buf;
        sHelppath.Replace(_T("_en"), sLang);
        if (PathFileExists(sHelppath))
        {
            free((void*)m_pszHelpFilePath);
            m_pszHelpFilePath=_tcsdup(sHelppath);
            break;
        }
        sHelppath.Replace(sLang, _T("_en"));

        DWORD lid = SUBLANGID(langId);
        lid--;
        if (lid > 0)
        {
            langId = MAKELANGID(PRIMARYLANGID(langId), lid);
        }
        else
            langId = 0;
    } while (langId);
    setlocale(LC_ALL, "");
    // We need to explicitly set the thread locale to the system default one to avoid possible problems with saving files in its original codepage
    // The problems occures when the language of OS differs from the regional settings
    // See the details here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100887
    SetThreadLocale(LOCALE_SYSTEM_DEFAULT);

    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    CWinAppEx::InitInstance();

    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL);

    // Initialize OLE libraries
    if (!AfxOleInit())
    {
        AfxMessageBox(IDP_OLE_INIT_FAILED);
        return FALSE;
    }
    AfxEnableControlContainer();
    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need
    // Change the registry key under which our settings are stored

    SetRegistryKey(_T("TortoiseGit"));
    LoadStdProfileSettings(4);  // Load standard INI file options (including MRU)

    InitContextMenuManager();

    InitKeyboardManager();

    InitTooltipManager();
    CMFCToolTipInfo ttParams;
    ttParams.m_bVislManagerTheme = TRUE;
    theApp.GetTooltipManager()->SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
            RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);

    // Register the application's document templates.  Document templates
    //  serve as the connection between documents, frame windows and views
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_TORTOISE_GIT_BLAME_MAINFRAME,
        RUNTIME_CLASS(CTortoiseGitBlameDoc),
        RUNTIME_CLASS(CMainFrame),       // main SDI frame window
        RUNTIME_CLASS(CTortoiseGitBlameView));
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);

    CCmdLineParser parser = CCmdLineParser(this->m_lpCmdLine);
    g_sGroupingUUID = parser.GetVal(L"groupuuid");

    // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);

    // Dispatch commands specified on the command line.  Will return FALSE if
    // app was launched with /RegServer, /Register, /Unregserver or /Unregister.
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;

    // The one and only window has been initialized, so show and update it
    m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->UpdateWindow();
    // call DragAcceptFiles only if there's a suffix
    //  In an SDI app, this should occur after ProcessShellCommand
    return TRUE;
}
Beispiel #2
0
// CTortoiseMergeApp initialization
BOOL CTortoiseMergeApp::InitInstance()
{
	SetDllDirectory(L"");

	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
	CMFCButton::EnableWindowsTheming();

	{
		DWORD len = GetCurrentDirectory(0, NULL);
		if (len)
		{
			auto_buffer<TCHAR> originalCurrentDirectory(len);
			if (GetCurrentDirectory(len, originalCurrentDirectory))
			{
				sOrigCWD = originalCurrentDirectory;
				sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
			}
		}
	}

	//set the resource dll for the required language
	CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
	long langId = loc;
	CString langDll;
	HINSTANCE hInst = NULL;
	do
	{
		langDll.Format(_T("%sLanguages\\TortoiseMerge%d.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);

		hInst = LoadLibrary(langDll);
		CString sVer = _T(STRPRODUCTVER);
		CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
		if (sFileVer.Compare(sVer)!=0)
		{
			FreeLibrary(hInst);
			hInst = NULL;
		}
		if (hInst != NULL)
			AfxSetResourceHandle(hInst);
		else
		{
			DWORD lid = SUBLANGID(langId);
			lid--;
			if (lid > 0)
			{
				langId = MAKELANGID(PRIMARYLANGID(langId), lid);
			}
			else
				langId = 0;
		}
	} while ((hInst == NULL) && (langId != 0));
	TCHAR buf[6];
	_tcscpy_s(buf, _T("en"));
	langId = loc;
	CString sHelppath;
	sHelppath = this->m_pszHelpFilePath;
	sHelppath = sHelppath.MakeLower();
	sHelppath.Replace(_T(".chm"), _T("_en.chm"));
	free((void*)m_pszHelpFilePath);
	m_pszHelpFilePath=_tcsdup(sHelppath);
	sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseMerge_en.chm");
	do
	{
		GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf));
		CString sLang = _T("_");
		sLang += buf;
		sHelppath.Replace(_T("_en"), sLang);
		if (PathFileExists(sHelppath))
		{
			free((void*)m_pszHelpFilePath);
			m_pszHelpFilePath=_tcsdup(sHelppath);
			break;
		}
		sHelppath.Replace(sLang, _T("_en"));
		GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf));
		sLang += _T("_");
		sLang += buf;
		sHelppath.Replace(_T("_en"), sLang);
		if (PathFileExists(sHelppath))
		{
			free((void*)m_pszHelpFilePath);
			m_pszHelpFilePath=_tcsdup(sHelppath);
			break;
		}
		sHelppath.Replace(sLang, _T("_en"));

		DWORD lid = SUBLANGID(langId);
		lid--;
		if (lid > 0)
		{
			langId = MAKELANGID(PRIMARYLANGID(langId), lid);
		}
		else
			langId = 0;
	} while (langId);
	setlocale(LC_ALL, ""); 
	// We need to explicitly set the thread locale to the system default one to avoid possible problems with saving files in its original codepage
	// The problems occures when the language of OS differs from the regional settings
	// See the details here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100887
	SetThreadLocale(LOCALE_SYSTEM_DEFAULT);

	// InitCommonControls() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.
	InitCommonControls();

	// Initialize all Managers for usage. They are automatically constructed
	// if not yet present
	InitContextMenuManager();
	InitKeyboardManager();

	CCmdLineParser parser = CCmdLineParser(this->m_lpCmdLine);

	if (parser.HasKey(_T("?")) || parser.HasKey(_T("help")))
	{
		CString sHelpText;
		sHelpText.LoadString(IDS_COMMANDLINEHELP);
		MessageBox(NULL, sHelpText, _T("TortoiseMerge"), MB_ICONINFORMATION);
		return FALSE;
	}

	// Initialize OLE libraries
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}
	AfxEnableControlContainer();
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	// of your final executable, you should remove from the following
	// the specific initialization routines you do not need
	// Change the registry key under which our settings are stored
	SetRegistryKey(_T("TortoiseMerge"));

	if (CRegDWORD(_T("Software\\TortoiseMerge\\Debug"), FALSE)==TRUE)
		AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);

	// To create the main window, this code creates a new frame window
	// object and then sets it as the application's main window object
	CMainFrame* pFrame = new CMainFrame;
	if (pFrame == NULL)
		return FALSE;
	m_pMainWnd = pFrame;

	// create and load the frame with its resources
	pFrame->LoadFrame(IDR_MAINFRAME,
		WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
		NULL);

	// Fill in the command line options
	pFrame->m_Data.m_baseFile.SetFileName(parser.GetVal(_T("base")));
	pFrame->m_Data.m_baseFile.SetDescriptiveName(parser.GetVal(_T("basename")));
	pFrame->m_Data.m_theirFile.SetFileName(parser.GetVal(_T("theirs")));
	pFrame->m_Data.m_theirFile.SetDescriptiveName(parser.GetVal(_T("theirsname")));
	pFrame->m_Data.m_yourFile.SetFileName(parser.GetVal(_T("mine")));
	pFrame->m_Data.m_yourFile.SetDescriptiveName(parser.GetVal(_T("minename")));
	pFrame->m_Data.m_mergedFile.SetFileName(parser.GetVal(_T("merged")));
	pFrame->m_Data.m_mergedFile.SetDescriptiveName(parser.GetVal(_T("mergedname")));
	pFrame->m_Data.m_sPatchPath = parser.HasVal(_T("patchpath")) ? parser.GetVal(_T("patchpath")) : _T("");
	pFrame->m_Data.m_sPatchPath.Replace('/', '\\');
	if (parser.HasKey(_T("patchoriginal")))
		pFrame->m_Data.m_sPatchOriginal = parser.GetVal(_T("patchoriginal"));
	if (parser.HasKey(_T("patchpatched")))
		pFrame->m_Data.m_sPatchPatched = parser.GetVal(_T("patchpatched"));
	pFrame->m_Data.m_sDiffFile = parser.GetVal(_T("diff"));
	pFrame->m_Data.m_sDiffFile.Replace('/', '\\');
	if (parser.HasKey(_T("oneway")))
		pFrame->m_bOneWay = TRUE;
	if (parser.HasKey(_T("diff")))
		pFrame->m_bOneWay = FALSE;
	if (parser.HasKey(_T("reversedpatch")))
		pFrame->m_bReversedPatch = TRUE;
	if (pFrame->m_Data.IsBaseFileInUse() && !pFrame->m_Data.IsYourFileInUse() && pFrame->m_Data.IsTheirFileInUse())
	{
		pFrame->m_Data.m_yourFile.TransferDetailsFrom(pFrame->m_Data.m_theirFile);
	}

	if ((!parser.HasKey(_T("patchpath")))&&(parser.HasVal(_T("diff"))))
	{
		// a patchfile was given, but not folder path to apply the patch to
		// If the patchfile is located inside a working copy, then use the parent directory
		// of the patchfile as the target directory, otherwise ask the user for a path.
		if (parser.HasKey(_T("wc")))
			pFrame->m_Data.m_sPatchPath = pFrame->m_Data.m_sDiffFile.Left(pFrame->m_Data.m_sDiffFile.ReverseFind('\\'));
		else
		{
			CBrowseFolder fbrowser;
			fbrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
			if (fbrowser.Show(NULL, pFrame->m_Data.m_sPatchPath)==CBrowseFolder::CANCEL)
				return FALSE;
		}
	}

	if ((parser.HasKey(_T("patchpath")))&&(!parser.HasVal(_T("diff"))))
	{
		// A path was given for applying a patchfile, but
		// the patchfile itself was not.
		// So ask the user for that patchfile

		OPENFILENAME ofn = {0};			// common dialog box structure
		TCHAR szFile[MAX_PATH] = {0};	// buffer for file name
		// Initialize OPENFILENAME
		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = pFrame->m_hWnd;
		ofn.lpstrFile = szFile;
		ofn.nMaxFile = _countof(szFile);
		CString temp;
		temp.LoadString(IDS_OPENDIFFFILETITLE);
		if (temp.IsEmpty())
			ofn.lpstrTitle = NULL;
		else
			ofn.lpstrTitle = temp;

		ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;
		// check if there's a patchfile in the clipboard
		UINT cFormat = RegisterClipboardFormat(_T("TSVN_UNIFIEDDIFF"));
		if (cFormat)
		{
			if (OpenClipboard(NULL))
			{
				UINT enumFormat = 0;
				do 
				{
					if (enumFormat == cFormat)
					{
						// yes, there's a patchfile in the clipboard
						ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_EXPLORER;

						ofn.hInstance = AfxGetResourceHandle();
						ofn.lpTemplateName = MAKEINTRESOURCE(IDD_PATCH_FILE_OPEN_CUSTOM);
						ofn.lpfnHook = CreatePatchFileOpenHook;
					}
				} while((enumFormat = EnumClipboardFormats(enumFormat))!=0);
				CloseClipboard();
			}
		}

		CString sFilter;
		sFilter.LoadString(IDS_PATCHFILEFILTER);
		TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
		_tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
		// Replace '|' delimiters with '\0's
		TCHAR *ptr = pszFilters + _tcslen(pszFilters);  //set ptr at the NULL
		while (ptr != pszFilters)
		{
			if (*ptr == '|')
				*ptr = '\0';
			ptr--;
		}
		ofn.lpstrFilter = pszFilters;
		ofn.nFilterIndex = 1;

		// Display the Open dialog box. 
		CString tempfile;
		if (GetOpenFileName(&ofn)==FALSE)
		{
			delete [] pszFilters;
			return FALSE;
		}
		delete [] pszFilters;
		pFrame->m_Data.m_sDiffFile = ofn.lpstrFile;
	}

	if ( pFrame->m_Data.m_baseFile.GetFilename().IsEmpty() && pFrame->m_Data.m_yourFile.GetFilename().IsEmpty() )
	{
		LPWSTR *szArglist;
		int nArgs;

		szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
		if( NULL == szArglist )
		{
			TRACE("CommandLineToArgvW failed\n");
		}
		else
		{
			if ( nArgs==3 || nArgs==4 )
			{
				// Four parameters:
				// [0]: Program name
				// [1]: BASE file
				// [2]: my file
				// [3]: THEIR file (optional)
				// This is the same format CAppUtils::StartExtDiff
				// uses if %base and %mine are not set and most
				// other diff tools use it too.
				if ( PathFileExists(szArglist[1]) && PathFileExists(szArglist[2]) )
				{
					pFrame->m_Data.m_baseFile.SetFileName(szArglist[1]);
					pFrame->m_Data.m_yourFile.SetFileName(szArglist[2]);
					if ( nArgs == 4 && PathFileExists(szArglist[3]) )
					{
						pFrame->m_Data.m_theirFile.SetFileName(szArglist[3]);
					}
				}
			}
		}

		// Free memory allocated for CommandLineToArgvW arguments.
		LocalFree(szArglist);
	}

	pFrame->m_bReadOnly = !!parser.HasKey(_T("readonly"));
	if (GetFileAttributes(pFrame->m_Data.m_yourFile.GetFilename()) & FILE_ATTRIBUTE_READONLY)
		pFrame->m_bReadOnly = true;
	pFrame->m_bBlame = !!parser.HasKey(_T("blame"));
	// diffing a blame means no editing!
	if (pFrame->m_bBlame)
		pFrame->m_bReadOnly = true;

	// try to find a suitable window title
	CString sYour = pFrame->m_Data.m_yourFile.GetDescriptiveName();
	if (sYour.Find(_T(" - "))>=0)
		sYour = sYour.Left(sYour.Find(_T(" - ")));
	if (sYour.Find(_T(" : "))>=0)
		sYour = sYour.Left(sYour.Find(_T(" : ")));
	CString sTheir = pFrame->m_Data.m_theirFile.GetDescriptiveName();
	if (sTheir.Find(_T(" - "))>=0)
		sTheir = sTheir.Left(sTheir.Find(_T(" - ")));
	if (sTheir.Find(_T(" : "))>=0)
		sTheir = sTheir.Left(sTheir.Find(_T(" : ")));

	if (!sYour.IsEmpty() && !sTheir.IsEmpty())
	{
		if (sYour.CompareNoCase(sTheir)==0)
			pFrame->SetWindowText(sYour + _T(" - TortoiseMerge"));
		else if ((sYour.GetLength() < 10) &&
				(sTheir.GetLength() < 10))
			pFrame->SetWindowText(sYour + _T(" - ") + sTheir + _T(" - TortoiseMerge"));
		else
		{
			// we have two very long descriptive texts here, which
			// means we have to find a way to use them as a window 
			// title in a shorter way.
			// for simplicity, we just use the one from "yourfile"
			pFrame->SetWindowText(sYour + _T(" - TortoiseMerge"));
		}
	}
	else if (!sYour.IsEmpty())
		pFrame->SetWindowText(sYour + _T(" - TortoiseMerge"));
	else if (!sTheir.IsEmpty())
		pFrame->SetWindowText(sTheir + _T(" - TortoiseMerge"));

	if (parser.HasKey(_T("createunifieddiff")))
	{
		// user requested to create a unified diff file
		CString origFile = parser.GetVal(_T("origfile"));
		CString modifiedFile = parser.GetVal(_T("modifiedfile"));
		if (!origFile.IsEmpty() && !modifiedFile.IsEmpty())
		{
			CString outfile = parser.GetVal(_T("outfile"));
			if (outfile.IsEmpty())
			{
				OPENFILENAME ofn = {0};			// common dialog box structure
				TCHAR szFile[MAX_PATH] = {0};	// buffer for file name
				ofn.lStructSize = sizeof(OPENFILENAME);
				ofn.lpstrFile = szFile;
				ofn.nMaxFile = _countof(szFile);
				CString temp;
				temp.LoadString(IDS_SAVEASTITLE);
				if (!temp.IsEmpty())
					ofn.lpstrTitle = temp;
				ofn.Flags = OFN_OVERWRITEPROMPT;
				CString sFilter;
				sFilter.LoadString(IDS_COMMONFILEFILTER);
				TCHAR * pszFilters = new TCHAR[sFilter.GetLength()+4];
				_tcscpy_s (pszFilters, sFilter.GetLength()+4, sFilter);
				// Replace '|' delimiters with '\0's
				TCHAR *ptr = pszFilters + _tcslen(pszFilters);  //set ptr at the NULL
				while (ptr != pszFilters)
				{
					if (*ptr == '|')
						*ptr = '\0';
					ptr--;
				}
				ofn.lpstrFilter = pszFilters;
				ofn.nFilterIndex = 1;

				// Display the Save dialog box. 
				CString sFile;
				if (GetSaveFileName(&ofn)==TRUE)
				{
					outfile = CString(ofn.lpstrFile);
				}
				delete [] pszFilters;
			}
			if (!outfile.IsEmpty())
			{
				CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outfile, false);
				return FALSE;
			}
		}
	}
	// The one and only window has been initialized, so show and update it
	pFrame->ActivateFrame();
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	pFrame->ShowDiffBar(!pFrame->m_bOneWay);
	if (!pFrame->m_Data.IsBaseFileInUse() && pFrame->m_Data.m_sPatchPath.IsEmpty() && pFrame->m_Data.m_sDiffFile.IsEmpty())
	{
		pFrame->OnFileOpen();
		return TRUE;
	}

	return pFrame->LoadViews();
}
// CTortoiseMergeApp initialization
BOOL CTortoiseMergeApp::InitInstance()
{
	SetDllDirectory(L"");
	SetTaskIDPerUUID();
	CCrashReport::Instance().AddUserInfoToReport(L"CommandLine", GetCommandLine());

	{
		DWORD len = GetCurrentDirectory(0, NULL);
		if (len)
		{
			std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);
			if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
			{
				sOrigCWD = originalCurrentDirectory.get();
				sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
			}
		}
	}

	//set the resource dll for the required language
	CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
	long langId = loc;
	CString langDll;
	HINSTANCE hInst = NULL;
	do
	{
		langDll.Format(_T("%sLanguages\\TortoiseMerge%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);

		hInst = LoadLibrary(langDll);
		CString sVer = _T(STRPRODUCTVER);
		CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
		if (sFileVer.Compare(sVer)!=0)
		{
			FreeLibrary(hInst);
			hInst = NULL;
		}
		if (hInst != NULL)
			AfxSetResourceHandle(hInst);
		else
		{
			DWORD lid = SUBLANGID(langId);
			lid--;
			if (lid > 0)
			{
				langId = MAKELANGID(PRIMARYLANGID(langId), lid);
			}
			else
				langId = 0;
		}
	} while ((hInst == NULL) && (langId != 0));
	TCHAR buf[6] = { 0 };
	_tcscpy_s(buf, _T("en"));
	langId = loc;
	CString sHelppath = CPathUtils::GetAppDirectory() + _T("TortoiseMerge_en.chm");
	free((void*)m_pszHelpFilePath);
	m_pszHelpFilePath=_tcsdup(sHelppath);
	sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseMerge_en.chm");
	do
	{
		GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf));
		CString sLang = _T("_");
		sLang += buf;
		sHelppath.Replace(_T("_en"), sLang);
		if (PathFileExists(sHelppath))
		{
			free((void*)m_pszHelpFilePath);
			m_pszHelpFilePath=_tcsdup(sHelppath);
			break;
		}
		sHelppath.Replace(sLang, _T("_en"));
		GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf));
		sLang += _T("_");
		sLang += buf;
		sHelppath.Replace(_T("_en"), sLang);
		if (PathFileExists(sHelppath))
		{
			free((void*)m_pszHelpFilePath);
			m_pszHelpFilePath=_tcsdup(sHelppath);
			break;
		}
		sHelppath.Replace(sLang, _T("_en"));

		DWORD lid = SUBLANGID(langId);
		lid--;
		if (lid > 0)
		{
			langId = MAKELANGID(PRIMARYLANGID(langId), lid);
		}
		else
			langId = 0;
	} while (langId);
	setlocale(LC_ALL, "");
	// We need to explicitly set the thread locale to the system default one to avoid possible problems with saving files in its original codepage
	// The problems occures when the language of OS differs from the regional settings
	// See the details here: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100887
	SetThreadLocale(LOCALE_SYSTEM_DEFAULT);

	// InitCommonControls() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.
	InitCommonControls();

	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
	CMFCButton::EnableWindowsTheming();
	EnableTaskbarInteraction(FALSE);

	// Initialize all Managers for usage. They are automatically constructed
	// if not yet present
	InitContextMenuManager();
	InitKeyboardManager();
	InitTooltipManager ();
	CMFCToolTipInfo params;
	params.m_bVislManagerTheme = TRUE;

	GetTooltipManager ()->SetTooltipParams (
		AFX_TOOLTIP_TYPE_ALL,
		RUNTIME_CLASS (CMFCToolTipCtrl),
		&params);

	CCmdLineParser parser = CCmdLineParser(this->m_lpCmdLine);

	g_sGroupingUUID = parser.GetVal(L"groupuuid");

	if (parser.HasKey(_T("?")) || parser.HasKey(_T("help")))
	{
		CString sHelpText;
		sHelpText.LoadString(IDS_COMMANDLINEHELP);
		MessageBox(NULL, sHelpText, _T("TortoiseGitMerge"), MB_ICONINFORMATION);
		return FALSE;
	}

	// Initialize OLE libraries
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}
	AfxEnableControlContainer();
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	// of your final executable, you should remove from the following
	// the specific initialization routines you do not need
	// Change the registry key under which our settings are stored
	SetRegistryKey(_T("TortoiseGitMerge"));

	if (CRegDWORD(_T("Software\\TortoiseGitMerge\\Debug"), FALSE)==TRUE)
		AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);

	// To create the main window, this code creates a new frame window
	// object and then sets it as the application's main window object
	CMainFrame* pFrame = new CMainFrame;
	if (pFrame == NULL)
		return FALSE;
	m_pMainWnd = pFrame;

	// create and load the frame with its resources
	if (!pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL))
		return FALSE;

	// Fill in the command line options
	pFrame->m_Data.m_baseFile.SetFileName(parser.GetVal(_T("base")));
	pFrame->m_Data.m_baseFile.SetDescriptiveName(parser.GetVal(_T("basename")));
	pFrame->m_Data.m_baseFile.SetReflectedName(parser.GetVal(_T("basereflectedname")));
	pFrame->m_Data.m_theirFile.SetFileName(parser.GetVal(_T("theirs")));
	pFrame->m_Data.m_theirFile.SetDescriptiveName(parser.GetVal(_T("theirsname")));
	pFrame->m_Data.m_theirFile.SetReflectedName(parser.GetVal(_T("theirsreflectedname")));
	pFrame->m_Data.m_yourFile.SetFileName(parser.GetVal(_T("mine")));
	pFrame->m_Data.m_yourFile.SetDescriptiveName(parser.GetVal(_T("minename")));
	pFrame->m_Data.m_yourFile.SetReflectedName(parser.GetVal(_T("minereflectedname")));
	pFrame->m_Data.m_mergedFile.SetFileName(parser.GetVal(_T("merged")));
	pFrame->m_Data.m_mergedFile.SetDescriptiveName(parser.GetVal(_T("mergedname")));
	pFrame->m_Data.m_mergedFile.SetReflectedName(parser.GetVal(_T("mergedreflectedname")));
	pFrame->m_Data.m_sPatchPath = parser.HasVal(_T("patchpath")) ? parser.GetVal(_T("patchpath")) : _T("");
	pFrame->m_Data.m_sPatchPath.Replace('/', '\\');
	if (parser.HasKey(_T("patchoriginal")))
		pFrame->m_Data.m_sPatchOriginal = parser.GetVal(_T("patchoriginal"));
	if (parser.HasKey(_T("patchpatched")))
		pFrame->m_Data.m_sPatchPatched = parser.GetVal(_T("patchpatched"));
	pFrame->m_Data.m_sDiffFile = parser.GetVal(_T("diff"));
	pFrame->m_Data.m_sDiffFile.Replace('/', '\\');
	if (parser.HasKey(_T("oneway")))
		pFrame->m_bOneWay = TRUE;
	if (parser.HasKey(_T("diff")))
		pFrame->m_bOneWay = FALSE;
	if (parser.HasKey(_T("reversedpatch")))
		pFrame->m_bReversedPatch = TRUE;
	if (parser.HasKey(_T("saverequired")))
		pFrame->m_bSaveRequired = true;
	if (parser.HasKey(_T("saverequiredonconflicts")))
		pFrame->m_bSaveRequiredOnConflicts = true;
	if (parser.HasKey(_T("deletebasetheirsmineonclose")))
		pFrame->m_bDeleteBaseTheirsMineOnClose = true;
	if (pFrame->m_Data.IsBaseFileInUse() && !pFrame->m_Data.IsYourFileInUse() && pFrame->m_Data.IsTheirFileInUse())
	{
		pFrame->m_Data.m_yourFile.TransferDetailsFrom(pFrame->m_Data.m_theirFile);
	}

	if ((!parser.HasKey(_T("patchpath")))&&(parser.HasVal(_T("diff"))))
	{
		// a patchfile was given, but not folder path to apply the patch to
		// If the patchfile is located inside a working copy, then use the parent directory
		// of the patchfile as the target directory, otherwise ask the user for a path.
		if (parser.HasKey(_T("wc")))
			pFrame->m_Data.m_sPatchPath = pFrame->m_Data.m_sDiffFile.Left(pFrame->m_Data.m_sDiffFile.ReverseFind('\\'));
		else
		{
			CBrowseFolder fbrowser;
			fbrowser.m_style = BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS;
			if (fbrowser.Show(NULL, pFrame->m_Data.m_sPatchPath)==CBrowseFolder::CANCEL)
				return FALSE;
		}
	}

	if ((parser.HasKey(_T("patchpath")))&&(!parser.HasVal(_T("diff"))))
	{
		// A path was given for applying a patchfile, but
		// the patchfile itself was not.
		// So ask the user for that patchfile

		HRESULT hr;
		// Create a new common save file dialog
		CComPtr<IFileOpenDialog> pfd = NULL;
		hr = pfd.CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER);
		if (SUCCEEDED(hr))
		{
			// Set the dialog options
			DWORD dwOptions;
			if (SUCCEEDED(hr = pfd->GetOptions(&dwOptions)))
			{
				hr = pfd->SetOptions(dwOptions | FOS_FILEMUSTEXIST | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST);
			}

			// Set a title
			if (SUCCEEDED(hr))
			{
				CString temp;
				temp.LoadString(IDS_OPENDIFFFILETITLE);
				pfd->SetTitle(temp);
			}
			CSelectFileFilter fileFilter(IDS_PATCHFILEFILTER);
			hr = pfd->SetFileTypes(fileFilter.GetCount(), fileFilter);
			bool bAdvised = false;
			DWORD dwCookie = 0;
			CComObjectStackEx<PatchOpenDlgEventHandler> cbk;
			CComQIPtr<IFileDialogEvents> pEvents = cbk.GetUnknown();

			{
				CComPtr<IFileDialogCustomize> pfdCustomize;
				hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdCustomize));
				if (SUCCEEDED(hr))
				{
					// check if there's a unified diff on the clipboard and
					// add a button to the fileopen dialog if there is.
					UINT cFormat = RegisterClipboardFormat(_T("TSVN_UNIFIEDDIFF"));
					if ((cFormat)&&(OpenClipboard(NULL)))
					{
						HGLOBAL hglb = GetClipboardData(cFormat);
						if (hglb)
						{
							pfdCustomize->AddPushButton(101, CString(MAKEINTRESOURCE(IDS_PATCH_COPYFROMCLIPBOARD)));
							hr = pfd->Advise(pEvents, &dwCookie);
							bAdvised = SUCCEEDED(hr);
						}
						CloseClipboard();
					}
				}
			}

			// Show the save file dialog
			if (SUCCEEDED(hr) && SUCCEEDED(hr = pfd->Show(pFrame->m_hWnd)))
			{
				// Get the selection from the user
				CComPtr<IShellItem> psiResult = NULL;
				hr = pfd->GetResult(&psiResult);
				if (bAdvised)
					pfd->Unadvise(dwCookie);
				if (SUCCEEDED(hr))
				{
					PWSTR pszPath = NULL;
					hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
					if (SUCCEEDED(hr))
					{
						pFrame->m_Data.m_sDiffFile = pszPath;
						CoTaskMemFree(pszPath);
					}
				}
				else
				{
					// no result, which means we closed the dialog in our button handler
					std::wstring sTempFile;
					if (TrySavePatchFromClipboard(sTempFile))
						pFrame->m_Data.m_sDiffFile = sTempFile.c_str();
				}
			}
			else
			{
				if (bAdvised)
					pfd->Unadvise(dwCookie);
				return FALSE;
			}
		}
		else
		{
			OPENFILENAME ofn = {0};         // common dialog box structure
			TCHAR szFile[MAX_PATH] = {0};   // buffer for file name
			// Initialize OPENFILENAME
			ofn.lStructSize = sizeof(OPENFILENAME);
			ofn.hwndOwner = pFrame->m_hWnd;
			ofn.lpstrFile = szFile;
			ofn.nMaxFile = _countof(szFile);
			CString temp;
			temp.LoadString(IDS_OPENDIFFFILETITLE);
			if (temp.IsEmpty())
				ofn.lpstrTitle = NULL;
			else
				ofn.lpstrTitle = temp;

			ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_EXPLORER;
			if( HasClipboardPatch() ) {
				ofn.Flags |= ( OFN_ENABLETEMPLATE | OFN_ENABLEHOOK );
				ofn.hInstance = AfxGetResourceHandle();
				ofn.lpTemplateName = MAKEINTRESOURCE(IDD_PATCH_FILE_OPEN_CUSTOM);
				ofn.lpfnHook = CreatePatchFileOpenHook;
			}

			CSelectFileFilter fileFilter(IDS_PATCHFILEFILTER);
			ofn.lpstrFilter = fileFilter;
			ofn.nFilterIndex = 1;

			// Display the Open dialog box.
			if (GetOpenFileName(&ofn)==FALSE)
			{
				return FALSE;
			}
			pFrame->m_Data.m_sDiffFile = ofn.lpstrFile;
		}
	}

	if ( pFrame->m_Data.m_baseFile.GetFilename().IsEmpty() && pFrame->m_Data.m_yourFile.GetFilename().IsEmpty() )
	{
		int nArgs;
		LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
		if( NULL == szArglist )
		{
			TRACE("CommandLineToArgvW failed\n");
		}
		else
		{
			if ( nArgs==3 || nArgs==4 )
			{
				// Four parameters:
				// [0]: Program name
				// [1]: BASE file
				// [2]: my file
				// [3]: THEIR file (optional)
				// This is the same format CAppUtils::StartExtDiff
				// uses if %base and %mine are not set and most
				// other diff tools use it too.
				if ( PathFileExists(szArglist[1]) && PathFileExists(szArglist[2]) )
				{
					pFrame->m_Data.m_baseFile.SetFileName(szArglist[1]);
					pFrame->m_Data.m_yourFile.SetFileName(szArglist[2]);
					if ( nArgs == 4 && PathFileExists(szArglist[3]) )
					{
						pFrame->m_Data.m_theirFile.SetFileName(szArglist[3]);
					}
				}
			}
			else if (nArgs == 2)
			{
				// only one path specified: use it to fill the "open" dialog
				if (PathFileExists(szArglist[1]))
				{
					pFrame->m_Data.m_yourFile.SetFileName(szArglist[1]);
					pFrame->m_Data.m_yourFile.StoreFileAttributes();
				}
			}
		}

		// Free memory allocated for CommandLineToArgvW arguments.
		LocalFree(szArglist);
	}

	pFrame->m_bReadOnly = !!parser.HasKey(_T("readonly"));
	if (GetFileAttributes(pFrame->m_Data.m_yourFile.GetFilename()) & FILE_ATTRIBUTE_READONLY)
		pFrame->m_bReadOnly = true;
	pFrame->m_bBlame = !!parser.HasKey(_T("blame"));
	// diffing a blame means no editing!
	if (pFrame->m_bBlame)
		pFrame->m_bReadOnly = true;

	pFrame->SetWindowTitle();

	if (parser.HasKey(_T("createunifieddiff")))
	{
		// user requested to create a unified diff file
		CString origFile = parser.GetVal(_T("origfile"));
		CString modifiedFile = parser.GetVal(_T("modifiedfile"));
		if (!origFile.IsEmpty() && !modifiedFile.IsEmpty())
		{
			CString outfile = parser.GetVal(_T("outfile"));
			if (outfile.IsEmpty())
			{
				CCommonAppUtils::FileOpenSave(outfile, NULL, IDS_SAVEASTITLE, IDS_COMMONFILEFILTER, false, NULL);
			}
			if (!outfile.IsEmpty())
			{
				CRegStdDWORD regContextLines(L"Software\\TortoiseGitMerge\\ContextLines", (DWORD)-1);
				CAppUtils::CreateUnifiedDiff(origFile, modifiedFile, outfile, regContextLines, false);
				return FALSE;
			}
		}
	}

	pFrame->resolveMsgWnd    = parser.HasVal(L"resolvemsghwnd")   ? (HWND)parser.GetLongLongVal(L"resolvemsghwnd")     : 0;
	pFrame->resolveMsgWParam = parser.HasVal(L"resolvemsgwparam") ? (WPARAM)parser.GetLongLongVal(L"resolvemsgwparam") : 0;
	pFrame->resolveMsgLParam = parser.HasVal(L"resolvemsglparam") ? (LPARAM)parser.GetLongLongVal(L"resolvemsglparam") : 0;

	// The one and only window has been initialized, so show and update it
	pFrame->ActivateFrame();
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	pFrame->ShowDiffBar(!pFrame->m_bOneWay);
	if (!pFrame->m_Data.IsBaseFileInUse() && pFrame->m_Data.m_sPatchPath.IsEmpty() && pFrame->m_Data.m_sDiffFile.IsEmpty())
	{
		pFrame->OnFileOpen(pFrame->m_Data.m_yourFile.InUse());
		return TRUE;
	}

	int line = -2;
	if (parser.HasVal(_T("line")))
	{
		line = parser.GetLongVal(_T("line"));
		line--; // we need the index
	}

	return pFrame->LoadViews(line);
}
BOOL CTortoiseProcApp::InitInstance()
{
	CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": InitInstance\n"));
	CheckUpgrade();
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
	CMFCButton::EnableWindowsTheming();
	CHistoryCombo::m_nGitIconIndex = SYS_IMAGE_LIST().AddIcon((HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_GITCONFIG), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE));

	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL);

	//set the resource dll for the required language
	CRegDWORD loc = CRegDWORD(_T("Software\\TortoiseGit\\LanguageID"), 1033);
	long langId = loc;
	{
		CString langStr;
		langStr.Format(_T("%ld"), langId);
		CCrashReport::Instance().AddUserInfoToReport(L"LanguageID", langStr);
	}
	CString langDll;
	CStringA langpath = CStringA(CPathUtils::GetAppParentDirectory());
	langpath += "Languages";
	do
	{
		langDll.Format(_T("%sLanguages\\TortoiseProc%ld.dll"), (LPCTSTR)CPathUtils::GetAppParentDirectory(), langId);

		CString sVer = _T(STRPRODUCTVER);
		CString sFileVer = CPathUtils::GetVersionFromFile(langDll);
		if (sFileVer == sVer)
		{
			HINSTANCE hInst = LoadLibrary(langDll);
			if (hInst != NULL)
			{
				CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Load Language DLL %s\n"), langDll);
				AfxSetResourceHandle(hInst);
				break;
			}
		}
		{
			DWORD lid = SUBLANGID(langId);
			lid--;
			if (lid > 0)
			{
				langId = MAKELANGID(PRIMARYLANGID(langId), lid);
			}
			else
				langId = 0;
		}
	} while (langId != 0);
	TCHAR buf[6] = { 0 };
	_tcscpy_s(buf, _T("en"));
	langId = loc;
	// MFC uses a help file with the same name as the application by default,
	// which means we have to change that default to our language specific help files
	CString sHelppath = CPathUtils::GetAppDirectory() + _T("TortoiseGit_en.chm");
	free((void*)m_pszHelpFilePath);
	m_pszHelpFilePath=_tcsdup(sHelppath);
	sHelppath = CPathUtils::GetAppParentDirectory() + _T("Languages\\TortoiseGit_en.chm");
	do
	{
		CString sLang = _T("_");
		if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO639LANGNAME, buf, _countof(buf)))
		{
			sLang += buf;
			sHelppath.Replace(_T("_en"), sLang);
			if (PathFileExists(sHelppath))
			{
				free((void*)m_pszHelpFilePath);
				m_pszHelpFilePath=_tcsdup(sHelppath);
				break;
			}
		}
		sHelppath.Replace(sLang, _T("_en"));
		if (GetLocaleInfo(MAKELCID(langId, SORT_DEFAULT), LOCALE_SISO3166CTRYNAME, buf, _countof(buf)))
		{
			sLang += _T("_");
			sLang += buf;
			sHelppath.Replace(_T("_en"), sLang);
			if (PathFileExists(sHelppath))
			{
				free((void*)m_pszHelpFilePath);
				m_pszHelpFilePath=_tcsdup(sHelppath);
				break;
			}
		}
		sHelppath.Replace(sLang, _T("_en"));

		DWORD lid = SUBLANGID(langId);
		lid--;
		if (lid > 0)
		{
			langId = MAKELANGID(PRIMARYLANGID(langId), lid);
		}
		else
			langId = 0;
	} while (langId);
	CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Set Help Filename %s\n"), m_pszHelpFilePath);
	setlocale(LC_ALL, "");

	if (!g_Git.CheckMsysGitDir())
	{
		UINT ret = CMessageBox::Show(NULL, IDS_PROC_NOMSYSGIT, IDS_APPNAME, 3, IDI_HAND, IDS_PROC_SETMSYSGITPATH, IDS_PROC_GOTOMSYSGITWEBSITE, IDS_ABORTBUTTON);
		if(ret == 2)
		{
			ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW);
		}
		else if(ret == 1)
		{
			// open settings dialog
			CSinglePropSheetDlg(CString(MAKEINTRESOURCE(IDS_PROC_SETTINGS_TITLE)), new CSetMainPage(), this->GetMainWnd()).DoModal();
		}
		return FALSE;
	}
	if (CAppUtils::GetMsysgitVersion() < 0x01070a00)
	{
		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);
		if (ret == 1)
		{
			CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
			ShellExecute(NULL, NULL, _T("http://msysgit.github.io/"), NULL, NULL, SW_SHOW);
			return FALSE;
		}
		else if (ret == 2)
		{
			CMessageBox::RemoveRegistryKey(_T("OldMsysgitVersionWarning")); // only store answer if it is "Ignore"
			return FALSE;
		}
	}

	{
		CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Registering Crash Report ...\n"));
		CCrashReport::Instance().AddUserInfoToReport(L"msysGitDir", CGit::ms_LastMsysGitDir);
		CString versionString;
		versionString.Format(_T("%d"), CGit::ms_LastMsysGitVersion);
		CCrashReport::Instance().AddUserInfoToReport(L"msysGitVersion", versionString);
	}

	CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Initializing UI components ...\n"));
	// InitCommonControls() is required on Windows XP if an application
	// manifest specifies use of ComCtl32.dll version 6 or later to enable
	// visual styles.  Otherwise, any window creation will fail.

	INITCOMMONCONTROLSEX used = {
		sizeof(INITCOMMONCONTROLSEX),
			ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES | ICC_DATE_CLASSES |
			ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES | ICC_LISTVIEW_CLASSES |
			ICC_NATIVEFNTCTL_CLASS | ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
			ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS |
			ICC_USEREX_CLASSES | ICC_WIN95_CLASSES
	};
	InitCommonControlsEx(&used);
	AfxOleInit();
	AfxEnableControlContainer();
	AfxInitRichEdit5();
	CWinAppEx::InitInstance();
	SetRegistryKey(_T("TortoiseGit"));
	AfxGetApp()->m_pszProfileName = _tcsdup(_T("TortoiseProc")); // w/o this ResizableLib will store data under TortoiseGitProc which is not compatible with older versions

	CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);

	hWndExplorer = NULL;
	CString sVal = parser.GetVal(_T("hwnd"));
	if (!sVal.IsEmpty())
		hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);

	while (GetParent(hWndExplorer)!=NULL)
		hWndExplorer = GetParent(hWndExplorer);
	if (!IsWindow(hWndExplorer))
	{
		hWndExplorer = NULL;
	}

	// if HKCU\Software\TortoiseGit\Debug is not 0, show our command line
	// in a message box
	if (CRegDWORD(_T("Software\\TortoiseGit\\Debug"), FALSE)==TRUE)
		AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);

	if (parser.HasKey(_T("urlhandler")))
	{
		CString url = parser.GetVal(_T("urlhandler"));
		if (url.Find(_T("tgit://clone/")) == 0)
		{
			url = url.Mid(13); // 21 = "tgit://clone/".GetLength()
		}
		else if (url.Find(_T("github-windows://openRepo/")) == 0)
		{
			url = url.Mid(26); // 26 = "github-windows://openRepo/".GetLength()
			int questioMark = url.Find('?');
			if (questioMark > 0)
				url = url.Left(questioMark);
		}
		else if (url.Find(_T("smartgit://cloneRepo/")) == 0)
		{
			url = url.Mid(21); // 21 = "smartgit://cloneRepo/".GetLength()
		}
		else
		{
			CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
			return FALSE;
		}
		CString newCmd;
		newCmd.Format(_T("/command:clone /url:\"%s\" /hasurlhandler"), url);
		parser = CCmdLineParser(newCmd);
	}

	if ( parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile")))
	{
		CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
		return FALSE;
	}

	CTGitPath cmdLinePath;
	CTGitPathList pathList;
	if (g_sGroupingUUID.IsEmpty())
		g_sGroupingUUID = parser.GetVal(L"groupuuid");
	if ( parser.HasKey(_T("pathfile")) )
	{

		CString sPathfileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile")));

		cmdLinePath.SetFromUnknown(sPathfileArgument);
		if (pathList.LoadFromFile(cmdLinePath)==false)
			return FALSE;		// no path specified!
		if ( parser.HasKey(_T("deletepathfile")) )
		{
			// We can delete the temporary path file, now that we've loaded it
			::DeleteFile(cmdLinePath.GetWinPath());
		}
		// This was a path to a temporary file - it's got no meaning now, and
		// anybody who uses it again is in for a problem...
		cmdLinePath.Reset();

	}
	else
	{

		CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path")));
		if (parser.HasKey(_T("expaths")))
		{
			// an /expaths param means we're started via the buttons in our Win7 library
			// and that means the value of /expaths is the current directory, and
			// the selected paths are then added as additional parameters but without a key, only a value

			// because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW"
			// we have to escape the backslashes first. Since we're only dealing with paths here, that's
			// a save bet.
			// Without this, a command line like:
			// /command:commit /expaths:"D:\" "D:\Utils"
			// would fail because the "D:\" is treated as the backslash being the escape char for the quotation
			// mark and we'd end up with:
			// argv[1] = /command:commit
			// argv[2] = /expaths:D:" D:\Utils
			// See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx
			CString cmdLine = GetCommandLineW();
			cmdLine.Replace(L"\\", L"\\\\");
			int nArgs = 0;
			LPWSTR *szArglist = CommandLineToArgvW(cmdLine, &nArgs);
			if (szArglist)
			{
				// argument 0 is the process path, so start with 1
				for (int i = 1; i < nArgs; ++i)
				{
					if (szArglist[i][0] != '/')
					{
						if (!sPathArgument.IsEmpty())
							sPathArgument += '*';
						sPathArgument += szArglist[i];
					}
				}
				sPathArgument.Replace(L"\\\\", L"\\");
			}
			LocalFree(szArglist);
		}
		if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
		{
			CMessageBox::Show(hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
			return FALSE;
		}
		int asterisk = sPathArgument.Find('*');
		cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
		pathList.LoadFromAsteriskSeparatedString(sPathArgument);
	}

	if (pathList.IsEmpty()) {
		pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
	}

	// Set CWD to temporary dir, and restore it later
	{
		DWORD len = GetCurrentDirectory(0, NULL);
		if (len)
		{
			std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);
			if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
			{
				sOrigCWD = originalCurrentDirectory.get();
				sOrigCWD = CPathUtils::GetLongPathname(sOrigCWD);
			}
		}
		TCHAR pathbuf[MAX_PATH] = {0};
		GetTortoiseGitTempPath(MAX_PATH, pathbuf);
		SetCurrentDirectory(pathbuf);
	}

	CheckForNewerVersion();

	CAutoGeneralHandle TGitMutex = ::CreateMutex(NULL, FALSE, _T("TortoiseGitProc.exe"));
	if (!g_Git.SetCurrentDir(cmdLinePath.GetWinPathString(), parser.HasKey(_T("submodule")) == TRUE))
	{
		for (int i = 0; i < pathList.GetCount(); ++i)
			if(g_Git.SetCurrentDir(pathList[i].GetWinPath()))
				break;
	}

	if(!g_Git.m_CurrentDir.IsEmpty())
	{
		sOrigCWD = g_Git.m_CurrentDir;
		SetCurrentDirectory(g_Git.m_CurrentDir);
	}

	if (g_sGroupingUUID.IsEmpty())
	{
		CRegStdDWORD groupSetting = CRegStdDWORD(_T("Software\\TortoiseGit\\GroupTaskbarIconsPerRepo"), 3);
		switch (DWORD(groupSetting))
		{
		case 1:
		case 2:
			// implemented differently to TortoiseSVN atm
			break;
		case 3:
		case 4:
			{
				CString wcroot;
				if (g_GitAdminDir.HasAdminDir(g_Git.m_CurrentDir, true, &wcroot))
				{
					git_oid oid;
					CStringA wcRootA(wcroot + CPathUtils::GetAppDirectory());
					if (!git_odb_hash(&oid, wcRootA, wcRootA.GetLength(), GIT_OBJ_BLOB))
					{
						CStringA hash;
						git_oid_tostr(hash.GetBufferSetLength(GIT_OID_HEXSZ + 1), GIT_OID_HEXSZ + 1, &oid);
						hash.ReleaseBuffer();
						g_sGroupingUUID = hash;
					}
					ProjectProperties pp;
					pp.ReadProps();
					CString icon = pp.sIcon;
					icon.Replace('/', '\\');
					if (icon.IsEmpty())
						g_bGroupingRemoveIcon = true;
					g_sGroupingIcon = icon;
				}
			}
		}
	}

	CString sAppID = GetTaskIDPerUUID(g_sGroupingUUID).c_str();
	InitializeJumpList(sAppID);
	EnsureGitLibrary(false);

	{
		CString err;
		try
		{
			// requires CWD to be set
			CGit::m_LogEncode = CAppUtils::GetLogOutputEncode();

			// make sure all config files are read in order to check that none contains an error
			g_Git.GetConfigValue(_T("doesnot.exist"));
		}
		catch (char* msg)
		{
			err = CString(msg);
		}

		if (!err.IsEmpty())
		{
			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)));
			if (choice == 1)
			{
				// open the config file with alternative editor
				CAppUtils::LaunchAlternativeEditor(g_Git.GetGitLocalConfig());
			}
			else if (choice == 2)
			{
				// open the global config file with alternative editor
				CAppUtils::LaunchAlternativeEditor(g_Git.GetGitGlobalConfig());
			}
			return FALSE;
		}
	}

	// execute the requested command
	CommandServer server;
	Command * cmd = server.GetCommand(parser.GetVal(_T("command")));
	if (cmd)
	{
		cmd->SetExplorerHwnd(hWndExplorer);

		cmd->SetParser(parser);
		cmd->SetPaths(pathList, cmdLinePath);

		retSuccess = cmd->Execute();
		delete cmd;
	}

	// Look for temporary files left around by TortoiseSVN and
	// remove them. But only delete 'old' files because some
	// apps might still be needing the recent ones.
	{
		DWORD len = GetTortoiseGitTempPath(0, NULL);
		std::unique_ptr<TCHAR[]> path(new TCHAR[len + 100]);
		len = GetTortoiseGitTempPath (len + 100, path.get());
		if (len != 0)
		{
			CDirFileEnum finder(path.get());
			FILETIME systime_;
			::GetSystemTimeAsFileTime(&systime_);
			__int64 systime = (((_int64)systime_.dwHighDateTime)<<32) | ((__int64)systime_.dwLowDateTime);
			bool isDir;
			CString filepath;
			while (finder.NextFile(filepath, &isDir))
			{
				HANDLE hFile = ::CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, isDir ? FILE_FLAG_BACKUP_SEMANTICS : NULL, NULL);
				if (hFile != INVALID_HANDLE_VALUE)
				{
					FILETIME createtime_;
					if (::GetFileTime(hFile, &createtime_, NULL, NULL))
					{
						::CloseHandle(hFile);
						__int64 createtime = (((_int64)createtime_.dwHighDateTime)<<32) | ((__int64)createtime_.dwLowDateTime);
						if ((createtime + 864000000000) < systime)		//only delete files older than a day
						{
							::SetFileAttributes(filepath, FILE_ATTRIBUTE_NORMAL);
							if (isDir)
								::RemoveDirectory(filepath);
							else
								::DeleteFile(filepath);
						}
					}
					else
						::CloseHandle(hFile);
				}
			}
		}
	}

	// Since the dialog has been closed, return FALSE so that we exit the
	// application, rather than start the application's message pump.
	return FALSE;
}
BOOL CTortoiseSIProcApp::ProcessCommandLine()
{
	CCmdLineParser parser(AfxGetApp()->m_lpCmdLine);

	CString sVal = parser.GetVal(_T("hwnd"));

	if (!sVal.IsEmpty()) {
		m_hWndExplorer = (HWND)_wcstoui64(sVal, nullptr, 16);
	}

	while (GetParent(m_hWndExplorer) != NULL) {
		m_hWndExplorer = GetParent(m_hWndExplorer);
	}

	if (!IsWindow(m_hWndExplorer))
	{
		m_hWndExplorer = NULL;
	}

#if _DEBUG
	if (CRegDWORD(_T("Software\\TortoiseSI\\Debug"), FALSE) == TRUE) {
		AfxMessageBox(AfxGetApp()->m_lpCmdLine, MB_OK | MB_ICONINFORMATION);
	}
#endif

	// The path and pathfile arguments are mutually exclusive
	if (parser.HasKey(_T("path")) && parser.HasKey(_T("pathfile")))
	{
		CMessageBox::Show(NULL, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
		return FALSE;
	}

	CTGitPath cmdLinePath;
	CTGitPathList pathList;

	if (parser.HasKey(_T("pathfile")))
	{
		// Process /pathfile argument

		CString sPathFileArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("pathfile")));

		cmdLinePath.SetFromUnknown(sPathFileArgument);

		if (pathList.LoadFromFile(cmdLinePath) == false) {
			// no path specified!
			return FALSE;		
	    }

		if (parser.HasKey(_T("deletepathfile")))
		{
			// We can delete the temporary path file, now that we've loaded it
			::DeleteFile(cmdLinePath.GetWinPath());
		}

		// This was a path to a temporary file - it's got no meaning now, and
		// anybody who uses it again is in for a problem...
		cmdLinePath.Reset();

	} else {

		// Process /path and /expaths argument
		// Build-uo /path value as /path:<value>*<arg1>*<arg2>...
		// Where <arg1>, <arg2> etc are extracted from /expath arguments.
		// Since all arguments are passed in the form of /parameter:<argument>
		// We process only those arguments which are not preceded by a /parameter:
		// This only includes arguments specified following /expaths (See comments below)

		CString sPathArgument = CPathUtils::GetLongPathname(parser.GetVal(_T("path")));

		if (parser.HasKey(_T("expaths")))
		{
			// An /expaths param means we are started via the buttons in our Win7 library
			// and that means the value of /expaths is the current directory and
			// the selected paths are then added as additional parameters but without a key, only a value
			//
			//     e.g. /expaths:"D:\" "D:\Utils"
			//
			// Because of the "strange treatment of quotation marks and backslashes by CommandLineToArgvW",
			// we have to escape the backslashes first.  Since we're only dealing with paths here, that's
			// a safe bet.  Without this, a command line like:
			//
			//     /command:commit /expaths:"D:\" "D:\Utils"
			// 
			// would fail because the "D:\" is treated as the backslash being the escape char for the quotation
			// mark and we'd end up with:
			//
			//     argv[1] = /command:commit
			//     argv[2] = /expaths:D:" D:\Utils
			//
			// See here for more details: http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx

			CString cmdLine = GetCommandLineW();

			// Escape backslashes
			cmdLine.Replace(L"\\", L"\\\\");

			int nArgs = 0;
			LPWSTR *szArgList = CommandLineToArgvW(cmdLine, &nArgs);

			if (szArgList)
			{
				// Argument 0 is the process path, so start with 1
				for (int i = 1; i < nArgs; i++)
				{
					if (szArgList[i][0] != '/')
					{
						if (!sPathArgument.IsEmpty()) {
							sPathArgument += '*';
						}
						sPathArgument += szArgList[i];
					}
				}

				sPathArgument.Replace(L"\\\\", L"\\");
			}

			LocalFree(szArgList);
		}

		if (sPathArgument.IsEmpty() && parser.HasKey(L"path"))
		{
			CMessageBox::Show(m_hWndExplorer, IDS_ERR_INVALIDPATH, IDS_APPNAME, MB_ICONERROR);
			return FALSE;
		}

		int asterisk = sPathArgument.Find('*');
		cmdLinePath.SetFromUnknown(asterisk >= 0 ? sPathArgument.Left(asterisk) : sPathArgument);
		pathList.LoadFromAsteriskSeparatedString(sPathArgument);
	}

	if (pathList.IsEmpty()) {
		pathList.AddPath(CTGitPath::CTGitPath(g_Git.m_CurrentDir));
	}

	// Set CWD to temporary dir, and restore it later
	{
		DWORD len = GetCurrentDirectory(0, NULL);

		if (len)
		{
			std::unique_ptr<TCHAR[]> originalCurrentDirectory(new TCHAR[len]);

			if (GetCurrentDirectory(len, originalCurrentDirectory.get()))
			{
				m_sOrigCWD = originalCurrentDirectory.get();
				m_sOrigCWD = CPathUtils::GetLongPathname(m_sOrigCWD);
			}
		}

		TCHAR pathbuf[MAX_PATH] = { 0 };
		GetTortoiseGitTempPath(MAX_PATH, pathbuf);
		SetCurrentDirectory(pathbuf);
	}

	if (!g_Git.m_CurrentDir.IsEmpty())
	{
		m_sOrigCWD = g_Git.m_CurrentDir;
		SetCurrentDirectory(m_sOrigCWD);
	}

	// Execute the requested command
	CommandServer server;

	Command *cmd = server.GetCommand(parser.GetVal(_T("command")));

	if (cmd)
	{
		cmd->SetExplorerHwnd(m_hWndExplorer);
		cmd->SetParser(parser);
		cmd->SetPaths(pathList, cmdLinePath);
		m_bRetSuccess = cmd->Execute();
		delete cmd;
	}

	return TRUE;
}