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