5 #include "Common/MyInitGuid.h"
\r
7 #include "Common/CommandLineParser.h"
\r
8 #include "Common/StringConvert.h"
\r
9 #include "Common/TextConfig.h"
\r
11 #include "Windows/DLL.h"
\r
12 #include "Windows/FileDir.h"
\r
13 #include "Windows/FileFind.h"
\r
14 #include "Windows/FileIO.h"
\r
15 #include "Windows/NtCheck.h"
\r
16 #include "Windows/ResourceString.h"
\r
18 #include "../../UI/Explorer/MyMessages.h"
\r
20 #include "ExtractEngine.h"
\r
22 #include "resource.h"
\r
24 using namespace NWindows;
\r
26 HINSTANCE g_hInstance;
\r
28 static LPCTSTR kTempDirPrefix = TEXT("7zS");
\r
30 #define _SHELL_EXECUTE
\r
32 static bool ReadDataString(LPCWSTR fileName, LPCSTR startID,
\r
33 LPCSTR endID, AString &stringResult)
\r
35 stringResult.Empty();
\r
36 NFile::NIO::CInFile inFile;
\r
37 if (!inFile.Open(fileName))
\r
39 const int kBufferSize = (1 << 12);
\r
41 Byte buffer[kBufferSize];
\r
42 int signatureStartSize = MyStringLen(startID);
\r
43 int signatureEndSize = MyStringLen(endID);
\r
45 UInt32 numBytesPrev = 0;
\r
46 bool writeMode = false;
\r
47 UInt64 posTotal = 0;
\r
50 if (posTotal > (1 << 20))
\r
51 return (stringResult.IsEmpty());
\r
52 UInt32 numReadBytes = kBufferSize - numBytesPrev;
\r
53 UInt32 processedSize;
\r
54 if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize))
\r
56 if (processedSize == 0)
\r
58 UInt32 numBytesInBuffer = numBytesPrev + processedSize;
\r
64 if (pos > numBytesInBuffer - signatureEndSize)
\r
66 if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
\r
68 char b = buffer[pos];
\r
76 if (pos > numBytesInBuffer - signatureStartSize)
\r
78 if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
\r
81 pos += signatureStartSize;
\r
87 numBytesPrev = numBytesInBuffer - pos;
\r
89 memmove(buffer, buffer + pos, numBytesPrev);
\r
93 static char kStartID[] = ",!@Install@!UTF-8!";
\r
94 static char kEndID[] = ",!@InstallEnd@!";
\r
96 class CInstallIDInit
\r
104 } g_CInstallIDInit;
\r
108 class CCurrentDirRestorer
\r
110 CSysString m_CurrentDirectory;
\r
112 CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }
\r
113 ~CCurrentDirRestorer() { RestoreDirectory();}
\r
114 bool RestoreDirectory() { return BOOLToBool(::SetCurrentDirectory(m_CurrentDirectory)); }
\r
118 #define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
\r
120 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
\r
126 /* lpCmdLine */,int /* nCmdShow */)
\r
128 g_hInstance = (HINSTANCE)hInstance;
\r
132 // InitCommonControls();
\r
134 UString archiveName, switches;
\r
135 #ifdef _SHELL_EXECUTE
\r
136 UString executeFile, executeParameters;
\r
138 NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
\r
141 NDLL::MyGetModuleFileName(g_hInstance, fullPath);
\r
144 bool assumeYes = false;
\r
145 if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0)
\r
148 switches = switches.Mid(2);
\r
153 if (!ReadDataString(fullPath, kStartID, kEndID, config))
\r
156 ShowErrorMessage(L"Can't load config info");
\r
160 UString dirPrefix = L"." WSTRING_PATH_SEPARATOR;
\r
161 UString appLaunched;
\r
162 bool showProgress = true;
\r
163 if (!config.IsEmpty())
\r
165 CObjectVector<CTextConfigPair> pairs;
\r
166 if (!GetTextConfig(config, pairs))
\r
169 ShowErrorMessage(L"Config failed");
\r
172 UString friendlyName = GetTextConfigValue(pairs, L"Title");
\r
173 UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");
\r
174 UString progress = GetTextConfigValue(pairs, L"Progress");
\r
175 if (progress.CompareNoCase(L"no") == 0)
\r
176 showProgress = false;
\r
177 int index = FindTextConfigItem(pairs, L"Directory");
\r
179 dirPrefix = pairs[index].String;
\r
180 if (!installPrompt.IsEmpty() && !assumeYes)
\r
182 if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |
\r
183 MB_ICONQUESTION) != IDYES)
\r
186 appLaunched = GetTextConfigValue(pairs, L"RunProgram");
\r
188 #ifdef _SHELL_EXECUTE
\r
189 executeFile = GetTextConfigValue(pairs, L"ExecuteFile");
\r
190 executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches;
\r
194 NFile::NDirectory::CTempDirectory tempDir;
\r
195 if (!tempDir.Create(kTempDirPrefix))
\r
198 ShowErrorMessage(L"Can not create temp folder archive");
\r
202 CCodecs *codecs = new CCodecs;
\r
203 CMyComPtr<IUnknown> compressCodecsInfo = codecs;
\r
204 HRESULT result = codecs->Load();
\r
205 if (result != S_OK)
\r
207 ShowErrorMessage(L"Can not load codecs");
\r
211 UString tempDirPath = GetUnicodeString(tempDir.GetPath());
\r
213 bool isCorrupt = false;
\r
214 UString errorMessage;
\r
215 HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
\r
216 isCorrupt, errorMessage);
\r
218 if (result != S_OK)
\r
222 if (result == S_FALSE || isCorrupt)
\r
224 errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE);
\r
227 if (result != E_ABORT && !errorMessage.IsEmpty())
\r
228 ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
\r
235 CCurrentDirRestorer currentDirRestorer;
\r
236 if (!SetCurrentDirectory(tempDir.GetPath()))
\r
240 HANDLE hProcess = 0;
\r
241 #ifdef _SHELL_EXECUTE
\r
242 if (!executeFile.IsEmpty())
\r
244 CSysString filePath = GetSystemString(executeFile);
\r
245 SHELLEXECUTEINFO execInfo;
\r
246 execInfo.cbSize = sizeof(execInfo);
\r
247 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
\r
249 | SEE_MASK_FLAG_DDEWAIT
\r
252 execInfo.hwnd = NULL;
\r
253 execInfo.lpVerb = NULL;
\r
254 execInfo.lpFile = filePath;
\r
256 if (!switches.IsEmpty())
\r
257 executeParameters += switches;
\r
259 CSysString parametersSys = GetSystemString(executeParameters);
\r
260 if (parametersSys.IsEmpty())
\r
261 execInfo.lpParameters = NULL;
\r
263 execInfo.lpParameters = parametersSys;
\r
265 execInfo.lpDirectory = NULL;
\r
266 execInfo.nShow = SW_SHOWNORMAL;
\r
267 execInfo.hProcess = 0;
\r
268 /* BOOL success = */ ::ShellExecuteEx(&execInfo);
\r
269 UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
\r
273 ShowErrorMessage(L"Can not open file");
\r
276 hProcess = execInfo.hProcess;
\r
281 if (appLaunched.IsEmpty())
\r
283 appLaunched = L"setup.exe";
\r
284 if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched)))
\r
287 ShowErrorMessage(L"Can not find setup.exe");
\r
293 UString s2 = tempDirPath;
\r
294 NFile::NName::NormalizeDirPathPrefix(s2);
\r
295 appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, s2);
\r
298 appLaunched.Replace(L"%%T", tempDirPath);
\r
300 if (!switches.IsEmpty())
\r
302 appLaunched += L' ';
\r
303 appLaunched += switches;
\r
305 STARTUPINFO startupInfo;
\r
306 startupInfo.cb = sizeof(startupInfo);
\r
307 startupInfo.lpReserved = 0;
\r
308 startupInfo.lpDesktop = 0;
\r
309 startupInfo.lpTitle = 0;
\r
310 startupInfo.dwFlags = 0;
\r
311 startupInfo.cbReserved2 = 0;
\r
312 startupInfo.lpReserved2 = 0;
\r
314 PROCESS_INFORMATION processInformation;
\r
316 CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched);
\r
318 BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,
\r
319 NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
\r
320 &startupInfo, &processInformation);
\r
321 if (createResult == 0)
\r
324 ShowLastErrorMessage();
\r
327 ::CloseHandle(processInformation.hThread);
\r
328 hProcess = processInformation.hProcess;
\r
332 WaitForSingleObject(hProcess, INFINITE);
\r
333 ::CloseHandle(hProcess);
\r