Exemplo n.º 1
0
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
#endif
{
	hInst = hInstance;
	isWin64 = IsWindows64();

	GetVersionEx(&gOSVer);

	int nInstallVer = 0;

	wsprintf(gsTitle, msgConEmuInstaller, CONEMUVERL);
	lstrcpyn(gsRunAsAdm, msgRunSetupAsAdmin, countof(gsRunAsAdm));

	wchar_t szArg[MAX_PATH+1];
	LPCWSTR pszCmdToken = GetCommandLine();
	LPCWSTR pszCmdLineW = pszCmdToken;

	CTempDir temp_dir; // gsTempFolder[0] = 0;

	while (0 == NextArg(&pszCmdToken, szArg))
	{
		if (lstrcmp(szArg, L"/?") == 0 || lstrcmp(szArg, L"-?") == 0 || lstrcmp(szArg, L"-h") == 0
			|| lstrcmp(szArg, L"-help") == 0 || lstrcmp(szArg, L"--help") == 0)
		{
			MessageBox(NULL, msgUsageExample, gsTitle, MB_ICONINFORMATION);
			return exit_Cancelled;
		}

		if (*szArg == L'/')
		{
			if (szArg[1] == L'e' || szArg[1] == L'E')
			{
				gbExtractOnly = true;
				if (szArg[2] == L':' && szArg[3])
				{
					lstrcpyn(gsTempFolder, (szArg[3]==L'"') ? (szArg+4) : (szArg+3), countof(gsTempFolder));
				}
				continue;
			}

		    if (memcmp(szArg, L"/p:x", 4*sizeof(*szArg)) == 0)
		    {
		    	gbAlreadyAdmin = IsUserAdmin();
				if (lstrcmpi(szArg+4, L"86") == 0)
				{
					nInstallVer = Ver86;
				}
				else if (lstrcmpi(szArg+4, L"86,adm") == 0)
				{
					nInstallVer = Ver86;
					gbUseElevation = !gbAlreadyAdmin;
				}
				else if (lstrcmpi(szArg+4, L"64") == 0)
				{
					nInstallVer = Ver64;
				}
				else if (lstrcmpi(szArg+4, L"64,adm") == 0)
				{
					nInstallVer = Ver64;
					gbUseElevation = !gbAlreadyAdmin;
				}
			}
			else
				pszCmdToken = pszCmdLineW;
			break;
		}
		else if (*szArg == L'-')
		{
			pszCmdToken = pszCmdLineW;
			break;
		}

		pszCmdLineW = pszCmdToken;
	}

	if (!temp_dir.Acquire())
	{
		return exit_CreateDirectory;
	}

	if (!gbExtractOnly)
	{
		// If pszCmdToken is not empty - set global var
		gbAutoMode = (pszCmdToken && *pszCmdToken);

		wchar_t szInstallPath[MAX_PATH+32];
		bool bInstalled;
		HKEY hk;

		lstrcpyn(gsMessage, msgChooseInstallVer, countof(gsMessage));

			szInstallPath[0] = 0; bInstalled = false;
			struct {HKEY hk; LPCWSTR path; LPCWSTR name; bool our;}
				Keys[] = {
					{HKEY_LOCAL_MACHINE,L"SOFTWARE\\ConEmu",L"InstallDir",true},
					//Current installer does not use FarManager installation dir anymore
					//{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far Manager",L"InstallDir"},
					//{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far2",L"InstallDir"},
					//{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far",L"InstallDir"},
				};
			for (size_t s = 0; s < countof(Keys); s++)
			{
				if (!RegOpenKeyEx(Keys[s].hk, Keys[s].path, 0, KEY_READ, &hk)
					|| !RegOpenKeyEx(Keys[s].hk, Keys[s].path, 0, KEY_READ|KEY_WOW64_32KEY, &hk))
				{
					wchar_t szPath[MAX_PATH+1] = {}; DWORD cbSize = sizeof(szPath)-2;
					LONG lRc = RegQueryValueEx(hk, Keys[s].name, NULL, NULL, (LPBYTE)szPath, &cbSize);
					RegCloseKey(hk);
					if (!lRc && *szPath)
					{
						bInstalled = Keys[s].our;
						lstrcpy(szInstallPath, szPath);
						cbSize = lstrlen(szInstallPath);
						if (szInstallPath[cbSize-1] == L'\\') szInstallPath[cbSize-1] = 0;
						break;
					}
				}
			}
			if (szInstallPath[0] == 0)
			{
				GetEnvironmentVariable(L"ProgramFiles", szInstallPath, MAX_PATH);
				int nLen = lstrlen(szInstallPath);
				lstrcat(szInstallPath, (nLen > 0 && szInstallPath[nLen-1] != L'\\') ? L"\\ConEmu" : L"ConEmu");
			}
			wsprintf(gsVer86, msgInstallFolderIs, CONEMUVERL, L"x86", bInstalled ? msgPathCurrent : msgPathDefault, szInstallPath);


		if (isWin64)
		{

				szInstallPath[0] = 0; bInstalled = false;
				struct {HKEY hk; LPCWSTR path; LPCWSTR name; bool our;}
					Keys[] = {
						{HKEY_LOCAL_MACHINE,L"SOFTWARE\\ConEmu",L"InstallDir_x64",true},
						//Current installer does not use FarManager installation dir anymore
						//{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far Manager",L"InstallDir_x64"},
						//{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far2",L"InstallDir_x64"},
						//{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far",L"InstallDir_x64"},
					};
				for (size_t s = 0; s < countof(Keys); s++)
				{
					if (!RegOpenKeyEx(Keys[s].hk, Keys[s].path, 0, KEY_READ|KEY_WOW64_64KEY, &hk))
					{
						wchar_t szPath[MAX_PATH+1] = {}; DWORD cbSize = sizeof(szPath)-2;
						LONG lRc = RegQueryValueEx(hk, Keys[s].name, NULL, NULL, (LPBYTE)szPath, &cbSize);
						RegCloseKey(hk);
						if (!lRc && *szPath)
						{
							bInstalled = Keys[s].our;
							lstrcpy(szInstallPath, szPath);
							cbSize = lstrlen(szInstallPath);
							if (szInstallPath[cbSize-1] == L'\\') szInstallPath[cbSize-1] = 0;
							break;
						}
					}
				}
				if (szInstallPath[0] == 0)
				{
					GetEnvironmentVariable(L"ProgramW6432", szInstallPath, MAX_PATH);
					int nLen = lstrlen(szInstallPath);
					lstrcat(szInstallPath, (nLen > 0 && szInstallPath[nLen-1] != L'\\') ? L"\\ConEmu" : L"ConEmu");
				}
				wsprintf(gsVer64, msgInstallFolderIs, CONEMUVERL, L"x64", bInstalled ? msgPathCurrent : msgPathDefault, szInstallPath);

			wsprintf(gsFull, msgInstallConfirm, gsMessage);
		}
		else
		{
			gsVer64[0] = 0;
		}
	}
	else
	{
		LPCWSTR szPath = gsTempFolder;
		lstrcpyn(gsMessage, msgChooseExtractVer, countof(gsMessage));
		wsprintf(gsVer86, msgExtractX86X64, CONEMUVERL, L"x86", szPath);
		wsprintf(gsVer64, msgExtractX86X64, CONEMUVERL, L"x64", szPath);
		wsprintf(gsFull, msgExtractConfirm, gsMessage, szPath);
	}

	if (nInstallVer == 0)
	{
		nInstallVer = ChooseVersion(); // IDCANCEL/Ver86/Ver64
	}

	if (nInstallVer != Ver86 && nInstallVer != Ver64)
	{
		return exit_Cancelled;
	}

	// Preparing full paths
	wsprintf(gsMsiFile, L"%s\\ConEmu.%s.%s.msi", gsTempFolder, CONEMUVERL, (nInstallVer == Ver86) ? L"x86" : L"x64");
	wsprintf(gsCabFile, L"%s\\ConEmu.cab", gsTempFolder);

	bool lbNeedExe = false;
	if (!gbExtractOnly && gOSVer.dwMajorVersion >= 6)
		lbNeedExe = true;

	if (!lbNeedExe)
		gsExeFile[0] = 0;
	else
		wsprintf(gsExeFile, L"%s\\ConEmuSetup.exe", gsTempFolder);

	int iExpMsi = ExportFile(nInstallVer, gsMsiFile);
	int iExpCab = (iExpMsi == 0) ? ExportFile(CABFILE, gsCabFile) : -1;
	int iExpExe = (!lbNeedExe) ? 0 : (iExpCab == 0) ? ExportFile(EXEFILE, gsExeFile) : -1;
	if (iExpMsi != 0 || iExpCab != 0 || iExpExe != 0)
	{
		DeleteFile(gsMsiFile);
		DeleteFile(gsCabFile);
		if (*gsExeFile)
			DeleteFile(gsExeFile);
		return (iExpMsi != 0) ? iExpMsi : iExpCab;
	}

	if (gbExtractOnly)
	{
		temp_dir.DontRemove();
		wchar_t szMessage[MAX_PATH*2];
		wsprintf(szMessage, msgExtractedSuccessfully, gsTempFolder);
		MessageBox(NULL, szMessage, gsTitle, MB_ICONINFORMATION);
		return exit_Succeeded;
	}

	int iInstRc = exit_Succeeded;
	SHELLEXECUTEINFO sei = {sizeof(sei)};
	wchar_t* pszParms = NULL;
	sei.fMask = SEE_MASK_NOCLOSEPROCESS|/*SEE_MASK_NOASYNC*/0x00000100; //|/*SEE_MASK_NOZONECHECKS*/0x00800000;
	sei.lpVerb = L"open";
	if (gOSVer.dwMajorVersion<=5 || !gbUseElevation)
	{
		sei.lpFile = gsMsiFile;
		sei.lpParameters = pszCmdToken;
	}
	else
	{
		// Executor has `<requestedExecutionLevel level="requireAdministrator" ...>` in manifest
		sei.lpFile = gsExeFile;
		int nMaxLen = lstrlen(gsMsiFile) + (pszCmdToken ? lstrlen(pszCmdToken) : 0) + 64;
		pszParms = (wchar_t*)malloc(nMaxLen*sizeof(wchar_t));
		wsprintf(pszParms, L"/i \"%s\" %s", gsMsiFile, pszCmdToken ? pszCmdToken : L"");
		sei.lpParameters = pszParms;
	}
	sei.lpDirectory = gsTempFolder;
	sei.nShow = SW_SHOWNORMAL;

	BOOL lbExecute = ShellExecuteEx(&sei);

	#if 0
	if (!lbExecute && lbNeedExe)
	{
		DWORD nErr = GetLastError();
		if (nErr == 1223)
		{
			// Отмена пользователем UAC, или правов не хватило?
			sei.fMask = SEE_MASK_NOCLOSEPROCESS|/*SEE_MASK_NOASYNC*/0x00000100; //|/*SEE_MASK_NOZONECHECKS*/0x00800000;
			sei.lpVerb = L"open";
			sei.lpFile = gsMsiFile;
			sei.lpParameters = pszCmdToken;
			sei.lpDirectory = gsTempFolder;
			sei.nShow = SW_SHOWNORMAL;

			lbExecute = ShellExecuteEx(&sei);
		}
	}
	#endif

	if (!lbExecute)
	{
		iInstRc = ReportError(exit_ShellExecuteEx, msgInstallerFailed, gsMsiFile);
	}
	else
	{
		if (!sei.hProcess)
		{
			iInstRc = ReportError(exit_NullProcess, msgInstallerFailed, gsMsiFile);
		}
		else
		{
			WaitForSingleObject(sei.hProcess, INFINITE);
			DWORD nCode = 0;
			SetLastError(0);
			wchar_t szFormat[256];
			if (GetExitCodeProcess(sei.hProcess, &nCode))
			{
				switch (nCode)
				{
				case 0:
					iInstRc = exit_Succeeded;
					break;
				case 1602: // cancelled by user
					iInstRc = exit_Cancelled; // don't show any errors
					break;
				case 3010: // reboot is required
					wsprintf(szFormat, msgRebootRequired, nCode);
					iInstRc = ReportError(exit_AddWin32Code+nCode, szFormat, gsMsiFile);
					break;
				default:
					wsprintf(szFormat, msgInstallerFailedEx, nCode);
					iInstRc = ReportError(exit_AddWin32Code+nCode, szFormat, gsMsiFile);
				}
			}
			else
			{
				lstrcpyn(szFormat, msgExitCodeFailed, countof(szFormat));
				iInstRc = ReportError(exit_ExitCodeProcess, szFormat, gsMsiFile);
			}
		}
	}

	DeleteFile(gsMsiFile);
	DeleteFile(gsCabFile);
	if (*gsExeFile)
		DeleteFile(gsExeFile);

	return iInstRc;
}
Exemplo n.º 2
0
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
#endif
{
	hInst = hInstance;
	isWin64 = IsWindows64();
	
	GetVersionEx(&gOSVer);
	
	int nInstallVer = 0;
	
	wsprintf(gsTitle, L"ConEmu %s installer", CONEMUVERL);
	lstrcpyn(gsRunAsAdm, L"Run installer as administrator", countof(gsRunAsAdm));

	wchar_t szArg[MAX_PATH+1];
	LPCWSTR pszCmdToken = GetCommandLine();
	LPCWSTR pszCmdLineW = pszCmdToken;
	
	gsTempFolder[0] = 0;
	
	while (0 == NextArg(&pszCmdToken, szArg))
	{
		if (lstrcmp(szArg, L"/?") == 0 || lstrcmp(szArg, L"-?") == 0)
		{
			MessageBox(NULL, L"Usage:\nConEmuSetup [/e[:<extract path>]] [/p:x86 | /p:x64] [<msi args>]", gsTitle, MB_ICONINFORMATION);
			return 1;
		}
		
		if (*szArg == L'/')
		{
			if (szArg[1] == L'e' || szArg[1] == L'E')
			{
				gbExtractOnly = true;
				if (szArg[2] == L':' && szArg[3])
				{
					lstrcpyn(gsTempFolder, (szArg[3]==L'"') ? (szArg+4) : (szArg+3), countof(gsTempFolder));
				}
				continue;
			}
		
			if (lstrcmpi(szArg, L"/p:x86") == 0)
				nInstallVer = Ver86;
			else if (lstrcmpi(szArg, L"/p:x64") == 0)
				nInstallVer = Ver64;
			else
				pszCmdToken = pszCmdLineW;
			break;
		}
		else if (*szArg == L'-')
		{
			pszCmdToken = pszCmdLineW;
			break;
		}
			
		pszCmdLineW = pszCmdToken;
	}
	

	if (!gbExtractOnly)
	{
		wchar_t szInstallPath[MAX_PATH+32];
		bool bInstalled;
		HKEY hk;
	
		lstrcpyn(gsMessage, L"Choose version to install", countof(gsMessage));
		
			szInstallPath[0] = 0; bInstalled = false;
			struct {HKEY hk; LPCWSTR path; LPCWSTR name; bool our;}
				Keys[] = {
					{HKEY_LOCAL_MACHINE,L"SOFTWARE\\ConEmu",L"InstallDir",true},
					{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far Manager",L"InstallDir"},
					{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far2",L"InstallDir"},
					{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far",L"InstallDir"},
				};
			for (size_t s = 0; s < countof(Keys); s++)
			{
				if (!RegOpenKeyEx(Keys[s].hk, Keys[s].path, 0, KEY_READ, &hk)
					|| !RegOpenKeyEx(Keys[s].hk, Keys[s].path, 0, KEY_READ|KEY_WOW64_32KEY, &hk))
				{
					wchar_t szPath[MAX_PATH+1] = {}; DWORD cbSize = sizeof(szPath)-2;
					LONG lRc = RegQueryValueEx(hk, Keys[s].name, NULL, NULL, (LPBYTE)szPath, &cbSize);
					RegCloseKey(hk);
					if (!lRc && *szPath)
					{
						bInstalled = Keys[s].our;
						lstrcpy(szInstallPath, szPath);
						cbSize = lstrlen(szInstallPath);
						if (szInstallPath[cbSize-1] == L'\\') szInstallPath[cbSize-1] = 0;
						break;
					}
				}
			}
			if (szInstallPath[0] == 0)
			{
				GetEnvironmentVariable(L"ProgramFiles", szInstallPath, MAX_PATH);
				int nLen = lstrlen(szInstallPath);
				lstrcat(szInstallPath, (nLen > 0 && szInstallPath[nLen-1] != L'\\') ? L"\\ConEmu" : L"ConEmu");
			}
			wsprintf(gsVer86, L"%s x86\n%s installation folder is\n%s", CONEMUVERL, bInstalled ? L"Current" : L"Default", szInstallPath);

			
		if (isWin64)
		{
			
				szInstallPath[0] = 0; bInstalled = false;
				struct {HKEY hk; LPCWSTR path; LPCWSTR name; bool our;}
					Keys[] = {
						{HKEY_LOCAL_MACHINE,L"SOFTWARE\\ConEmu",L"InstallDir_x64",true},
						{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far Manager",L"InstallDir_x64"},
						{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far2",L"InstallDir_x64"},
						{HKEY_LOCAL_MACHINE,L"SOFTWARE\\Far",L"InstallDir_x64"},
					};
				for (size_t s = 0; s < countof(Keys); s++)
				{
					if (!RegOpenKeyEx(Keys[s].hk, Keys[s].path, 0, KEY_READ|KEY_WOW64_64KEY, &hk))
					{
						wchar_t szPath[MAX_PATH+1] = {}; DWORD cbSize = sizeof(szPath)-2;
						LONG lRc = RegQueryValueEx(hk, Keys[s].name, NULL, NULL, (LPBYTE)szPath, &cbSize);
						RegCloseKey(hk);
						if (!lRc && *szPath)
						{
							bInstalled = Keys[s].our;
							lstrcpy(szInstallPath, szPath);
							cbSize = lstrlen(szInstallPath);
							if (szInstallPath[cbSize-1] == L'\\') szInstallPath[cbSize-1] = 0;
							break;
						}
					}
				}
				if (szInstallPath[0] == 0)
				{
					GetEnvironmentVariable(L"ProgramW6432", szInstallPath, MAX_PATH);
					int nLen = lstrlen(szInstallPath);
					lstrcat(szInstallPath, (nLen > 0 && szInstallPath[nLen-1] != L'\\') ? L"\\ConEmu" : L"ConEmu");
				}
				wsprintf(gsVer64, L"%s x64\n%s installation folder is\n%s", CONEMUVERL, bInstalled ? L"Current" : L"Default", szInstallPath);

			wsprintf(gsFull, L"%s\n\nPress `Yes` to install x64 version\nPress `No` to install x86 version", gsMessage);
		}
		else
		{
			gsVer64[0] = 0;
		}
	}
	else
	{
		wchar_t szPath[MAX_PATH+1];
		if (*gsTempFolder)
		{
			lstrcpy(szPath, gsTempFolder);
		}
		else
		{
			GetTempPath(countof(szPath) - 14, szPath);
			wchar_t* pszSubDir = szPath+lstrlen(szPath);
			lstrcpy(pszSubDir, L"ConEmu");
			pszSubDir += 6;
			lstrcpy(pszSubDir, CONEMUVERL);
		}
		
		lstrcpyn(gsMessage, L"Choose version to extract", countof(gsMessage));
		wsprintf(gsVer86, L"%s x86\nExtract installation files to\n%s", CONEMUVERL, szPath);
		wsprintf(gsVer64, L"%s x64\nExtract installation files to\n%s", CONEMUVERL, szPath);
		wsprintf(gsFull, L"%s\n\nPress `Yes` to extract x64 version\nPress `No` to extract x86 version\n\n%s", gsMessage, szPath);
	}
	
	if (nInstallVer == 0)
		nInstallVer = ChooseVersion(); // IDCANCEL/Ver86/Ver64
		
	if (nInstallVer != Ver86 && nInstallVer != Ver64)
		return 1;
	
	if (gbExtractOnly && *gsTempFolder)
	{
		CreateDirectory(gsTempFolder, NULL);
	}
	else
	{
		GetTempPath(countof(gsTempFolder) - 14, gsTempFolder);
		
		wchar_t* pszSubDir = gsTempFolder+lstrlen(gsTempFolder);
		lstrcpy(pszSubDir, L"ConEmu");
		pszSubDir += 6;
		lstrcpy(pszSubDir, CONEMUVERL);
		pszSubDir += lstrlen(pszSubDir);
		if (!CreateDirectory(gsTempFolder, NULL))
		{
			bool lbCreated = false;
			SYSTEMTIME st = {}; GetLocalTime(&st);
			for (int i = 0; i < 100; i++)
			{
				wsprintf(pszSubDir, L"_%02i%02i%02i%i", st.wHour, st.wMinute, st.wSecond, i);
				if (CreateDirectory(gsTempFolder, NULL))
				{
					lbCreated = true;
					break;
				}
			}
			if (!lbCreated)
			{
				return ReportError(10, L"Can't create temp folder\n%s", gsTempFolder);
			}
		}
	}

	wsprintf(gsMsiFile, L"%s\\ConEmu.%s.%s.msi", gsTempFolder, CONEMUVERL, (nInstallVer == Ver86) ? L"x86" : L"x64");
	wsprintf(gsCabFile, L"%s\\ConEmu.cab", gsTempFolder);
	
	bool lbNeedExe = false;
	if (!gbExtractOnly && gOSVer.dwMajorVersion >= 6)
		lbNeedExe = true;

	if (!lbNeedExe)
		gsExeFile[0] = 0;
	else
		wsprintf(gsExeFile, L"%s\\ConEmuSetup.exe", gsTempFolder);
	
	int iExpMsi = ExportFile(nInstallVer, gsMsiFile);
	int iExpCab = (iExpMsi == 0) ? ExportFile(CABFILE, gsCabFile) : -1;
	int iExpExe = (!lbNeedExe) ? 0 : (iExpCab == 0) ? ExportFile(EXEFILE, gsExeFile) : -1;
	if (iExpMsi != 0 || iExpCab != 0 || iExpExe != 0)
	{
		DeleteFile(gsMsiFile);
		DeleteFile(gsCabFile);
		if (*gsExeFile)
			DeleteFile(gsExeFile);
		RemoveDirectory(gsTempFolder);
		return (iExpMsi != 0) ? iExpMsi : iExpCab;
	}
	
	if (gbExtractOnly)
	{
		wchar_t szMessage[MAX_PATH*2];
		wsprintf(szMessage, L"Installation files was extracted successfully\n%s", gsTempFolder);
		MessageBox(NULL, szMessage, gsTitle, MB_ICONINFORMATION);
		return 0;
	}

	int iInstRc = 0;
	SHELLEXECUTEINFO sei = {sizeof(sei)};
	wchar_t* pszParms = NULL;
	sei.fMask = SEE_MASK_NOCLOSEPROCESS|/*SEE_MASK_NOASYNC*/0x00000100; //|/*SEE_MASK_NOZONECHECKS*/0x00800000;
	sei.lpVerb = L"open";
	if (gOSVer.dwMajorVersion<=5 || !gbUseElevation)
	{
		sei.lpFile = gsMsiFile;
		sei.lpParameters = pszCmdToken;
	}
	else
	{
		sei.lpFile = gsExeFile;
		int nMaxLen = lstrlen(gsMsiFile) + (pszCmdToken ? lstrlen(pszCmdToken) : 0) + 64;
		pszParms = (wchar_t*)malloc(nMaxLen*sizeof(wchar_t));
		wsprintf(pszParms, L"/i \"%s\" %s", gsMsiFile, pszCmdToken ? pszCmdToken : L"");
		sei.lpParameters = pszParms;
	}
	sei.lpDirectory = gsTempFolder;
	sei.nShow = SW_SHOWNORMAL;
	
	BOOL lbExecute = ShellExecuteEx(&sei);
	
	#if 0
	if (!lbExecute && lbNeedExe)
	{
		DWORD nErr = GetLastError();
		if (nErr == 1223)
		{
			// Отмена пользователем UAC, или правов не хватило?
			sei.fMask = SEE_MASK_NOCLOSEPROCESS|/*SEE_MASK_NOASYNC*/0x00000100; //|/*SEE_MASK_NOZONECHECKS*/0x00800000;
			sei.lpVerb = L"open";
			sei.lpFile = gsMsiFile;
			sei.lpParameters = pszCmdToken;
			sei.lpDirectory = gsTempFolder;
			sei.nShow = SW_SHOWNORMAL;
			
			lbExecute = ShellExecuteEx(&sei);
		}
	}
	#endif
	
	if (!lbExecute)
	{
		iInstRc = ReportError(20, L"Installer failed\n%s", gsMsiFile);
	}
	else
	{
		if (!sei.hProcess)
		{
			iInstRc = ReportError(21, L"Installer failed\n%s", gsMsiFile);
		}
		else
		{
			WaitForSingleObject(sei.hProcess, INFINITE);
			DWORD nCode = 0;
			SetLastError(0);
			//1602 - это похоже "Отмена" пользователем
			if (!GetExitCodeProcess(sei.hProcess, &nCode) || (nCode != 0 && nCode != 1602))
			{
				wchar_t szFormat[128]; wsprintf(szFormat, L"Installer failed\n%%s\nExitCode=%u", nCode);
				iInstRc = ReportError(100+nCode, szFormat, gsMsiFile);
			}
		}
	}
	
	DeleteFile(gsMsiFile);
	DeleteFile(gsCabFile);
	if (*gsExeFile)
		DeleteFile(gsExeFile);
	RemoveDirectory(gsTempFolder);
	
	return iInstRc;
}