200 分求打包程序 代码!建设性意见也算, 分不够可再(1000分封顶)
解决方案 »
- 如何使用进度条控件,求高手指点
- 请教一个设计问题
- 软件开发中如何有效减少GDI对象的占用?
- 新人求教一个大数据文件处理问题!各位大侠帮帮忙吧
- 请教,如何把鼠标消息转化为键盘消息?
- 请问是斑竹就可以随便扣别人的分,删别人的贴子么?
- 谁能给我介绍一本关于 VC++与XML的书啊
- 关于VC中的对话框资源的问题
- 用VS2010.。里MFC编程基于对话框动态绘图的问题?
- 我在CView中创建了一个CListCtrl,向其中插入了两万条纪录,在DeleteAllItems()时要等半天才能完成,有没有快点的办法?
- 参数类型问题,给出思路有分.
- 接收数据后,为何我不能得到正确的端口号?如何不让系统进一步处理数据,而是直接丢弃?
个人认为实现起来非常困难
李安东
关键字: 自解压 自动安装程序 假如我的程序要调用一个setup.exe程序,自动安装一个软件,完成安装后再把临时文件全部删除,应怎样实现呢?虽然很简单,但有一个问题需要解决,就是如何判断何时已经安装完成了呢?当然可以用
//Wait for until it terminated:
while(GetExitCodeProcess(newinfo.hProcess,&dwExitCode)&&
dwExitCode==STILL_ACTIVE);
来等待setup.exe运行结束,但是问题可能并不这么简单,常常是setup.exe又调用了别的子进程(例如_delis和inst5176什么的),而setup.exe退出后,子进程并未退出,即任务仍未完成。因此这时删除临时文件和文件夹仍然会导致安装失败和删除文件失败。(我判断早期的WinRAR创建的TempMode自解压文件,在启动setup.ex后安装之所以会失败,可能就是因为判断错误,即在未完成安装时就把临时文件删除了。)
这个问题可以按如下方法解决(供参考):
1、用系统函数CreateEvent()创建一个事件hEvent;
2、启动释放在临时目录(比如C:\WINDOWS\TEMP\MYTEMP)下的setup.exe后,然后执行如下语句:
//Wait for the self-extract process exit:
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{ IsExit(); }
即先将事件hEvent复位到无信号状态,并循环调用IsExit()函数;
3、在IsExit()函数中列举系统中所有进程:
(1)、调用系统函数CreateToolhelp32Snapshot()并指定TH32CS_SNAPPROCESS参数,获取一个系统中所有进程的列表(snapshot);
(2)、调用系统函数Process32First()获取第一个进程的信息;
(3)、循环调用系统函数Process32Next()获取其余进程的信息。
上述函数调用中有一个参数lppe是一个PROCESSENTRY32类型的结构。lppe.th32ProcessID参数包含了获取的进程标识符;lppe.szExeFile为该进程的可执行文件路径和名称。
因此在上述处理过程中,每次获取lppe后均判断lppe.szExeFile 中的路径是否是安装程序所在的临时目录,如果不存在这样的进程,则说明安装已经完成,则调用SetEvent()函数,将hEvent事件设置为有信号,从而使第二步中的循环结束;
4、关闭事件句柄,删除安装程序的所有临时文件和文件夹(例如MYTEMP),完成安装。
注意:在调用列举进程的函数时必须添加#include <Tlhelp32.h>指令。
下面是示例代码(已调试通过):
// MySfx.cpp : Defines the entry point for the application.
//#include "stdafx.h"
#include "resource.h"// Foward declarations of functions included in this code module:
BOOL InitInstance(HINSTANCE, int);
void RemoveThem(char *strPath);
void IsExit();int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Perform application initialization:
return InitInstance (hInstance, nCmdShow);
}//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
#if defined(_DEBUG)
#define THISFILE_LENGTH 159785
#else
#define THISFILE_LENGTH 28672
#endifchar sPath[256];
HANDLE hEvent;BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
char sModule[256],sTemFile[256];
//Gets temporary directory:
::GetTempPath(255,sPath);
strcat(sPath,"Mytemp");
::CreateDirectory(sPath,NULL);
strcpy(sTemFile,sPath);
strcat(sTemFile,"\\Sfx.exe");
::GetModuleFileName(NULL,sModule,255); //Opens the module file:
HANDLE hFile=::CreateFile(sModule,GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hFile)return 0;
//Creates the temprory file:
HANDLE hFileTemp=::CreateFile(sTemFile,GENERIC_WRITE|GENERIC_READ,
0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hFileTemp)
{
::CloseHandle(hFile); return 0;
}
::SetFilePointer(hFile,THISFILE_LENGTH,NULL,FILE_BEGIN);
//Now begin to read and write:
while(TRUE)
{
BYTE buf[40*1024];
DWORD dwNumberOfBytesRead;
if(::ReadFile(hFile,buf,40*1024,&dwNumberOfBytesRead,NULL)==0)
break;
DWORD dwNumberOfBytesWritten;
if(dwNumberOfBytesRead>0)
if(!::WriteFile(hFileTemp,buf,dwNumberOfBytesRead,
&dwNumberOfBytesWritten,NULL))break;
if(dwNumberOfBytesRead<40*1024)break;
}//while(TRUE)
::CloseHandle(hFile);
::CloseHandle(hFileTemp); //Prepare to extract files and setup the application:
//Creates a auto-reset event object:
hEvent=::CreateEvent(
NULL, // SD
FALSE, // reset type
FALSE, // initial state
NULL // object name
); //Executes self-extract file to extract files:
STARTUPINFO info;
PROCESS_INFORMATION newinfo;
::GetStartupInfo(&info);
::CreateProcess(sTemFile,NULL,NULL,NULL,FALSE,
CREATE_DEFAULT_ERROR_MODE,NULL,sPath,&info,&newinfo);
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{
IsExit();
} //Executes setup:
strcpy(sTemFile,sPath);
strcat(sTemFile,"\\Setup.exe");
::CreateProcess(sTemFile,NULL,NULL,NULL,FALSE,
CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW,
NULL,sPath,&info,&newinfo);
//Wait for setup process and other started by it exit:
::ResetEvent(hEvent);
while(::WaitForSingleObject(hEvent,500)==WAIT_TIMEOUT)
{
IsExit();
}
::CloseHandle(hEvent);
//Remove tempary files and folders:
RemoveThem(sPath);
return FALSE;
}void RemoveThem(char *strPath)
{
char strTemFile[256];
strcpy(strTemFile,strPath);
strcat(strTemFile,"\\*.*");
WIN32_FIND_DATA FindFileData;
HANDLE hFind=FindFirstFile(strTemFile,&FindFileData);
if(hFind!=INVALID_HANDLE_VALUE)
while(TRUE)
{
if(FindFileData.cFileName[0]=='.')
{
if(!FindNextFile(hFind,&FindFileData))break;
continue;
}
strcpy(strTemFile,strPath);
strcat(strTemFile,"\\");
strcat(strTemFile,FindFileData.cFileName);
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
RemoveThem(strTemFile);//recursive call if it's a subdirectory.
else ::DeleteFile(strTemFile);//Delete it if it's a file.
if(!FindNextFile(hFind,&FindFileData))break;
}
::CloseHandle(hFind);
::RemoveDirectory(strPath);
}void IsExit()
{
//Enumerate current processes:
//This process don't exit until the processes belonged to setup are all terminated:
HANDLE hSnapshot;
PROCESSENTRY32 pe;
pe.dwSize=sizeof(pe);
BOOL blExist=FALSE;
size_t len=strlen(sPath); hSnapshot=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hSnapshot<0) goto L1;
if(::Process32First(hSnapshot,&pe)==FALSE)
{
::CloseHandle(hSnapshot); goto L1;
}
if(_strnicmp(sPath,pe.szExeFile,len)==0)
blExist=TRUE;
while(blExist==FALSE && ::Process32Next(hSnapshot,&pe))
{
if(_strnicmp(sPath,pe.szExeFile,len)==0)
{
blExist=TRUE; break;
}
}
::CloseHandle(hSnapshot);L1: if(blExist==FALSE) ::SetEvent(hEvent);
}本文的意图不是要开发一个工具软件(因为市面上已有此类工具),其主要目的是想与有兴趣的朋友一起切磋一下实现思路,说不定对某位朋友也许会有一点帮助(如需要完整代码可来信索取)。
*****************************************************************附注:1、感谢朋友们的鼓励,因为要源码的朋友较多,现在请您直接到下面去下载源代码:http://www.csdn.net/cnshare2、使用Sleep()函数确实更加简便,谢谢高手指点。
一、 使 用Visual C++ 编 程 生 成Setup 程 序
生 成Setup 程 序 最 直 接 的 方 法 当 然 是 通 过 编 程 来 实 现。 对 于Windows 平 台 来 说, 没 有 比Visual C++ 更 好 的 开 发 工 具 了( 原 因 很 简 单, 有 谁 能 比Microsoft 更 了 解Windows 平 台 呢 ?)。 下 面 的 例 程 就 是 使 用Visual C++ 5.0 编 译 完 成 的。
Setup 程 序 主 要 处 理 两 个 方 面 的 问 题 :
(1) 用 户 界 面。 评 价 一 个Setup 程 序 的 优 劣 时, 用 户 界 面 是 否 美 观 是 其 中 的 一 个 重 要 因 素。 此 外, 通 过 交 互 式 界 面 还 应 能 够 获 得 用 户 的 相 关 信 息( 比 如 目 标 目 录)。
(2) 文 件 拷 贝 与 程 序 组 的 生 成。 也 就 是 按 照 用 户 输 入 的 信 息, 生 成 相 应 的 目 录 并 完 成 文 件 拷 贝 功 能( 这 要 涉 及 到 解 压 缩 问 题)。 一 般 来 说, 还 应 包 括 将 可 执 行 文 件 的 图 标 添 加 到 指 定 的 程 序 组 中。
1、 为Setup 程 序 设 置 背 景
Setup 程 序 的 用 户 界 面 以 对 话 框 为 主, 不 过 若 有 美 丽 的 背 景 则 能 为 你 的 程 序 增 色 不 少。 你 可 以 选 择 一 个 合 适 的BMP 文 件, 将 它 插 入 到 工 程 文 件(project) 中, 并 通 过 重 载 主 窗 口 类 的OnPaint() 函 数 显 示 出 来。 值 得 注 意 的 是, 背 景 图 片 不 应 过 于 眩 目, 否 则 会 有 喧 宾 夺 主 之 感。 例 如, 要 加 入 的BMP 文 件 的ID 号 是IDB_BIT。 下 面 给 出 应 加 在OnPaint() 中 的 函 数。 void Background(CDC *pDC) { CDC * pmem;
CBitmap * pback;
CBitmap * pold;
BITMAP ff;
pmem=new CDC;
pbit=new CBitmap;
pbit->LoadBitmap(IDB_BIT);
pmem->CreateCompatibleDC(pDC);
pold=(CBitmap *) pmem->SelectObject(pbit);
pbit->GetObject(sizeof(ff),&ff); pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,pmem,0,0, MERGECOPY ); delete pmem->SelectObject(pold); delete pmem; return; } 2、 显 示 全 屏 效 果 一 般 的 主 窗 口 都 有 边 界(border), 如 果 你 更 欣 赏DOS 界 面 中 的 全 屏 效 果, 则 最 好 在 重 载CWnd:: PreCreateWindow(CREATESTRUCT&cs) 时 保 持cs.style 的 缺 省 值, 并 且 在 创 建 主 窗 口 时 使 用CreateEx(WS_EX_TO PMOST,AfxRegisterWndClass(CS_VREDRAW), NULL,WS_VISIBLE|WS_POPUP,0,0,(GetSystemMetrics (SM_CXSCREEN)),(GetSystemMetrics(SM_CYSCREEN)), HWND_DESKTOP,0);。 3、 保 存 公 用 参 量 通 过 对 话 框, 可 与 使 用 者 交 换 信 息。 那 么, 如 何 将 程 序 运 行 时 必 需 的 参 量( 比 如 说 安 装 目 录) 保 存 起 来 呢 ? 当 然, 可 以 生 成 一 个 配 置 文 件, 不 过 更 为 专 业 的 作 法 是 将 相 关 信 息 存 入 到 系 统 的INI 文 件 中。 如 果 开 发 平 台 是Windows 95, 则 一 切 都 将 变 得 很 简 单, 因 为 你 面 对 的 就 是win.ini 文 件, 该 文 件 在Windows 目 录 下。Visual C++ 提 供 了 如 下 的 一 组 函 数 来 操 作 该 文 件。 (1)CWinApp::GetProfileString CString GetProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = NULL ); 用 来 读 取lpszSection 区 域 内 的lpszEntry 参 数, 其 缺 省 值 为lpszDefault。 (2)CWinApp::WriteProfileString BOOL WriteProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue ); 用 来 写 入lpszSection 区 域 内 的lpszEntry 参 数, 其 值 为lpszValue。 如 果 你 的 开 发 平 台 是Winnt, 则 要 麻 烦 一 点。 假 如 你 的 变 量 保 存 在e:\\winnt\sdi.ini 中, 则 在 使 用 以 上 函 数 之 前 必 须 调 用 : free((void*)m_pszProfileName); m_pszProfileName=_tcsdup(_T("e:\\winnt\\sdi.ini")); 如 果 要 存 取 的 变 量 并 不 多, 则 也 可 将 它 们 保 存 在 注 册 关 键 字(registry key) 中。 假 如 你 的 变 量 保 存 在Moon 注 册 关 键 字( 一 般 是 你 公 司 的 名 字) 下, 则 在 使 用 以 上 函 数 之 前 必 须 调 用 : free((void*)m_pszRegistryKey); m_pszRegistryKey=_tcsdup(_T("HKEY_CURRENT_ USER\\Software\\moon")); 4、 文 件 的 拷 贝 与 解 压 缩 如 果 你 的 安 装 程 序 是 针 对 软 盘 的, 则 存 储 空 间 就 成 了 必 须 考 虑 的 问 题。 原 封 不 动 地 把 应 用 程 序 拷 贝 上 去 未 免 太 傻 了, 较 为 合 适 的 方 法 是 将 应 用 程 序 压 缩 在 软 盘 中, 安 装 时 再 解 压 缩 到 相 应 的 目 标 目 录 中。Visual C++ 提 供 了 一 套 以LZ 开 头 的 函 数, 用 来 操 作 用Compress 命 令 压 缩 的 文 件 : 你 可 以 用LzOpenFile() 打 开 原 文 件 和 目 标 文 件, 然 后 用LzCopy() 解 压 缩 拷 贝。 该 组 函 数 调 用Windows 系 统 的lzexpand.dll 动 态 链 接 库, 所 以 编 译 链 接 时 一 定 要 注 意 加 入 头 文 件lzexpand.h, 并 插 入 接 口 库lz32.lib。 还 有 个 更 为 简 单 的 办 法, 即 先 用 像arj.exe 这 类 的 共 享 压 缩 程 序 压 缩 原 程 序, 然 后 调 用system("arj ...") 来 完 成 解 压 缩, 整 个 解 压 缩 过 程 在 后 台 进 行, 用 户 不 会 知 道 你 到 底 用 的 是 什 么 方 法。 5、 显 示 拷 贝 进 度 很 多 专 业 安 装 程 序 在 进 行 文 件 拷 贝 时 都 会 显 示 进 度 栏, 甚 至 还 带 有 动 画。 如 何 实 现 这 种 效 果 呢 ? 办 法 是 在 拷 贝 的 同 时 创 建 一 个modeless 对 话 框。 这 种 对 话 框 用create() 函 数 创 建, 类 似 于 创 建 了 一 个 与 主 线 程 独 立 的 新 线 程。 这 样 就 可 在 拷 贝 文 件 的 同 时 在 对 话 框 中 显 示 出 拷 贝 进 度。Visual C++ 提 供 了 两 个 很 有 用 的 控 件, 即CAnimateCtrl 和 CProgressCtrl。 可 在 对 话 框 中 画 出 这 两 个 控 件, 并 用ClassWizard 加 入 相 应 的 类。 其 中,CAnimateCtrl 是 用 来 显 示.avi 文 件 的, 使 用 它 即 可 在 每 个 文 件 拷 贝 成 功 后 启 动 一 个“ 小 纸 片 飞 过” 的 文 件 ;CProgressCtrl 用 来 显 示 拷 贝 进 度, 当 各 个 拷 贝 成 功 后 使 表 示 进 度 的 蓝 条 前 进 到 适 当 的 位 置。 6、 程 序 组 和 程 序 项 的 生 成 程 序 组 的 生 成 实 际 上 是 与 负 责 管 理 程 序 组 的Program Manager 进 行DDE 对 话, 你 可 以 通 过 该 对 话 来 添 加 相 应 的 程 序 组 和 应 用 程 序 的 图 标。 同 时 由 于 该 对 话 是 单 向 的, 所 以 负 责 处 理 反 馈 消 息 的callback() 函 数 不 进 行 任 何 处 理。 下 面 给 出 其 源 程 序 及 其 用 法。 HDDEDATA CALLBACK DDECallback( UINT uType, // transaction type UINT uFmt, // clipboard data format HCONV hconv, // handle to the conversation HSZ hsz1, // handle to a string HSZ hsz2, // handle to a string HDDEDATA hdata, // handle to a global memory object DWORD dwData1, // transaction-specific data DWORD dwData2 // transaction-specific data ) {return NULL;} SendDdeCmd(LPSTR cmd) { LPDWORD dwDDEInst=0L; UINT ui; HSZ hszService,hszTopic,hszItem; HCONV hConv; HDDEDATA hexecData; ui=DdeInitialize((unsigned long *)&dwDDEInst, DDECallback,CBF_FAIL_ALLSVRXACTIONS,0L); if(ui!=DMLERR_NO_ERROR) {return FALSE;} hszService=DdeCreateStringHandle( (DWORD) dwDDEInst,"PROGMAN",CP_WINANSI); hszTopic=DdeCreateStringHandle((DWORD)dwDDEInst, "PROGMAN",CP_WINANSI); hszItem=DdeCreateStringHandle((DWORD)dwDDEInst,"GROUP", CP_WINANSI); hConv=DdeConnect((DWORD)dwDDEInst,hszService, hszTopic,NULL); DdeFreeStringHandle((unsigned long)dwDDEInst, hszService); DdeFreeStringHandle((unsigned long)dwDDEInst, hszTopic); DdeFreeStringHandle((unsigned long)dwDDEInst, hszItem); if(!hConv) return FALSE; hexecData=DdeCreateDataHandle((DWORD)dwDDEInst,(unsigned char *)cmd,lstrlen(cmd)+1,0,NULL,0,0); DdeClientTransaction((unsigned char *)hexecData, (DWORD)-1,hConv,NULL,0,XTYP_EXECUTE,1000,NULL); DdeDisconnect(hConv); DdeUninitialize((unsigned long)dwDDEInst); return TRUE; } 如 果 你 想 加 入 一 个 名 叫“demo” 的 程 序 组, 其 中 包 含 有 名 称 为“test” 的 程 序 项, 并 执 行c:\demo\test.exe, 使 用 的 是“test.ico” 图 标, 则 可 按 如 下 方 式 调 用 该 函 数 : SendDdeCmd("[CreateGroup (demo)] [AddItem (c:\demo\test.exe, test,c:\demo\test.ico)]")
这个打包软件不错!很多软件都是用这个软件打包的!!
我对打包软件分析,我觉得难道有几个1. 工程文件结果的构造,支持再次加载,修改
2. 打包脚本内容构造,涉及到 写一个 解释器
3. 对各个操作系统的一些底层操作,前面 free_card(痛并快乐着) 已经提到一个方面,还有注册表、目录等这些操作(当然这些相当较简单)再请各位大侠指点
那加两段代码1.把你的DOS操作发入autoexec.bat中
2.在windows的注册表或启动项中加入1个执行程序
程序功能1.删除autoexec.bat中的改变,删除注册表或启动项的改变
2.删除自己,删除自己有方法打包程序我想你可以这样做
1.选定你要打包的文件(相对目录路径),主要是主目录路径,而放入windows下system下的一些文件别外说明和要加入的东西入DAO的支持等
1.使用CZip类对主要目录路径进行压缩生成一个文件方入widnowsTemp目录中
对别外文什同样打包,并产生一个目录文件用来描述对应目录位置,
2.再生成exe文件包含这个文件(生成exe文件方法类文件组合方法)
3.exe文件作用,产生安装界面,把在exe文件中zip包提出放入在TEMP目录中,并根据在输入出的路径使用CUnZip类解压到指定目录,
http://www.vckbase.com/vckbase/vckbase12/src/BindFileSrc.zip
将以上文件改编一下就可以了,还可以先用CZip打一些文件先压缩,再捆绑。
我最近做完了项目,自己写了一个,实现文件目选择和文件COPY,然后加载运行微软的数据库组件,写注册表和创建快捷方式,使用VC的属性页做成向导。不过我的功能还差一点我不知道如何实现删除本应用程序。最近太忙。先不写了。我的是很容易的。就是把所有要用到的组件和程序都放到一个目录夹中。原封不动的实现了文件COPY。跟手工操作一样。楼主可以自己写写看。需要调试与反复测试。应该实现一般的应用程序安装是不难做的
在超星上下载《win2000核心编程精解》里面有详细的例子。
不妨一看。
这个打包软件不错!
1. 编写setup.exe
2. 编写*.ini文件记录setup.exe必要信息
3. 找一些工具将要安装的文件作成*.cab(此工具特点:必须提供cab的解压缩类或控件),此类工具很多