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