• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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