VC++制作安装包

经过多少日夜的潜心编程,你的软件终于大功告成时,你一定想马上将她呈现在用户面前,于是她的包装(安装程序)便成了当务之急。当然你可以选用InstallShield来制作软件的安装程序,但在它带给你制作简便的同时,却给你匠心独具的软件赋予了千篇一律的包装。
  
  一个好的安装程序有助于增加软件的特色、提升软件的品位。本文介绍用Visual C++来制作通用安装程序的方法,由此你便拥有了一个独具特色的通用安装程序。
  
  1.在硬盘中创建安装目录
  
  软件由若干文件组成,我们通常将其中大部分文件拷贝至安装目录下,另有小部分文件须拷贝至特定的目录(如C:\Windows\System)下。首先应在硬盘中创建安装目录。Windows的API函数CreateDirectory()可创建目录。
  
  2.获取特定目录
  
  若软件中包含须拷贝至特定目录的文件,那么应获取所需的特定目录。GetWindowsDirectory()可得到Windows目录;GetSystemDirectory()可得到Windows的系统目录,SHGetSpecialFolderLocation()可得到Windows的特定目录(如Desktop、Start Menu\Programs、Recent、Help等)。
  
  3.拷贝文件
  
  创建安装目录和获取特定目录之后,将软件中的所有文件分别拷贝至这些目录中,CopyFile()可完成文件的拷贝。在拷贝文件的同时,最好用进度条显示文件拷贝的进度。
  
  4.创建快捷方式
  
  完成软件中所有文件的拷贝之后,在“桌面”或“程序”中创建快捷方式,使之与应用程序相关联。
  
  5.具体实现
  
  假定软件中有5个文件:Myprog.exe,Myprog.hlp,Myprog.dll,Example.dat及Myprog.vxd。其中前4个文件须拷贝至安装目录下,第5个文件须安装在Windows的系统目录下。
  
  5.1 创建基于对话框的项目
  
  项目名称为Setup,资源中对话框至少应有两个编辑控件IDC_EDIT1、IDC_EDIT2(对应的CString变量为m_strEdit1、m_strEdit2),分别为“安装目录”、“快捷方式名称”,并且将按钮“确定”改为“安装”,人工输入资源ID的名称IDC_PROGRESSBAR,作为进度条的ID。
  
  5.2 编写自定义函数
  
  编写自定义函数ReadConfig()和CreateShortcut()。其中ReadConfig()从安装配置文件Setup.cfg中读取安装信息,CreateShortcut()生成快捷方式。
  
  5.2.1 配置信息文件Setup.cfg
  
  [General]
  
   Topic=安装《我的程序》 //对话框的标题
  
   SetupDir=C:\Mysoft //安装目录
  
   Shortcut=我的程序 //快捷方式名称
  
   ProgName=Myprog.exe //应用程序名称
  
  [CopyFiles] //须拷贝的文件
  
   Source1=Myprog.exe //第1个源文件
  
   Target1=Myprog.exe //第1个目标文件(与源文件可不同名)
  
   Source2=Myprog.hlp
  
   Target2=Myprog.hlp
  
   Source3=Myprog.dll
  
   Target3=Myprog.dll
  
   Source4=Example.dat
  
   Target4=Example.dat
  
   Source5=Myprog.vxd
  
   Target5=>Sy\Myprog.vxd //该文件拷贝至Windows系统目录下
  
   ………… //拷贝的文件数目不限
  
   [End]
  
  5.2.2 读取配置信息函数
  
  BOOL CSetupDlg::ReadConfig(){//从Setup.cfg中读取配置信息
  
   CFile fileCfg;
  
   if(!fileCfg.Open("Setup.cfg",CFile::modeRead)){
  
   MessageBox("Can’t open file: Setup.cfg");//打开文件错误
  
   return false;
  
   }
  
   char pcBuf[1024];//假定文件长度小于1024
  
   fileCfg.Read(pcBuf,fileCfg.GetLength());//配置信息读入到pcBuf[]中
  
   CString strBuf=pcBuf;
  
   char pcItem[20][30]={"Topic","SetupDir","Shortcut","ProgName", "Source1","Target1","Source2","Target2","Source3","Target3","Source4","Target4","Source5","Target5","Source6","Target6","Source7","Target7","Source8","Target8"};//配置信息条目,这里列举20个,可根据需要增减
  
   int nLoc=-1;//各条目的起始位置
  
   for(int i=0;i<20;i++){
  
   nLoc=strBuf.Find(pcItem[i]);
  
   if(nLoc>=0){ //得到各条目内容char pcCont[][](CSetupDlg成员变量),每条内容最多为30个字符
  
  strcpy(pcCont[i],strBuf.Mid(nLoc+strlen(pcItem[i])+1,30));
  
   for(int j=0;j<30;j++){
  
   if(pcCont[i][j]==0x0d)//遇回车符,则置结束符
  
   pcCont[i][j]=0;
  
   }
  
   nCopyFiles=(i-2)/2;// 须拷贝的文件个数,CSetupDlg成员变量
  
   }
  
   }
  
   fileCfg.Close();
  
   return true;
  
  }
  
  5.2.3 创建快捷方式函数
  
  BOOL CSetupDlg::CreateShortcut(LPSTR szProgPath,LPSTR szShortcut)
  
  {// szProgPath为目标程序路径,szShortcut为快捷方式名称
  
   IShellLink* pISL;
  
   IPersistFile* pIPF;
  
   HRESULT hr;
  
   WCHAR wszShortcut[MAX_PATH];
  
   hr=CoCreateInstance(CLSID_ShellLink,0,1,IID_IShellLink,(void**)&pISL);
  
  //创建IShellLink接口
  
   if(FAILED(hr)) return false;
  
   pISL->SetPath(szProgPath);//设置目标应用程序
  
   pISL->SetShowCmd(…);//设置显示方式
  
   pISL->SetWorkingDirectory(…);//设置工作目录(其它设置参阅MSDN)
  
   hr=pISL->QueryInterface(IID_IPersistFile,(void**)&pIPF);
  
  //得到IPersistFile接口
  
   if(FAILED(hr)){
  
  pISL->Release();return false;}
  
   MultiByteToWideChar(0,0,szShortcut,-1,wszShortcut,MAX_PATH);//将char*转换为WCHAR*格式
  
   hr=pIPF->Save(wszShortcut,false);//保存快捷方式数据
  
   pIPF->Release();
  
   pISL->Release();
  
  if(FAILED(hr)) return false;
  
   SHChangeNotify(SHCNE_ALLEVENTS,SHCNF_PATH|SHCNF_FLUSH,szShortcut,0);//通知系统更新
  
   return true;
  
  }
  
  5.3 修改对话框初始化函数
  
   通过ClassWizard映射消息WM_INITDIALOG,生成OnInitDialog()函数。在其中增加初始化的内容。
  
  BOOL CSetupDlg::OnInitDialog()
  
  {
  
   …………//自动生成的内容
  
   nCopyFiles=0;//初始化须拷贝的文件数
  
   ReadConfig();//读取配置信息
  
   SetWindowText(pcCont[0]);//设置对话框标题
  
   SetDlgItemText(IDC_EDIT1,pcCont[1]);//初始化安装目录
  
   SetDlgItemText(IDC_EDIT2,pcCont[2]);//初始化快捷方式名称
  
   return true;
  
  }
  
  5.4 修改OnOK()函数
  
  对话框中的按钮“确定”改为“安装”,但其ID名称仍为IDOK,通过ClassWizard映射该消息,生成OnOK()函数。在其中增加的内容为:
  
  (1)创建、设置进度条
  
  (2)取得当前目录
  
  (3)取得Windows特定目录
  
  (4)创建安装目录
  
  (5)拷贝文件
  
  (6)生成快捷方式
  
  void CSetupDlg::OnOK()
  
  {
  
   GetDlgItemText(IDC_EDIT1,m_strEdit1);//将IDC_EDIT1的值赋给m_strEdit1
  
   GetDlgItemText(IDC_EDIT2,m_strEdit2);//将IDC_EDIT2的值赋给m_strEdit2
  
   GetDlgItem(IDOK)->EnableWindow(false);//不能第二次按“安装”
  
  //设置进度条(在对话框中添加进度条控件,为其添加控制变量m_progCtrl)
  
   m_prgCtrl.SetRange(0,100);//设置进度条的范围
  
   m_prgCtrl.SetPos(0); //设置进度条的初始位置
  
   //取得当前目录
  
   char szCurrentDir[MAX_PATH];
  
   GetCurrentDirectory(MAX_PATH,szCurrentDir);
  
   if(szCurrentDir[strlen(szCurrentDir)-1]=='\\') //去掉最后的'\'
  
   szCurrentDir[strlen(szCurrentDir)-1]=0;
  
   //取得Windows和系统目录
  
   char szWindowsDir[MAX_PATH];
  
   char szSystemDir[MAX_PATH];
  
   GetWindowsDirectory(szWindowsDir,MAX_PATH);
  
   GetSystemDirectory(szSystemDir,MAX_PATH);
  
   //取得桌面和程序的目录
  
   LPITEMIDLIST lpIIDL;
  
   char szDesktopDir[MAX_PATH];//桌面的目录
  
   SHGetSpecialFolderLocation(HWND_DESKTOP,CSIDL_DESKTOP,&lpIIDL);
  
   SHGetPathFromIDList(lpIIDL,szDesktopDir);
  
   char szProgramDir[MAX_PATH];//程序的目录
  
   SHGetSpecialFolderLocation(HWND_DESKTOP,CSIDL_PROGRAMS,&lpIIDL);
  
   SHGetPathFromIDList(lpIIDL,szProgramDir);
  
   //创建安装目录
  
   char szDir[MAX_PATH];
  
   if(m_strEdit1.GetAt(m_strEdit1.GetLength()-1)!='\\')
  
   m_strEdit1+='\\';//若m_strEdit1最后不为'\',则加上'\'
  
   for(int i=0;i<M_STREDIT1.GETLENGTH();I++){ 目录必须逐级创建
  
   if(m_strEdit1.GetAt(i)=='\\'){
  
   strcpy(szDir,m_strEdit1);
  
   szDir[i]=0;
  
   CreateDirectory(szDir,NULL);
  
   }
  
   }
  
   m_strEdit1=m_strEdit1.Left(m_strEdit1.GetLength()-1); //去掉最后的'\'
  
   //拷贝文件
  
   char szSourceFile[MAX_PATH];
  
   char szTargetFile[MAX_PATH];
  
   for(i=0;i<NCOPYFILES;I++){
  
   sprintf(szSourceFile,"%s\\%s",szCurrentDir,pcCont[i*2+4]);
  
   if(pcCont[i*2+5][0]=='>' && pcCont[i*2+5][3]=='\\'){//拷贝至特定目录下
  
  if(pcCont[i*2+5][1]=='W' && pcCont[i*2+5][2]=='i')//Windows目录
  
   sprintf(szTargetFile,"%s\\%s",szWindowsDir,&pcCont[i*2+5][4]);
  
   else if(pcCont[i*2+5][1]=='S'&&pcCont[i*2+5][2]=='y')//System目录
  
   else return;
  
   }
  
   else //拷贝至安装目录下
  
   sprintf(szTargetFile,"%s\\%s",m_strEdit1,pcCont[i*2+5]);
  
   if(!CopyFile(szSourceFile,szTargetFile,FALSE)){
  
   char pcMessage[50];
  
   sprintf(pcMessage,"拷贝文件 %s 失败",pcCont[i*2+4]);
  
   MessageBox(pcMessage,"错误信息",MB_ICONERROR|MB_OK);
  
   return;
  
   }
  
   m_prgCtrl.SetPos((i+1)*100/nCopyFiles);//显示拷贝文件的进度
  
   }
  
   //创建快捷方式
  
   char szProgPath[MAX_PATH];//应用程序的路径全名
  
   sprintf(szProgPath,"%s\\%s",m_strEdit1,pcCont[3]);
  
   char szShortcut[MAX_PATH];//快捷方式名称
  
   //在桌面创建快捷方式
  
   sprintf(szShortcut,"%s\\%s.lnk",szDesktopDir,m_strEdit2);
  
   if(!CreateShortcut(szProgPath,szShortcut)) return;
  
   //在程序中创建快捷方式
  
   sprintf(szShortcut,"%s\\%s.lnk",szProgramDir,m_strEdit2);
  
   if(!CreateShortcut(szProgPath,szShortcut)) return;
  
   CDialog::OnOK();//关闭安装窗口
  
  }
  
  5.5 定制安装界面
  
  前面介绍了制作安装程序的基本方法,为了使安装程序独具特色,应在界面上下些功夫。如通过重载OnEraseBkgnd()函数,在其中加入显示位图的代码,可制作非常漂亮的安装界面。又如映射WM_CTLCOLOR消息,在生成的函数OnCtlColor()中增加设置文本显示属性的代码,可改变显示文本及背景的颜色,进一步美化安装界面。
  
  5.6 安装程序的使用
  
   将上述项目编译链接成发行版的应用程序Setup.exe,须与配置文件Setup.cfg配对使用。在制作安装盘时,首先编辑Setup.cfg文件,以纯文本格式存盘,再将Setup.exe、Setup.cfg与须安装的其它文件一同拷入安装盘,运行Setup.exe即可实现软件的安装。
  
  6.说明
  
   本程序在Windows 98(中文版)、Visual C++ 6.0环境下编译通过。

你可能感兴趣的:(编程,windows,System,Path,vc++,menu)