Home | History | Annotate | Download | only in SFXSetup
      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