准备
- 安装
7z后,在官网下载LZMA SDK,然后下面几个文件拷贝到7z安装目录LZMA SDK7zS2.sfx7zS2con.sfx7zSD.sfx
压缩目标文件
-
准备好要打包的目标文件,放到一个文件夹
- 把独立的
UI程序放到这里,并改名为setup.exe
- 把独立的
-
在
7z安装目录下执行命令,把该文件夹里面的内容压缩成一个7z压缩包
|
1 2 3 |
rem 递归压缩 7z a aet.7z ./aet/*.* -r |
- 成功生成
aet.7z后,准备一个配置文件,如下
配置文件
config.txt
|
1 2 3 4 |
;!@Install@!UTF-8! InstallPath="C:\\Users\\Admin\\AppData\\Local\\Temp\\xunyoutt" RunProgram="setup.exe" ;!@InstallEnd@! |
|
1 2 3 4 5 |
;!@Install@!UTF-8! Title="Patch Tool" ExecuteFile="launcher.exe" ExecuteParameters="-startkey=1213113131311" ;!@InstallEnd@! |
|
1 2 3 4 5 |
;!@Install@!UTF-8! Title="7-Zip 4.00" BeginPrompt="Do you want to install the 7-Zip 4.00?" RunProgram="setup.exe" ;!@InstallEnd@! |
参数
关于解压路径
- 发现上面配置的
InstallPath是不生效的。 - 所以在
setup.exe里面去获取当前文件夹路径。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
BOOL CMainDlg::OnInitDialog(HWND hWnd, LPARAM lParam) { m_bLayoutInited = TRUE; TCHAR exeFullPath[MAX_PATH] = { 0 }; ::GetModuleFileName(NULL, exeFullPath, MAX_PATH); PathRemoveFileSpec(exeFullPath); PathAddBackslash(exeFullPath); m_strCurPath = exeFullPath; return 0; } |
关于InstallPath
- 时隔三年多,重新遇到了这个问题
- 虽然网上教程中经常可以看到这个配置,但是经实践发现从
7z官网下载的sdk确实对这个InstallPath没反应- 尝试了以下版本都不行:
lzma2500lzma2301lzma2107lzma1900lzma1604lzma920
- 解决:
- 从这个仓库
OlegScherbakov下载了增强版本7zsd_extra_170_3900.7z - 使用了
7zsd_All.sfx,可以识别到InstallPath
- 从这个仓库
配置文件二
概述
- 下午操作基于增强版
7zsd_extra_170_3900.7z
静默启动
|
1 2 3 4 5 6 |
;!@Install@!UTF-8! Title="我的应用程序安装" InstallPath="%%S\\Easy" GUIMode="2" RunProgram="Utils\\EasyRe.exe" ;!@InstallEnd@! |
命令行传参
- 方法一
- 命令行直接传参,
EasyRe可以收到
- 命令行直接传参,
|
1 2 3 4 5 6 |
;!@Install@!UTF-8! Title="我的应用程序安装" InstallPath="%%S\\Easy" GUIMode="2" RunProgram="Utils\\EasyRe.exe" ;!@InstallEnd@! |
|
1 |
inst.exe --source=aet |
- 方法二
- 中转一层,
launcher.bat位于Easy目录下
- 中转一层,
|
1 2 3 4 5 6 7 |
;!@Install@!UTF-8! Title="我的应用程序安装" InstallPath="%%S\\Easy" GUIMode="2" RunProgram="launcher.bat" ;!@InstallEnd@! |
|
1 2 3 |
@echo off start /b "" "%~dp0Utils\EasyRecycle.exe" %* |
|
1 |
inst.exe --source=aet |
build
|
1 2 3 4 5 |
@echo off "c:\Program Files (x86)\7-Zip\7z.exe" a temp.7z ./temp/*.* -r -mx=9 copy /b 7zsd_y.sfx + config.txt + temp.7z inst.exe |
生成安装包
- 执行下述命令
|
1 |
copy /b 7zS2.sfx + config.txt + aet.7z installer.exe |
- 这样,就会生成一个
installer.exe,双击运行,会启动launcher.exe,启动参数也是在配置文件里面指定了。
脚本
- 把压缩和生成
exe
|
1 2 3 4 5 |
@echo off 7z a xy.7z ./xunyou/*.* -r copy /b 7zS2.sfx + config.txt + xy.7z installer.exe del /q xy.7z |
setup.exe
- 这个
exe是用来给用户操作的一个UI,点了快速安装后,主要做了以下几件事情:- 计算相关文件的
md5 - 从解压路径把所有文件拷贝到用户选择的目标路径下
- 用之前算好的
md5,拼一个启动参数,去调起相关进程
- 计算相关文件的
判断路径
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
bool CMainDlg::IsValidDirectory() { auto str = m_strSelPath.GetBuffer(m_strSelPath.GetLength()); m_strSelPath.ReleaseBuffer(); PathAddBackslash(str); std::string strPath = to_string(str); std::regex r(R"(^([a-zA-Z]:|([a-zA-Z]:)?\\[^\/\:\*\?\""\<\>\|\,]*)$)"); if (std::regex_match(strPath, r)) { return true; } return false; } |
判断进程是否运行
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
bool CMainDlg::IsXunyouRunning() { std::vector<DWORD> process_id_list = GetProcessIDListByName("xunyou.exe"); if (process_id_list.size() < 1) { process_id_list = GetProcessIDListByName("kspeeder.exe"); if (process_id_list.size() < 1) return false; } return true; } std::vector<DWORD> CMainDlg::GetProcessIDListByName(const char* process_name) { std::vector<DWORD> processID_list; HANDLE process_handle; PROCESSENTRY32 process_entry32; assert(process_name); process_handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (process_handle != INVALID_HANDLE_VALUE) { process_entry32.dwSize = sizeof(PROCESSENTRY32); if (::Process32First(process_handle, &process_entry32)) { do { std::string tmp_str = to_string(process_entry32.szExeFile); if (0 == ::_stricmp(tmp_str.c_str(), process_name)) { processID_list.push_back(process_entry32.th32ProcessID); } } while (::Process32Next(process_handle, &process_entry32)); } ::CloseHandle(process_handle); } return processID_list; } |
杀进程
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void CMainDlg::KillXunyouProcess() { std::vector<DWORD> process_id_list = GetProcessIDListByName("xunyou.exe"); std::vector<DWORD> process_id_list_ex = GetProcessIDListByName("kspeeder.exe"); for each (auto var in process_id_list) { HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, var); if (hProcess != NULL) TerminateProcess(hProcess, 0); } for each (auto var in process_id_list_ex) { HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, var); if (hProcess != NULL) TerminateProcess(hProcess, 0); } } |
启动进程
- 启动进程的同时,创建事件和线程
- 线程用于监控启动的进程有没有结束,结束就设置事件有信号
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
BOOL CMainDlg::StartLauncher(const std::wstring& str) { auto temp = m_strSelPath; temp.Append(L"\\launcher.exe"); SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(SHELLEXECUTEINFOW); sei.fMask = SEE_MASK_FLAG_NO_UI; sei.lpFile = temp; sei.lpVerb = L"open"; sei.lpParameters = str.c_str(); sei.nShow = SW_SHOW; m_hEvt = ::CreateEventW(NULL, TRUE, FALSE, NULL); if (m_hEvt == NULL) { return false; } m_hThr = ::CreateThread(NULL, 0, StartWork, (LPVOID)m_hEvt, 0, NULL); if (m_hThr == NULL) { ::CloseHandle(m_hEvt); m_hEvt = NULL; return false; } return ::ShellExecuteEx(&sei); } |
- 在后面等待事件的触发
|
1 2 3 4 5 6 7 8 9 |
if (!QuickInstall()) { ::MessageBox(m_hWnd, L"请重新启动。", L"更新失败", MB_OK); break; } DWORD wait = ::WaitForSingleObject(m_hEvt, INFINITE); if (wait != WAIT_TIMEOUT) { is_destroy = true; } |
rapidjson读取json文件
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
void CMainDlg::ReadJson() { auto tmp_path = m_strSelPath; tmp_path.Append(L"start.json"); if (!PathFileExists(tmp_path)) { return; } wchar_t* temp_path = tmp_path.GetBuffer(tmp_path.GetLength()); tmp_path.ReleaseBuffer(); std::string str = to_string(temp_path); FILE* pFile = fopen(str.c_str(), "rb"); char buffer[4096] = { 0 }; rapidjson::FileReadStream is(pFile, buffer, sizeof(buffer)); rapidjson::Document doc; doc.ParseStream(is); fclose(pFile); if (doc.HasParseError()) { return; } if (!doc.HasMember("cmd")) { return; } rapidjson::Value value; value = doc["cmd"]; if (value.IsArray() && !value.Empty()) { for (rapidjson::SizeType i = 0; i < value.Size(); i++) { rapidjson::Value& v = value[i]; if (v.HasMember("exe") && v.HasMember("para")) { std::string exe = v["exe"].GetString(); std::string para = v["para"].GetString(); m_Map.insert(std::make_pair(exe, para)); } } } } |
删文件
start.json普通删除setup.exe由于走到这里时它正在运行,重启删除
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void CMainDlg::DelFiles() { if (m_strSelPath.IsEmpty()) { return; } auto temp1 = m_strSelPath, temp2 = m_strSelPath; temp1.Append(L"start.json"); ::DeleteFile(temp1); temp2.Append(L"setup.exe"); ::MoveFileEx(temp2, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } |
copy
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <experimental/filesystem> try { std::wstring from = m_strCurPath; std::wstring to = m_strSelPath; std::experimental::filesystem::path source = from; std::experimental::filesystem::path target_parent = to; auto target = target_parent / source.filename(); std::experimental::filesystem::create_directories(target); std::experimental::filesystem::copy(source, target, std::experimental::filesystem::copy_options::recursive); } catch (std::exception& e) { } |
替换ICON
方法一
resource hacker- 使用
resource hacker直接把以下二进制文件的icon替换成想要的icon7zS2.sfx7zS2con.sfx7zSD.sfx
方法二
resource hacker- 使用
resource hacker对7z打包出来的exe替换icon
声明:本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Windows线程同步相关03/10
- ♥ C++标准模板库编程实战_算法和随机数12/08
- ♥ gflags记述:记录210/09
- ♥ C++_函数模板、类模板、特化、模板元编程、SFINAE、概念06/22
- ♥ Skia总结概述11/15
- ♥ 51CTO:C++网络通信引擎架构与实现一09/09
