diff options
Diffstat (limited to 'CPP/7zip/Bundles/SFXSetup/Main.cpp')
-rwxr-xr-x | CPP/7zip/Bundles/SFXSetup/Main.cpp | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/CPP/7zip/Bundles/SFXSetup/Main.cpp b/CPP/7zip/Bundles/SFXSetup/Main.cpp new file mode 100755 index 00000000..12de5c01 --- /dev/null +++ b/CPP/7zip/Bundles/SFXSetup/Main.cpp @@ -0,0 +1,335 @@ +// Main.cpp + +#include "StdAfx.h" + +#include <initguid.h> + +#include "Common/StringConvert.h" +#include "Common/Random.h" +#include "Common/TextConfig.h" +#include "Common/CommandLineParser.h" + +#include "Windows/FileDir.h" +#include "Windows/FileIO.h" +#include "Windows/FileFind.h" +#include "Windows/FileName.h" +#include "Windows/DLL.h" +#include "Windows/ResourceString.h" + +#include "../../IPassword.h" +#include "../../ICoder.h" +#include "../../Archive/IArchive.h" +#include "../../UI/Explorer/MyMessages.h" + +// #include "../../UI/GUI/ExtractGUI.h" + +#include "ExtractEngine.h" + +#include "resource.h" + +using namespace NWindows; + +HINSTANCE g_hInstance; + +static LPCTSTR kTempDirPrefix = TEXT("7zS"); + +#define _SHELL_EXECUTE + +static bool ReadDataString(LPCWSTR fileName, LPCSTR startID, + LPCSTR endID, AString &stringResult) +{ + stringResult.Empty(); + NFile::NIO::CInFile inFile; + if (!inFile.Open(fileName)) + return false; + const int kBufferSize = (1 << 12); + + Byte buffer[kBufferSize]; + int signatureStartSize = lstrlenA(startID); + int signatureEndSize = lstrlenA(endID); + + UInt32 numBytesPrev = 0; + bool writeMode = false; + UInt64 posTotal = 0; + for (;;) + { + if (posTotal > (1 << 20)) + return (stringResult.IsEmpty()); + UInt32 numReadBytes = kBufferSize - numBytesPrev; + UInt32 processedSize; + if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize)) + return false; + if (processedSize == 0) + return true; + UInt32 numBytesInBuffer = numBytesPrev + processedSize; + UInt32 pos = 0; + for (;;) + { + if (writeMode) + { + if (pos > numBytesInBuffer - signatureEndSize) + break; + if (memcmp(buffer + pos, endID, signatureEndSize) == 0) + return true; + char b = buffer[pos]; + if (b == 0) + return false; + stringResult += b; + pos++; + } + else + { + if (pos > numBytesInBuffer - signatureStartSize) + break; + if (memcmp(buffer + pos, startID, signatureStartSize) == 0) + { + writeMode = true; + pos += signatureStartSize; + } + else + pos++; + } + } + numBytesPrev = numBytesInBuffer - pos; + posTotal += pos; + memmove(buffer, buffer + pos, numBytesPrev); + } +} + +static char kStartID[] = ",!@Install@!UTF-8!"; +static char kEndID[] = ",!@InstallEnd@!"; + +class CInstallIDInit +{ +public: + CInstallIDInit() + { + kStartID[0] = ';'; + kEndID[0] = ';'; + }; +} g_CInstallIDInit; + + +class CCurrentDirRestorer +{ + CSysString m_CurrentDirectory; +public: + CCurrentDirRestorer() + { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); } + ~CCurrentDirRestorer() + { RestoreDirectory();} + bool RestoreDirectory() + { return BOOLToBool(::SetCurrentDirectory(m_CurrentDirectory)); } +}; + +#ifndef _UNICODE +bool g_IsNT = false; +static inline bool IsItWindowsNT() +{ + OSVERSIONINFO versionInfo; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + if (!::GetVersionEx(&versionInfo)) + return false; + return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); +} +#endif + +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */,int /* nCmdShow */) +{ + g_hInstance = (HINSTANCE)hInstance; + #ifndef _UNICODE + g_IsNT = IsItWindowsNT(); + #endif + InitCommonControls(); + + UString archiveName, switches; + #ifdef _SHELL_EXECUTE + UString executeFile, executeParameters; + #endif + NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches); + + UString fullPath; + NDLL::MyGetModuleFileName(g_hInstance, fullPath); + + switches.Trim(); + bool assumeYes = false; + if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0) + { + assumeYes = true; + switches = switches.Mid(2); + switches.Trim(); + } + + AString config; + if (!ReadDataString(fullPath, kStartID, kEndID, config)) + { + if (!assumeYes) + MyMessageBox(L"Can't load config info"); + return 1; + } + + UString dirPrefix = L".\\"; + UString appLaunched; + bool showProgress = true; + if (!config.IsEmpty()) + { + CObjectVector<CTextConfigPair> pairs; + if (!GetTextConfig(config, pairs)) + { + if (!assumeYes) + MyMessageBox(L"Config failed"); + return 1; + } + UString friendlyName = GetTextConfigValue(pairs, L"Title"); + UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt"); + UString progress = GetTextConfigValue(pairs, L"Progress"); + if (progress.CompareNoCase(L"no") == 0) + showProgress = false; + int index = FindTextConfigItem(pairs, L"Directory"); + if (index >= 0) + dirPrefix = pairs[index].String; + if (!installPrompt.IsEmpty() && !assumeYes) + { + if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO | + MB_ICONQUESTION) != IDYES) + return 0; + } + appLaunched = GetTextConfigValue(pairs, L"RunProgram"); + + #ifdef _SHELL_EXECUTE + executeFile = GetTextConfigValue(pairs, L"ExecuteFile"); + executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches; + #endif + } + + NFile::NDirectory::CTempDirectory tempDir; + if (!tempDir.Create(kTempDirPrefix)) + { + if (!assumeYes) + MyMessageBox(L"Can not create temp folder archive"); + return 1; + } + + COpenCallbackGUI openCallback; + + UString tempDirPath = GetUnicodeString(tempDir.GetPath()); + { + bool isCorrupt = false; + UString errorMessage; + HRESULT result = ExtractArchive(fullPath, tempDirPath, &openCallback, showProgress, + isCorrupt, errorMessage); + + if (result != S_OK) + { + if (!assumeYes) + { + if (result == S_FALSE || isCorrupt) + { + errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE); + result = E_FAIL; + } + if (result != E_ABORT && !errorMessage.IsEmpty()) + ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR); + } + return 1; + } + } + + CCurrentDirRestorer currentDirRestorer; + + if (!SetCurrentDirectory(tempDir.GetPath())) + return 1; + + HANDLE hProcess = 0; +#ifdef _SHELL_EXECUTE + if (!executeFile.IsEmpty()) + { + CSysString filePath = GetSystemString(executeFile); + SHELLEXECUTEINFO execInfo; + execInfo.cbSize = sizeof(execInfo); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; + execInfo.hwnd = NULL; + execInfo.lpVerb = NULL; + execInfo.lpFile = filePath; + + if (!switches.IsEmpty()) + executeParameters += switches; + + CSysString parametersSys = GetSystemString(executeParameters); + if (parametersSys.IsEmpty()) + execInfo.lpParameters = NULL; + else + execInfo.lpParameters = parametersSys; + + execInfo.lpDirectory = NULL; + execInfo.nShow = SW_SHOWNORMAL; + execInfo.hProcess = 0; + /* BOOL success = */ ::ShellExecuteEx(&execInfo); + UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp; + if(result <= 32) + { + if (!assumeYes) + MyMessageBox(L"Can not open file"); + return 1; + } + hProcess = execInfo.hProcess; + } + else +#endif + { + if (appLaunched.IsEmpty()) + { + appLaunched = L"setup.exe"; + if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched))) + { + if (!assumeYes) + MyMessageBox(L"Can not find setup.exe"); + return 1; + } + } + + { + UString s2 = tempDirPath; + NFile::NName::NormalizeDirPathPrefix(s2); + appLaunched.Replace(L"%%T\\", s2); + } + + appLaunched.Replace(L"%%T", tempDirPath); + + if (!switches.IsEmpty()) + { + appLaunched += L' '; + appLaunched += switches; + } + STARTUPINFO startupInfo; + startupInfo.cb = sizeof(startupInfo); + startupInfo.lpReserved = 0; + startupInfo.lpDesktop = 0; + startupInfo.lpTitle = 0; + startupInfo.dwFlags = 0; + startupInfo.cbReserved2 = 0; + startupInfo.lpReserved2 = 0; + + PROCESS_INFORMATION processInformation; + + CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched); + + BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys, + NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, + &startupInfo, &processInformation); + if (createResult == 0) + { + if (!assumeYes) + ShowLastErrorMessage(); + return 1; + } + ::CloseHandle(processInformation.hThread); + hProcess = processInformation.hProcess; + } + if (hProcess != 0) + { + WaitForSingleObject(hProcess, INFINITE); + ::CloseHandle(hProcess); + } + return 0; +} |