mirror of https://github.com/BOINC/boinc.git
187 lines
5.5 KiB
C++
187 lines
5.5 KiB
C++
// This file is part of BOINC.
|
|
// https://boinc.berkeley.edu
|
|
// Copyright (C) 2024 University of California
|
|
//
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// BOINC is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include <windows.h>
|
|
|
|
#include <string>
|
|
#include <filesystem>
|
|
|
|
#include "installer_setup.h"
|
|
#include "version.h"
|
|
|
|
HBITMAP hBitmap = NULL;
|
|
|
|
void LoadSplashImage(HDC hdc, HWND hwnd) {
|
|
auto hdcMem = CreateCompatibleDC(hdc);
|
|
SelectObject(hdcMem, hBitmap);
|
|
|
|
BITMAP bitmap;
|
|
GetObject(hBitmap, sizeof(BITMAP), &bitmap);
|
|
|
|
RECT rect;
|
|
GetClientRect(hwnd, &rect);
|
|
|
|
StretchBlt(hdc, 0, 0, rect.right, rect.bottom,
|
|
hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
|
|
|
|
DeleteDC(hdcMem);
|
|
}
|
|
|
|
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
|
switch (msg) {
|
|
case WM_PAINT: {
|
|
PAINTSTRUCT ps;
|
|
auto hdc = BeginPaint(hwnd, &ps);
|
|
LoadSplashImage(hdc, hwnd);
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
}
|
|
case WM_DESTROY:
|
|
DeleteObject(hBitmap);
|
|
PostQuitMessage(0);
|
|
break;
|
|
default:
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool ExtractResourceAndExecute(UINT ResourceID, std::string OutputFileName)
|
|
{
|
|
char buffer[MAX_PATH];
|
|
const auto result = GetWindowsDirectory(buffer, MAX_PATH);
|
|
if (result == 0 || result > MAX_PATH) {
|
|
MessageBox(NULL, "Failed to get the Windows directory!", "Error",
|
|
MB_ICONERROR);
|
|
return false;
|
|
}
|
|
|
|
const std::filesystem::path windowsDir(buffer);
|
|
const auto outputDir = windowsDir / "Downloaded Installations" / "BOINC" /
|
|
BOINC_VERSION_STRING;
|
|
if (!std::filesystem::exists(outputDir)) {
|
|
if (!std::filesystem::create_directories(outputDir)) {
|
|
MessageBox(NULL, "Failed to create output directory!", "Error",
|
|
MB_ICONERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try {
|
|
auto hResource = FindResource(nullptr, MAKEINTRESOURCE(ResourceID),
|
|
"BINARY");
|
|
if (hResource == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
auto hFileResource = LoadResource(nullptr, hResource);
|
|
if (hFileResource == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
auto lpFile = LockResource(hFileResource);
|
|
if (lpFile == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
const auto dwSize = SizeofResource(nullptr, hResource);
|
|
if (dwSize == 0) {
|
|
return false;
|
|
}
|
|
|
|
auto hFile = CreateFile((outputDir / OutputFileName).string().c_str(),
|
|
GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
auto hFilemap = CreateFileMapping(hFile, nullptr, PAGE_READWRITE, 0,
|
|
dwSize, nullptr);
|
|
if (hFilemap == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
auto lpBaseAddress = MapViewOfFile(hFilemap, FILE_MAP_WRITE, 0, 0, 0);
|
|
if (lpBaseAddress == nullptr) {
|
|
return false;
|
|
}
|
|
CopyMemory(lpBaseAddress, lpFile, dwSize);
|
|
UnmapViewOfFile(lpBaseAddress);
|
|
CloseHandle(hFilemap);
|
|
CloseHandle(hFile);
|
|
|
|
const auto hInstance = ShellExecute(nullptr, "open",
|
|
(outputDir / OutputFileName).string().c_str(), nullptr, nullptr,
|
|
SW_SHOWNORMAL);
|
|
if (reinterpret_cast<int>(hInstance) <= 32) {
|
|
MessageBox(NULL, "Failed to execute the installer!", "Error",
|
|
MB_ICONERROR);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (const std::exception& ex) {
|
|
MessageBox(NULL, "Failed to extract resource!", ex.what(),
|
|
MB_ICONERROR);
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
|
|
hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SPLASH));
|
|
if (!hBitmap) {
|
|
MessageBox(NULL, "Failed to load image!", "Error", MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
|
|
const auto CLASS_NAME = "SplashScreen";
|
|
WNDCLASS wc = {};
|
|
wc.lpfnWndProc = WndProc;
|
|
wc.hInstance = hInstance;
|
|
wc.lpszClassName = CLASS_NAME;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
if (!RegisterClass(&wc)) {
|
|
MessageBox(NULL, "Window registration failed!", "Error", MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
|
|
auto hwnd = CreateWindowEx(
|
|
WS_EX_TOPMOST, CLASS_NAME, "Splash Screen", WS_POPUP,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);
|
|
|
|
if (!hwnd) {
|
|
MessageBox(NULL, "Window creation failed!", "Error", MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
|
|
RECT rect;
|
|
GetWindowRect(hwnd, &rect);
|
|
const auto screenWidth = GetSystemMetrics(SM_CXSCREEN);
|
|
const auto screenHeight = GetSystemMetrics(SM_CYSCREEN);
|
|
const auto x = (screenWidth - 400) / 2;
|
|
const auto y = (screenHeight - 300) / 2;
|
|
SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, 400, 300,
|
|
SWP_SHOWWINDOW);
|
|
|
|
ShowWindow(hwnd, nCmdShow);
|
|
UpdateWindow(hwnd);
|
|
|
|
ExtractResourceAndExecute(IDB_MSI, "BOINC.msi");
|
|
|
|
return 0;
|
|
}
|