From 65b2b32c28df8b47183c11ec3ac81ff1b102862c Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Fri, 8 Jun 2012 15:53:33 +0300 Subject: [PATCH] Rewrote SkinInstaller .rmskin install code. Added support for new .rmskin format. --- SkinInstaller/Application.cpp | 98 +- SkinInstaller/Application.h | 16 +- SkinInstaller/DialogBackup.cpp | 16 +- SkinInstaller/DialogBackup.h | 4 +- SkinInstaller/DialogInstall.cpp | 1175 +++++++++++++ SkinInstaller/DialogInstall.h | 125 ++ SkinInstaller/Rainstaller.cpp | 1752 ------------------- SkinInstaller/Rainstaller.h | 104 -- SkinInstaller/SkinInstaller.rc | 92 +- SkinInstaller/SkinInstaller.vcxproj | 41 +- SkinInstaller/SkinInstaller.vcxproj.filters | 22 +- SkinInstaller/StdAfx.h | 17 +- SkinInstaller/resource.h | 54 +- 13 files changed, 1451 insertions(+), 2065 deletions(-) create mode 100644 SkinInstaller/DialogInstall.cpp create mode 100644 SkinInstaller/DialogInstall.h delete mode 100644 SkinInstaller/Rainstaller.cpp delete mode 100644 SkinInstaller/Rainstaller.h diff --git a/SkinInstaller/Application.cpp b/SkinInstaller/Application.cpp index 66e91964..388bbeea 100644 --- a/SkinInstaller/Application.cpp +++ b/SkinInstaller/Application.cpp @@ -18,11 +18,11 @@ #include "StdAfx.h" #include "DialogBackup.h" +#include "DialogInstall.h" #include "resource.h" #include "Application.h" -#include "Rainstaller.h" -GLOBALDATA g_Data; +GlobalData g_Data; /* ** Entry point @@ -30,16 +30,23 @@ GLOBALDATA g_Data; */ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { - bool loadTheme = (_wcsnicmp(lpCmdLine, L"/LoadTheme ", 11) == 0); - if (wcscmp(lpCmdLine, L"/BACKUP") != 0 && !loadTheme) - { - // Temporary solution until Rainstaller rewrite - return Rainstaller(hInstance, hPrevInstance, lpCmdLine, nCmdShow); - } - // Avoid loading a dll from current directory SetDllDirectory(L""); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); + InitCommonControls(); + + if (lpCmdLine[0] == L'"') + { + // Strip quotes + ++lpCmdLine; + WCHAR* pos = wcsrchr(lpCmdLine, L'"'); + if (pos) + { + *pos = L'\0'; + } + } + WCHAR buffer[MAX_PATH]; GetModuleFileName(hInstance, buffer, MAX_PATH); @@ -95,39 +102,36 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi } } - if (loadTheme) + if (_wcsnicmp(lpCmdLine, L"/LoadTheme ", 11) == 0) { - // Skip "/LOADTHEME " + // Skip "/LoadTheme " lpCmdLine += 11; if (CloseRainmeterIfActive() && *lpCmdLine) { - LoadTheme(lpCmdLine); + CDialogInstall::LoadTheme(lpCmdLine, true); std::wstring file = g_Data.programPath + L"Rainmeter.exe"; SHELLEXECUTEINFO sei = {0}; sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = SEE_MASK_UNICODE; sei.lpFile = file.c_str(); + sei.lpDirectory = g_Data.programPath.c_str(); sei.nShow = SW_SHOWNORMAL; ShellExecuteEx(&sei); } return 0; } - - // Check whether Rainstaller.exe is already running and bring it to front if so - HANDLE hMutex; - if (IsRunning(L"RmSkinInstallerMutex", &hMutex)) + else if (wcscmp(lpCmdLine, L"/BACKUP") == 0) { - HWND hwnd = FindWindow(L"#32770", L"Backup Rainmeter"); - SetForegroundWindow(hwnd); - return 0; + CDialogBackup::Create(hInstance, lpCmdLine); + } + else + { + CDialogInstall::Create(hInstance, lpCmdLine); } - CDialogBackup::Create(hInstance, lpCmdLine); - - ReleaseMutex(hMutex); return 0; } @@ -156,56 +160,6 @@ bool CloseRainmeterIfActive() return true; } -void LoadTheme(const WCHAR* name) -{ - std::wstring backup = g_Data.settingsPath + L"Themes\\Backup"; - CreateDirectory(backup.c_str(), NULL); - backup += L"\\Rainmeter.thm"; - - // Make a copy of current Rainmeter.ini - CopyFiles(g_Data.iniFile, backup); - - // Replace Rainmeter.ini with theme - std::wstring theme = g_Data.settingsPath + L"Themes\\"; - theme += name; - std::wstring wallpaper = theme + L"\\RainThemes.bmp"; - theme += L"\\Rainmeter.thm"; - if (CopyFiles(theme, g_Data.iniFile)) - { - PreserveSetting(backup, L"SkinPath"); - PreserveSetting(backup, L"ConfigEditor"); - PreserveSetting(backup, L"LogViewer"); - PreserveSetting(backup, L"Logging"); - PreserveSetting(backup, L"DisableVersionCheck"); - PreserveSetting(backup, L"Language"); - PreserveSetting(backup, L"NormalStayDesktop"); - PreserveSetting(backup, L"TrayExecuteL", false); - PreserveSetting(backup, L"TrayExecuteM", false); - PreserveSetting(backup, L"TrayExecuteR", false); - PreserveSetting(backup, L"TrayExecuteDM", false); - PreserveSetting(backup, L"TrayExecuteDR", false); - - // Set wallpaper if it exists - if (_waccess(wallpaper.c_str(), 0) != -1) - { - SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)wallpaper.c_str(), SPIF_UPDATEINIFILE); - } - } -} - -void PreserveSetting(const std::wstring& from, LPCTSTR key, bool replace) -{ - WCHAR* buffer = new WCHAR[MAX_LINE_LENGTH]; - - if ((replace || GetPrivateProfileString(L"Rainmeter", key, L"", buffer, 4, g_Data.iniFile.c_str()) == 0) && - GetPrivateProfileString(L"Rainmeter", key, L"", buffer, MAX_LINE_LENGTH, from.c_str()) > 0) - { - WritePrivateProfileString(L"Rainmeter", key, buffer, g_Data.iniFile.c_str()); - } - - delete buffer; -} - // ----------------------------------------------------------------------------------------------- // Stolen functions from Rainmeter Litestep.cpp, System.cpp, and Application.cpp // ----------------------------------------------------------------------------------------------- diff --git a/SkinInstaller/Application.h b/SkinInstaller/Application.h index 9ff9baad..f130739a 100644 --- a/SkinInstaller/Application.h +++ b/SkinInstaller/Application.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __APPLICATION_H__ -#define __APPLICATION_H__ +#ifndef SKININSTALLER_APPLICATION_H_ +#define SKININSTALLER_APPLICATION_H_ #include #include "zip.h" @@ -25,18 +25,14 @@ #if defined _M_IX86 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") -#elif defined _M_IA64 -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") #elif defined _M_X64 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") -#else -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif -#define MAX_LINE_LENGTH 4096 -#define MB_ERROR MB_OK | MB_TOPMOST | MB_ICONERROR +#define MAX_LINE_LENGTH 4096 +#define MB_ERROR MB_OK | MB_TOPMOST | MB_ICONERROR -struct GLOBALDATA +struct GlobalData { std::wstring programPath; std::wstring settingsPath; @@ -53,8 +49,6 @@ enum OSPLATFORM }; bool CloseRainmeterIfActive(); -void LoadTheme(const WCHAR* name); -void PreserveSetting(const std::wstring& from, LPCTSTR key, bool replace = true); OSPLATFORM GetOSPlatform(); bool IsRunning(const WCHAR* name, HANDLE* hMutex); diff --git a/SkinInstaller/DialogBackup.cpp b/SkinInstaller/DialogBackup.cpp index a1802af0..96281969 100644 --- a/SkinInstaller/DialogBackup.cpp +++ b/SkinInstaller/DialogBackup.cpp @@ -24,7 +24,7 @@ #define WM_DELAYED_CLOSE WM_APP + 0 -extern GLOBALDATA g_Data; +extern GlobalData g_Data; CDialogBackup* CDialogBackup::c_Dialog = NULL; @@ -54,7 +54,17 @@ CDialogBackup::~CDialogBackup() */ void CDialogBackup::Create(HINSTANCE hInstance, LPWSTR lpCmdLine) { - DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_BACKUP_DIALOG), NULL, (DLGPROC)DlgProc, (LPARAM)lpCmdLine); + HANDLE hMutex; + if (IsRunning(L"RainmeterBackup", &hMutex)) + { + HWND hwnd = FindWindow(L"#32770", L"Backup Rainmeter"); + SetForegroundWindow(hwnd); + } + else + { + DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_BACKUP_DIALOG), NULL, (DLGPROC)DlgProc, (LPARAM)lpCmdLine); + ReleaseMutex(hMutex); + } } CDialog::CTab& CDialogBackup::GetActiveTab() @@ -99,7 +109,7 @@ INT_PTR CALLBACK CDialogBackup::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPA INT_PTR CDialogBackup::OnInitDialog(WPARAM wParam, LPARAM lParam) { - HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_INSTALLER), IMAGE_ICON, 16, 16, LR_SHARED); + HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SKININSTALLER), IMAGE_ICON, 16, 16, LR_SHARED); SendMessage(m_Window, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); if (GetOSPlatform() >= OSPLATFORM_VISTA) diff --git a/SkinInstaller/DialogBackup.h b/SkinInstaller/DialogBackup.h index ba55d775..3dd789ca 100644 --- a/SkinInstaller/DialogBackup.h +++ b/SkinInstaller/DialogBackup.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _DIALOGBACKUP_H_ -#define _DIALOGBACKUP_H_ +#ifndef SKININSTALLER_DIALOGBACKUP_H_ +#define SKININSTALLER_DIALOGBACKUP_H_ #include #include "zip.h" diff --git a/SkinInstaller/DialogInstall.cpp b/SkinInstaller/DialogInstall.cpp new file mode 100644 index 00000000..31022b50 --- /dev/null +++ b/SkinInstaller/DialogInstall.cpp @@ -0,0 +1,1175 @@ +/* + Copyright (C) 2012 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "StdAfx.h" +#include "Application.h" +#include "DialogInstall.h" +#include "../Library/pcre-8.10/config.h" +#include "../Library/pcre-8.10/pcre.h" +#include "resource.h" +#include "../Version.h" + +#define WM_DELAYED_CLOSE WM_APP + 0 + +extern GlobalData g_Data; + +CDialogInstall* CDialogInstall::c_Dialog = NULL; + +inline bool IsWin32Build() +{ +#ifdef _WIN32 + return true; +#else + return false; +#endif +} + +/* +** Constructor. +** +*/ +CDialogInstall::CDialogInstall(HWND wnd, const WCHAR* file) : CDialog(wnd), + m_TabInstall(wnd), + m_InstallThread(), + m_BackupPackage(false), + m_PackageUnzFile(), + m_PackageFileName(file), + m_PackageFormat(PackageFormat::Old), + m_MergeSkins(false) +{ +} + +/* +** Destructor. +** +*/ +CDialogInstall::~CDialogInstall() +{ + if (m_PackageUnzFile) + { + unzClose(m_PackageUnzFile); + } +} + +/* +** Creates the dialog. +** +*/ +void CDialogInstall::Create(HINSTANCE hInstance, LPWSTR lpCmdLine) +{ + // Prompt to select .rmskin file if needed + WCHAR buffer[MAX_PATH]; + if (!*lpCmdLine) + { + buffer[0] = L'\0'; + + OPENFILENAME ofn = {0}; + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.lpstrFilter = L"Rainmeter skin file (.rmskin)\0*.rmskin;*.zip"; + ofn.nFilterIndex = 1; + ofn.lpstrFile = buffer; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrTitle = L"Select Rainmeter skin file"; + ofn.lpstrDefExt = L"rmskin"; + ofn.Flags = OFN_FILEMUSTEXIST; + + if (!GetOpenFileName(&ofn)) + { + return; + } + + lpCmdLine = buffer; + } + + HANDLE hMutex; + if (IsRunning(L"RainmeterSkinInstaller", &hMutex)) + { + HWND hwnd = FindWindow(L"#32770", L"Rainmeter Skin Installer"); + SetForegroundWindow(hwnd); + } + else + { + DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_INSTALL_DIALOG), NULL, (DLGPROC)DlgProc, (LPARAM)lpCmdLine); + ReleaseMutex(hMutex); + } +} + +CDialog::CTab& CDialogInstall::GetActiveTab() +{ + return m_TabInstall; +} + +INT_PTR CALLBACK CDialogInstall::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (!c_Dialog) + { + if (uMsg == WM_INITDIALOG) + { + c_Dialog = new CDialogInstall(hWnd, (const WCHAR*)lParam); + return c_Dialog->OnInitDialog(wParam, lParam); + } + } + else + { + switch (uMsg) + { + case WM_COMMAND: + return c_Dialog->OnCommand(wParam, lParam); + + case WM_CLOSE: + EndDialog(hWnd, 0); + return TRUE; + + case WM_DESTROY: + delete c_Dialog; + c_Dialog = NULL; + return FALSE; + } + } + + return FALSE; +} + +INT_PTR CDialogInstall::OnInitDialog(WPARAM wParam, LPARAM lParam) +{ + HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SKININSTALLER), IMAGE_ICON, 16, 16, LR_SHARED); + SendMessage(m_Window, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + + if (GetOSPlatform() >= OSPLATFORM_VISTA) + { + SetDialogFont(); + + BUTTON_SPLITINFO bsi; + bsi.mask = BCSIF_SIZE; + bsi.size.cx = 20; + bsi.size.cy = 14; + + HWND item = GetDlgItem(m_Window, IDC_INSTALL_ADVANCED_BUTTON); + Button_SetStyle(item, BS_SPLITBUTTON, TRUE); + Button_SetSplitInfo(item, &bsi); + } + + if (ReadPackage()) + { + m_TabInstall.Activate(); + } + else + { + if (m_ErrorMessage.empty()) + { + m_ErrorMessage = L"Invalid package:\n"; + m_ErrorMessage += m_PackageFileName; + } + + MessageBox(NULL, m_ErrorMessage.c_str(), L"Rainmeter Skin Installer", MB_ERROR); + EndDialog(m_Window, 0); + } + + + return TRUE; +} + +INT_PTR CDialogInstall::OnCommand(WPARAM wParam, LPARAM lParam) +{ + switch (LOWORD(wParam)) + { + case IDC_INSTALL_INSTALL_BUTTON: + BeginInstall(); + break; + + case IDCLOSE: + if (!m_InstallThread) + { + EndDialog(m_Window, 0); + } + break; + + default: + return FALSE; + } + + return TRUE; +} + +bool CDialogInstall::ExtractCurrentFile(const std::wstring& fileName) +{ + // Some archives don't explicity list directories, so create them recursively + if (!CreateDirectoryRecursive(fileName)) + { + return false; + } + + if (fileName.back() == L'\\') + { + // Nothing left to do + return true; + } + + if (unzOpenCurrentFile(m_PackageUnzFile) != UNZ_OK) + { + return false; + } + + HANDLE hFile = CreateFile(fileName.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + return false; + } + + int read; + do + { + BYTE buffer[16384]; + DWORD written; + read = unzReadCurrentFile(m_PackageUnzFile, buffer, 16384); + if (read < 0 || !WriteFile(hFile, (LPCVOID)buffer, read, &written, NULL) || read != written) + { + read = UNZ_ERRNO; + break; + } + } + while (read != UNZ_EOF); + + CloseHandle(hFile); + + return unzCloseCurrentFile(m_PackageUnzFile) == UNZ_OK && read == UNZ_EOF; +} + +bool CDialogInstall::ReadPackage() +{ + const WCHAR* fileName = m_PackageFileName.c_str(); + const WCHAR* fileExtension = PathFindExtension(fileName); + + if (_wcsicmp(fileExtension, L".rmskin") == 0) + { + // Check if the footer is present (for new .rmskin format) + PackageFooter footer = {0}; + + FILE* file = _wfopen(fileName, L"rb"); + __int64 fileSize = 0; + if (file) + { + fseek(file, sizeof(footer), SEEK_END); + fileSize = _ftelli64(file); + fread(&footer, sizeof(footer), 1, file); + fclose(file); + } + + if (strcmp(footer.key, "RMSKIN") == 0) + { + m_PackageFormat = PackageFormat::New; + if (footer.size != fileSize) + { + return false; + } + + if (footer.flags) + { + m_BackupPackage = footer.flags & PackageFlag::Backup; + } + } + } + else if (_wcsicmp(fileExtension, L".zip") != 0) + { + return false; + } + + m_PackageUnzFile = unzOpen(ConvertToAscii(fileName).c_str()); + if (!m_PackageUnzFile) + { + return false; + } + + // Temporary file to extract the options file and header bitmap + WCHAR tempFile[MAX_PATH]; + GetTempPath(MAX_PATH, tempFile); + GetTempFileName(tempFile, L"dat", 0, tempFile); + + WCHAR buffer[MAX_PATH]; + + // Helper to sets buffer with current file name + auto getFileInfo = [&]()->bool + { + char cBuffer[MAX_PATH]; + unz_file_info ufi; + if (unzGetCurrentFileInfo(m_PackageUnzFile, &ufi, cBuffer, MAX_PATH, NULL, 0, NULL, 0) == UNZ_OK) + { + MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); + while (WCHAR* pos = wcschr(buffer, L'/')) *pos = L'\\'; + return true; + } + + return false; + }; + + // Loop through the contents of the archive until the settings file is found + WCHAR* path; + bool optionsFound = false; + do + { + if (!getFileInfo()) + { + return false; + } + + path = wcsrchr(buffer, L'\\'); + if (!path) + { + path = buffer; + + if (m_PackageFormat == PackageFormat::New) + { + // New package files must be in root of archive + continue; + } + } + else + { + ++path; // Skip slash + } + + if (_wcsicmp(path, m_PackageFormat == PackageFormat::New ? L"RMSKIN.bmp" : L"Rainstaller.bmp") == 0) + { + if (!ExtractCurrentFile(tempFile)) + { + break; + } + + HBITMAP header = (HBITMAP)LoadImage(NULL, tempFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + SendMessage(GetDlgItem(m_Window, IDC_INSTALL_HEADER_BITMAP), STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)header); + } + else if (_wcsicmp(path, m_PackageFormat == PackageFormat::New ? L"RMSKIN.ini" : L"Rainstaller.cfg") == 0) + { + optionsFound = ExtractCurrentFile(tempFile) && ReadOptions(tempFile); + break; + } + } + while (unzGoToNextFile(m_PackageUnzFile) == UNZ_OK); + + DeleteFile(tempFile); + + if (!optionsFound) + { + return false; + } + + // Loop through the archive a second time and find included components + unzGoToFirstFile(m_PackageUnzFile); + + m_PackageRoot.assign(buffer, path - buffer); + const WCHAR* root = m_PackageRoot.c_str(); + do + { + if (!getFileInfo()) + { + return false; + } + + if (wcsncmp(buffer, root, m_PackageRoot.length()) != 0) + { + // Ignore everything that isn't in the root directory + continue; + } + + WCHAR* component = buffer + m_PackageRoot.length(); + path = wcschr(component, L'\\'); + if (path) + { + *path = L'\0'; + ++path; + } + else + { + continue; + } + + const WCHAR* pos = wcschr(path, L'\\'); + const WCHAR* extension = PathFindExtension(pos ? pos : path); + if (pos) + { + // Component with subfolders + const std::wstring item(path, pos - path); + const WCHAR* itemSz = item.c_str(); + + if (_wcsicmp(component, L"Skins") == 0) + { + m_PackageSkins.insert(item); + } + else if (_wcsicmp(component, L"Themes") == 0 && + _wcsicmp(extension, L".thm") == 0) + { + m_PackageThemes.insert(item); + } + else if (_wcsicmp(component, L"Addons") == 0 && + m_PackageFormat == PackageFormat::Old) + { + m_PackageAddons.insert(item); + } + else if (_wcsicmp(component, L"Plugins") == 0 && + _wcsicmp(itemSz, IsWin32Build() ? L"32bit" : L"64bit") == 0 && + _wcsicmp(extension, L".dll") == 0 && + !wcschr(pos + 1, L'\\')) + { + m_PackagePlugins.insert(item); + } + } + else + { + // Component with subfiles + const std::wstring item = path; + const WCHAR* itemSz = item.c_str(); + + if (_wcsicmp(component, L"Fonts") == 0 && + m_PackageFormat == PackageFormat::Old && + _wcsicmp(extension, L".ttf") == 0) + { + m_PackageFonts.insert(item); + } + } + } + while (unzGoToNextFile(m_PackageUnzFile) == UNZ_OK); + + if (m_PackageSkins.empty()) + { + // Fonts can be installed only with skins + m_PackageFonts.clear(); + } + + return !(m_PackageSkins.empty() && m_PackageThemes.empty() && + m_PackageAddons.empty() && m_PackageFonts.empty() && m_PackagePlugins.empty()); +} + +bool CDialogInstall::ReadOptions(const WCHAR* file) +{ + WCHAR buffer[MAX_LINE_LENGTH]; + + const bool newFormat = m_PackageFormat == PackageFormat::New; + const WCHAR* section = newFormat ? L"rmskin" : L"Rainstaller"; + + const HWND window = m_TabInstall.GetWindow(); + + if (GetPrivateProfileString(section, L"Name", L"", buffer, 64, file) == 0) + { + return false; + } + Static_SetText(GetDlgItem(window, IDC_INSTALLTAB_NAME_TEXT), buffer); + + GetPrivateProfileString(section, L"Author", L"", buffer, 64, file); + Static_SetText(GetDlgItem(window, IDC_INSTALLTAB_AUTHOR_TEXT), buffer); + + GetPrivateProfileString(section, L"Version", L"", buffer, 64, file); + Static_SetText(GetDlgItem(window, IDC_INSTALLTAB_VERSION_TEXT), buffer); + + m_MergeSkins = GetPrivateProfileInt(section, newFormat ? L"MergeSkins" : L"Merge", 0, file) != 0; + + GetPrivateProfileString(section, newFormat ? L"VariableFiles" : L"KeepVar", L"", buffer, MAX_LINE_LENGTH, file); + m_VariablesFiles = Tokenize(buffer, L"|"); + + if (GetPrivateProfileString(section, newFormat ? L"MinimumRainmeter" : L"MinRainmeterVer", L"", buffer, MAX_LINE_LENGTH, file) > 0) + { + std::wstring rainmeterDll = g_Data.programPath + L"Rainmeter.dll"; + std::wstring rainmeterVersion = GetFileVersionString(rainmeterDll.c_str()); + if (CompareVersions(buffer, rainmeterVersion) == 1) + { + m_ErrorMessage = L"Rainmeter "; + m_ErrorMessage += buffer; + m_ErrorMessage += L" or higher is required to install this package.\n\n" + L"Get the latest version from rainmeter.net and try again."; + return false; + } + } + + if (newFormat) + { + if (GetPrivateProfileString(section, L"MinimumDotNET", L"", buffer, MAX_LINE_LENGTH, file) > 0 && + CompareVersions(buffer, GetDotNetVersionString()) == 1) + { + m_ErrorMessage = L".NET framework "; + m_ErrorMessage += buffer; + m_ErrorMessage += L" or higher is required to install this package."; + return false; + } + + if (GetPrivateProfileString(section, L"MinimumWindows", L"", buffer, MAX_LINE_LENGTH, file) > 0 && + CompareVersions(buffer, GetWindowsVersionString()) == 1) + { + m_ErrorMessage = L"Your version of Windows is not supported by this package.\n\n" + L"Contact the package author for more information."; + return false; + } + } + else + { + if (GetPrivateProfileString(section, L"LaunchType", L"", buffer, MAX_LINE_LENGTH, file) > 0) + { + bool loadSkins = _wcsicmp(buffer, L"load") == 0; + + GetPrivateProfileString(section, L"LaunchCommand", L"", buffer, MAX_LINE_LENGTH, file); + if (loadSkins) + { + m_LoadSkins = Tokenize(buffer, L"|"); + } + else + { + m_LoadTheme = buffer; + } + } + + return true; + } + + return true; +} + +bool CDialogInstall::InstallPackage() +{ + WCHAR buffer[MAX_PATH]; + + // Helper to sets buffer with current file name + auto getFileInfo = [&]()->bool + { + char cBuffer[MAX_PATH]; + unz_file_info ufi; + if (unzGetCurrentFileInfo(m_PackageUnzFile, &ufi, cBuffer, MAX_PATH, NULL, 0, NULL, 0) == UNZ_OK) + { + MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); + while (WCHAR* pos = wcschr(buffer, L'/')) *pos = L'\\'; + return true; + } + + return false; + }; + + // Move skins into backup folder + if (!m_MergeSkins) + { + for (auto iter = m_PackageSkins.cbegin(); iter != m_PackageSkins.cend(); ++iter) + { + std::wstring from = g_Data.skinsPath + *iter; + std::wstring to = g_Data.skinsPath + L"Backup\\"; + to += m_InstallTime; + to += L'\\'; + to += *iter; + CopyFiles(from, to, true); + } + } + + unzGoToFirstFile(m_PackageUnzFile); + const WCHAR* root = m_PackageRoot.c_str(); + do + { + if (!getFileInfo()) + { + m_ErrorMessage = L"Error retrieving file info."; + return false; + } + + if (wcsncmp(buffer, root, m_PackageRoot.length()) != 0) + { + // Ignore everything that isn't in the root directory + continue; + } + + WCHAR* component = buffer + m_PackageRoot.length(); + WCHAR* path = wcschr(component, L'\\'); + if (path) + { + *path = L'\0'; + ++path; + } + else + { + continue; + } + + bool error = false; + std::wstring targetPath; + + WCHAR* pos = wcschr(path, L'\\'); + WCHAR* extension = PathFindExtension(pos ? pos : path); + if (pos) + { + const std::wstring item(path, pos - path); + + if (_wcsicmp(component, L"Skins") == 0 && + m_PackageSkins.find(item) != m_PackageSkins.end()) + { + targetPath = g_Data.skinsPath; + } + else if (_wcsicmp(component, L"Themes") == 0 && + _wcsicmp(extension, L".thm") == 0 && + m_PackageThemes.find(item) != m_PackageThemes.end()) + { + targetPath = g_Data.settingsPath; + targetPath += L"Themes\\"; + } + else if (_wcsicmp(component, L"Addons") == 0 && + m_PackageFormat == PackageFormat::Old && + m_PackageAddons.find(item) != m_PackageAddons.end()) + { + targetPath = g_Data.settingsPath; + targetPath += L"Addons\\"; + } + else if (_wcsicmp(component, L"Plugins") == 0 && + _wcsnicmp(path, IsWin32Build() ? L"32bit" : L"64bit", pos - path) == 0 && + _wcsicmp(extension, L".dll") == 0 && + !wcschr(pos + 1, L'\\')) + { + path = pos + 1; + targetPath = g_Data.settingsPath; + targetPath += L"Plugins\\"; + } + + if (!targetPath.empty()) + { + targetPath += path; + error = !ExtractCurrentFile(targetPath); + } + } + else + { + if (_wcsicmp(component, L"Fonts") == 0 && + m_PackageFormat == PackageFormat::Old && + _wcsicmp(extension, L".ttf") == 0) + { + for (auto iter = m_PackageSkins.cbegin(); iter != m_PackageSkins.cend(); ++iter) + { + targetPath = g_Data.skinsPath; + targetPath += *iter; + targetPath += L"\\@Resources\\Fonts\\"; + targetPath += path; + error = !ExtractCurrentFile(targetPath); + if (error) + { + break; + } + } + } + } + + if (error) + { + m_ErrorMessage = L"Unable to create file:\n"; + m_ErrorMessage += targetPath; + m_ErrorMessage += L"\n\nSkin Installer will now quit."; + return false; + } + } + while (unzGoToNextFile(m_PackageUnzFile) == UNZ_OK); + + return true; +} + +void CDialogInstall::BeginInstall() +{ + if (!CloseRainmeterIfActive()) + { + MessageBox(m_Window, L"Unable to close Rainmeter.", L"Rainmeter S Rainmeter", MB_ERROR); + return; + } + + WCHAR buffer[64]; + SYSTEMTIME lt; + GetLocalTime(<); + int len = _snwprintf_s(buffer, _TRUNCATE, L"%02d.%02d.%02d %02d.%02d-%02d", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); + m_InstallTime.assign(buffer, len); + + m_InstallThread = (HANDLE)_beginthreadex(NULL, 0, InstallThread, this, 0, NULL); + if (!m_InstallThread) + { + MessageBox(m_Window, L"Unable to start backup.", L"Backup Rainmeter", MB_ERROR); + return; + } + + HWND item = GetDlgItem(m_Window, IDC_INSTALL_ADVANCED_BUTTON); + EnableWindow(item, FALSE); + + item = GetDlgItem(m_Window, IDC_INSTALL_INSTALL_BUTTON); + EnableWindow(item, FALSE); + + item = GetDlgItem(m_Window, IDCLOSE); + EnableWindow(item, FALSE); + + item = GetDlgItem(m_TabInstall.GetWindow(), IDC_INSTALLTAB_COMPONENTS_LIST); + EnableWindow(item, FALSE); + + item = GetDlgItem(m_TabInstall.GetWindow(), IDC_INSTALLTAB_THEME_CHECKBOX); + if (Button_GetCheck(item) == BST_UNCHECKED) + { + m_LoadTheme.clear(); + m_LoadSkins.clear(); + } + EnableWindow(item, FALSE); + + item = GetDlgItem(m_TabInstall.GetWindow(), IDC_INSTALLTAB_INPROGRESS_TEXT); + ShowWindow(item, SW_SHOWNORMAL); + + item = GetDlgItem(m_TabInstall.GetWindow(), IDC_INSTALLTAB_PROGRESS); + ShowWindow(item, SW_SHOWNORMAL); + + SendMessage(item, PBM_SETMARQUEE, (WPARAM)TRUE, 0); +} + +unsigned __stdcall CDialogInstall::InstallThread(void* pParam) +{ + CDialogInstall* dialog = (CDialogInstall*)pParam; + + if (!dialog->InstallPackage()) + { + if (dialog->m_ErrorMessage.empty()) + { + dialog->m_ErrorMessage = L"Unknown error."; + } + + MessageBox(NULL, dialog->m_ErrorMessage.c_str(), L"Rainmeter Skin Installer", MB_ERROR); + + dialog->m_LoadSkins.clear(); + dialog->m_LoadTheme.clear(); + } + + dialog->LaunchRainmeter(); + + EndDialog(dialog->GetWindow(), 0); + return 0; +} + +void CDialogInstall::KeepVariables() +{ + WCHAR keyname[32767]; // Max size returned by GetPrivateProfileSection + WCHAR buffer[4]; + std::wstring currKey, currValue; + + for (int i = 0, isize = m_VariablesFiles.size(); i < isize; ++i) + { + std::wstring fromPath = g_Data.skinsPath + L"Backup\\"; + fromPath += m_InstallTime; + fromPath += L'\\'; + fromPath += m_VariablesFiles[i]; + std::wstring toPath = g_Data.skinsPath + m_VariablesFiles[i]; + + unsigned int count = GetPrivateProfileSection(L"Variables", keyname, 32767, fromPath.c_str()); + + if ((_waccess(fromPath.c_str(), 0) == 0) && (_waccess(toPath.c_str(), 0) == 0) + && (count > 0)) + { + for (unsigned int j = 0; j < count; ++j) + { + if (keyname[j] == L'=') + { + if (GetPrivateProfileString(L"Variables", currKey.c_str(), NULL, buffer, 4, toPath.c_str()) > 0) + { + while (keyname[++j] != L'\0') currValue += keyname[j]; + WritePrivateProfileString(L"Variables", currKey.c_str(), currValue.c_str(), toPath.c_str()); + currValue.clear(); + } + else + { + while (keyname[j] != L'\0') ++j; + } + currKey.clear(); + } + else + { + currKey += keyname[j]; + } + } + } + } +} + +void CDialogInstall::LoadTheme(const std::wstring& name, bool setWallpaper) +{ + // Take a copy of current Rainmeter.ini before doing anything + std::wstring backupFile = g_Data.settingsPath; + backupFile += L"Themes\\Backup\\"; + CreateDirectory(backupFile.c_str(), NULL); + backupFile += L"Rainmeter.thm"; + CopyFiles(g_Data.iniFile, backupFile, false); + + if (name.empty()) + { + return; + } + + std::wstring themeFile = g_Data.settingsPath; + themeFile += L"Themes\\"; + themeFile += name; + std::wstring wallpaperFile = themeFile + L"\\RainThemes.bmp"; + themeFile += L"\\Rainmeter.thm"; + if (_waccess(themeFile.c_str(), 0) != -1) + { + CopyFiles(themeFile, g_Data.iniFile, false); + + const WCHAR* iniFileSz = g_Data.iniFile.c_str(); + const WCHAR* backupFileSz = backupFile.c_str(); + + auto preserveOption = [&](LPCTSTR section, LPCTSTR key) + { + WCHAR buffer[MAX_LINE_LENGTH]; + if (GetPrivateProfileString(section, key, L"", buffer, MAX_LINE_LENGTH, iniFileSz) == 0 && + GetPrivateProfileString(section, key, L"", buffer, MAX_LINE_LENGTH, backupFileSz) > 0) + { + WritePrivateProfileString(section, key, buffer, iniFileSz); + } + }; + + preserveOption(L"Rainmeter", L"SkinPath"); + preserveOption(L"Rainmeter", L"ConfigEditor"); + preserveOption(L"Rainmeter", L"LogViewer"); + preserveOption(L"Rainmeter", L"Logging"); + preserveOption(L"Rainmeter", L"DisableVersionCheck"); + preserveOption(L"Rainmeter", L"Language"); + preserveOption(L"Rainmeter", L"TrayExecuteM"); + preserveOption(L"Rainmeter", L"TrayExecuteR"); + preserveOption(L"Rainmeter", L"TrayExecuteDM"); + preserveOption(L"Rainmeter", L"TrayExecuteDR"); + + // Set wallpaper if it exists + const WCHAR* wallpaperFileSz = wallpaperFile.c_str(); + if (_waccess(wallpaperFileSz, 0) != -1) + { + SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)wallpaperFileSz, SPIF_UPDATEINIFILE); + } + } +} + +void CDialogInstall::LaunchRainmeter() +{ + // Backup Rainmeter.ini and load theme (if specified) + LoadTheme(m_LoadTheme, false); + + // Execute Rainmeter and wait up to a minute for it process all messages + std::wstring rainmeterExe = g_Data.programPath + L"Rainmeter.exe"; + + SHELLEXECUTEINFO sei = {0}; + sei.cbSize = sizeof(SHELLEXECUTEINFO); + sei.fMask = SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_UNICODE; + sei.hwnd = NULL; + sei.lpVerb = NULL; + sei.lpFile = rainmeterExe.c_str(); + sei.lpDirectory = g_Data.programPath.c_str(); + sei.lpParameters = NULL; + sei.nShow = SW_SHOWNORMAL; + ShellExecuteEx(&sei); + + if (!m_LoadSkins.empty()) + { + std::wstring::size_type pos; + std::wstring bang; + + for (int i = 0, isize = (int)m_LoadSkins.size(); i < isize; ++i) + { + const std::wstring& skinName = m_LoadSkins[i]; + pos = skinName.find_last_of(L"\\"); + if (pos != std::wstring::npos) + { + // Append with [!ActivateConfig "Config" "File.ini"] + bang += L"[!ActivateConfig \""; + bang.append(skinName, 0, pos); + bang += L"\" \"";; + bang.append(skinName, pos + 1, skinName.length() - pos + 1); + bang += L"\"]"; + } + } + + if (!bang.empty()) + { + sei.fMask = SEE_MASK_UNICODE; + sei.lpParameters = (LPCTSTR)bang.c_str(); + ShellExecuteEx(&sei); + } + } +} + +/* +** Splits the string from the delimiters and trims whitespace. +*/ +std::vector CDialogInstall::Tokenize(const std::wstring& str, const std::wstring& delimiters) +{ + // Modified from http://www.digitalpeer.com/id/simple + std::vector tokens; + std::wstring::size_type lastPos = str.find_first_not_of(delimiters, 0); // Skip delimiters at beginning + std::wstring::size_type pos = str.find_first_of(delimiters, lastPos); // Find first "non-delimiter" + + while (std::wstring::npos != pos || std::wstring::npos != lastPos) + { + std::wstring tmpStr = str.substr(lastPos, pos - lastPos); + std::wstring::size_type tmpPos = tmpStr.find_first_not_of(L" \t"); + if (tmpPos != std::wstring::npos) + { + tmpStr.erase(0, tmpPos); + tmpPos = tmpStr.find_last_not_of(L" \t"); + if (tmpPos != std::wstring::npos) + { + tmpStr.resize(tmpPos + 1); + } + tokens.push_back(tmpStr); + } + else + { + tokens.push_back(L""); // Add empty string + } + lastPos = str.find_first_not_of(delimiters, pos); // Skip delimiters. Note the "not_of" + pos = str.find_first_of(delimiters, lastPos); // Find next "non-delimiter" + } + + return tokens; +} + +/* +** Compares two version strings. Returns 0 if equal, 1 if A > B and -1 if A < B. +*/ +int CDialogInstall::CompareVersions(const std::wstring& strA, const std::wstring& strB) +{ + if (strA.empty() && strB.empty()) return 0; + if (strA.empty()) return -1; + if (strB.empty()) return 1; + + std::vector arrayA = Tokenize(strA, L"."); + std::vector arrayB = Tokenize(strB, L"."); + + size_t len = max(arrayA.size(), arrayB.size()); + for (size_t i = 0; i < len; ++i) + { + int a = 0; + int b = 0; + + if (i < arrayA.size()) + { + a = _wtoi(arrayA[i].c_str()); + } + if (i < arrayB.size()) + { + b = _wtoi(arrayB[i].c_str()); + } + + if (a > b) return 1; + if (a < b) return -1; + } + return 0; +} + +bool CDialogInstall::CreateDirectoryRecursive(const std::wstring& path) +{ + // Dirty... + std::wstring& directory = (std::wstring&)path; + const WCHAR* directorySz = directory.c_str(); + + bool failed = true; + std::wstring::size_type pos = std::wstring::npos; + while ((pos = failed ? directory.find_last_of(L'\\', pos) : directory.find_first_of(L'\\', pos)) != std::wstring::npos) + { + // Temporarily terminate string + directory[pos] = L'\0'; + + failed = CreateDirectory(directorySz, NULL) == 0 && GetLastError() == ERROR_PATH_NOT_FOUND; + + // Restore slash + directory[pos] = L'\\'; + + pos += failed ? -1 : 1; + } + + return !failed; +} + +std::wstring CDialogInstall::GetFileVersionString(const WCHAR* fileName) +{ + DWORD bufSize = GetFileVersionInfoSize(fileName, 0); + void* versionInfo = new WCHAR[bufSize]; + void* fileVersion = 0; + UINT valueSize; + std::wstring result; + + if (GetFileVersionInfo(fileName, 0, bufSize, versionInfo)) + { + struct LANGANDCODEPAGE + { + WORD wLanguage; + WORD wCodePage; + } *languageInfo; + + VerQueryValue(versionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&languageInfo, &valueSize); + WCHAR blockName[64]; + _snwprintf_s(blockName, _TRUNCATE, L"\\StringFileInfo\\%04x%04x\\FileVersion", languageInfo[0].wLanguage, languageInfo[0].wCodePage); + + VerQueryValue(versionInfo, blockName, &fileVersion, &valueSize); + if (valueSize) + { + result = (WCHAR*)fileVersion; + } + } + + delete [] (WCHAR*)versionInfo; + return result; +} + +std::wstring CDialogInstall::GetDotNetVersionString() +{ + WCHAR buffer[255]; + HKEY hKey; + LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", 0L, KEY_READ, &hKey); + std::wstring currVer(L"v0"), prevVer; + int i = 0; + + while (lRet == ERROR_SUCCESS) + { + lRet = RegEnumKey(hKey, i, buffer, 255); + if (buffer[0] == L'v') + { + currVer = buffer; + } + ++i; + } + + RegCloseKey(hKey); + currVer.erase(0, 1); // Get rid of the 'v' + return currVer; +} + +std::wstring CDialogInstall::GetWindowsVersionString() +{ + WCHAR buffer[16]; + OSVERSIONINFOEX osvi = {sizeof(OSVERSIONINFOEX)}; + GetVersionEx((OSVERSIONINFO*)&osvi); + _snwprintf_s(buffer, _TRUNCATE, L"%d.%d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); + + return buffer; +} + +// ----------------------------------------------------------------------------------------------- +// +// Backup tab +// +// ----------------------------------------------------------------------------------------------- + +/* +** Constructor. +** +*/ +CDialogInstall::CTabInstall::CTabInstall(HWND wnd) : CTab(GetModuleHandle(NULL), wnd, IDD_INSTALL_TAB, DlgProc) +{ +} + +void CDialogInstall::CTabInstall::Initialize() +{ + HWND item = GetDlgItem(m_Window, IDC_INSTALLTAB_COMPONENTS_LIST); + + ListView_SetExtendedListViewStyleEx(item, 0, LVS_EX_CHECKBOXES | LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT); + ListView_EnableGroupView(item, TRUE); + + // Add columns + LVCOLUMN lvc; + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + lvc.fmt = LVCFMT_LEFT; + lvc.iSubItem = 0; + lvc.cx = 180; + lvc.pszText = L"Name"; + ListView_InsertColumn(item, 0, &lvc); + lvc.iSubItem = 1; + lvc.cx = 150; + lvc.pszText = L"Action"; + ListView_InsertColumn(item, 1, &lvc); + + // Add groups and items + LVGROUP lvg; + lvg.cbSize = sizeof(LVGROUP); + lvg.mask = LVGF_HEADER | LVGF_GROUPID | LVGF_STATE; + lvg.state = (GetOSPlatform() >= OSPLATFORM_VISTA) ? LVGS_COLLAPSIBLE : LVGS_NORMAL; + + LVITEM lvi; + lvi.mask = LVIF_TEXT | LVIF_GROUPID | LVIF_PARAM; + lvi.iSubItem = 0; + lvi.iItem = 0; + lvi.lParam = 0; + + auto addComponent = [&](const WCHAR* name, const std::set& items, const std::wstring& path, int groupId) + { + lvg.iGroupId = groupId; + lvg.pszHeader = (WCHAR*)name; + ListView_InsertGroup(item, groupId, &lvg); + + lvi.iGroupId = groupId; + lvi.iItem = 0; + for (auto iter = items.cbegin(); iter != items.cend(); ++iter) + { + lvi.pszText = (WCHAR*)(*iter).c_str(); + ListView_InsertItem(item, &lvi); + ListView_SetCheckState(item, lvi.iItem, TRUE); + + std::wstring itemPath = path + *iter; + WCHAR* text = L"Add"; + if (_waccess(itemPath.c_str(), 0) != -1) + { + text = (groupId == 0) ? L"Backup and replace" : L"Replace"; + } + ListView_SetItemText(item, lvi.iItem, 1, text); + + ++lvi.iItem; + } + }; + + addComponent(L"Skins", c_Dialog->m_PackageSkins, g_Data.skinsPath, 0); + addComponent(L"Themes", c_Dialog->m_PackageThemes, g_Data.settingsPath + L"Themes\\", 1); + addComponent(L"Addons", c_Dialog->m_PackageAddons, g_Data.settingsPath + L"Addons\\", 2); + addComponent(L"Plugins", c_Dialog->m_PackagePlugins, g_Data.settingsPath + L"Plugins\\", 3); + + item = GetDlgItem(m_Window, IDC_INSTALLTAB_THEME_CHECKBOX); + if (!c_Dialog->m_LoadTheme.empty()) + { + Button_SetCheck(item, BST_CHECKED); + } + else if (!c_Dialog->m_LoadSkins.empty()) + { + SetWindowText(item, L"Load included skins"); + Button_SetCheck(item, BST_CHECKED); + } + else + { + ShowWindow(item, SW_HIDE); + } + + m_Initialized = true; +} + +INT_PTR CALLBACK CDialogInstall::CTabInstall::DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_COMMAND: + return c_Dialog->m_TabInstall.OnCommand(wParam, lParam); + } + + return FALSE; +} + +INT_PTR CDialogInstall::CTabInstall::OnCommand(WPARAM wParam, LPARAM lParam) +{ + switch (LOWORD(wParam)) + { + case IDC_BACKUP_BROWSE_BUTTON: + { + } + break; + + default: + return FALSE; + } + + return TRUE; +} diff --git a/SkinInstaller/DialogInstall.h b/SkinInstaller/DialogInstall.h new file mode 100644 index 00000000..0f853c1d --- /dev/null +++ b/SkinInstaller/DialogInstall.h @@ -0,0 +1,125 @@ +/* + Copyright (C) 2012 Birunthan Mohanathas + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SKININSTALLER_DIALOGINSTALL_H_ +#define SKININSTALLER_DIALOGINSTALL_H_ + +#include +#include "unzip.h" +#include "../Library/Dialog.h" + +class CDialogInstall : public CDialog +{ +public: + static void Create(HINSTANCE hInstance, LPWSTR lpCmdLine); + + static INT_PTR CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + INT_PTR OnInitDialog(WPARAM wParam, LPARAM lParam); + INT_PTR OnCommand(WPARAM wParam, LPARAM lParam); + + static void LoadTheme(const std::wstring& name, bool setWallpaper); + + static CDialogInstall* c_Dialog; + +protected: + virtual CTab& GetActiveTab(); + +private: + class CTabInstall : public CTab + { + public: + CTabInstall(HWND window); + + virtual void Initialize(); + + static INT_PTR CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + INT_PTR OnCommand(WPARAM wParam, LPARAM lParam); + }; + + enum Timer + { + Thread = 1 + }; + + enum PackageFormat + { + None, + New, + Old + }; + + enum PackageFlag + { + Backup = 0x0001 + }; + + struct PackageFooter + { + __int64 size; + BYTE flags; + char key[7]; + }; + + CDialogInstall(HWND wnd, const WCHAR* file); + virtual ~CDialogInstall(); + + bool ReadPackage(); + bool ReadOptions(const WCHAR* file); + bool InstallPackage(); + void BeginInstall(); + bool ExtractCurrentFile(const std::wstring& fileName); + + static unsigned __stdcall InstallThread(void* pParam); + + void LaunchRainmeter(); + void KeepVariables(); + + static int CompareVersions(const std::wstring& strA, const std::wstring& strB); + static std::vector Tokenize(const std::wstring& str, const std::wstring& delimiters); + static bool CreateDirectoryRecursive(const std::wstring& path); + static std::wstring GetFileVersionString(const WCHAR* fileName); + static std::wstring GetDotNetVersionString(); + static std::wstring GetWindowsVersionString(); + + CTabInstall m_TabInstall; + + HANDLE m_InstallThread; + std::wstring m_InstallTime; + + std::wstring m_ErrorMessage; + + bool m_BackupPackage; + + unzFile m_PackageUnzFile; + std::wstring m_PackageFileName; + std::wstring m_PackageRoot; + PackageFormat m_PackageFormat; + std::set m_PackageSkins; + std::set m_PackageThemes; + std::set m_PackageAddons; + std::set m_PackageFonts; + std::set m_PackagePlugins; + + // Package options + bool m_MergeSkins; + std::vector m_VariablesFiles; + std::vector m_LoadSkins; + std::wstring m_LoadTheme; +}; + +#endif diff --git a/SkinInstaller/Rainstaller.cpp b/SkinInstaller/Rainstaller.cpp deleted file mode 100644 index 7b5096c7..00000000 --- a/SkinInstaller/Rainstaller.cpp +++ /dev/null @@ -1,1752 +0,0 @@ -/* - Copyright (C) 2011 Birunthan Mohanathas - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "StdAfx.h" -#include "resource.h" -#include "unzip.h" -#include "Application.h" -#include "Rainstaller.h" - -RMSKIN_DATA data; -HBITMAP hBitmap; -HANDLE hMapFile; -LPCTSTR pBuffer; -std::wstring exeFile; -#define APP_NAME L"Rainstaller" - -/* -** Entry point -*/ -int Rainstaller(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) -{ - if (wcscmp(lpCmdLine, L"/ELEVATE") == 0) - { - if (!IsCurrentProcessAdmin()) - { - std::wstring error = L"Elevated process does not have administrative rights."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - - // If the main (or dialog) process of Rainstaller isn't running as admin, it calls CreateProcessElevated() - // to create create an elevated process of Rainstaller with the /ELEVATE switch. - hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, OBJECT_NAME); - if (hMapFile == NULL) - { - std::wstring error = L"Error in elevated process: unable to open file mapping."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - - pBuffer = (LPCTSTR)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 2048); - if (pBuffer == NULL) - { - CloseHandle(hMapFile); - std::wstring error = L"Error in elevated process: unable to view map of file."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - - // Split the shared buffer into tokens - std::vector vec = Tokenize(pBuffer, L"\""); - UnmapViewOfFile(pBuffer); - CloseHandle(hMapFile); - - // Check that the .rmskin file is acessible from elevated account - data.rmskinFile = vec[0]; - if (_waccess(data.rmskinFile.c_str(), 0) == -1) - { - std::wstring error = L"Error in elevated process: Unable to access .rmskin file.\n\nMake sure that the .rmskin file saved at a location accessible to all users and try again."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - - // Assign the tokens to variables - data.instType = INSTTYPE_ADMIN; - data.rootLen = _wtoi(vec[1].c_str()); - data.rainmeterPath = vec[2]; - data.backupFolder = vec[3]; - data.addonsList = vec[4]; - data.pluginsList = vec[5]; - data.fontsList = vec[6]; - if (vec[7] == L"1") data.rainmeterFonts = true; - - if (!InstallComponents(&data)) - { - std::wstring error = L"Error in elevated process: Install failed."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - return 0; - } - - // Check whether Rainstaller.exe is already running and bring it to front if so - HANDLE hMutex; - if (IsRunning(L"RainstallerMutex_6D42B76464DA", &hMutex)) - { - HWND hwnd = FindWindow(L"#32770", L"Rainstaller"); - SetForegroundWindow(hwnd); - return 0; - } - - // Avoid loading a dll from current directory - SetDllDirectory(L""); - WCHAR buffer[MAX_PATH]; - - GetModuleFileName(hInstance, buffer, MAX_PATH); - exeFile = buffer; - - // Remove the module's name from the path - WCHAR* pos = wcsrchr(buffer, L'\\'); - if (pos) - { - *(pos + 1) = L'\0'; - } - - std::wstring str = buffer; - str += L"Rainmeter.exe"; - if (_waccess(str.c_str(), 0) != 0) - { - std::wstring error = L"Unable to locate Rainmeter."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - - data.rainmeterPath = buffer; - str.replace(str.length() - 3, 3, L"ini"); - - // Find the settings file and read skins path off it - if (_waccess(str.c_str(), 0) == 0) - { - data.iniPath = buffer; - if (GetPrivateProfileString(L"Rainmeter", L"SkinPath", L"", buffer, MAX_LINE_LENGTH, str.c_str()) > 0) - { - data.skinsPath = buffer; - } - else - { - data.skinsPath = data.rainmeterPath; - data.skinsPath += L"Skins\\"; - } - } - else - { - HRESULT hr = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, buffer); - wcscat(buffer, L"\\Rainmeter\\"); - data.iniPath = buffer; - wcscat(buffer, L"Rainmeter.ini"); - if (SUCCEEDED(hr) && _waccess(buffer, 0) == 0) - { - if (GetPrivateProfileString(L"Rainmeter", L"SkinPath", L"", buffer, MAX_LINE_LENGTH, buffer) > 0) - { - data.skinsPath = buffer; - } - else - { - std::wstring error = L"SkinPath not found.\nMake sure that Rainmeter has been run at least once."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - } - else - { - std::wstring error = L"Rainmeter.ini not found.\nMake sure that Rainmeter has been run at least once."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return 1; - } - } - - data.rmskinFile = lpCmdLine; - if (data.rmskinFile.empty()) - { - // Show the Open File dialog if no arguments were given - OPENFILENAME ofn = {0}; - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.lpstrFilter = L"Rainmeter skin file (.rmskin)\0*.rmskin;*.zip"; - ofn.nFilterIndex = 1; - ofn.lpstrFile = buffer; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrTitle = L"Select Rainmeter skin file"; - ofn.lpstrDefExt = L"rmskin"; - ofn.Flags = OFN_FILEMUSTEXIST; - - buffer[0] = L'\0'; - if (!GetOpenFileName((OPENFILENAME*)&ofn)) return 0; // Abort without warning on cancel - data.rmskinFile = buffer; - } - else if (data.rmskinFile[0] == L'\"') - { - // Remove first and last quote if needed - data.rmskinFile.erase(0, 1); - data.rmskinFile.resize(data.rmskinFile.length() - 1); - } - - return ReadArchive() ? DialogBox(hInstance, MAKEINTRESOURCE(IDD_INSTALLER_DIALOG), NULL, (DLGPROC)DlgProc) : 1; -} - -/* -** Main dialog window procedure -*/ -BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_INITDIALOG: - InitDialog(hwnd); - SetForegroundWindow(hwnd); - break; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_CANCEL_BUTTON: - EndDialog(hwnd, 0); - break; - - case IDC_INSTALL_BUTTON: - InitInstall(hwnd); - break; - - case IDC_SKINS_LABEL: - EnableWindow((HWND)lParam, 0); - data.skinsList.clear(); - break; - - case IDC_THEMES_LABEL: - EnableWindow((HWND)lParam, 0); - data.themesList.clear(); - break; - - case IDC_ADDONS_LABEL: - EnableWindow((HWND)lParam, 0); - data.addonsList.clear(); - break; - - case IDC_PLUGINS_LABEL: - EnableWindow((HWND)lParam, 0); - data.pluginsList.clear(); - break; - - case IDC_FONTS_LABEL: - EnableWindow((HWND)lParam, 0); - data.fontsList.clear(); - break; - } - break; - - case WM_TIMER: - switch (wParam) - { - case TIMER_THREAD: - { - DWORD exitCode; - GetExitCodeThread(data.instHandle, &exitCode); - if (exitCode != STILL_ACTIVE) - { - KillTimer(hwnd, TIMER_THREAD); - CloseHandle(data.instHandle); - - if (exitCode != 0) - { - std::wstring error = L"Install thead failed."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - } - else if (data.launchRainmeter) - { - LaunchRainmeter(); - } - EndDialog(hwnd, 0); - } - } - break; - - case TIMER_PROCESS: - { - DWORD exitCode; - GetExitCodeProcess(data.instHandle, &exitCode); - if (exitCode != STILL_ACTIVE) - { - KillTimer(hwnd, TIMER_PROCESS); - UnmapViewOfFile(pBuffer); - CloseHandle(hMapFile); - CloseHandle(data.instHandle); - - if (exitCode == 0) - { - if (!data.skinsList.empty() || !data.themesList.empty()) - { - data.instType = INSTTYPE_NOADMIN; - data.instHandle = (HANDLE)_beginthreadex(NULL, 0, CreateInstallThread, &data, 0, NULL); - SetTimer(hwnd, TIMER_THREAD, 100, NULL); - break; - } - else if (data.launchRainmeter) - { - LaunchRainmeter(); - } - } - EndDialog(hwnd, 0); - } - } - break; - } - break; - - case WM_CLOSE: - // Don't close dialog if install is running - if (!data.instHandle) EndDialog(hwnd, 0); - break; - - default: - return FALSE; - } - return TRUE; -} - -void InitDialog(HWND hwnd) -{ - SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_INSTALLER))); - SendMessage(GetDlgItem(hwnd, IDC_LAUNCH_CHECKBOX), BM_SETCHECK, BST_CHECKED, 0); - ShowWindow(GetDlgItem(hwnd, IDC_PROGRESSBAR), SW_HIDE); - - if (data.loadTheme.empty()) - { - ShowWindow(GetDlgItem(hwnd, IDC_THEME_CHECKBOX), SW_HIDE); - } - else - { - std::wstring text = L"Apply theme ("; - text += data.loadTheme; - text += L")"; - SendMessage(GetDlgItem(hwnd, IDC_THEME_CHECKBOX), BM_SETCHECK, BST_CHECKED, 0); - SetDlgItemText(hwnd, IDC_THEME_CHECKBOX, text.c_str()); - } - - if (data.backupFolder.empty()) // Hide the backup footnote if not needed - { - RECT dlgRect, sepRect; - GetWindowRect(hwnd, &dlgRect); - GetWindowRect(GetDlgItem(hwnd, IDC_SEPERATOR), &sepRect); - - // Width is kept same, the height is cut to the relative y-pos of the sepeator - SetWindowPos(hwnd, NULL, NULL, NULL, dlgRect.right - dlgRect.left, - dlgRect.bottom - dlgRect.top - (dlgRect.bottom - sepRect.bottom) + 1, - SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER); - } - else - { - HICON hIcon = (HICON)LoadIcon(NULL, IDI_WARNING); - SendMessage(GetDlgItem(hwnd, IDC_WARNING_ICON), STM_SETICON, (WPARAM)hIcon, 0); - } - - // Show UAC sheild if needed - if (!IsCurrentProcessAdmin() && (!data.addonsList.empty() || !data.fontsList.empty() || !data.pluginsList.empty())) - { - SendMessage(GetDlgItem(hwnd, IDC_INSTALL_BUTTON), BCM_SETSHIELD, 0, (LPARAM)TRUE); - } - - // Set custom header - if (hBitmap) - { - SendMessage(GetDlgItem(hwnd, IDC_BITMAP), STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap); - } - - // Get the system font and size (Tahoma/8 on XP, Segoe UI/9 on Vista+) - NONCLIENTMETRICS ncm; - ncm.cbSize = sizeof(NONCLIENTMETRICS) - sizeof(ncm.iPaddedBorderWidth); - SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0); - HFONT hFont = CreateFontIndirect(&ncm.lfMenuFont); - ncm.lfMenuFont.lfWeight = FW_BOLD; - HFONT hFontBold = CreateFontIndirect(&ncm.lfMenuFont); - - SendMessage(GetDlgItem(hwnd, IDC_NAME_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_AUTHOR_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_VERSION_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_SKINS_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_THEMES_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_ADDONS_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_PLUGINS_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_FONTS_LABEL), WM_SETFONT, (WPARAM)hFontBold, 0); - SendMessage(GetDlgItem(hwnd, IDC_NAME_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_AUTHOR_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_VERSION_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_SKINS_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_THEMES_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_ADDONS_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_PLUGINS_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_FONTS_VALUE), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_THEME_CHECKBOX), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_LAUNCH_CHECKBOX), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_INSTALL_BUTTON), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_CANCEL_BUTTON), WM_SETFONT, (WPARAM)hFont, 0); - SendMessage(GetDlgItem(hwnd, IDC_BACKUP_LABEL), WM_SETFONT, (WPARAM)hFont, 0); - - SetDlgItemText(hwnd, IDC_NAME_VALUE, data.packageName.c_str()); - SetDlgItemText(hwnd, IDC_AUTHOR_VALUE, data.packageAuthor.c_str()); - SetDlgItemText(hwnd, IDC_VERSION_VALUE, data.packageVersion.c_str()); - data.skinsList.empty() ? EnableWindow(GetDlgItem(hwnd, IDC_SKINS_LABEL), 0) : SetDlgItemText(hwnd, IDC_SKINS_VALUE, data.skinsList.c_str()); - data.themesList.empty() ? EnableWindow(GetDlgItem(hwnd, IDC_THEMES_LABEL), 0) : SetDlgItemText(hwnd, IDC_THEMES_VALUE, data.themesList.c_str()); - data.addonsList.empty() ? EnableWindow(GetDlgItem(hwnd, IDC_ADDONS_LABEL), 0) : SetDlgItemText(hwnd, IDC_ADDONS_VALUE, data.addonsList.c_str()); - data.pluginsList.empty() ? EnableWindow(GetDlgItem(hwnd, IDC_PLUGINS_LABEL), 0) : SetDlgItemText(hwnd, IDC_PLUGINS_VALUE, data.pluginsList.c_str()); - data.fontsList.empty() ? EnableWindow(GetDlgItem(hwnd, IDC_FONTS_LABEL), 0) : SetDlgItemText(hwnd, IDC_FONTS_VALUE, data.fontsList.c_str()); - - // Enable tooltips for the component lists - HWND hwndTT = CreateWindow(TOOLTIPS_CLASS, NULL, WS_POPUP, 0, 0, 0, 0, hwnd, NULL, NULL, 0); - if (hwndTT) - { - SendMessage(hwndTT, TTM_ACTIVATE, TRUE, 0); - - TOOLINFO toolinfo = {0}; - toolinfo.cbSize = sizeof(TOOLINFO); - toolinfo.uFlags = TTF_SUBCLASS | TTF_IDISHWND; - toolinfo.hwnd = hwnd; - toolinfo.hinst = NULL; - - toolinfo.uId = (LPARAM)GetDlgItem(hwnd, IDC_SKINS_VALUE); - toolinfo.lpszText = (LPTSTR)data.skinsList.c_str(); - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&toolinfo); - - toolinfo.uId = (LPARAM)GetDlgItem(hwnd, IDC_THEMES_VALUE); - toolinfo.lpszText = (LPTSTR)data.themesList.c_str(); - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&toolinfo); - - toolinfo.uId = (LPARAM)GetDlgItem(hwnd, IDC_ADDONS_VALUE); - toolinfo.lpszText = (LPTSTR)data.addonsList.c_str(); - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&toolinfo); - - toolinfo.uId = (LPARAM)GetDlgItem(hwnd, IDC_PLUGINS_VALUE); - toolinfo.lpszText = (LPTSTR)data.pluginsList.c_str(); - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&toolinfo); - - toolinfo.uId = (LPARAM)GetDlgItem(hwnd, IDC_FONTS_VALUE); - toolinfo.lpszText = (LPTSTR)data.fontsList.c_str(); - SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM)&toolinfo); - } -} - -void InitInstall(HWND hwnd) -{ - // Disable the X button - HMENU hMenu = GetSystemMenu(hwnd, false); - RemoveMenu(hMenu, GetMenuItemCount(hMenu) - 1, MF_DISABLED | MF_BYPOSITION); - - EnableWindow(GetDlgItem(hwnd, IDC_CANCEL_BUTTON), 0); - EnableWindow(GetDlgItem(hwnd, IDC_INSTALL_BUTTON), 0); - EnableWindow(GetDlgItem(hwnd, IDC_THEME_CHECKBOX), 0); - EnableWindow(GetDlgItem(hwnd, IDC_LAUNCH_CHECKBOX), 0); - - if (SendMessage(GetDlgItem(hwnd, IDC_LAUNCH_CHECKBOX), BM_GETCHECK, 0, 0) == BST_CHECKED) data.launchRainmeter = true; - - if (IsCurrentProcessAdmin()) - { - data.instType = INSTTYPE_FULL; - data.instHandle = (HANDLE)_beginthreadex(NULL, 0, CreateInstallThread, &data, 0, NULL); - SetTimer(hwnd, TIMER_THREAD, 250, NULL); - } - else - { - if (!data.addonsList.empty() || !data.pluginsList.empty() || !data.fontsList.empty()) - { - data.instHandle = CreateProcessElevated(hwnd); - if (data.instHandle == NULL) - { - std::wstring error = L"Failed to create elevated process."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - UnmapViewOfFile(pBuffer); - CloseHandle(hMapFile); - EndDialog(hwnd, 0); - } - SetTimer(hwnd, TIMER_PROCESS, 250, NULL); - } - else if (!data.skinsList.empty() || !data.themesList.empty()) - { - data.instType = INSTTYPE_NOADMIN; - data.instHandle = (HANDLE)_beginthreadex(NULL, 0, CreateInstallThread, &data, 0, NULL); - SetTimer(hwnd, TIMER_THREAD, 250, NULL); - } - } - - // Hide the backup text if necessary and show the progress bar - ShowWindow(GetDlgItem(hwnd, IDC_PROGRESSBAR), SW_SHOWNORMAL); - SendMessage(GetDlgItem(hwnd, IDC_PROGRESSBAR), PBM_SETMARQUEE, (WPARAM)true, IsAboveVista() ? 0 : 50); - SendMessage(GetDlgItem(hwnd, IDC_INSTALL_BUTTON), BCM_SETSHIELD, 0, (LPARAM)FALSE); - SetDlgItemText(hwnd, IDC_INSTALL_BUTTON, L"Installing.."); - - // Clear loadTheme if checkbox unchecked - if (SendMessage(GetDlgItem(hwnd, IDC_THEME_CHECKBOX), BM_GETCHECK, 0, 0) != BST_CHECKED) data.loadTheme.clear(); -} - -/* -** Run As dialog window prodcedure(for Vista/7 with UAC disabled) -*/ -BOOL CALLBACK RunAsProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - // Based on the work of Anders Kjersem - switch (msg) - { - case WM_INITDIALOG: - { - HMODULE hDLL = LoadLibrary(L"shell32.dll"); - HICON hIcon = (HICON)LoadImage(hDLL, MAKEINTRESOURCE(220), IMAGE_ICON, 16, 16, LR_SHARED); - SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); - hIcon = (HICON)LoadImage(hDLL, MAKEINTRESOURCE(194), IMAGE_ICON, 32, 32, LR_SHARED); - SendMessage(GetDlgItem(hwnd, IDC_KEY_ICON), STM_SETICON, (WPARAM)hIcon, 0); - FreeLibrary(hDLL); - - SendMessage(GetDlgItem(hwnd, IDC_USERNAME), EM_LIMITTEXT, (WPARAM)256, 0); - SendMessage(GetDlgItem(hwnd, IDC_PASSWORD), EM_LIMITTEXT, (WPARAM)256, 0); - SendMessage(GetDlgItem(hwnd, IDC_SPECIFIED_BUTTON), BM_SETCHECK, BST_CHECKED, 0); - } - return TRUE; - - case WM_CLOSE: - return EndDialog(hwnd, 1); - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - WCHAR wszPwd[256]; - WCHAR wszUser[256]; - PROCESS_INFORMATION pi = {0}; - STARTUPINFO si = {sizeof(STARTUPINFO)}; - SendMessage(GetDlgItem(hwnd,IDC_USERNAME), WM_GETTEXT, (WPARAM)256, (LPARAM)wszUser); - SendMessage(GetDlgItem(hwnd,IDC_PASSWORD), WM_GETTEXT, (WPARAM)256, (LPARAM)wszPwd); - - WCHAR arg[MAX_PATH]; - _snwprintf_s(arg, _TRUNCATE, L"\"%s\" /ELEVATE", exeFile.c_str()); - if (!CreateProcessWithLogonW(wszUser, 0, wszPwd, LOGON_WITH_PROFILE, NULL, arg, 0, 0, 0, &si, &pi)) - { - std::wstring error = L"Unable to logon with given creditials.\nPlease ensure that both the username and password are correct."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - } - else - { - if (pi.hProcess) - { - data.instHandle = pi.hProcess; - EndDialog(hwnd, 0); - } - else - { - EndDialog(hwnd, 1); - } - } - } - break; - - case IDCANCEL: - EndDialog(hwnd, 1); - break; - } - break; - } - return FALSE; -} - -/* -** Go through archive, list contents, and read settings -*/ -bool ReadArchive() -{ - unzFile ufile = unzOpen(ConvertToAscii(data.rmskinFile.c_str()).c_str()); - if (!ufile) - { - std::wstring error = L"The specified file is not a valid archive:\n"; - error += data.rmskinFile; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } - - // Get temp file path for the configuration file/bitmap - WCHAR tempFile[MAX_PATH]; - GetTempPath(MAX_PATH, tempFile); - GetTempFileName(tempFile, L"dat", 0, tempFile); - - char cBuffer[MAX_PATH * 3]; - WCHAR buffer[MAX_PATH]; - unz_file_info ufi; - - // Loop through the contents of the archive until the settings file is found - do - { - if (unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0) != UNZ_OK) break; - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - WCHAR* fileName = wcsrchr(buffer, L'/'); - - if (!fileName) - { - fileName = buffer; - } - else - { - ++fileName; // Get rid of leading slash - } - - if (_wcsicmp(fileName, L"RMSKIN.ini") == 0 || _wcsicmp(fileName, L"Rainstaller.cfg") == 0) - { - if (!ExtractCurrentFile(ufile, tempFile)) return false; - - // The number of characters in path before the configuration file - data.rootLen = wcslen(buffer) - wcslen(fileName); - break; - } - else if (_wcsicmp(fileName, L"RMSKIN.bmp") == 0 || _wcsicmp(fileName, L"Rainstaller.bmp") == 0) - { - if (!ExtractCurrentFile(ufile, tempFile)) return false; - hBitmap = (HBITMAP)LoadImage(NULL, tempFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); - } - } while (unzGoToNextFile(ufile) == UNZ_OK); - - if (!ReadSettings(tempFile)) - { - unzClose(ufile); - std::wstring error = L"Invalid settings file in:\n"; - error += data.rmskinFile; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } - - bool backupRequired = false; - WCHAR* filePath = buffer; - filePath += data.rootLen; - WCHAR* filePath6(filePath), * filePath7(filePath), * filePath14(filePath); - filePath6 += 6; // Relative to path to the beginning of the skin/font root - filePath7 += 7; // Relative to path to the beginning of the theme/addon root - filePath14 += 14; // Relative to path to the beginning of the plugin root - - std::wstring themesPath(data.iniPath), addonsPath(data.rainmeterPath), pluginsPath(data.rainmeterPath); - themesPath += L"Themes\\"; - addonsPath += L"Addons\\"; - pluginsPath += L"Plugins\\"; - - // Loop through the archive a second time now that we know the where the contents are. Ugly code ahead! - unzGoToFirstFile(ufile); - do - { - if (unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0) != UNZ_OK) break; - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - - if (_wcsnicmp(filePath, L"Skins/", 6) == 0) - { - WCHAR* pos = wcschr(filePath6, L'/'); - if (pos) - { - pos[0] = L'\0'; - std::wstring name(filePath6), root(filePath); - root += L"/"; - int len = root.length(); - - // Loop until we get to another skin (or another component altogether) - while (unzGoToNextFile(ufile) == UNZ_OK) - { - unzGoToNextFile(ufile); - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - if (_wcsnicmp(filePath, root.c_str(), len) != 0) break; - } - - if (_wcsicmp(name.c_str(), L"Backup") != 0) - { - // Add the folder to list - if (!data.skinsList.empty()) data.skinsList += L" | "; - data.skinsList += name; - name.insert(0, data.skinsPath); - if (_waccess(name.c_str(), 0) == 0) - { - data.skinsList += L"*"; - backupRequired = true; - } - } - continue; - } - } - else if (_wcsnicmp(filePath, L"Themes/", 7) == 0) - { - WCHAR* pos = wcschr(filePath7, L'/'); - if (pos) - { - pos[0] = L'\0'; - std::wstring name(filePath7), root(filePath); - root += L"/"; - int len = root.length(); - - while (unzGoToNextFile(ufile) == UNZ_OK) - { - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - if (_wcsnicmp(filePath, root.c_str(), len) != 0) break; - } - - if (_wcsicmp(name.c_str(), L"Backup") != 0) - { - if (!data.themesList.empty()) data.themesList += L" | "; - data.themesList += name; - name.insert(0, themesPath); - if (_waccess(name.c_str(), 0) == 0) - { - data.themesList += L"*"; - backupRequired = true; - } - } - continue; - } - } - else if (_wcsnicmp(filePath, L"Addons/", 7) == 0) - { - WCHAR* pos = wcschr(filePath7, L'/'); - if (pos) - { - pos[0] = L'\0'; - std::wstring name(filePath7), root(filePath); - root += L"/"; - int len = root.length(); - - while (unzGoToNextFile(ufile) == UNZ_OK) - { - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - if (_wcsnicmp(filePath, root.c_str(), len) != 0) break; - } - - if (_wcsicmp(name.c_str(), L"Backup") != 0 && !IsDefaultAddon(name.c_str())) - { - if (!data.addonsList.empty()) data.addonsList += L" | "; - data.addonsList += name; - name.insert(0, addonsPath); - if (_waccess(name.c_str(), 0) == 0) - { - data.addonsList += L"*"; - backupRequired = true; - } - } - continue; - } - } - else if (_wcsnicmp(filePath, L"Fonts/", 6) == 0 && filePath6[0] != L'\0' && - !wcschr(filePath14, L'/') && - _wcsicmp(wcschr(filePath6, L'.'), L".ttf") == 0) - { - if (!data.fontsList.empty()) data.fontsList += L" | "; - data.fontsList += filePath6; - } - else if (_wcsnicmp(filePath, PLUGINS_ROOT, 14) == 0 && - filePath14[0] != L'\0' && - !wcschr(filePath14, L'/') && - _wcsicmp(wcschr(filePath14, L'.'), L".dll") == 0 - && !IsDefaultPlugin(filePath14)) - { - if (!data.pluginsList.empty()) data.pluginsList += L" | "; - - std::wstring name = filePath14; - data.pluginsList += name; - name.insert(0, pluginsPath); - if (_waccess(name.c_str(), 0) == 0) - { - backupRequired = true; - data.pluginsList += L"*"; - } - } - } while (unzGoToNextFile(ufile) == UNZ_OK); - - unzClose(ufile); - DeleteFile(tempFile); - - if (!data.skinsList.empty() || !data.themesList.empty() || !data.fontsList.empty() || !data.addonsList.empty() || !data.pluginsList.empty()) - { - if (backupRequired) // Get current time as the name for backup folders - { - SYSTEMTIME lt; - GetLocalTime(<); - _snwprintf_s(buffer, _TRUNCATE, L"%02d.%02d.%02d %02d.%02d-%02d", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); - data.backupFolder = buffer; - } - return true; - } - else - { - std::wstring error = L"The specified file did not contain any components to install:\n"; - error += data.rmskinFile; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } -} - -bool ExtractCurrentFile(unzFile& ufile, LPCTSTR fileName) -{ - if (fileName[wcslen(fileName) - 1] == L'/') - { - CreateDirectory(fileName, 0); - return true; - } - - HANDLE hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if (hFile == INVALID_HANDLE_VALUE) - { - // Some zip files don't list directories, so try creating all directories first - std::wstring path = fileName; - std::wstring::size_type pos = 0; - while (true) - { - pos = path.find_first_of(L"/", pos); - if (pos == std::wstring::npos) break; - ++pos; - - std::wstring dir = path.substr(0, pos); - if (_waccess(dir.c_str(), 0) == -1) CreateDirectory(dir.c_str(), 0); - } - - hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - if (hFile == INVALID_HANDLE_VALUE) - { - // Creating the directories didn't help.. - std::wstring error = L"Unable to create file: "; - error += fileName; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK); - return false; - } - } - - bool ret = true; - int res = unzOpenCurrentFile(ufile); - if (res != UNZ_OK) - { - std::wstring error = L"Unable to open file for extraction: "; - error += fileName; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK); - ret = false; - } - else - { - do - { - char buffer[16384]; - DWORD dwWritten; - res = unzReadCurrentFile(ufile, buffer, 16384); - - if (res < 0 || (res > 0 && !WriteFile(hFile, (LPCVOID)buffer, res, &dwWritten, NULL))) - { - std::wstring error = L"Unable to write file: "; - error += fileName; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK); - ret = false; - break; - } - } while (res > 0); - - if (unzCloseCurrentFile(ufile) == UNZ_CRCERROR) - { - std::wstring error = L"Checksum error (archive is damaged) with file: "; - error += fileName; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK); - ret = false; - } - } - - if (!ret) unzClose(ufile); - CloseHandle(hFile); - return ret; -} - -bool ReadSettings(LPCTSTR filePath) -{ - std::wstring rainmeterFile = data.rainmeterPath; - rainmeterFile += L"Rainmeter.exe"; - std::wstring rainmeterVersion = GetFileVersion(rainmeterFile); - - WCHAR buffer[MAX_LINE_LENGTH]; - - if (GetPrivateProfileString(L"Rainstaller", L"Name", L"", buffer, 64, filePath) > 0) - { - // Old, pre-2.0 format - data.packageName = buffer; - - GetPrivateProfileString(L"Rainstaller", L"Author", L"", buffer, 64, filePath); - data.packageAuthor = buffer; - - GetPrivateProfileString(L"Rainstaller", L"Version", L"", buffer, 64, filePath); - data.packageVersion = buffer; - - if ((GetPrivateProfileString(L"Rainstaller", L"LaunchType", L"", buffer, MAX_LINE_LENGTH, filePath) > 0)) - { - if (_wcsicmp(buffer, L"load") == 0) - { - GetPrivateProfileString(L"Rainstaller", L"LaunchCommand", L"", buffer, MAX_LINE_LENGTH, filePath); - data.loadSkins = buffer; - } - else - { - GetPrivateProfileString(L"Rainstaller", L"LaunchCommand", L"", buffer, MAX_LINE_LENGTH, filePath); - data.loadTheme = buffer; - } - } - if (GetPrivateProfileString(L"Rainstaller", L"RainmeterFonts", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.rainmeterFonts = (buffer[0] == L'1') ? true : false; - } - if (GetPrivateProfileString(L"Rainstaller", L"Merge", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.mergeSkins = (buffer[0] == L'1' || buffer[0] == L'2') ? true : false; - } - if (GetPrivateProfileString(L"Rainstaller", L"KeepVar", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.keepVariables = buffer; - } - if ((GetPrivateProfileString(L"Rainstaller", L"MinRainmeterVer", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - && (CompareVersions(buffer, rainmeterVersion) == 1)) - { - std::wstring error = L"This package requires Rainmeter version "; - error += buffer; - error += L" or higher.\nDownload the latest version at rainmeter.net and try again."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK | MB_ICONERROR); - return false; - } - - return true; - } - else if (GetPrivateProfileString(L"RMSKIN", L"PackageName", L"", buffer, 64, filePath) > 0) - { - // New format - data.packageName = buffer; - - GetPrivateProfileString(L"RMSKIN", L"PackageAuthor", L"", buffer, 64, filePath); - data.packageAuthor = buffer; - - GetPrivateProfileString(L"RMSKIN", L"PackageVersion", L"", buffer, 64, filePath); - data.packageVersion = buffer; - - if (GetPrivateProfileString(L"RMSKIN", L"LoadTheme", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.loadTheme = buffer; - } - if (GetPrivateProfileString(L"RMSKIN", L"LoadSkins", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.loadSkins = buffer; - } - if (GetPrivateProfileString(L"RMSKIN", L"FontDirectory", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.rainmeterFonts = (_wcsicmp(buffer, L"rainmeter") == 0) ? true : false; - } - if (GetPrivateProfileString(L"RMSKIN", L"MergeSkins", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.mergeSkins = (buffer[0] == L'1') ? true : false; - } - if (GetPrivateProfileString(L"RMSKIN", L"KeepVariables", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - { - data.keepVariables = buffer; - } - if ((GetPrivateProfileString(L"RMSKIN", L"MinimumRainmeter", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - && (CompareVersions(buffer, rainmeterVersion) == 1)) - { - std::wstring error = L"This package requires Rainmeter version "; - error += buffer; - error += L" or higher.\nDownload the latest version at rainmeter.net and try again."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK | MB_ICONERROR); - return false; - } - if ((GetPrivateProfileString(L"RMSKIN", L"MinimumDotNET", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - && (CompareVersions(buffer, GetDotNETVersion()) == 1)) - { - std::wstring error = L"This packages requires .NET framework version "; - error += buffer; - error += L" or higher.\nEnsure that you have the required .NET framework and try again."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_OK | MB_ICONERROR); - return false; - } - if ((GetPrivateProfileString(L"RMSKIN", L"MinimumWindows", L"", buffer, MAX_LINE_LENGTH, filePath) > 0) - && (CompareVersions(buffer, GetWindowsVersion()) == 1)) - { - std::wstring error = L"This package requires Windows "; - error += buffer; - error += L" or higher.\nContact the package author for more information."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } - - return true; - } - else - { - return false; - } -} - -bool IsDefaultPlugin(LPCTSTR plugin) -{ - return (_wcsicmp(plugin, L"AdvancedCPU.dll") == 0 || - _wcsicmp(plugin, L"CoreTemp.dll") == 0 || - _wcsicmp(plugin, L"FolderInfo.dll") == 0 || - _wcsicmp(plugin, L"InputText.dll") == 0 || - _wcsicmp(plugin, L"iTunesPlugin.dll") == 0 || - _wcsicmp(plugin, L"MediaKey.dll") == 0 || - _wcsicmp(plugin, L"NowPlaying.dll") == 0 || - _wcsicmp(plugin, L"PerfMon.dll") == 0 || - _wcsicmp(plugin, L"PingPlugin.dll") == 0 || - _wcsicmp(plugin, L"PowerPlugin.dll") == 0 || - _wcsicmp(plugin, L"Process.dll") == 0 || - _wcsicmp(plugin, L"QuotePlugin.dll") == 0 || - _wcsicmp(plugin, L"RecycleManager.dll") == 0 || - _wcsicmp(plugin, L"ResMon.dll") == 0 || - _wcsicmp(plugin, L"SpeedFanPlugin.dll") == 0 || - _wcsicmp(plugin, L"SysInfo.dll") == 0 || - _wcsicmp(plugin, L"VirtualDesktops.dll") == 0 || - _wcsicmp(plugin, L"WebParser.dll") == 0 || - _wcsicmp(plugin, L"WifiStatus.dll") == 0 || - _wcsicmp(plugin, L"Win7AudioPlugin.dll") == 0 || - _wcsicmp(plugin, L"WindowMessagePlugin.dll") == 0) ? true : false; -} - -bool IsDefaultAddon(LPCTSTR addon) -{ - return (_wcsnicmp(addon, L"RainBackup", 10) == 0 || - _wcsnicmp(addon, L"Rainstaller", 11) == 0) ? true : false; -} - -/* -** Backup and install components -*/ -bool InstallComponents(RMSKIN_DATA* data) -{ - if (!CloseRainmeterIfActive()) - { - std::wstring error = L"Failed to close Rainmeter."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } - - int result; - char cBuffer[MAX_PATH * 3]; - WCHAR buffer[MAX_PATH]; - unzFile ufile = unzOpen(ConvertToAscii(data->rmskinFile.c_str()).c_str()); - unz_file_info ufi; - WCHAR* filePath = buffer; - filePath += data->rootLen; - - // Loop through the archive and install stuff. Get ready to scratch your head. - do - { - // Assume no errors as we've already looped through archive - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - - if (data->instType & INSTTYPE_NOADMIN) - { - if (_wcsnicmp(filePath, L"Skins/", 6) == 0 && wcslen(filePath) > 6 && !data->skinsList.empty()) - { - WCHAR* fileName = filePath; - fileName += 6; - SetCurrentDirectory(data->skinsPath.c_str()); - if (!data->mergeSkins && !BackupComponent(data->backupFolder, data->skinsList, data->skinsPath)) break; - - // Loop and extract everything in Skins/ - do - { - if (!ExtractCurrentFile(ufile, fileName)) return false; - result = unzGoToNextFile(ufile); - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - } while (result == UNZ_OK && _wcsnicmp(filePath, L"Skins/", 6) == 0); - - if (!data->keepVariables.empty()) KeepVariables(data->backupFolder, data->skinsPath, data->keepVariables); - continue; // To skip the unzGotoNextFile at end of loop - } - else if (_wcsnicmp(filePath, L"Themes/", 7) == 0 && wcslen(filePath) > 7 && !data->themesList.empty()) - { - std::wstring themesPath = data->iniPath; - themesPath += L"Themes\\"; - SetCurrentDirectory(data->iniPath.c_str()); - if (!BackupComponent(data->backupFolder, data->themesList, themesPath)) break; - - do - { - if (!ExtractCurrentFile(ufile, filePath)) return false; - - if (wcsstr(filePath, L"Rainmeter.thm")) // Remove per-user values from Rainmeter.thm - { - WritePrivateProfileString(L"Rainmeter", L"SkinPath", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"ConfigEditor", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"DisableDragging", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"DisableRDP", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"DisableVersionCheck", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"Logging", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"Language", NULL, filePath); - WritePrivateProfileString(L"Rainmeter", L"Debug", NULL, filePath); - } - - result = unzGoToNextFile(ufile); - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - } while (result == UNZ_OK && _wcsnicmp(filePath, L"Themes/", 7) == 0); - continue; - } - } - - if (data->instType & INSTTYPE_ADMIN) - { - if (_wcsnicmp(filePath, L"Addons/", 7) == 0 && wcslen(filePath) > 7 && !data->addonsList.empty()) - { - WCHAR* fileName = filePath; - fileName += 7; - - std::wstring addonsPath = data->rainmeterPath; - addonsPath += L"Addons\\"; - SetCurrentDirectory(data->rainmeterPath.c_str()); - if (!BackupComponent(data->backupFolder, data->addonsList, addonsPath)) break; - - do - { - if (!IsDefaultAddon(fileName)) - { - if (!ExtractCurrentFile(ufile, filePath)) return false; - } - - result = unzGoToNextFile(ufile); - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - } while (result == UNZ_OK && _wcsnicmp(filePath, L"Addons/", 7) == 0); - continue; - } - else if (_wcsnicmp(filePath, L"Fonts/", 6) == 0 && wcslen(filePath) > 6 && !data->fontsList.empty()) - { - std::wstring fontsPath; - HMODULE hDLL; - GETFONTRESOURCEINFO GetFontResourceInfo; - HKEY hKey; - - if (data->rainmeterFonts) - { - fontsPath = data->rainmeterPath; - fontsPath += L"Fonts\\"; - CreateDirectory(fontsPath.c_str(), NULL); - } - else - { - WCHAR buffer[MAX_PATH]; - if (!SHGetSpecialFolderPath(NULL, buffer, CSIDL_FONTS, FALSE)) break; - fontsPath = buffer; - fontsPath += L"\\"; - - // Undocumented API - hDLL = LoadLibrary(L"gdi32.dll"); - GetFontResourceInfo = (GETFONTRESOURCEINFO)GetProcAddress(hDLL, "GetFontResourceInfoW"); - - if (!GetFontResourceInfo || - RegOpenKeyEx(HKEY_LOCAL_MACHINE, - L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", - 0, - KEY_READ | KEY_WRITE, - &hKey) != ERROR_SUCCESS) - { - std::wstring error = L"Failed to access GetFontResourceInfo."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - FreeLibrary(hDLL); - break; - } - } - - SetCurrentDirectory(fontsPath.c_str()); - WCHAR* fileName = filePath; - fileName += 6; - - do - { - if (!wcschr(fileName, L'/') && _wcsicmp(wcschr(fileName, L'.'), L".ttf") == 0 && _waccess(fileName, 0) == -1) - { - if (!ExtractCurrentFile(ufile, fileName)) return false; - - if (!data->rainmeterFonts) - { - // Write the font information to registry so that it will be enumerated by Rainmeter - DWORD dwSize = MAX_PATH; - WCHAR buffer[MAX_PATH]; - AddFontResource(fileName); - if (GetFontResourceInfo(fileName, &dwSize, &buffer, 1) != 0) - { - wcscat(buffer, L" (TrueType)"); - if (RegQueryValueEx(hKey, buffer, NULL, NULL, NULL, NULL) == ERROR_FILE_NOT_FOUND) - { - RegSetValueEx(hKey, buffer, 0, REG_SZ, (PBYTE)fileName, ((DWORD)wcslen(fileName) + 1) * sizeof(WCHAR)); - } - else - { - // Font is already installed with a different filename - RemoveFontResource(fileName); - DeleteFile(fileName); - } - } - } - } - - result = unzGoToNextFile(ufile); - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - } while (result == UNZ_OK && _wcsnicmp(filePath, L"Fonts/", 6) == 0); - - FreeLibrary(hDLL); - if (!data->rainmeterFonts) PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); - continue; - } - else if (_wcsnicmp(filePath, PLUGINS_ROOT, 14) == 0 && wcslen(filePath) > 14 && !data->pluginsList.empty()) - { - std::wstring pluginsPath = data->rainmeterPath; - pluginsPath += L"Plugins\\"; - SetCurrentDirectory(pluginsPath.c_str()); - WCHAR* fileName = filePath; - fileName += 14; - - if (!BackupComponent(data->backupFolder, data->pluginsList, pluginsPath)) break; - - do - { - if (!wcschr(fileName, L'/') && _wcsicmp(wcschr(fileName, L'.'), L".dll") == 0 && !IsDefaultPlugin(fileName)) - { - if (!ExtractCurrentFile(ufile, fileName)) return false; - } - - result = unzGoToNextFile(ufile); - unzGetCurrentFileInfo(ufile, &ufi, cBuffer, MAX_PATH * 3, NULL, 0, NULL, 0); - MultiByteToWideChar(CP_ACP, 0, cBuffer, strlen(cBuffer) + 1, buffer, MAX_PATH); - while (WCHAR* pos = wcschr(buffer, L'\\')) *pos = L'/'; - } while (result == UNZ_OK && _wcsnicmp(filePath, PLUGINS_ROOT, 14) == 0); - continue; - } - } - - result = unzGoToNextFile(ufile); - } while (result == UNZ_OK); - - unzClose(ufile); - return (result == UNZ_END_OF_LIST_OF_FILE) ? true : false; -} - -bool BackupComponent(const std::wstring& backupFolder, const std::wstring& list, const std::wstring& path) -{ - if (!list.empty() && (list.find(L"*") != std::wstring::npos)) - { - std::vector vec = Tokenize(list, L"|"); - std::vector::size_type vecSize = vec.size(); - - std::wstring tmpFrom(path), tmpTo(path); - tmpTo += L"Backup\\"; - if (_waccess(tmpTo.c_str(), 0) == -1) CreateDirectory(tmpTo.c_str(), NULL); - - tmpTo += backupFolder; - CreateDirectory(tmpTo.c_str(), NULL); - tmpTo += L'\\'; - - for (unsigned int i = 0; i < vecSize; ++i) - { - if (vec[i][vec[i].length() - 1] == L'*') - { - vec[i].resize(vec[i].length() - 1); // Get rid of trailing asterisk - tmpFrom += vec[i]; - tmpTo += vec[i]; - - if (!CopyFiles(tmpFrom.c_str(), tmpTo.c_str(), true)) - { - std::wstring error = L"Unable to backup from:\n"; - error += tmpFrom; - error += L"\n\nTo:\n"; - error += tmpTo; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } - - tmpFrom.resize(tmpFrom.length() - vec[i].length()); - tmpTo.resize(tmpTo.length() - vec[i].length()); - } - } - } - - return true; -} - -void KeepVariables(const std::wstring& backupFolder, const std::wstring& skinsPath, const std::wstring& fileList) -{ - WCHAR keyname[32767]; // Max size returned by GetPrivateProfileSection - WCHAR buffer[4]; - std::wstring currKey, currValue; - std::vector vec = Tokenize(fileList, L"|"); - - for (unsigned int i = 0, max = vec.size(); i < max; ++i) - { - std::wstring fromPath = skinsPath; - fromPath += L"Backup\\"; - fromPath += backupFolder; - fromPath += L"\\"; - fromPath += vec[i]; - std::wstring toPath = skinsPath; - toPath += vec[i]; - - unsigned int count = GetPrivateProfileSection(L"Variables", keyname, 32767, fromPath.c_str()); - - if ((_waccess(fromPath.c_str(), 0) == 0) && (_waccess(toPath.c_str(), 0) == 0) - && (count > 0)) - { - for (unsigned int j = 0; j < count; ++j) - { - if (keyname[j] == L'=') - { - if (GetPrivateProfileString(L"Variables", currKey.c_str(), NULL, buffer, 4, toPath.c_str()) > 0) - { - while (keyname[++j] != L'\0') currValue += keyname[j]; - WritePrivateProfileString(L"Variables", currKey.c_str(), currValue.c_str(), toPath.c_str()); - currValue.clear(); - } - else - { - while (keyname[j] != L'\0') ++j; - } - currKey.clear(); - } - else - { - currKey += keyname[j]; - } - } - } - } -} - -void PreserveSetting(std::wstring& iniFile, std::wstring& backupFile, LPCTSTR section, LPCTSTR key) -{ - WCHAR buffer[MAX_LINE_LENGTH]; - if (GetPrivateProfileString(section, key, L"", buffer, MAX_LINE_LENGTH, iniFile.c_str()) == 0 && - GetPrivateProfileString(section, key, L"", buffer, MAX_LINE_LENGTH, backupFile.c_str()) > 0) - { - WritePrivateProfileString(section, key, buffer, iniFile.c_str()); - } -} - -void LaunchRainmeter() -{ - SetCurrentDirectory(data.rainmeterPath.c_str()); - - // Take a copy of current Rainmeter.ini before doing anything - std::wstring iniFile = data.iniPath; - iniFile += L"Rainmeter.ini"; - std::wstring backupFile = data.iniPath; - backupFile += L"Themes\\Backup\\"; - CreateDirectory(backupFile.c_str(), NULL); - backupFile += L"Rainmeter.thm"; - CopyFiles(iniFile, backupFile, false); - - if (!data.loadTheme.empty()) - { - std::wstring themeFile = data.iniPath; - themeFile += L"Themes\\"; - themeFile += data.loadTheme; - themeFile += L"\\Rainmeter.thm"; - if (_waccess(themeFile.c_str(), 0) == 0) - { - CopyFiles(themeFile, iniFile, false); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"SkinPath"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"ConfigEditor"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"LogViewer"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"Logging"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"DisableVersionCheck"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"Language"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"TrayExecuteM"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"TrayExecuteR"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"TrayExecuteDM"); - PreserveSetting(iniFile, backupFile, L"Rainmeter", L"TrayExecuteDR"); - } - } - - // Execute and wait up to a minute for Rainmeter to process all messages - SHELLEXECUTEINFO sei = {0}; - sei.cbSize = sizeof(SHELLEXECUTEINFO); - sei.fMask = SEE_MASK_WAITFORINPUTIDLE | SEE_MASK_UNICODE; - sei.hwnd = NULL; - sei.lpVerb = NULL; - sei.lpFile = L"Rainmeter.exe"; - sei.lpParameters = NULL; - sei.nShow = SW_SHOWNORMAL; - ShellExecuteEx(&sei); - - if (!data.loadSkins.empty()) - { - std::wstring::size_type pos; - std::wstring bang; - std::vector vec = Tokenize(data.loadSkins, L"|"); - - for (unsigned int i = 0, max = vec.size(); i < max; ++i) - { - pos = vec[i].find_last_of(L"\\"); - if (pos != std::wstring::npos) - { - // Append with [!RainmeterActivateConfig "Config" "File.ini"] - bang += L"[!RainmeterActivateConfig \""; - bang += vec[i].substr(0, pos); - bang += L"\" \""; - bang += vec[i].substr(pos + 1); - bang += L"\"]"; - } - } - - if (!bang.empty()) - { - bang.insert(0, L"!Execute "); - sei.fMask = SEE_MASK_UNICODE; - sei.lpParameters = (LPCTSTR)bang.c_str(); - ShellExecuteEx(&sei); - } - } -} - -/* -** Create elevated process (to install addons, fonts, and plugins) -*/ -HANDLE CreateProcessElevated(HWND hwnd) -{ - WCHAR secDesc[SECURITY_DESCRIPTOR_MIN_LENGTH]; - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = FALSE; - sa.lpSecurityDescriptor = &secDesc; - InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); - SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, 0, FALSE); - - // Create shared memory - hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, 2048, OBJECT_NAME); - if (hMapFile == NULL) - { - std::wstring error = L"Failed to create elevated process (unable to create file mapping)."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return NULL; - } - - pBuffer = (LPCTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 2048); - if (pBuffer == NULL) - { - CloseHandle(hMapFile); - std::wstring error = L"Failed to create elevated process (unable to view file mapping)."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return NULL; - } - - WCHAR buffer[2048]; - - // Copy values that are to be passed to the elevated process into buffer - _snwprintf_s(buffer, _TRUNCATE, L"%s\"%i\"%s\"%s\"%s\"%s\"%s\"%i", - data.rmskinFile.c_str(), - data.rootLen, - data.rainmeterPath.c_str(), - data.backupFolder.empty() ? L" " : data.backupFolder.c_str(), - data.addonsList.empty() ? L" " : data.addonsList.c_str(), - data.pluginsList.empty() ? L" " : data.pluginsList.c_str(), - data.fontsList.empty() ? L" " : data.fontsList.c_str(), - data.rainmeterFonts ? 1 : 0); - - CopyMemory((PVOID)pBuffer, buffer, sizeof(buffer)); - - // If UAC is not active, show custom Run As dialog. There is a bug in Vista/7, which makes elevation - // impossible when UAC is disabled - if (IsAboveVista() && !IsActiveUAC()) - { - return (DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_RUNAS), hwnd, (DLGPROC)RunAsProc) == 0) ? data.instHandle : NULL; - } - - SHELLEXECUTEINFO sei = {0}; - sei.cbSize = sizeof(SHELLEXECUTEINFO); - sei.fMask = SEE_MASK_NOCLOSEPROCESS; - sei.hwnd = NULL; - sei.lpVerb = L"runas"; - sei.lpFile = exeFile.c_str(); - sei.lpParameters = L"/ELEVATE"; - sei.nShow = SW_SHOWNORMAL; - ShellExecuteEx(&sei); - - if (!IsAboveVista()) _beginthreadex(NULL, 0, SetRunAsThread, NULL, 0, NULL); - - return (sei.hProcess) ? sei.hProcess : NULL; -} - -unsigned __stdcall SetRunAsThread(void*) -{ - const UINT IDC_USRSAFER = 0x106, IDC_OTHERUSER = 0x104; - - // Wait for up to 5 seconds for the Run As dialog to appear - for (int i = 0; i < 50; ++i) - { - Sleep(100); - HWND hwnd = FindWindow(L"#32770", L"Run As..."); - if (hwnd) - { - SendMessage(GetDlgItem(hwnd, IDC_USRSAFER), BM_SETCHECK, BST_UNCHECKED, 0); - SendMessage(GetDlgItem(hwnd, IDC_OTHERUSER), BM_CLICK, 0, 0); - break; - } - } - return 0; -} - -unsigned __stdcall CreateInstallThread(void* pParam) -{ - return InstallComponents((RMSKIN_DATA*)pParam) ? 0 : 1; -} - -/* -** Splits the string from the delimiters and trims whitespace -*/ -std::vector Tokenize(const std::wstring& str, const std::wstring& delimiters) -{ - // Modified from http://www.digitalpeer.com/id/simple - std::vector tokens; - std::wstring::size_type lastPos = str.find_first_not_of(delimiters, 0); // Skip delimiters at beginning - std::wstring::size_type pos = str.find_first_of(delimiters, lastPos); // Find first "non-delimiter" - - while (std::wstring::npos != pos || std::wstring::npos != lastPos) - { - std::wstring tmpStr = str.substr(lastPos, pos - lastPos); - std::wstring::size_type tmpPos = tmpStr.find_first_not_of(L" \t"); - if (tmpPos != std::wstring::npos) - { - tmpStr.erase(0, tmpPos); - tmpPos = tmpStr.find_last_not_of(L" \t"); - if (tmpPos != std::wstring::npos) - { - tmpStr.resize(tmpPos + 1); - } - tokens.push_back(tmpStr); - } - else - { - tokens.push_back(L""); // Add empty string - } - lastPos = str.find_first_not_of(delimiters, pos); // Skip delimiters. Note the "not_of" - pos = str.find_first_of(delimiters, lastPos); // Find next "non-delimiter" - } - - return tokens; -} - -/* -** Compares two version strings. Returns 0 if equal, 1 if A > B and -1 if A < B. -*/ -int CompareVersions(const std::wstring& strA, const std::wstring& strB) -{ - if (strA.empty() && strB.empty()) return 0; - if (strA.empty()) return -1; - if (strB.empty()) return 1; - - std::vector arrayA = Tokenize(strA, L"."); - std::vector arrayB = Tokenize(strB, L"."); - - size_t len = max(arrayA.size(), arrayB.size()); - for (size_t i = 0; i < len; ++i) - { - int a = 0; - int b = 0; - - if (i < arrayA.size()) - { - a = _wtoi(arrayA[i].c_str()); - } - if (i < arrayB.size()) - { - b = _wtoi(arrayB[i].c_str()); - } - - if (a > b) return 1; - if (a < b) return -1; - } - return 0; -} - -std::wstring GetFileVersion(const std::wstring& file) -{ - DWORD bufSize = GetFileVersionInfoSize(file.c_str(), 0); - void* versionInfo = new WCHAR[bufSize]; - void* fileVersion = 0; - UINT valueSize; - std::wstring result; - - if (GetFileVersionInfo(file.c_str(), 0, bufSize, versionInfo)) - { - struct LANGANDCODEPAGE - { - WORD wLanguage; - WORD wCodePage; - } *languageInfo; - - VerQueryValue(versionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&languageInfo, &valueSize); - WCHAR blockName[64]; - _snwprintf_s(blockName, _TRUNCATE, L"\\StringFileInfo\\%04x%04x\\FileVersion", languageInfo[0].wLanguage, languageInfo[0].wCodePage); - - VerQueryValue(versionInfo, blockName, &fileVersion, &valueSize); - if (valueSize) - { - result = (WCHAR*)fileVersion; - } - } - - delete [] (WCHAR*)versionInfo; - return result; -} - -std::wstring GetDotNETVersion() -{ - WCHAR buffer[255]; - HKEY hKey; - LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", 0L, KEY_READ, &hKey); - std::wstring currVer(L"v0"), prevVer; - int i = 0; - - while (lRet == ERROR_SUCCESS) - { - lRet = RegEnumKey(hKey, i, buffer, 255); - if (buffer[0] == L'v') - { - currVer = buffer; - } - ++i; - } - - RegCloseKey(hKey); - currVer.erase(0, 1); // Get rid of the 'v' - return currVer; -} - -std::wstring GetWindowsVersion() -{ - WCHAR buffer[16]; - OSVERSIONINFOEX osvi = {sizeof(OSVERSIONINFOEX)}; - GetVersionEx((OSVERSIONINFO*)&osvi); - _snwprintf_s(buffer, _TRUNCATE, L"%d.%d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); - - return buffer; -} - -BOOL IsActiveUAC() -{ - // First check if user has a split token (that implies UAC) - HANDLE hToken; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) - { - TOKEN_ELEVATION_TYPE tet; - DWORD dwReturnLength = 0; - if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(TOKEN_ELEVATION_TYPE), &dwReturnLength) && - tet != TokenElevationTypeDefault) - { - return TRUE; - } - - CloseHandle(hToken); - } - - // Check from registry - DWORD dwValue = 0; - DWORD dwSize = sizeof(DWORD); - HKEY hKey; - RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 0L, KEY_QUERY_VALUE, &hKey); - RegQueryValueEx(hKey, L"EnableLUA", NULL, NULL, (LPBYTE)&dwValue, (LPDWORD)&dwSize); - RegCloseKey(hKey); - - return (dwValue != 0) ? TRUE : FALSE; -} - -BOOL IsAboveVista() -{ - static BOOL isAbove = -1; - - if (isAbove == -1) - { - OSVERSIONINFOEX osvi = {sizeof(OSVERSIONINFOEX)}; - GetVersionEx((OSVERSIONINFO*)&osvi); - isAbove = (osvi.dwMajorVersion >= 6) ? TRUE : FALSE; - } - - return isAbove; -} - -BOOL IsCurrentProcessAdmin() -{ - static BOOL isAdmin = -1; - - // Based on the work of Anders Kjersem: http://nsis.sourceforge.net/UAC_plug-in - if (isAdmin == -1) - { - isAdmin = FALSE; - HANDLE hToken; - - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) - { - SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; - PSID psid = 0; - if (AllocateAndInitializeSid(&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psid)) - { - if (!CheckTokenMembership(0, psid, &isAdmin)) - { - isAdmin = FALSE; - DWORD cbTokenGrps; - if (!GetTokenInformation(hToken, TokenGroups, 0, 0, &cbTokenGrps) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - TOKEN_GROUPS* ptg = (TOKEN_GROUPS*)GlobalAlloc(LPTR, cbTokenGrps); - if (ptg) - { - if (GetTokenInformation(hToken, TokenGroups, ptg, cbTokenGrps, &cbTokenGrps)) - { - for (DWORD i = 0; i < ptg->GroupCount; ++i) - { - if (EqualSid(ptg->Groups[i].Sid, psid)) - { - isAdmin = TRUE; - break; - } - } - } - GlobalFree(ptg); - } - } - } - - FreeSid(psid); - } - - // Check if UAC admin with split token check - if (isAdmin && IsAboveVista()) - { - TOKEN_ELEVATION_TYPE tet; - DWORD dwReturnLength = 0; - if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(TOKEN_ELEVATION_TYPE), &dwReturnLength) && - tet == TokenElevationTypeLimited) - { - isAdmin = FALSE; - } - } - - CloseHandle(hToken); - } - } - - return isAdmin; -} diff --git a/SkinInstaller/Rainstaller.h b/SkinInstaller/Rainstaller.h deleted file mode 100644 index db6f5374..00000000 --- a/SkinInstaller/Rainstaller.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright (C) 2011 Birunthan Mohanathas - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef __RAINSTALLER_H__ -#define __RAINSTALLER_H__ - -#define OBJECT_NAME L"RainstallerObject_6D42B76464DA" -#define MB_ERROR MB_OK | MB_TOPMOST | MB_ICONERROR - -#ifdef _WIN64 - #define PLUGINS_ROOT L"Plugins/64bit/" -#else - #define PLUGINS_ROOT L"Plugins/32bit/" -#endif - -typedef BOOL (WINAPI* CHECKTOKENMEMBERSHIP)(HANDLE tokenHandle, PSID sidToCheck, PBOOL isMember); -typedef BOOL (WINAPI* GETFONTRESOURCEINFO)(LPCTSTR lpszFilename, LPDWORD cbBuffer, LPVOID lpBuffer, DWORD dwQueryType); - -enum INSTTYPE -{ - INSTTYPE_ADMIN = 1, // Installs plugins, addons, and fonts - INSTTYPE_NOADMIN, // Installs skins and themes - INSTTYPE_FULL // Install all components -}; - -enum TIMER -{ - TIMER_THREAD = 1, - TIMER_PROCESS -}; - -struct RMSKIN_DATA -{ - INSTTYPE instType; - HANDLE instHandle; - int rootLen; - bool mergeSkins; - bool launchRainmeter; - bool rainmeterFonts; - - std::wstring packageName; - std::wstring packageAuthor; - std::wstring packageVersion; - std::wstring rmskinFile; - std::wstring backupFolder; - std::wstring iniPath; - std::wstring skinsPath; - std::wstring rainmeterPath; - std::wstring addonsList; - std::wstring pluginsList; - std::wstring skinsList; - std::wstring themesList; - std::wstring fontsList; - std::wstring loadTheme; - std::wstring loadSkins; - std::wstring keepVariables; -}; - -int Rainstaller(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow); - -BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -BOOL CALLBACK RunAsProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -void InitDialog(HWND hwnd); -void InitInstall(HWND hwnd); - -bool ReadArchive(); -bool ReadSettings(LPCTSTR filePath); -bool ExtractCurrentFile(unzFile& ufile, LPCTSTR fileName); -bool IsDefaultPlugin(LPCTSTR plugin); -bool IsDefaultAddon(LPCTSTR addon); - -HANDLE CreateProcessElevated(HWND hwnd); -unsigned __stdcall CreateInstallThread(void* pParam); -unsigned __stdcall SetRunAsThread(void*); -bool InstallComponents(RMSKIN_DATA* data); -bool BackupComponent(const std::wstring& backupFolder, const std::wstring& list, const std::wstring& path); -void KeepVariables(const std::wstring& backupFolder, const std::wstring& skinsPath, const std::wstring& fileList); -void LaunchRainmeter(); - -int CompareVersions(const std::wstring& strA, const std::wstring& strB); -std::vector Tokenize(const std::wstring& str, const std::wstring& delimiters); -std::wstring GetDotNETVersion(); -std::wstring GetFileVersion(const std::wstring& file); -std::wstring GetWindowsVersion(); -BOOL IsCurrentProcessAdmin(); -BOOL IsAboveVista(); -BOOL IsActiveUAC(); - -#endif diff --git a/SkinInstaller/SkinInstaller.rc b/SkinInstaller/SkinInstaller.rc index 726156e7..79f2117e 100644 --- a/SkinInstaller/SkinInstaller.rc +++ b/SkinInstaller/SkinInstaller.rc @@ -11,7 +11,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,0,0,0 + FILEVERSION 4,0,0,0 PRODUCTVERSION PRODUCTVER FILEFLAGSMASK 0x17L #ifdef _DEBUG @@ -27,12 +27,11 @@ VS_VERSION_INFO VERSIONINFO { BLOCK "040904E4" { - VALUE "FileDescription", "Rainstaller" - VALUE "FileVersion", "3.0.0.0" - VALUE "InternalName", "Rainstaller" - VALUE "LegalCopyright", "Copyright (C) 2011 - Birunthan Mohanathas" - VALUE "OriginalFilename", "Rainstaller.exe" - VALUE "ProductName", "Rainstaller" + VALUE "FileDescription", "Rainmeter Skin Installer" + VALUE "FileVersion", "4.0.0.0" + VALUE "LegalCopyright", "© 2012 - Birunthan Mohanathas" + VALUE "OriginalFilename", "SkinInstaller.exe" + VALUE "ProductName", "Rainmeter" #ifdef _WIN64 VALUE "ProductVersion", STRPRODUCTVER " (64-bit)" #else @@ -69,60 +68,41 @@ FONT 8, "MS Shell Dlg 2" EDITTEXT IDC_BACKUP_FILE_TEXT, 0, 42, 220, 14, WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL | ES_READONLY PUSHBUTTON "...", IDC_BACKUP_BROWSE_BUTTON, 225, 42, 25, 14, WS_TABSTOP - LTEXT "Backup in progress...\n\nThis may take several minutes to complete.", IDC_BACKUP_INPROGRESS_TEXT, 0, 0, 245, 39, NOT WS_VISIBLE + LTEXT "Backup in progress...", IDC_BACKUP_INPROGRESS_TEXT, 0, 0, 245, 9, NOT WS_VISIBLE CONTROL "", IDC_BACKUP_PROGRESS, "msctls_progress32", PBS_MARQUEE | NOT WS_VISIBLE | WS_BORDER, 0, 42, 250, 11 } -IDD_INSTALLER_DIALOG DIALOGEX 0, 0, 266, 240 -STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +IDD_INSTALL_DIALOG DIALOGEX 0, 0, 266, 270 +STYLE DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Rainmeter Skin Installer" +FONT 8, "MS Shell Dlg 2" +{ + CONTROL IDB_INSTALLHEADER, IDC_INSTALL_HEADER_BITMAP, STATIC, SS_BITMAP | WS_CHILD | WS_VISIBLE, 0, 0, 266, 37 + CONTROL "", IDC_STATIC, STATIC, SS_ETCHEDHORZ | WS_CHILD | WS_VISIBLE, 0, 37, 270, 1 + CONTROL "", IDC_INSTALL_TAB, "SysTabControl32", TCS_TABS | TCS_FIXEDWIDTH, 6, 42, 254, 205 + PUSHBUTTON "Advanced", IDC_INSTALL_ADVANCED_BUTTON, 6, 251, 70, 14 + DEFPUSHBUTTON "Install", IDC_INSTALL_INSTALL_BUTTON, 155, 251, 50, 14 + PUSHBUTTON "Cancel", IDCLOSE, 210, 251, 50, 14 +} + +IDD_INSTALL_TAB DIALOGEX 15, 51, 236, 188 +STYLE DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS CAPTION "Rainstaller" FONT 8, "MS Shell Dlg 2" { - CONTROL IDB_INSTALLER, IDC_BITMAP, STATIC, SS_BITMAP | WS_CHILD | WS_VISIBLE, 0, 0, 266, 37 - CONTROL "", IDC_STATIC, STATIC, SS_ETCHEDHORZ | WS_CHILD | WS_VISIBLE, 0, 37, 270, 1 - GROUPBOX "", IDC_STATIC, 7, 39, 252, 44 - LTEXT "Name:", IDC_NAME_LABEL, 13, 48, 35, 9 - LTEXT "", IDC_NAME_VALUE, 50, 48, 200, 9, SS_NOPREFIX - LTEXT "Author:", IDC_AUTHOR_LABEL, 13, 59, 35, 9 - LTEXT "", IDC_AUTHOR_VALUE, 50, 59, 200, 9, SS_NOPREFIX - LTEXT "Version:", IDC_VERSION_LABEL, 13, 70, 35, 9 - LTEXT "", IDC_VERSION_VALUE, 50, 70, 200, 9, SS_NOPREFIX - GROUPBOX "", IDC_STATIC, 7, 83, 252, 95 - LTEXT "Skins:", IDC_SKINS_LABEL, 13, 91, 35, 9, SS_NOTIFY - LTEXT "", IDC_SKINS_VALUE, 50, 91, 200, 9, SS_NOTIFY | SS_ENDELLIPSIS | SS_NOPREFIX - LTEXT "Themes:", IDC_THEMES_LABEL, 13, 102, 35, 9, SS_NOTIFY - LTEXT "", IDC_THEMES_VALUE, 50, 102, 200, 9, SS_NOTIFY | SS_ENDELLIPSIS | SS_NOPREFIX - LTEXT "Addons:", IDC_ADDONS_LABEL, 13, 113, 35, 9, SS_NOTIFY - LTEXT "", IDC_ADDONS_VALUE, 50, 113, 200, 9, SS_NOTIFY | SS_ENDELLIPSIS | SS_NOPREFIX - LTEXT "Plugins:", IDC_PLUGINS_LABEL, 13, 124, 35, 9, SS_NOTIFY - LTEXT "", IDC_PLUGINS_VALUE, 50, 124, 200, 9, SS_NOTIFY | SS_ENDELLIPSIS | SS_NOPREFIX - LTEXT "Fonts:", IDC_FONTS_LABEL, 13, 135, 35, 9, SS_NOTIFY - LTEXT "", IDC_FONTS_VALUE, 50, 135, 200, 9, SS_NOTIFY | SS_ENDELLIPSIS | SS_NOPREFIX - AUTOCHECKBOX "Apply theme ()", IDC_THEME_CHECKBOX, 13, 150, 220, 9, BST_CHECKED - AUTOCHECKBOX "Launch Rainmeter after install", IDC_LAUNCH_CHECKBOX, 13, 162, 220, 9, BST_CHECKED - CONTROL "", IDC_PROGRESSBAR, "msctls_progress32", PBS_MARQUEE | WS_CHILD | WS_VISIBLE | WS_BORDER, 7, 186, 135, 11 - DEFPUSHBUTTON "&Install", IDC_INSTALL_BUTTON, 155, 184, 50, 14 - PUSHBUTTON "&Cancel", IDC_CANCEL_BUTTON, 209, 184, 50, 14 - CONTROL "", IDC_SEPERATOR, STATIC, SS_ETCHEDHORZ | WS_CHILD | WS_VISIBLE, 0, 204, 270, 1 - ICON "", IDC_WARNING_ICON, 8, 212, 20, 20 - LTEXT "Components marked with an asterisk (*) will be replaced. Backups will be made should you want to restore.", IDC_BACKUP_LABEL, 38, 213, 220, 18 -} + LTEXT "The following package is about to be installed.", IDC_STATIC, 0, 0, 231, 39 + LTEXT "Name:", IDC_STATIC, 0, 20, 35, 9 + LTEXT "", IDC_INSTALLTAB_NAME_TEXT, 50, 20, 200, 9, SS_NOPREFIX + LTEXT "Author:", IDC_STATIC, 0, 33, 35, 9 + LTEXT "", IDC_INSTALLTAB_AUTHOR_TEXT, 50, 33, 200, 9, SS_NOPREFIX + LTEXT "Version:", IDC_STATIC, 0, 46, 35, 9 + LTEXT "", IDC_INSTALLTAB_VERSION_TEXT, 50, 46, 200, 9, SS_NOPREFIX + LTEXT "Included components:", IDC_STATIC, 0, 65, 80, 9 + CONTROL "", IDC_INSTALLTAB_COMPONENTS_LIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP, 0, 80, 234, 86 + AUTOCHECKBOX "Apply included theme", IDC_INSTALLTAB_THEME_CHECKBOX, 4, 175, 220, 9 -IDD_RUNAS DIALOGEX 0, 0, 250, 145 -STYLE DS_MODALFRAME | DS_CENTER | DS_NOIDLEMSG | DS_SETFOREGROUND | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Run As..." -FONT 8, "MS Shell Dlg 2" -{ - ICON "", IDC_KEY_ICON, 7, 8, 20, 20 - LTEXT "You do not have the necessary permissions to install the components. You need to run this program as a different administrative user in order to continue with the installation.", IDC_HELPTEXT, 38, 7, 204, 35 - CONTROL "&Current user", IDC_CURRENT_BUTTON, "Button", BS_AUTORADIOBUTTON | WS_DISABLED, 20, 49, 218, 10 - CONTROL "Run the program as the &following user:", IDC_SPECIFIED_BUTTON, "Button", BS_AUTORADIOBUTTON, 20, 65, 218, 10 - LTEXT "&User name:", IDC_USERNAME_LABEL, 20, 84, 42, 16 - EDITTEXT IDC_USERNAME, 63, 83, 175, 14, ES_AUTOHSCROLL - LTEXT "&Password:", IDC_PASSWORD_LABEL, 20, 102, 42, 20 - EDITTEXT IDC_PASSWORD, 63, 100, 175, 14, ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "&OK", IDOK, 132, 122, 50, 14 - PUSHBUTTON "Ca&ncel", IDCANCEL, 188, 122, 50, 14 + LTEXT "Installing...", IDC_INSTALLTAB_INPROGRESS_TEXT, 0, 0, 236, 60, NOT WS_VISIBLE + CONTROL "", IDC_INSTALLTAB_PROGRESS, "msctls_progress32", PBS_MARQUEE | NOT WS_VISIBLE | WS_BORDER, 0, 15, 236, 11 } ///////////////////////////////////////////////////////////////////////////// @@ -130,11 +110,11 @@ FONT 8, "MS Shell Dlg 2" // Bitmap // -IDB_INSTALLER BITMAP "res/Rainstaller.bmp" +IDB_INSTALLHEADER BITMAP "res/Rainstaller.bmp" ///////////////////////////////////////////////////////////////////////////// // // Icon // -IDI_INSTALLER ICON DISCARDABLE "res/Rainstaller.ico" +IDI_SKININSTALLER ICON DISCARDABLE "res/Rainstaller.ico" diff --git a/SkinInstaller/SkinInstaller.vcxproj b/SkinInstaller/SkinInstaller.vcxproj index 60b5e08f..cd83d6a4 100644 --- a/SkinInstaller/SkinInstaller.vcxproj +++ b/SkinInstaller/SkinInstaller.vcxproj @@ -84,9 +84,9 @@ MaxSpeed - WIN32;NDEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;HAVE_CONFIG_H;SUPPORT_UTF8;%(PreprocessorDefinitions) Level3 - 4530;4996 + 4244;4267;4482;4530;4996 ./zlib;./zlib/minizip false false @@ -100,8 +100,8 @@ Windows true MachineX86 - %(AdditionalLibraryDirectories) - Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) + Rainmeter.lib;Wininet.lib;Comctl32.lib;Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) + ..\Library\x32\$(Configuration);%(AdditionalLibraryDirectories) wWinMainCRTStartup .rdata=.text true @@ -120,9 +120,9 @@ MaxSpeed - WIN32;NDEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;HAVE_CONFIG_H;SUPPORT_UTF8;%(PreprocessorDefinitions) Level3 - 4244;4267;4530;4996 + 4244;4267;4482;4530;4996 ./zlib;./zlib/minizip false false @@ -135,8 +135,8 @@ ..\TestBench\x64\$(Configuration)\SkinInstaller.exe Windows true - %(AdditionalLibraryDirectories) - Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) + Rainmeter.lib;Wininet.lib;Comctl32.lib;Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) + ..\Library\x64\$(Configuration);%(AdditionalLibraryDirectories) wWinMainCRTStartup .rdata=.text true @@ -155,13 +155,13 @@ Disabled - WIN32;_DEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;HAVE_CONFIG_H;SUPPORT_UTF8;%(PreprocessorDefinitions) true EnableFastChecks Level3 EditAndContinue ./zlib;./zlib/minizip - 4244;4267;4530;4996 + 4244;4267;4482;4530;4996 false @@ -175,8 +175,8 @@ true MachineX86 wWinMainCRTStartup - Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) + Rainmeter.lib;Wininet.lib;Comctl32.lib;Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) + ..\Library\x32\$(Configuration);%(AdditionalLibraryDirectories) $(IntDir)$(TargetName).pdb @@ -189,12 +189,12 @@ Disabled - WIN32;_DEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;ZLIB_WINAPI;NOUNCRYPT;NOCRYPT;ASMV;ASMINF;NOOLDPENTIUMCODE;HAVE_CONFIG_H;SUPPORT_UTF8;%(PreprocessorDefinitions) EnableFastChecks Level3 ProgramDatabase ./zlib;./zlib/minizip - 4244;4267;4530;4996 + 4244;4267;4482;4530;4996 false @@ -207,8 +207,8 @@ Windows true wWinMainCRTStartup - Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) - %(AdditionalLibraryDirectories) + Rainmeter.lib;Wininet.lib;Comctl32.lib;Version.lib;UxTheme.lib;shlwapi.lib;%(AdditionalDependencies) + ..\Library\x64\$(Configuration);%(AdditionalLibraryDirectories) $(IntDir)$(TargetName).pdb @@ -219,7 +219,7 @@ - + @@ -237,6 +237,7 @@ true true + @@ -254,9 +255,13 @@ - + + + + + diff --git a/SkinInstaller/SkinInstaller.vcxproj.filters b/SkinInstaller/SkinInstaller.vcxproj.filters index 75c9ebac..666428b9 100644 --- a/SkinInstaller/SkinInstaller.vcxproj.filters +++ b/SkinInstaller/SkinInstaller.vcxproj.filters @@ -19,6 +19,9 @@ {b726e25d-2977-424a-b45b-8ee60ce6bd49} + + {73cc243e-5b60-4fbc-ae48-069c6decc4ed} + @@ -78,9 +81,12 @@ Source Files - + Source Files + + pcre + @@ -134,9 +140,21 @@ Header Files - + Header Files + + pcre + + + pcre + + + pcre + + + pcre + diff --git a/SkinInstaller/StdAfx.h b/SkinInstaller/StdAfx.h index 1323766e..f5ed3bf1 100644 --- a/SkinInstaller/StdAfx.h +++ b/SkinInstaller/StdAfx.h @@ -20,22 +20,27 @@ #define __STDAFX_H__ // WINAPI -#include -#include -#include -#include +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include // STL #include #include #include +#include +#include #include #include +#include #include // RUNTIME -#include -#include #include #endif diff --git a/SkinInstaller/resource.h b/SkinInstaller/resource.h index 8d38bfc6..3cfab313 100644 --- a/SkinInstaller/resource.h +++ b/SkinInstaller/resource.h @@ -1,8 +1,8 @@ #define IDC_STATIC -1 -#define IDI_INSTALLER 100 -#define IDB_INSTALLER 101 -#define IDD_INSTALLER_DIALOG 102 -#define IDD_INSTALLER_TAB 103 +#define IDI_SKININSTALLER 100 +#define IDB_INSTALLHEADER 101 +#define IDD_INSTALL_DIALOG 102 +#define IDD_INSTALL_TAB 103 #define IDD_BACKUP_DIALOG 104 #define IDD_BACKUP_TABDIALOG 105 @@ -14,39 +14,15 @@ #define IDC_BACKUP_DESCRIPTION_TEXT 1024 #define IDC_BACKUP_INPROGRESS_TEXT 1025 -// Rainstaller -#define IDC_BITMAP 1000 -#define IDC_NAME_LABEL 1001 -#define IDC_NAME_VALUE 1002 -#define IDC_AUTHOR_LABEL 1003 -#define IDC_AUTHOR_VALUE 1004 -#define IDC_VERSION_LABEL 1005 -#define IDC_VERSION_VALUE 1006 -#define IDC_SKINS_LABEL 1007 -#define IDC_SKINS_VALUE 1008 -#define IDC_THEMES_LABEL 1009 -#define IDC_THEMES_VALUE 1010 -#define IDC_ADDONS_LABEL 1011 -#define IDC_ADDONS_VALUE 1012 -#define IDC_PLUGINS_LABEL 1013 -#define IDC_PLUGINS_VALUE 1014 -#define IDC_FONTS_LABEL 1015 -#define IDC_FONTS_VALUE 1016 -#define IDC_THEME_CHECKBOX 1017 -#define IDC_LAUNCH_CHECKBOX 1018 -#define IDC_BACKUP_LABEL 1019 -#define IDC_PROGRESSBAR 1020 -#define IDC_INSTALL_BUTTON 1021 -#define IDC_CANCEL_BUTTON 1022 -#define IDC_SEPERATOR 1023 -#define IDC_WARNING_ICON 1024 +#define IDC_INSTALL_TAB 1000 +#define IDC_INSTALL_HEADER_BITMAP 1001 +#define IDC_INSTALL_ADVANCED_BUTTON 1002 +#define IDC_INSTALL_INSTALL_BUTTON 1003 -#define IDD_RUNAS 111 -#define IDC_CURRENT_BUTTON 1100 -#define IDC_SPECIFIED_BUTTON 1101 -#define IDC_KEY_ICON 1102 -#define IDC_HELPTEXT 1103 -#define IDC_USERNAME 1104 -#define IDC_PASSWORD 1105 -#define IDC_USERNAME_LABEL 1107 -#define IDC_PASSWORD_LABEL 1108 +#define IDC_INSTALLTAB_NAME_TEXT 1000 +#define IDC_INSTALLTAB_AUTHOR_TEXT 1001 +#define IDC_INSTALLTAB_VERSION_TEXT 1002 +#define IDC_INSTALLTAB_COMPONENTS_LIST 1003 +#define IDC_INSTALLTAB_THEME_CHECKBOX 1004 +#define IDC_INSTALLTAB_INPROGRESS_TEXT 1005 +#define IDC_INSTALLTAB_PROGRESS 1006