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 kTempDirPrefix = FTEXT("7zS"); 37 38 #define _SHELL_EXECUTE 39 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 { 106 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 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 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 = L"." WSTRING_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, L"Title"); 185 UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt"); 186 UString progress = GetTextConfigValue(pairs, L"Progress"); 187 if (progress.IsEqualTo_Ascii_NoCase("no")) 188 showProgress = false; 189 int index = FindTextConfigItem(pairs, L"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, L"RunProgram"); 199 200 #ifdef _SHELL_EXECUTE 201 executeFile = GetTextConfigValue(pairs, L"ExecuteFile"); 202 executeParameters = GetTextConfigValue(pairs, L"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