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

Revision 538, 8.9 KB checked in by lowjoel, 6 years ago (diff)

Reshuffle all the global functions into classes. It is way neater now.

  • 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            MainWindow& mainWin = Application::Get().GetTopWindow();
85            mainWin.SetProgress((float)((double)s->FileRead / s->FileSize));
86        }
87
88        return SZ_OK;
89    }
90
91    static SZ_RESULT LzFileStreamSeek(void *object, CFileSize pos)
92    {
93        LZFileStream* s = static_cast<LZFileStream*>(object);
94
95        LARGE_INTEGER value;
96        value.LowPart = (DWORD)pos;
97        value.HighPart = (LONG)((UInt64)pos >> 32);
98        if (!SetFilePointerEx(s->FileHandle, value, NULL, FILE_BEGIN) &&
99            GetLastError() != NO_ERROR)
100            return SZE_FAIL;
101        return SZ_OK;
102    }
103};
104
105void ExtractTempFiles(std::wstring pathToExtract)
106{
107    if (std::wstring(L"\\/").find(pathToExtract[pathToExtract.length() - 1]) == std::wstring::npos)
108        pathToExtract += L"\\";
109
110    //Open the file
111#if _DEBUG
112    HANDLE srcFile = CreateFileW((GetApplicationPath() + L".7z").c_str(), GENERIC_READ, FILE_SHARE_READ,
113        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL , NULL);
114    if (srcFile == INVALID_HANDLE_VALUE)
115        throw GetErrorMessage(GetLastError());
116
117    //Seek to the 128th kb.
118    LARGE_INTEGER fPos;
119    fPos.QuadPart = 0;
120#else
121    HANDLE srcFile = CreateFileW(GetApplicationPath().c_str(), GENERIC_READ, FILE_SHARE_READ,
122        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL , NULL);
123    if (srcFile == INVALID_HANDLE_VALUE)
124        throw GetErrorMessage(GetLastError());
125
126    //Seek to the 128th kb.
127    LARGE_INTEGER fPos;
128    fPos.QuadPart = 128 * 1024;
129#endif
130
131    if (!SetFilePointerEx(srcFile, fPos, &fPos, FILE_BEGIN))
132        throw GetErrorMessage(GetLastError());
133
134    //7z archive database structure
135    CArchiveDatabaseEx db;
136
137    //memory functions
138    ISzAlloc allocImp;
139    ISzAlloc allocTempImp;
140    allocTempImp.Alloc = allocImp.Alloc = SzAlloc;
141    allocTempImp.Free = allocImp.Free = SzFree;
142
143    //Initialize the CRC and database structures
144    LZFileStream stream(srcFile);
145    CrcGenerateTable();
146    SzArDbExInit(&db);
147    if (SzArchiveOpen(&stream.InStream, &db, &allocImp, &allocTempImp) != SZ_OK)
148        throw std::wstring(L"Could not open archive for reading.");
149
150    //Read the database for files
151    unsigned blockIndex = 0;
152    Byte* outBuffer = NULL;
153    size_t outBufferSize = 524288;
154    for (unsigned i = 0; i < db.Database.NumFiles; ++i)
155    {
156        size_t offset = 0;
157        size_t processedSize = 0;
158        CFileItem *f = db.Database.Files + i;
159        SZ_RESULT result = SZ_OK;
160
161        //Create the output file
162        size_t convertedChars = 0;
163        wchar_t fileName[MAX_PATH];
164        mbstowcs_s(&convertedChars, fileName, f->Name, sizeof(fileName) / sizeof(fileName[0]));
165        HANDLE destFile = CreateFileW((pathToExtract + fileName).c_str(), GENERIC_WRITE, 0,
166            NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
167        if (destFile == INVALID_HANDLE_VALUE)
168            throw GetErrorMessage(GetLastError());
169        unsigned long long destFileSize = f->Size;
170
171        //Extract the file
172        while (result == SZ_OK && destFileSize)
173        {
174            result = SzExtract(&stream.InStream, &db, i, &blockIndex,
175                &outBuffer, &outBufferSize, &offset, &processedSize, &allocImp,
176                &allocTempImp);
177            if (result != SZ_OK)
178                _asm int 3;
179
180            DWORD bytesWritten = 0;
181            if (!WriteFile(destFile, outBuffer + offset, processedSize, &bytesWritten, NULL) ||
182                bytesWritten != processedSize)
183                throw GetErrorMessage(GetLastError());
184            destFileSize -= bytesWritten;
185        }
186
187        CloseHandle(destFile);
188    }
189    allocImp.Free(outBuffer);
190}
191
192bool HasNetFramework()
193{
194    HKEY key;
195    std::wstring highestVer;
196    std::wstring keys[] = { L"v2.0.50727", L"v3.0", L"v3.5" };
197
198    for (int i = 0, j = sizeof(keys) / sizeof(keys[0]); i != j; ++i)
199    {
200        //Open the key for reading
201        DWORD result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
202            (L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\" + keys[i]).c_str(),
203            0, KEY_READ, &key);
204
205        //Retry for 64-bit WoW
206        if (result == ERROR_FILE_NOT_FOUND)
207        {
208            result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
209                (L"SOFTWARE\\Wow6432Node\\Microsoft\\NET Framework Setup\\NDP\\" + keys[i]).c_str(),
210                0, KEY_READ, &key);
211        }
212
213        if (result != ERROR_SUCCESS)
214            throw GetErrorMessage(result);
215
216        //Query the Installed string
217        DWORD installedVal = 0;
218        DWORD bufferSize = sizeof(installedVal);
219        result = RegQueryValueExW(key, L"Install", NULL, NULL, (BYTE*)&installedVal,
220            &bufferSize);
221        if (result != ERROR_SUCCESS && result != ERROR_MORE_DATA)
222            throw GetErrorMessage(result);
223        if (installedVal == 1)
224            highestVer = keys[i].substr(1);
225        RegCloseKey(key);
226    }
227
228    return !highestVer.empty();
229}
230
231int CreateProcessAndWait(const std::wstring& commandLine)
232{
233    //Get a mutable version of the command line
234    wchar_t* cmdLine = new wchar_t[commandLine.length() + 1];
235    wcscpy_s(cmdLine, commandLine.length() + 1, commandLine.c_str());
236
237    //Launch the process
238    STARTUPINFOW startupInfo;
239    PROCESS_INFORMATION pInfo;
240    ::ZeroMemory(&startupInfo, sizeof(startupInfo));
241    ::ZeroMemory(&pInfo, sizeof(pInfo));
242    if (!CreateProcessW(NULL, cmdLine, NULL, NULL, false, 0, NULL,  NULL, &startupInfo,
243        &pInfo))
244    {
245        delete[] cmdLine;
246        throw GetErrorMessage(GetLastError());
247    }
248    delete[] cmdLine;
249
250    //Ok the process was created, wait for it to terminate.
251    DWORD lastWait = 0;
252    while ((lastWait = WaitForSingleObject(pInfo.hProcess, 50)) == WAIT_TIMEOUT)
253        Application::Get().Yield();
254    if (lastWait == WAIT_ABANDONED)
255        throw std::wstring(L"The condition waiting on the termination of the .NET installer was abandoned.");
256
257    //Get the exit code
258    DWORD exitCode = 0;
259    if (!GetExitCodeProcess(pInfo.hProcess, &exitCode))
260        throw GetErrorMessage(GetLastError());
261
262    //Clean up
263    CloseHandle(pInfo.hProcess);
264    CloseHandle(pInfo.hThread);
265
266    //Return the exit code.
267    return exitCode;
268}
269
270bool InstallNetFramework(std::wstring tempDir)
271{
272    //Update the UI
273    MainWindow& mainWin = Application::Get().GetTopWindow();
274    mainWin.SetProgressIndeterminate();
275    mainWin.SetMessage(L"Installing .NET Framework...");
276
277    //Get the path to the installer
278    if (std::wstring(L"\\/").find(tempDir[tempDir.length() - 1]) == std::wstring::npos)
279        tempDir += L"\\";
280    std::wstring commandLine(L'"' + tempDir);
281    commandLine += L"dotnetfx.exe\"";
282
283    //And the return code is true if the process exited with 0.
284    return CreateProcessAndWait(commandLine) == 0;
285}
286
287bool InstallEraser(std::wstring tempDir)
288{
289    MainWindow& mainWin = Application::Get().GetTopWindow();
290    mainWin.SetProgressIndeterminate();
291    mainWin.SetMessage(L"Installing Eraser...");
292
293    //Determine the system architecture.
294    SYSTEM_INFO sysInfo;
295    ZeroMemory(&sysInfo, sizeof(sysInfo));
296    GetSystemInfo(&sysInfo);
297
298    if (std::wstring(L"\\/").find(tempDir[tempDir.length() - 1]) == std::wstring::npos)
299        tempDir += L"\\";
300    switch (sysInfo.wProcessorArchitecture)
301    {
302    case PROCESSOR_ARCHITECTURE_AMD64:
303        tempDir += L"Eraser (x64).msi";
304        break;
305
306    default:
307        tempDir += L"Eraser (x86).msi";
308        break;
309    }
310
311    std::wstring commandLine(L"msiexec.exe /i ");
312    commandLine += L'"' + tempDir + L'"';
313   
314    //And the return code is true if the process exited with 0.
315    return CreateProcessAndWait(commandLine) == 0;
316}
Note: See TracBrowser for help on using the repository browser.