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 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: 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 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 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