diff --git a/.gitignore b/.gitignore index a5d95d6..adf6318 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .vs/ ghost_installer.vcxproj.user src/resource/ghost_installer.aps +src/resource/RC* diff --git a/builds/auto_upx.bat b/builds/auto_upx.bat new file mode 100644 index 0000000..d7b9979 --- /dev/null +++ b/builds/auto_upx.bat @@ -0,0 +1,4 @@ +cd Release +upx --ultra-brute --no-align --best --compress-resources=1 ghost_installer.exe +rename ghost_installer.exe Taromati2_Installer.exe +cd .. diff --git a/ghost_installer.sln b/ghost_installer.sln index d23d664..2d47640 100644 --- a/ghost_installer.sln +++ b/ghost_installer.sln @@ -7,18 +7,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ghost_installer", "ghost_in EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Debug|x64.ActiveCfg = Debug|x64 - {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Debug|x64.Build.0 = Debug|x64 {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Debug|x86.ActiveCfg = Debug|Win32 {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Debug|x86.Build.0 = Debug|Win32 - {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Release|x64.ActiveCfg = Release|x64 - {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Release|x64.Build.0 = Release|x64 {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Release|x86.ActiveCfg = Release|Win32 {C89F04AF-0793-410D-BA2F-10E7042ACD86}.Release|x86.Build.0 = Release|Win32 EndGlobalSection diff --git a/ghost_installer.vcxproj b/ghost_installer.vcxproj index 3756fc1..f586f97 100644 --- a/ghost_installer.vcxproj +++ b/ghost_installer.vcxproj @@ -19,9 +19,13 @@ - - + + /await %(AdditionalOptions) + /await %(AdditionalOptions) + /await %(AdditionalOptions) + /await %(AdditionalOptions) + @@ -30,6 +34,9 @@ + + + 16.0 Win32Proj @@ -126,12 +133,13 @@ AnySuitable Size true + MaxSpeed Windows true true - true + false false @@ -163,12 +171,13 @@ AnySuitable Size true + MaxSpeed Windows true true - true + false false diff --git a/ghost_installer.vcxproj.filters b/ghost_installer.vcxproj.filters index 59d52fd..e071530 100644 --- a/ghost_installer.vcxproj.filters +++ b/ghost_installer.vcxproj.filters @@ -17,9 +17,6 @@ 源文件 - - 源文件 - 源文件 @@ -37,4 +34,7 @@ 资源文件 + + + \ No newline at end of file diff --git a/src/_gists.cpp b/src/_gists.cpp index a00e6e2..933910a 100644 --- a/src/_gists.cpp +++ b/src/_gists.cpp @@ -1,2 +1,11 @@ #include "my-gists/ukagaka/SSP_Runner.cpp" -#include "my-gists/windows/LoadStringFromResource.cpp" +#include "my-gists/windows/WaitForXObjectWithMessageLoop.cpp" +#include "my-gists/windows/download_file.cpp" +#include "my-gists/windows/IsNetworkHasCost.cpp" + +const wchar_t* NetAgentName() { + return L"ghost_installer"; +} +const wchar_t* temp_filename_gen_header() { + return L"ghi"; +} diff --git a/src/download_temp_file.cpp b/src/download_temp_file.cpp deleted file mode 100644 index 8e17997..0000000 --- a/src/download_temp_file.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#include -#pragma comment(lib, "WinInet.lib") -std::wstring download_file(const std::wstring& url, const std::wstring& file) { - // - HANDLE hFileHandle = CreateFileW(file.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if(hFileHandle==INVALID_HANDLE_VALUE) { - throw std::runtime_error("CreateFileW failed"); - } - //download file - HINTERNET hInternet=InternetOpenW(L"ghost_installer", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - if(hInternet==NULL) { - throw std::runtime_error("InternetOpenW failed"); - } - HINTERNET hFile=InternetOpenUrlW(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0); - if(hFile==NULL) { - InternetCloseHandle(hInternet); - throw std::runtime_error("InternetOpenUrlW failed"); - } - DWORD dwBytesRead=0; - DWORD dwBytesWritten=0; - unsigned char buffer[1024]; - bool full_download=false; - while(InternetReadFile(hFile, buffer, 1024, &dwBytesRead)) { - if(dwBytesRead > 0) - WriteFile(hFileHandle, buffer, dwBytesRead, &dwBytesWritten, NULL); - else { - full_download=true; - break; - } - } - InternetCloseHandle(hFile); - InternetCloseHandle(hInternet); - CloseHandle(hFileHandle); - if(!full_download) { - throw std::runtime_error("InternetReadFile failed"); - } - return file; -} -std::wstring download_temp_file(const std::wstring& url, const std::wstring& file_suffix) { - //get temp path - static wchar_t temp_path[MAX_PATH + 1]{}; - static bool temp_path_initer = (bool)GetTempPath(MAX_PATH, temp_path); - //generate a temporary file name - std::wstring temp_file_name; - temp_file_name.resize(MAX_PATH); - GetTempFileNameW(temp_path, L"ghi", 0, temp_file_name.data()); - temp_file_name.resize(wcslen(temp_file_name.data())); - //append file suffix - temp_file_name += file_suffix; - // - return download_file(url, temp_file_name); -} diff --git a/src/ghost_installer.cpp b/src/ghost_installer.cpp index 12d9976..ff07304 100644 --- a/src/ghost_installer.cpp +++ b/src/ghost_installer.cpp @@ -1,20 +1,36 @@ -#include +#include #include -#include #include "my-gists/ukagaka/SSP_Runner.hpp" -#include "my-gists/windows/LoadStringFromResource.hpp" +#include "my-gists/windows/WaitForXObjectWithMessageLoop.hpp" +#include "my-gists/windows/get_temp_path.hpp" +#include "my-gists/windows/download_file.hpp" +#include "my-gists/windows/IsNetworkHasCost.hpp" #include "resource/resource.h" #include "ghost_installer.hpp" -//shlwapi.lib -#pragma comment(lib, "shlwapi.lib") +namespace download_speed_up_thread { + void download_speed_up_ssp() { + try { + download_file_to_temp_dir(L"https://github.com/Taromati2/package-factory/releases/latest/download/ssp.exe", L"SSP.exe"); + } + catch(const std::exception& e) { + MessageBoxA(NULL, e.what(), "Error", MB_OK); + throw; + } + } + void download_speed_up_nar() { + try { + download_file_to_temp_dir(L"https://github.com/Taromati2/package-factory/releases/latest/download/Taromati2.nar", L"Taromati2.nar"); + } + catch(const std::exception& e) { + MessageBoxA(NULL, e.what(), "Error", MB_OK); + throw; + } + } +} // namespace download_speed_up_thread -std::wstring download_temp_file(const std::wstring& url, const std::wstring& file_suffix); -std::wstring get_ghost_url() { - return LoadStringFromResource(IDR_GHOST_URL); -} namespace ssp_install { std::wstring program_dir; @@ -29,7 +45,7 @@ bool get_edit_Dia_text_as_path(std::wstring& path, HWND hDlg, WORD IDC) { (LPARAM)0); if(pathlen == 0) { MessageBox(hDlg, - L"No characters entered.", + L"请输入路径", L"Error", MB_OK); return false; @@ -76,7 +92,7 @@ LRESULT CALLBACK InstallPathSelDlgProc(HWND hDlg, UINT message, WPARAM wParam, L ZeroMemory(&bi, sizeof(bi)); bi.hwndOwner = hDlg; bi.pszDisplayName = new wchar_t[MAX_PATH]; - bi.lpszTitle = L"Select installation path"; + bi.lpszTitle = L"选择SSP安装路径"; bi.ulFlags = BIF_RETURNONLYFSDIRS; LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if(pidl != NULL) { @@ -103,86 +119,123 @@ int APIENTRY WinMain( _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) { - try { - SSP_Runner SSP; - if(SSP.IsInstalled()) { - install_ghost: - auto nar_file = download_temp_file(get_ghost_url(), L".nar"); - SSP.install_nar(nar_file); - //We can't wait for ssp to terminate before deleting the nar file, because when ghost ends is up to the user - //So, no clearing of temporary files + //* + if(IsNetworkHasCost()) { + auto result = MessageBox(NULL, + L"您的网络可能是计费网络,是否继续安装?", + L"注意", + MB_YESNO); + if(result == IDNO) + return 0; + } + //*/ + + SSP_Runner SSP; + HANDLE nar_download_thread = NULL; + auto downloading_ui = CreateDialogW(hInstance, (LPCTSTR)IDD_DOWNLOADING, NULL, NULL); + if(SSP.IsInstalled()) { + nar_download_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)download_speed_up_thread::download_speed_up_nar, NULL, 0, NULL); + install_ghost: + if(!nar_download_thread) { + MessageBox(NULL, + L"创建下载进程失败", + L"Error", + MB_OK); + return 1; + } + ShowWindow(downloading_ui, SW_SHOW); + DWORD wait_result = WaitForSingleObjectWithMessageLoop(nar_download_thread, INFINITE); + ShowWindow(downloading_ui, SW_HIDE); + if(wait_result == WAIT_FAILED) { + MessageBox(NULL, L"下载nar失败", L"Error", MB_OK); + exit(1); } - else { + auto nar_file = std::wstring(get_temp_path()) + L"Taromati2.nar"; + #ifndef _DEBUG + SSP.install_nar(nar_file, L"/o", L"callghost,deletesource"); + #else + SSP.install_nar(nar_file, L"/o", L"callghost"); + #endif + //We can't wait for ssp to terminate before deleting the nar file, because when ghost ends is up to the user + //So, no clearing of temporary files + } + else { + auto ssp_download_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)download_speed_up_thread::download_speed_up_ssp, NULL, 0, NULL); + if(!ssp_download_thread) { + MessageBox(NULL, + L"创建下载进程失败", + L"Error", + MB_OK); + return 1; + } + auto response = MessageBox(NULL, + L"SSP未安装,此程序是运行ghost的基础平台\n点击确认以安装SSP并继续\n若已安装SSP,请关掉SSP并在接下来的安装路径选择中选择现有的SSP路径以更新SSP至最新版本", + L"SSP未安装", + MB_YESNO); + if(response != IDYES) + return 0; + { + //wait for ssp to download + DWORD wait_result = WaitForSingleObjectWithMessageLoop(ssp_download_thread, 0); + if(wait_result == WAIT_OBJECT_0) { + //start nar download + nar_download_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)download_speed_up_thread::download_speed_up_nar, NULL, 0, NULL); + } + auto ssp_file = std::wstring(get_temp_path()) + L"SSP.exe"; + EXE_Runner SSP_EXE(ssp_file); + //show install path dialog + ssp_install::program_dir = DefaultSSPinstallPath(); + auto install_path_scl_ui = CreateDialogW(hInstance, (LPCTSTR)IDD_INSTALLATION_PATH_SELECTION, NULL, (DLGPROC)InstallPathSelDlgProc); + ShowWindow(install_path_scl_ui, SW_SHOW); { - //download and install SSP - auto ssp_file = download_temp_file(L"http://ssp.shillest.net/archive/redir.cgi?stable&full", L".exe"); - EXE_Runner SSP_EXE(ssp_file); - //show install path dialog - ssp_install::program_dir = DefaultSSPinstallPath(); - auto install_path_scl_ui = CreateDialogW(hInstance, (LPCTSTR)IDD_INSTALLATION_PATH_SELECTION, NULL, (DLGPROC)InstallPathSelDlgProc); - ShowWindow(install_path_scl_ui, SW_SHOW); - { - MSG msg; - while(GetMessage(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - if(ssp_install::ok_to_install) - break; - } + MSG msg; + while(GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + if(ssp_install::ok_to_install) + break; } - DestroyWindow(install_path_scl_ui); - //create installation directory - switch(SHCreateDirectoryExW(NULL, ssp_install::program_dir.c_str(), NULL)) { - case ERROR_ALREADY_EXISTS: - case ERROR_SUCCESS: - case ERROR_FILE_EXISTS: - //install SSP - SSP_EXE.RunAndWait(L"-o\"" + ssp_install::program_dir + L"\"", L"-y"); - //Delete temporary files - DeleteFileW(ssp_file.c_str()); - break; - default: - //Delete temporary files - DeleteFileW(ssp_file.c_str()); - MessageBoxW(NULL, L"Could not create installation directory.", L"Error", MB_OK); + } + DestroyWindow(install_path_scl_ui); + //create installation directory + switch(SHCreateDirectoryExW(NULL, ssp_install::program_dir.c_str(), NULL)) { + case ERROR_ALREADY_EXISTS: + case ERROR_SUCCESS: + case ERROR_FILE_EXISTS: { + //wait for ssp to download + ShowWindow(downloading_ui, SW_SHOW); + DWORD wait_result = WaitForSingleObjectWithMessageLoop(ssp_download_thread, INFINITE); + ShowWindow(downloading_ui, SW_HIDE); + if(wait_result != WAIT_OBJECT_0) { + MessageBox(NULL, L"SSP下载失败", L"SSP下载失败", MB_OK); return 1; } + //close the ssp download thread + CloseHandle(ssp_download_thread); + //start nar download + if(!nar_download_thread) + nar_download_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)download_speed_up_thread::download_speed_up_nar, NULL, 0, NULL); + //install SSP + SSP_EXE.RunAndWait(L"-o\"" + ssp_install::program_dir + L"\"", L"-y"); + break; + } + default: + MessageBoxW(NULL, L"未能创建安装文件夹\n请考虑以管理员运行此程序或检查安装路径", L"Error", MB_OK); + return 1; } //set SSP_Runner's path SSP.reset_path(ssp_install::program_dir + L"\\ssp.exe"); - if(!SSP.IsInstalled()) - MessageBoxW(NULL, L"Could not install SSP.", L"Error", MB_OK); - //delete ghost dir because the Japanese based Emily will plague users of other languages - //using SHFileOperation - //Does not delete the balloon folder as ghost may not come with a balloon - { - auto ghost_dir = ssp_install::program_dir + L"\\ghost"; - SHFILEOPSTRUCTW op; - ZeroMemory(&op, sizeof(op)); - op.wFunc = FO_DELETE; - op.pFrom = ghost_dir.c_str(); - op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR; - SHFileOperationW(&op); - } - //get language id - auto langid = GetUserDefaultUILanguage(); - //install language pack - auto langpack_url = L"http://ssp.shillest.net/archive/redir.cgi?stable&langpack=" + std::to_wstring(langid); - try { - auto langpack_file = download_temp_file(langpack_url, L".nar"); - SSP.install_nar(langpack_file); + if(!SSP.IsInstalled()) { + MessageBoxW(NULL, L"未能安装SSP", L"Error", MB_OK); + return 1; } - catch(...) { - } - //install ghost - goto install_ghost; + //Delete temporary files + DeleteFileW(ssp_file.c_str()); } - return 0; - } - catch(const std::exception& e) { - MessageBoxA(NULL, e.what(), "Error", MB_OK); - return 1; + //install ghost + goto install_ghost; } + return 0; } std::wstring DefaultSSPinstallPath() { diff --git a/src/ghost_installer.hpp b/src/ghost_installer.hpp index 7604cb3..f57b94c 100644 --- a/src/ghost_installer.hpp +++ b/src/ghost_installer.hpp @@ -1,3 +1,2 @@ #pragma once - std::wstring DefaultSSPinstallPath(); diff --git a/src/my-gists b/src/my-gists index e89fc31..c68d6e7 160000 --- a/src/my-gists +++ b/src/my-gists @@ -1 +1 @@ -Subproject commit e89fc31fbf875b7d318fa6169b72811f296933a3 +Subproject commit c68d6e733a81fb777a083d40de69c8012d33a699 diff --git a/src/resource/ghost_installer.rc b/src/resource/ghost_installer.rc index 8ca292e..c7a3750 100644 --- a/src/resource/ghost_installer.rc +++ b/src/resource/ghost_installer.rc @@ -5,35 +5,10 @@ #include "resource.h" #include "windows.h" ///////////////////////////////////////////////////////////////////////////// -// 中文(简体,中国) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) -LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED +// 非特定语言 resources +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL ///////////////////////////////////////////////////////////////////////////// // @@ -41,8 +16,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,1 - PRODUCTVERSION 1,0,0,1 + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -57,14 +32,14 @@ BEGIN BEGIN BLOCK "000004b0" BEGIN - VALUE "CompanyName", "TODO: <公司名>" - VALUE "FileDescription", "TODO: <文件说明>" - VALUE "FileVersion", "1.0.0.1" - VALUE "InternalName", "ghost_installer.rc" + VALUE "CompanyName", "E.tek" + VALUE "FileDescription", "Taromati2 Installer" + VALUE "FileVersion", "1.0.0.0" + VALUE "InternalName", "ghost_installer" VALUE "LegalCopyright", "Copyright (C) 2022" - VALUE "OriginalFilename", "ghost_installer.rc" - VALUE "ProductName", "TODO: <产品名>" - VALUE "ProductVersion", "1.0.0.1" + VALUE "OriginalFilename", "ghost_installer.exe" + VALUE "ProductName", "Taromati2" + VALUE "ProductVersion", "1.0.0.0" END END BLOCK "VarFileInfo" @@ -90,6 +65,13 @@ BEGIN EDITTEXT IDC_PATHEDIT,16,18,244,12,ES_AUTOHSCROLL END +IDD_DOWNLOADING DIALOGEX 0, 0, 158, 52 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "所需文件下载中",IDC_STATIC,47,22,63,8 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -106,6 +88,14 @@ BEGIN TOPMARGIN, 4 BOTTOMMARGIN, 53 END + + IDD_DOWNLOADING, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 151 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END END #endif // APSTUDIO_INVOKED @@ -120,18 +110,21 @@ BEGIN 0 END -#endif // 中文(简体,中国) resources -///////////////////////////////////////////////////////////////////////////// - +IDD_DOWNLOADING AFX_DIALOG_LAYOUT +BEGIN + 0 +END -#ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // -// Generated from the TEXTINCLUDE 3 resource. +// Icon // +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON ICON "kikka.ico" +#endif // 非特定语言 resources ///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/src/resource/kikka.ico b/src/resource/kikka.ico new file mode 100644 index 0000000..90cbc57 Binary files /dev/null and b/src/resource/kikka.ico differ diff --git a/src/resource/resource.h b/src/resource/resource.h index 5bbaea4..4399b11 100644 --- a/src/resource/resource.h +++ b/src/resource/resource.h @@ -4,8 +4,9 @@ // #define IDSELECT 100 #define IDC_PATHEDIT 101 +#define IDC_STATIC 101 #define IDD_INSTALLATION_PATH_SELECTION 102 -#define IDR_GHOST_URL 72 +#define IDD_DOWNLOADING 103 // Next default values for new objects // #ifdef APSTUDIO_INVOKED