diff --git a/SkinInstaller/Application.cpp b/SkinInstaller/Application.cpp index 3cbe5004..b44ddedc 100644 --- a/SkinInstaller/Application.cpp +++ b/SkinInstaller/Application.cpp @@ -29,21 +29,13 @@ GLOBALDATA g_Data; */ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { - if (wcscmp(lpCmdLine, L"/BACKUP") != 0) + bool loadTheme = (wcsncmp(lpCmdLine, L"/LOADTHEME ", 11) == 0); + if (wcscmp(lpCmdLine, L"/BACKUP") != 0 && !loadTheme) { // Temporary solution until Rainstaller rewrite return Rainstaller(hInstance, hPrevInstance, lpCmdLine, nCmdShow); } - // Check whether Rainstaller.exe is already running and bring it to front if so - HANDLE hMutex; - if (IsRunning(L"RmSkinInstallerMutex", &hMutex)) - { - HWND hwnd = FindWindow(L"#32770", L"Backup Rainmeter"); - SetForegroundWindow(hwnd); - return 0; - } - // Avoid loading a dll from current directory SetDllDirectory(L""); @@ -63,6 +55,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi // Find the settings file and read skins path off it if (_waccess(buffer, 0) == 0) { + g_Data.iniFile = buffer; if (GetPrivateProfileString(L"Rainmeter", L"SkinPath", L"", buffer, MAX_LINE_LENGTH, buffer) > 0) { g_Data.skinsPath = buffer; @@ -79,6 +72,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi wcscat(buffer, L"\\Rainmeter\\"); g_Data.settingsPath = buffer; wcscat(buffer, L"Rainmeter.ini"); + g_Data.iniFile = buffer; if (SUCCEEDED(hr) && _waccess(buffer, 0) == 0) { if (GetPrivateProfileString(L"Rainmeter", L"SkinPath", L"", buffer, MAX_LINE_LENGTH, buffer) > 0) @@ -100,16 +94,120 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi } } + if (loadTheme) + { + // Skip "/LOADTHEME " + lpCmdLine += 11; + + if (CloseRainmeterIfActive() && *lpCmdLine) + { + LoadTheme(lpCmdLine); + + 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.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)) + { + HWND hwnd = FindWindow(L"#32770", L"Backup Rainmeter"); + SetForegroundWindow(hwnd); + return 0; + } + CDialogBackup::Create(hInstance, lpCmdLine); ReleaseMutex(hMutex); - return 0; } -/* -** Checks whether Rainstaller.exe is running (modified from Application.cpp) -*/ +bool CloseRainmeterIfActive() +{ + // Close Rainmeter.exe + HWND hwnd = FindWindow(L"DummyRainWClass", L"Rainmeter control window"); + if (hwnd) + { + DWORD pID, exitCode; + GetWindowThreadProcessId(hwnd, &pID); + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pID); + PostMessage(hwnd, WM_DESTROY, 0, 0); + + // Wait up to 5 seconds for Rainmeter to close + WaitForSingleObject(hProcess, 5000); + GetExitCodeProcess(hProcess, &exitCode); + CloseHandle(hProcess); + + if (exitCode == STILL_ACTIVE) + { + return false; + } + } + + 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"; + 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 +// ----------------------------------------------------------------------------------------------- + bool IsRunning(const WCHAR* name, HANDLE* hMutex) { // Create mutex @@ -126,6 +224,26 @@ bool IsRunning(const WCHAR* name, HANDLE* hMutex) } } +bool CopyFiles(const std::wstring& strFrom, const std::wstring& strTo, bool bMove) +{ + std::wstring tmpFrom(strFrom), tmpTo(strTo); + + // The strings must end with double nul + tmpFrom.append(1, L'\0'); + tmpTo.append(1, L'\0'); + + SHFILEOPSTRUCT fo = + { + NULL, + bMove ? FO_MOVE : FO_COPY, + tmpFrom.c_str(), + tmpTo.c_str(), + FOF_NO_UI | FOF_NOCONFIRMATION | FOF_ALLOWUNDO + }; + + return SHFileOperation(&fo) != 0; +} + std::string ConvertToAscii(LPCTSTR str) { std::string szAscii; diff --git a/SkinInstaller/Application.h b/SkinInstaller/Application.h index 1480ef5f..08c5f14a 100644 --- a/SkinInstaller/Application.h +++ b/SkinInstaller/Application.h @@ -41,10 +41,15 @@ struct GLOBALDATA std::wstring programPath; std::wstring settingsPath; std::wstring skinsPath; + std::wstring iniFile; }; -bool IsRunning(const WCHAR* name, HANDLE* hMutex); +bool CloseRainmeterIfActive(); +void LoadTheme(const WCHAR* name); +void PreserveSetting(const std::wstring& from, LPCTSTR key, bool replace = true); +bool IsRunning(const WCHAR* name, HANDLE* hMutex); +bool CopyFiles(const std::wstring& strFrom, const std::wstring& strTo, bool bMove = false); std::string ConvertToAscii(LPCTSTR str); std::wstring ConvertToWide(LPCSTR str); diff --git a/SkinInstaller/DialogBackup.cpp b/SkinInstaller/DialogBackup.cpp index 90335102..2e6b0a79 100644 --- a/SkinInstaller/DialogBackup.cpp +++ b/SkinInstaller/DialogBackup.cpp @@ -144,27 +144,34 @@ INT_PTR CDialogBackup::OnCommand(WPARAM wParam, LPARAM lParam) void CDialogBackup::StartBackup() { - HWND item = GetDlgItem(m_Window, IDC_BACKUP_BACKUP_BUTTON); - EnableWindow(item, FALSE); - - item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_FILE_TEXT); - ShowWindow(item, SW_HIDE); - - item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_BROWSE_BUTTON); - ShowWindow(item, SW_HIDE); - - item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_INPROGRESS_TEXT); - ShowWindow(item, SW_SHOWNORMAL); - - item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_PROGRESS); - ShowWindow(item, SW_SHOWNORMAL); - SendMessage(item, PBM_SETMARQUEE, (WPARAM)TRUE, 0); - - m_ThreadHandle = (HANDLE)_beginthreadex(NULL, 0, BackupThreadProc, this, 0, NULL); - if (!m_ThreadHandle) + if (!CloseRainmeterIfActive()) { - MessageBox(m_Window, L"Unable to start backup.", L"Backup Rainmeter", MB_ERROR); - EndDialog(m_Window, 0); + MessageBox(m_Window, L"Unable to close Rainmeter.", L"Backup Rainmeter", MB_ERROR); + } + else + { + HWND item = GetDlgItem(m_Window, IDC_BACKUP_BACKUP_BUTTON); + EnableWindow(item, FALSE); + + item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_FILE_TEXT); + ShowWindow(item, SW_HIDE); + + item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_BROWSE_BUTTON); + ShowWindow(item, SW_HIDE); + + item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_INPROGRESS_TEXT); + ShowWindow(item, SW_SHOWNORMAL); + + item = GetDlgItem(m_TabBackup.GetWindow(), IDC_BACKUP_PROGRESS); + ShowWindow(item, SW_SHOWNORMAL); + SendMessage(item, PBM_SETMARQUEE, (WPARAM)TRUE, 0); + + m_ThreadHandle = (HANDLE)_beginthreadex(NULL, 0, BackupThreadProc, this, 0, NULL); + if (!m_ThreadHandle) + { + MessageBox(m_Window, L"Unable to start backup.", L"Backup Rainmeter", MB_ERROR); + EndDialog(m_Window, 0); + } } } diff --git a/SkinInstaller/Rainstaller.cpp b/SkinInstaller/Rainstaller.cpp index abb4e525..101458bf 100644 --- a/SkinInstaller/Rainstaller.cpp +++ b/SkinInstaller/Rainstaller.cpp @@ -1028,26 +1028,11 @@ bool IsDefaultAddon(LPCTSTR addon) */ bool InstallComponents(RMSKIN_DATA* data) { - // Close Rainmeter.exe - HWND hwnd = FindWindow(L"DummyRainWClass", L"Rainmeter control window"); - if (hwnd) + if (!CloseRainmeterIfActive()) { - DWORD pID, exitCode; - GetWindowThreadProcessId(hwnd, &pID); - HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pID); - PostMessage(hwnd, WM_DESTROY, 0, 0); - - // Wait up to 5 seconds for Rainmeter to close - WaitForSingleObject(hProcess, 5000); - GetExitCodeProcess(hProcess, &exitCode); - CloseHandle(hProcess); - - if (exitCode == STILL_ACTIVE) - { - std::wstring error = L"Failed to close Rainmeter."; - MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); - return false; - } + std::wstring error = L"Failed to close Rainmeter."; + MessageBox(NULL, error.c_str(), APP_NAME, MB_ERROR); + return false; } int result; @@ -1522,28 +1507,6 @@ unsigned __stdcall CreateInstallThread(void* pParam) return InstallComponents((RMSKIN_DATA*)pParam) ? 0 : 1; } -/* -** Copies files and folders from one location to another (from Rainmeter.cpp) -*/ -bool CopyFiles(const std::wstring& strFrom, const std::wstring& strTo, bool bMove) -{ - std::wstring tmpFrom(strFrom), tmpTo(strTo); - - // The strings must end with double null - tmpFrom.append(L"0"); - tmpFrom[tmpFrom.size() - 1] = L'\0'; - tmpTo.append(L"0"); - tmpTo[tmpTo.size() - 1] = L'\0'; - - SHFILEOPSTRUCT fo = {0}; - fo.wFunc = bMove ? FO_MOVE : FO_COPY; - fo.pFrom = tmpFrom.c_str(); - fo.pTo = tmpTo.c_str(); - fo.fFlags = FOF_NO_UI | FOF_SILENT | FOF_NOCONFIRMATION; - - return (SHFileOperation(&fo) != 0) ? false : true; -} - /* ** Splits the string from the delimiters and trims whitespace */ diff --git a/SkinInstaller/Rainstaller.h b/SkinInstaller/Rainstaller.h index f460af2c..aa45ca23 100644 --- a/SkinInstaller/Rainstaller.h +++ b/SkinInstaller/Rainstaller.h @@ -93,7 +93,6 @@ void KeepVariables(const std::wstring& backupFolder, const std::wstring& skinsPa void LaunchRainmeter(); int CompareVersions(const std::wstring& strA, const std::wstring& strB); -bool CopyFiles(const std::wstring& strFrom, const std::wstring& strTo, bool bMove); std::vector Tokenize(const std::wstring& str, const std::wstring& delimiters); std::wstring GetDotNETVersion(); std::wstring GetFileVersion(const std::wstring& file);