source: branches/eraser6/Installer/Bootstrapper/Bootstrapper.cpp @ 537

Revision 537, 8.7 KB checked in by lowjoel, 5 years ago (diff)

-Fixed Yield
-Fixed the TempDir? destructor
-Added exception handlers to Main, since it can't throw
-Few warning fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22#include "stdafx.h"
23#include "Bootstrapper.h"
24
25/// ISzInStream interface for extracting the archives.
26struct LZFileStream
27{
28public:
29    /// Constructor.
30    ///
31    /// \param[in] fileHandle A HANDLE to the file stream, returned by CreateFile.
32    LZFileStream(HANDLE fileHandle)
33    {
34        InStream.Read = LZFileStreamRead;
35        InStream.Seek = LzFileStreamSeek;
36        FileHandle = fileHandle;
37
38        FileRead = FileRead = 0;
39        LARGE_INTEGER largeInt;
40        largeInt.QuadPart = 0;
41        if (!SetFilePointerEx(FileHandle, largeInt, &largeInt, FILE_CURRENT))
42            throw GetErrorMessage(GetLastError());
43
44        long long currPos = largeInt.QuadPart;
45        largeInt.QuadPart = 0;
46        if (!SetFilePointerEx(FileHandle, largeInt, &largeInt, FILE_END))
47            throw GetErrorMessage(GetLastError());
48        FileSize = largeInt.QuadPart - currPos;
49
50        largeInt.QuadPart = currPos;
51        if (!SetFilePointerEx(FileHandle, largeInt, NULL, FILE_BEGIN))
52            throw GetErrorMessage(GetLastError());
53    }
54
55    ~LZFileStream()
56    {
57        CloseHandle(FileHandle);
58    }
59
60    ISzInStream InStream;
61
62private:
63    HANDLE FileHandle;
64    long long FileRead;
65    long long FileSize;
66
67    static SZ_RESULT LZFileStreamRead(void* object, void** bufferPtr, size_t size,
68        size_t* processedSize)
69    {
70        LZFileStream* s = static_cast<LZFileStream*>(object);
71
72        //Since we can allocate as much as we want to allocate, take a decent amount
73        //of memory and stop.
74        size = std::min(1048576u * 4, size);
75        char* buffer = new char[size];
76
77        DWORD readSize = 0;
78        if (ReadFile(s->FileHandle, buffer, size, &readSize, NULL) && readSize != 0)
79        {
80            *bufferPtr = buffer;
81            *processedSize = readSize;
82            s->FileRead += readSize;
83
84            SetProgress((float)((double)s->FileRead / s->FileSize));
85        }
86
87        return SZ_OK;
88    }
89
90    static SZ_RESULT LzFileStreamSeek(void *object, CFileSize pos)
91    {
92        LZFileStream* s = static_cast<LZFileStream*>(object);
93
94        LARGE_INTEGER value;
95        value.LowPart = (DWORD)pos;
96        value.HighPart = (LONG)((UInt64)pos >> 32);
97        if (!SetFilePointerEx(s->FileHandle, value, NULL, FILE_BEGIN) &&
98            GetLastError() != NO_ERROR)
99            return SZE_FAIL;
100        return SZ_OK;
101    }
102};
103
104void ExtractTempFiles(std::wstring pathToExtract)
105{
106    if (std::wstring(L"\\/").find(pathToExtract[pathToExtract.length() - 1]) == std::wstring::npos)
107        pathToExtract += L"\\";
108
109    //Open the file
110#if _DEBUG
111    HANDLE srcFile = CreateFileW((GetApplicationPath() + L".7z").c_str(), GENERIC_READ, FILE_SHARE_READ,
112        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL , NULL);
113    if (srcFile == INVALID_HANDLE_VALUE)
114        throw GetErrorMessage(GetLastError());
115
116    //Seek to the 128th kb.
117    LARGE_INTEGER fPos;
118    fPos.QuadPart = 0;
119#else
120    HANDLE srcFile = CreateFileW(GetApplicationPath().c_str(), GENERIC_READ, FILE_SHARE_READ,
121        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL , NULL);
122    if (srcFile == INVALID_HANDLE_VALUE)
123        throw GetErrorMessage(GetLastError());
124
125    //Seek to the 128th kb.
126    LARGE_INTEGER fPos;
127    fPos.QuadPart = 128 * 1024;
128#endif
129
130    if (!SetFilePointerEx(srcFile, fPos, &fPos, FILE_BEGIN))
131        throw GetErrorMessage(GetLastError());
132
133    //7z archive database structure
134    CArchiveDatabaseEx db;
135
136    //memory functions
137    ISzAlloc allocImp;
138    ISzAlloc allocTempImp;
139    allocTempImp.Alloc = allocImp.Alloc = SzAlloc;
140    allocTempImp.Free = allocImp.Free = SzFree;
141
142    //Initialize the CRC and database structures
143    LZFileStream stream(srcFile);
144    CrcGenerateTable();
145    SzArDbExInit(&db);
146    if (SzArchiveOpen(&stream.InStream, &db, &allocImp, &allocTempImp) != SZ_OK)
147        throw std::wstring(L"Could not open archive for reading.");
148
149    //Read the database for files
150    unsigned blockIndex = 0;
151    Byte* outBuffer = NULL;
152    size_t outBufferSize = 524288;
153    for (unsigned i = 0; i < db.Database.NumFiles; ++i)
154    {
155        size_t offset = 0;
156        size_t processedSize = 0;
157        CFileItem *f = db.Database.Files + i;
158        SZ_RESULT result = SZ_OK;
159
160        //Create the output file
161        size_t convertedChars = 0;
162        wchar_t fileName[MAX_PATH];
163        mbstowcs_s(&convertedChars, fileName, f->Name, sizeof(fileName) / sizeof(fileName[0]));
164        HANDLE destFile = CreateFileW((pathToExtract + fileName).c_str(), GENERIC_WRITE, 0,
165            NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
166        if (destFile == INVALID_HANDLE_VALUE)
167            throw GetErrorMessage(GetLastError());
168        unsigned long long destFileSize = f->Size;
169
170        //Extract the file
171        while (result == SZ_OK && destFileSize)
172        {
173            result = SzExtract(&stream.InStream, &db, i, &blockIndex,
174                &outBuffer, &outBufferSize, &offset, &processedSize, &allocImp,
175                &allocTempImp);
176            if (result != SZ_OK)
177                _asm int 3;
178
179            DWORD bytesWritten = 0;
180            if (!WriteFile(destFile, outBuffer + offset, processedSize, &bytesWritten, NULL) ||
181                bytesWritten != processedSize)
182                throw GetErrorMessage(GetLastError());
183            destFileSize -= bytesWritten;
184        }
185
186        CloseHandle(destFile);
187    }
188    allocImp.Free(outBuffer);
189}
190
191bool HasNetFramework()
192{
193    HKEY key;
194    std::wstring highestVer;
195    std::wstring keys[] = { L"v2.0.50727", L"v3.0", L"v3.5" };
196
197    for (int i = 0, j = sizeof(keys) / sizeof(keys[0]); i != j; ++i)
198    {
199        //Open the key for reading
200        DWORD result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
201            (L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\" + keys[i]).c_str(),
202            0, KEY_READ, &key);
203
204        //Retry for 64-bit WoW
205        if (result == ERROR_FILE_NOT_FOUND)
206        {
207            result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
208                (L"SOFTWARE\\Wow6432Node\\Microsoft\\NET Framework Setup\\NDP\\" + keys[i]).c_str(),
209                0, KEY_READ, &key);
210        }
211
212        if (result != ERROR_SUCCESS)
213            throw GetErrorMessage(result);
214
215        //Query the Installed string
216        DWORD installedVal = 0;
217        DWORD bufferSize = sizeof(installedVal);
218        result = RegQueryValueExW(key, L"Install", NULL, NULL, (BYTE*)&installedVal,
219            &bufferSize);
220        if (result != ERROR_SUCCESS && result != ERROR_MORE_DATA)
221            throw GetErrorMessage(result);
222        if (installedVal == 1)
223            highestVer = keys[i].substr(1);
224        RegCloseKey(key);
225    }
226
227    return !highestVer.empty();
228}
229
230int CreateProcessAndWait(const std::wstring& commandLine)
231{
232    //Get a mutable version of the command line
233    wchar_t* cmdLine = new wchar_t[commandLine.length() + 1];
234    wcscpy_s(cmdLine, commandLine.length() + 1, commandLine.c_str());
235
236    //Launch the process
237    STARTUPINFOW startupInfo;
238    PROCESS_INFORMATION pInfo;
239    ::ZeroMemory(&startupInfo, sizeof(startupInfo));
240    ::ZeroMemory(&pInfo, sizeof(pInfo));
241    if (!CreateProcessW(NULL, cmdLine, NULL, NULL, false, 0, NULL,  NULL, &startupInfo,
242        &pInfo))
243    {
244        delete[] cmdLine;
245        throw GetErrorMessage(GetLastError());
246    }
247    delete[] cmdLine;
248
249    //Ok the process was created, wait for it to terminate.
250    DWORD lastWait = 0;
251    while ((lastWait = WaitForSingleObject(pInfo.hProcess, 50)) == WAIT_TIMEOUT)
252        Yield();
253    if (lastWait == WAIT_ABANDONED)
254        throw std::wstring(L"The condition waiting on the termination of the .NET installer was abandoned.");
255
256    //Get the exit code
257    DWORD exitCode = 0;
258    if (!GetExitCodeProcess(pInfo.hProcess, &exitCode))
259        throw GetErrorMessage(GetLastError());
260
261    //Clean up
262    CloseHandle(pInfo.hProcess);
263    CloseHandle(pInfo.hThread);
264
265    //Return the exit code.
266    return exitCode;
267}
268
269bool InstallNetFramework(std::wstring tempDir)
270{
271    //Update the UI
272    SetProgressIndeterminate();
273    SetMessage(L"Installing .NET Framework...");
274
275    //Get the path to the installer
276    if (std::wstring(L"\\/").find(tempDir[tempDir.length() - 1]) == std::wstring::npos)
277        tempDir += L"\\";
278    std::wstring commandLine(L'"' + tempDir);
279    commandLine += L"dotnetfx.exe\"";
280
281    //And the return code is true if the process exited with 0.
282    return CreateProcessAndWait(commandLine) == 0;
283}
284
285bool InstallEraser(std::wstring tempDir)
286{
287    SetProgressIndeterminate();
288    SetMessage(L"Installing Eraser...");
289
290    //Determine the system architecture.
291    SYSTEM_INFO sysInfo;
292    ZeroMemory(&sysInfo, sizeof(sysInfo));
293    GetSystemInfo(&sysInfo);
294
295    if (std::wstring(L"\\/").find(tempDir[tempDir.length() - 1]) == std::wstring::npos)
296        tempDir += L"\\";
297    switch (sysInfo.wProcessorArchitecture)
298    {
299    case PROCESSOR_ARCHITECTURE_AMD64:
300        tempDir += L"Eraser (x64).msi";
301        break;
302
303    default:
304        tempDir += L"Eraser (x86).msi";
305        break;
306    }
307
308    std::wstring commandLine(L"msiexec.exe /i ");
309    commandLine += L'"' + tempDir + L'"';
310   
311    //And the return code is true if the process exited with 0.
312    return CreateProcessAndWait(commandLine) == 0;
313}
Note: See TracBrowser for help on using the repository browser.