Files
easy7zip/7zip/Bundles/SFXSetup/Main.cpp
Igor Pavlov e18587ba51 4.30 beta
2016-05-28 00:15:45 +01:00

311 lines
7.3 KiB
C++
Executable File

// 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 "../../IPassword.h"
#include "../../ICoder.h"
#include "../../Archive/IArchive.h"
#include "../../UI/Explorer/MyMessages.h"
// #include "../../UI/GUI/ExtractGUI.h"
#include "ExtractEngine.h"
HINSTANCE g_hInstance;
using namespace NWindows;
static LPCTSTR kTempDirPrefix = TEXT("7zS");
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;
while(true)
{
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;
while (true)
{
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;
NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
UString fullPath;
NDLL::MyGetModuleFileName(g_hInstance, fullPath);
AString config;
if (!ReadDataString(fullPath, kStartID, kEndID, config))
{
MyMessageBox(L"Can't load config info");
return 1;
}
switches.Trim();
bool assumeYes = false;
if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0)
{
assumeYes = true;
switches = switches.Mid(2);
switches.Trim();
}
#ifdef _SHELL_EXECUTE
bool executeMode = false;
#endif
UString appLaunched;
if (!config.IsEmpty())
{
CObjectVector<CTextConfigPair> pairs;
if (!GetTextConfig(config, pairs))
{
MyMessageBox(L"Config failed");
return 1;
}
UString friendlyName = GetTextConfigValue(pairs, L"Title");
UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");
if (!installPrompt.IsEmpty() && !assumeYes)
{
if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |
MB_ICONQUESTION) != IDYES)
return 0;
}
appLaunched = GetTextConfigValue(pairs, L"RunProgram");
#ifdef _SHELL_EXECUTE
if (appLaunched.IsEmpty())
{
executeMode = true;
appLaunched = GetTextConfigValue(pairs, L"Execute");
}
#endif
}
NFile::NDirectory::CTempDirectory tempDir;
if (!tempDir.Create(kTempDirPrefix))
{
MyMessageBox(L"Can not create temp folder archive");
return 1;
}
COpenCallbackGUI openCallback;
UString tempDirPath = GetUnicodeString(tempDir.GetPath());
HRESULT result = ExtractArchive(fullPath, tempDirPath, &openCallback);
if (result != S_OK)
{
if (result == S_FALSE)
MyMessageBox(L"Can not open archive");
else if (result != E_ABORT)
ShowErrorMessage(result);
return 1;
}
CCurrentDirRestorer currentDirRestorer;
if (!SetCurrentDirectory(tempDir.GetPath()))
return 1;
if (appLaunched.IsEmpty())
{
appLaunched = L"setup.exe";
if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched)))
{
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);
HANDLE hProcess = 0;
#ifdef _SHELL_EXECUTE
if (executeMode)
{
CSysString filePath = GetSystemString(appLaunched);
SHELLEXECUTEINFO execInfo;
execInfo.cbSize = sizeof(execInfo);
execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
execInfo.hwnd = NULL;
execInfo.lpVerb = NULL;
execInfo.lpFile = filePath;
CSysString switchesSys = GetSystemString(switches);
if (switchesSys.IsEmpty())
execInfo.lpParameters = NULL;
else
execInfo.lpParameters = switchesSys;
execInfo.lpDirectory = NULL;
execInfo.nShow = SW_SHOWNORMAL;
execInfo.hProcess = 0;
bool success = BOOLToBool(::ShellExecuteEx(&execInfo));
result = (UINT32)execInfo.hInstApp;
if(result <= 32)
{
MyMessageBox(L"Can not open file");
return 1;
}
hProcess = execInfo.hProcess;
}
else
#endif
{
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 = CSysString(TEXT(".\\")) + GetSystemString(appLaunched);
BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,
NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
&startupInfo, &processInformation);
if (createResult == 0)
{
ShowLastErrorMessage();
return 1;
}
::CloseHandle(processInformation.hThread);
hProcess = processInformation.hProcess;
}
if (hProcess != 0)
{
WaitForSingleObject(hProcess, INFINITE);
::CloseHandle(hProcess);
}
return 0;
}