1 // Main.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/MyInitGuid.h"
6
7 #include "../../../Common/CommandLineParser.h"
8 #include "../../../Common/StringConvert.h"
9 #include "../../../Common/TextConfig.h"
10
11 #include "../../../Windows/DLL.h"
12 #include "../../../Windows/ErrorMsg.h"
13 #include "../../../Windows/FileDir.h"
14 #include "../../../Windows/FileFind.h"
15 #include "../../../Windows/FileIO.h"
16 #include "../../../Windows/FileName.h"
17 #include "../../../Windows/NtCheck.h"
18 #include "../../../Windows/ResourceString.h"
19
20 #include "../../UI/Explorer/MyMessages.h"
21
22 #include "ExtractEngine.h"
23
24 #include "resource.h"
25
26 using namespace NWindows;
27 using namespace NFile;
28 using namespace NDir;
29
30 HINSTANCE g_hInstance;
31
32 static CFSTR kTempDirPrefix = FTEXT("7zS");
33
34 #define _SHELL_EXECUTE
35
ReadDataString(CFSTR fileName,LPCSTR startID,LPCSTR endID,AString & stringResult)36 static bool ReadDataString(CFSTR fileName, LPCSTR startID,
37 LPCSTR endID, AString &stringResult)
38 {
39 stringResult.Empty();
40 NIO::CInFile inFile;
41 if (!inFile.Open(fileName))
42 return false;
43 const int kBufferSize = (1 << 12);
44
45 Byte buffer[kBufferSize];
46 int signatureStartSize = MyStringLen(startID);
47 int signatureEndSize = MyStringLen(endID);
48
49 UInt32 numBytesPrev = 0;
50 bool writeMode = false;
51 UInt64 posTotal = 0;
52 for (;;)
53 {
54 if (posTotal > (1 << 20))
55 return (stringResult.IsEmpty());
56 UInt32 numReadBytes = kBufferSize - numBytesPrev;
57 UInt32 processedSize;
58 if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize))
59 return false;
60 if (processedSize == 0)
61 return true;
62 UInt32 numBytesInBuffer = numBytesPrev + processedSize;
63 UInt32 pos = 0;
64 for (;;)
65 {
66 if (writeMode)
67 {
68 if (pos > numBytesInBuffer - signatureEndSize)
69 break;
70 if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
71 return true;
72 char b = buffer[pos];
73 if (b == 0)
74 return false;
75 stringResult += b;
76 pos++;
77 }
78 else
79 {
80 if (pos > numBytesInBuffer - signatureStartSize)
81 break;
82 if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
83 {
84 writeMode = true;
85 pos += signatureStartSize;
86 }
87 else
88 pos++;
89 }
90 }
91 numBytesPrev = numBytesInBuffer - pos;
92 posTotal += pos;
93 memmove(buffer, buffer + pos, numBytesPrev);
94 }
95 }
96
97 static char kStartID[] = ",!@Install@!UTF-8!";
98 static char kEndID[] = ",!@InstallEnd@!";
99
100 class CInstallIDInit
101 {
102 public:
CInstallIDInit()103 CInstallIDInit()
104 {
105 kStartID[0] = ';';
106 kEndID[0] = ';';
107 };
108 } g_CInstallIDInit;
109
110
111 #define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
112
ShowErrorMessageSpec(const UString & name)113 static void ShowErrorMessageSpec(const UString &name)
114 {
115 UString message = NError::MyFormatMessage(::GetLastError());
116 int pos = message.Find(L"%1");
117 if (pos >= 0)
118 {
119 message.Delete(pos, 2);
120 message.Insert(pos, name);
121 }
122 ShowErrorMessage(NULL, message);
123 }
124
WinMain(HINSTANCE hInstance,HINSTANCE,LPWSTR,int)125 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
126 #ifdef UNDER_CE
127 LPWSTR
128 #else
129 LPSTR
130 #endif
131 /* lpCmdLine */,int /* nCmdShow */)
132 {
133 g_hInstance = (HINSTANCE)hInstance;
134
135 NT_CHECK
136
137 // InitCommonControls();
138
139 UString archiveName, switches;
140 #ifdef _SHELL_EXECUTE
141 UString executeFile, executeParameters;
142 #endif
143 NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
144
145 FString fullPath;
146 NDLL::MyGetModuleFileName(fullPath);
147
148 switches.Trim();
149 bool assumeYes = false;
150 if (MyStringCompareNoCase_N(switches, L"-y", 2) == 0)
151 {
152 assumeYes = true;
153 switches = switches.Ptr(2);
154 switches.Trim();
155 }
156
157 AString config;
158 if (!ReadDataString(fullPath, kStartID, kEndID, config))
159 {
160 if (!assumeYes)
161 ShowErrorMessage(L"Can't load config info");
162 return 1;
163 }
164
165 UString dirPrefix = L"." WSTRING_PATH_SEPARATOR;
166 UString appLaunched;
167 bool showProgress = true;
168 if (!config.IsEmpty())
169 {
170 CObjectVector<CTextConfigPair> pairs;
171 if (!GetTextConfig(config, pairs))
172 {
173 if (!assumeYes)
174 ShowErrorMessage(L"Config failed");
175 return 1;
176 }
177 UString friendlyName = GetTextConfigValue(pairs, L"Title");
178 UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt");
179 UString progress = GetTextConfigValue(pairs, L"Progress");
180 if (progress.IsEqualToNoCase(L"no"))
181 showProgress = false;
182 int index = FindTextConfigItem(pairs, L"Directory");
183 if (index >= 0)
184 dirPrefix = pairs[index].String;
185 if (!installPrompt.IsEmpty() && !assumeYes)
186 {
187 if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |
188 MB_ICONQUESTION) != IDYES)
189 return 0;
190 }
191 appLaunched = GetTextConfigValue(pairs, L"RunProgram");
192
193 #ifdef _SHELL_EXECUTE
194 executeFile = GetTextConfigValue(pairs, L"ExecuteFile");
195 executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters");
196 #endif
197 }
198
199 CTempDir tempDir;
200 if (!tempDir.Create(kTempDirPrefix))
201 {
202 if (!assumeYes)
203 ShowErrorMessage(L"Can not create temp folder archive");
204 return 1;
205 }
206
207 CCodecs *codecs = new CCodecs;
208 CMyComPtr<IUnknown> compressCodecsInfo = codecs;
209 HRESULT result = codecs->Load();
210 if (result != S_OK)
211 {
212 ShowErrorMessage(L"Can not load codecs");
213 return 1;
214 }
215
216 const FString tempDirPath = tempDir.GetPath();
217 // tempDirPath = L"M:\\1\\"; // to test low disk space
218 {
219 bool isCorrupt = false;
220 UString errorMessage;
221 HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
222 isCorrupt, errorMessage);
223
224 if (result != S_OK)
225 {
226 if (!assumeYes)
227 {
228 if (result == S_FALSE || isCorrupt)
229 {
230 NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
231 result = E_FAIL;
232 }
233 if (result != E_ABORT)
234 {
235 if (errorMessage.IsEmpty())
236 errorMessage = NError::MyFormatMessage(result);
237 ::MessageBoxW(0, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
238 }
239 }
240 return 1;
241 }
242 }
243
244 #ifndef UNDER_CE
245 CCurrentDirRestorer currentDirRestorer;
246 if (!SetCurrentDir(tempDirPath))
247 return 1;
248 #endif
249
250 HANDLE hProcess = 0;
251 #ifdef _SHELL_EXECUTE
252 if (!executeFile.IsEmpty())
253 {
254 CSysString filePath = GetSystemString(executeFile);
255 SHELLEXECUTEINFO execInfo;
256 execInfo.cbSize = sizeof(execInfo);
257 execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
258 #ifndef UNDER_CE
259 | SEE_MASK_FLAG_DDEWAIT
260 #endif
261 ;
262 execInfo.hwnd = NULL;
263 execInfo.lpVerb = NULL;
264 execInfo.lpFile = filePath;
265
266 if (!switches.IsEmpty())
267 {
268 if (!executeParameters.IsEmpty())
269 executeParameters += L' ';
270 executeParameters += switches;
271 }
272
273 CSysString parametersSys = GetSystemString(executeParameters);
274 if (parametersSys.IsEmpty())
275 execInfo.lpParameters = NULL;
276 else
277 execInfo.lpParameters = parametersSys;
278
279 execInfo.lpDirectory = NULL;
280 execInfo.nShow = SW_SHOWNORMAL;
281 execInfo.hProcess = 0;
282 /* BOOL success = */ ::ShellExecuteEx(&execInfo);
283 UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
284 if(result <= 32)
285 {
286 if (!assumeYes)
287 ShowErrorMessage(L"Can not open file");
288 return 1;
289 }
290 hProcess = execInfo.hProcess;
291 }
292 else
293 #endif
294 {
295 if (appLaunched.IsEmpty())
296 {
297 appLaunched = L"setup.exe";
298 if (!NFind::DoesFileExist(us2fs(appLaunched)))
299 {
300 if (!assumeYes)
301 ShowErrorMessage(L"Can not find setup.exe");
302 return 1;
303 }
304 }
305
306 {
307 FString s2 = tempDirPath;
308 NName::NormalizeDirPathPrefix(s2);
309 appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
310 }
311
312 UString appNameForError = appLaunched; // actually we need to rtemove parameters also
313
314 appLaunched.Replace(L"%%T", fs2us(tempDirPath));
315
316 if (!switches.IsEmpty())
317 {
318 appLaunched += L' ';
319 appLaunched += switches;
320 }
321 STARTUPINFO startupInfo;
322 startupInfo.cb = sizeof(startupInfo);
323 startupInfo.lpReserved = 0;
324 startupInfo.lpDesktop = 0;
325 startupInfo.lpTitle = 0;
326 startupInfo.dwFlags = 0;
327 startupInfo.cbReserved2 = 0;
328 startupInfo.lpReserved2 = 0;
329
330 PROCESS_INFORMATION processInformation;
331
332 CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched);
333
334 BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,
335 NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
336 &startupInfo, &processInformation);
337 if (createResult == 0)
338 {
339 if (!assumeYes)
340 {
341 // we print name of exe file, if error message is
342 // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
343 ShowErrorMessageSpec(appNameForError);
344 }
345 return 1;
346 }
347 ::CloseHandle(processInformation.hThread);
348 hProcess = processInformation.hProcess;
349 }
350 if (hProcess != 0)
351 {
352 WaitForSingleObject(hProcess, INFINITE);
353 ::CloseHandle(hProcess);
354 }
355 return 0;
356 }
357