blob: 202c262097ec89fba723b01e9a4874907710c98a [file] [log] [blame]
// Main.cpp
#include "StdAfx.h"
#include "../../../Common/MyInitGuid.h"
#include "../../../Common/CommandLineParser.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/TextConfig.h"
#include "../../../Windows/DLL.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileFind.h"
#include "../../../Windows/FileIO.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/NtCheck.h"
#include "../../../Windows/ResourceString.h"
#include "../../UI/Explorer/MyMessages.h"
#include "ExtractEngine.h"
#include "resource.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
HINSTANCE g_hInstance;
static CFSTR kTempDirPrefix = FTEXT("7zS");
#define _SHELL_EXECUTE
static bool ReadDataString(CFSTR fileName, LPCSTR startID,
LPCSTR endID, AString &stringResult)
{
stringResult.Empty();
NIO::CInFile inFile;
if (!inFile.Open(fileName))
return false;
const int kBufferSize = (1 << 12);
Byte buffer[kBufferSize];
int signatureStartSize = MyStringLen(startID);
int signatureEndSize = MyStringLen(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;
#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
static void ShowErrorMessageSpec(const UString &name)
{
UString message = NError::MyFormatMessage(::GetLastError());
int pos = message.Find(L"%1");
if (pos >= 0)
{
message.Delete(pos, 2);
message.Insert(pos, name);
}
ShowErrorMessage(NULL, message);
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
#ifdef UNDER_CE
LPWSTR
#else
LPSTR
#endif
/* lpCmdLine */,int /* nCmdShow */)
{
g_hInstance = (HINSTANCE)hInstance;
NT_CHECK
// InitCommonControls();
UString archiveName, switches;
#ifdef _SHELL_EXECUTE
UString executeFile, executeParameters;
#endif
NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
FString fullPath;
NDLL::MyGetModuleFileName(fullPath);
switches.Trim();
bool assumeYes = false;
if (MyStringCompareNoCase_N(switches, L"-y", 2) == 0)
{
assumeYes = true;
switches = switches.Ptr(2);
switches.Trim();
}
AString config;
if (!ReadDataString(fullPath, kStartID, kEndID, config))
{
if (!assumeYes)
ShowErrorMessage(L"Can't load config info");
return 1;
}
UString dirPrefix = L"." WSTRING_PATH_SEPARATOR;
UString appLaunched;
bool showProgress = true;
if (!config.IsEmpty())
{
CObjectVector<CTextConfigPair> pairs;
if (!GetTextConfig(config, pairs))
{
if (!assumeYes)
ShowErrorMessage(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.IsEqualToNoCase(L"no"))
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");
#endif
}
CTempDir tempDir;
if (!tempDir.Create(kTempDirPrefix))
{
if (!assumeYes)
ShowErrorMessage(L"Can not create temp folder archive");
return 1;
}
CCodecs *codecs = new CCodecs;
CMyComPtr<IUnknown> compressCodecsInfo = codecs;
HRESULT result = codecs->Load();
if (result != S_OK)
{
ShowErrorMessage(L"Can not load codecs");
return 1;
}
const FString tempDirPath = tempDir.GetPath();
// tempDirPath = L"M:\\1\\"; // to test low disk space
{
bool isCorrupt = false;
UString errorMessage;
HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
isCorrupt, errorMessage);
if (result != S_OK)
{
if (!assumeYes)
{
if (result == S_FALSE || isCorrupt)
{
NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
result = E_FAIL;
}
if (result != E_ABORT)
{
if (errorMessage.IsEmpty())
errorMessage = NError::MyFormatMessage(result);
::MessageBoxW(0, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
}
}
return 1;
}
}
#ifndef UNDER_CE
CCurrentDirRestorer currentDirRestorer;
if (!SetCurrentDir(tempDirPath))
return 1;
#endif
HANDLE hProcess = 0;
#ifdef _SHELL_EXECUTE
if (!executeFile.IsEmpty())
{
CSysString filePath = GetSystemString(executeFile);
SHELLEXECUTEINFO execInfo;
execInfo.cbSize = sizeof(execInfo);
execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
#ifndef UNDER_CE
| SEE_MASK_FLAG_DDEWAIT
#endif
;
execInfo.hwnd = NULL;
execInfo.lpVerb = NULL;
execInfo.lpFile = filePath;
if (!switches.IsEmpty())
{
if (!executeParameters.IsEmpty())
executeParameters += L' ';
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)
ShowErrorMessage(L"Can not open file");
return 1;
}
hProcess = execInfo.hProcess;
}
else
#endif
{
if (appLaunched.IsEmpty())
{
appLaunched = L"setup.exe";
if (!NFind::DoesFileExist(us2fs(appLaunched)))
{
if (!assumeYes)
ShowErrorMessage(L"Can not find setup.exe");
return 1;
}
}
{
FString s2 = tempDirPath;
NName::NormalizeDirPathPrefix(s2);
appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
}
UString appNameForError = appLaunched; // actually we need to rtemove parameters also
appLaunched.Replace(L"%%T", fs2us(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)
{
// we print name of exe file, if error message is
// ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
ShowErrorMessageSpec(appNameForError);
}
return 1;
}
::CloseHandle(processInformation.hThread);
hProcess = processInformation.hProcess;
}
if (hProcess != 0)
{
WaitForSingleObject(hProcess, INFINITE);
::CloseHandle(hProcess);
}
return 0;
}