• 制作部署安装包:Inno Setup


    前一篇尝试Office 2003 VSTO的开发、部署有提到用VS开发一个简单的VSTO程序。打包C/S程序,我首先想到的是VS里自带的Setup Project。很遗憾,VS2012及后面的版本都剔除了Setup Project,改用InstallShield Limited Edition。

    Setup Project配置起来N麻烦,如:配置完成了之后,一旦修改了项目的东西然后重新生成,只有移除原来定义好的快捷方式、主输出,然后重新设置才能应用修改。而ISLE,对于一些简单的打包,基本上都是满足了的,而且整个操作过程都有界面,动动鼠标就行了;里面有部分功能是可以写代码定制的,不过要授权收费!这是我个人的使用心得,安装打包用得不多,有误之处,还请多多指教。

    无意中发现了Inno这个小东西(官网地址),然后深深地被它吸引了。麻雀虽小,五脏俱全,可以完全免费使用,最主要的是它允许自己使用Pascal语言编写定制脚本。

    网上挺多资料的,但很多都是雷同,且测试时部分有bug。下面贴上自己的一个代码栗子,参考了网上的几篇文章,然后修改整理的。

    需要注意的:

    1、打包指定文件(夹)时,该文件(夹)必须存在文件,不然编译时提示错误。路径(可使用相对路径)CheckOfficeConsoleDotNetFramework必须要存在文件,可以是任何类型的。

    Source: "CheckOfficeConsoleDotNetFramework*"; DestDir: "{tmp}"; Flags: ignoreversion 

    2、检测.net framework,如果不存在则从指定网址下载安装包时,需要用到isxdl.dll。这个dll需要下载并安装ISTool

    3、.net framework 的下载地址,我找到了除v3.0、v1版本以外的安装包地址,测试时都可用。未来微软网站也许会对这些资源包地址更新,所以不保证一直可用。

    4、安装过程中,可通过Inno的函数读取指定目录的.ini文件,并获得文件里的参数值。这个太赞了有木有!一来可以减少在Inno脚本里硬编码,二来可以在安装过程中初始化相关数据。如:Output目录有一个setup.ini文件,里面的内容为:

    [Custom]
    dotNetVersion =  v4.5

    Inno的读取代码:

    function GetCustomConfig(key:string):string;
    var 
      myValue:string;
    begin
      myValue:=ExpandConstant('{ini:{src}Setup.ini,Custom,'+key+'}')
      result := myValue;
    end;
    
    //使用
    //.....
     GetCustomConfig('dotNetVersion');
    //.....

    完整版:

    ; Script generated by the Inno Setup Script Wizard.
    ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
    ; Ivan 2015-1-30
    
    #define MyAppName "VSTO Excel by Ivan"
    #define MyAppVersion "1.0"
    #define MyAppPublisher "My Company, Inc."
    #define MyAppURL "http://www.IvanBy.com/"
    #define MyAppExeName "CheckOfficeConsole.exe"
    
    [Setup]
    ; NOTE: The value of AppId uniquely identifies this application.
    ; Do not use the same AppId value in installers for other applications.
    ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
    AppId={{6DFC5AE2-4844-4440-A6B3-284E15A14AEA}
    AppName={#MyAppName}
    AppVersion={#MyAppVersion}
    ;AppVerName={#MyAppName} {#MyAppVersion}
    AppPublisher={#MyAppPublisher}
    AppPublisherURL={#MyAppURL}
    AppSupportURL={#MyAppURL}
    AppUpdatesURL={#MyAppURL}
    DefaultDirName={pf}{#MyAppName}
    DefaultGroupName={#MyAppName}
    OutputBaseFilename=setup
    Compression=lzma
    SolidCompression=yes
    
    [Languages]
    Name: "english"; MessagesFile: "compiler:Default.isl"
    
    [Tasks]
    Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
    
    [Files]
    Source: C:Program Files (x86)ISToolisxdl.dll; Flags: dontcopy;
    Source: "CheckOfficeConsoleinReleaseCheckOfficeConsole.exe"; DestDir: "{app}"; Flags: ignoreversion
    Source: "CheckOfficeConsoleDotNetFramework*"; DestDir: "{tmp}"; Flags: ignoreversion 
    Source: "Excel2010SetupExcel2010SetupExpressDVD-5DiskImages*"; DestDir: "{app}2010"; Flags: ignoreversion recursesubdirs createallsubdirs
    ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
    
    [Icons]
    Name: "{group}{#MyAppName}"; Filename: "{app}{#MyAppExeName}"
    Name: "{commondesktop}{#MyAppName}"; Filename: "{app}{#MyAppExeName}"; Tasks: desktopicon
    Name: "{group}{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" 
    
    ;更改显示在程序中显示的消息文本
    [Messages]
    BeveledLabel=Ivan Code
    
    [Run]
    ;Filename: "{app}{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
    Filename: "{app}{#MyAppExeName}"
    
    [Code]
    var 
        dotNetDownloadNeeded: boolean;
        dotNetLocalPath:string;
      
    procedure isxdl_AddFile(URL, Filename: PAnsiChar);
    external 'isxdl_AddFile@files:isxdl.dll stdcall';
    function isxdl_DownloadFiles(hWnd: Integer): Integer;
    external 'isxdl_DownloadFiles@files:isxdl.dll stdcall';
    function isxdl_SetOption(Option, Value: PAnsiChar): Integer;
    external 'isxdl_SetOption@files:isxdl.dll stdcall';
    
    //检测是否存在特定版本的.net framework
    function IsDotNetDetected(version: string; service:cardinal): boolean;
    // Indicates whether the specified version and service pack of the .NET Framework is installed.
    //
    // version -- Specify one of these strings for the required .NET Framework version:
    //    'v1.1.4322'     .NET Framework 1.1
    //    'v2.0.50727'    .NET Framework 2.0
    //    'v3.0'          .NET Framework 3.0
    //    'v3.5'          .NET Framework 3.5
    //    'v4Client'     .NET Framework 4.0 Client Profile
    //    'v4Full'       .NET Framework 4.0 Full Installation
    //    'v4.5'          .NET Framework 4.5
    //
    // service -- Specify any non-negative integer for the required service pack level:
    //    0               No service packs required
    //    1, 2, etc.      Service pack 1, 2, etc. required
    var
        key: string;
        install, release, serviceCount: cardinal;
        check45, success: boolean;
    begin
        // .NET 4.5 installs as update to .NET 4.0 Full
        if version = 'v4.5' then begin
            version := 'v4Full';
            check45 := true;
        end else
            check45 := false;
    
        // installation key group for all .NET versions
        key := 'SOFTWAREMicrosoftNET Framework SetupNDP' + version;
       
        // .NET 3.0 uses value InstallSuccess in subkey Setup
        if Pos('v3.0', version) = 1 then begin
            success := RegQueryDWordValue(HKLM, key + 'Setup', 'InstallSuccess', install);
        end else begin
            success := RegQueryDWordValue(HKLM, key, 'Install', install);
        end;
    
        // .NET 4.0/4.5 uses value Servicing instead of SP
        if Pos('v4', version) = 1 then begin
            success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount);
        end else begin
            success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount);
        end;
    
        // .NET 4.5 uses additional value Release
        if check45 then begin
            success := success and RegQueryDWordValue(HKLM, key, 'Release', release);
            success := success and (release >= 378389);
        end;
    
        result := success and (install = 1) and (serviceCount >= service);
    end;
    
    //准备安装.net framework需要的条件(本地还是联网)
    function PreInstallDotNet(dotNetName:string;dotNetDownloadUrl:string):boolean;
    begin
        if (not IsAdminLoggedOn()) then begin
          MsgBox('您电脑安装 Microsoft .NET Framework 需要管理员权限', mbInformation, MB_OK);
          Result := false;
        end else begin
            dotNetLocalPath := ExpandConstant('{src}') + ''+dotNetName;
            if not FileExists(dotNetLocalPath)  then begin
                dotNetLocalPath := ExpandConstant('{tmp}') + ''+dotNetName; 
                if not FileExists(dotNetLocalPath)  then begin
                    isxdl_AddFile(dotNetDownloadUrl, dotNetLocalPath);
                    dotNetDownloadNeeded := true;
                end;
            end;
            
            SetIniString('install', 'dotnetRedist', dotNetLocalPath, ExpandConstant('{tmp}dep.ini'));
        end;
        
    end;
    
    //执行安装.net framework
    function DoInstallDotNet():boolean;
    var
      hWnd: Integer;
      ResultCode: Integer;
    begin
        result := true;
        hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
    
        // don’t try to init isxdl if it’s not needed because it will error on < ie 3
        if dotNetDownloadNeeded then begin
          isxdl_SetOption('label', '正在下载 Microsoft .NET Framework');
          isxdl_SetOption('des-c-r-i-p-tion', '您还未安装Microsoft .NET Framework. 请您耐心等待几分钟,下载完成后会安装到您的的计算机中。');
          if isxdl_DownloadFiles(hWnd) = 0 then result := false;
        end;
        
        if result = true  then begin
          if Exec(ExpandConstant(dotNetLocalPath), '/qb', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
             // handle success if necessary; ResultCode contains the exit code
             if not (ResultCode = 0) then begin
               result := false;
             end;
          end else begin
             // handle failure if necessary; ResultCode contains the error code
             result := false;
          end;
        end;
        
    end;
    
    //检测是否安装了等于大于指定版本的.net framework
    function IsIncludeFramework(version: string): boolean;
    var
        isInclued:boolean;     
    begin    
        
        //最高版本的
        if IsDotNetDetected('v4.5',0) then begin
            isInclued := true;         
        end else if version = 'v4.5' then begin
            PreInstallDotNet('dotNetFx45_Full_setup.exe','http://download.microsoft.com/download/B/A/4/BA4A7E71-2906-4B2D-A0E1-80CF16844F5F/dotNetFx45_Full_setup.exe');
        end else if IsDotNetDetected('v4Full',0) then begin
            isInclued := true;
        end else if version = 'v4Full' then begin
            PreInstallDotNet('dotNetFx40_Full_x86_x64.exe','http://download.microsoft.com/download/9/5/A/95A9616B-7A37-4AF6-BC36-D6EA96C8DAAE/dotNetFx40_Full_x86_x64.exe');
        end else if IsDotNetDetected('v4Client',0) then begin
            isInclued := true;     
        end else if version = 'v4Client' then begin
             PreInstallDotNet('dotNetFx40_Client_x86_x64.exe','http://download.microsoft.com/download/5/6/2/562A10F9-C9F4-4313-A044-9C94E0A8FAC8/dotNetFx40_Client_x86_x64.exe');
        end else if IsDotNetDetected('v3.5',0) then begin
            isInclued := true;     
        end else if Pos('v3.5',version) = 1 then begin
             PreInstallDotNet('dotNetFx35setup.exe','http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe');
        end else if IsDotNetDetected('v3.0',0) then begin
            isInclued := true;     
        end else if Pos('v3.0',version) = 1 then begin
             PreInstallDotNet('dotNetFx35setup.exe','http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe');
        end else if IsDotNetDetected('v2.0.50727',0) then begin
            isInclued := true;     
        end else if Pos('v2',version) = 1 then begin
            PreInstallDotNet('dotnetfx.exe','http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe');
        end else if IsDotNetDetected('v1.1.4322',0) then begin
            isInclued:= true;
        end else if Pos('v1',version)=1 then begin
            PreInstallDotNet('dotNetFx35setup.exe','http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe');
        end;
        
        result := isInclued;
    end;
    
    //取得自定义的配置
    //     Setup.ini
    //     [Custom]
    //   dotNetVersion =  v4.5
    function GetCustomConfig(key:string):string;
    var 
      myValue:string;
    begin
      myValue:=ExpandConstant('{ini:{src}Setup.ini,Custom,'+key+'}')
      result := myValue;
    end;
    
    function InitializeSetup(): Boolean;
    begin
        //do something 
    
      result:= true;
    end;
    
    function NextButtonClick(CurPage: Integer): Boolean;
    var 
      dotNetVersion:string;
    begin
        Result := true;
    
      if (CurPage = wpReady) then begin
    
        dotNetVersion := GetCustomConfig('dotNetVersion');
        if Length(dotNetVersion) = 0 then begin
           dotNetVersion := 'v4.0';
        end else if not (Pos('v',dotNetVersion) = 1) then begin
            dotNetVersion := 'v'+dotNetVersion;
        end;
         
        if not IsIncludeFramework(dotNetVersion) then begin
          if not DoInstallDotNet() then begin
             MsgBox('当前操作需要安装.NET Framework ' + dotNetVersion + '或以上版本。'#13#13
              '在尝试自动安装期间,似乎出现一些小问题(或用户取消了安装),'#13
              '请重试尝试安装。', mbInformation, MB_OK);
            result:= false;
          end;
        end;
    
      end;
      
    end;
    
    procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
    var
      ErrorCode: Integer;
    begin
      case CurUninstallStep of
        usUninstall:
          begin        
            // 正在卸载
          end;
        usPostUninstall:
          begin
            //卸载完成       
            ShellExec('open', 'http://www.IvanBy.com', '', '', SW_SHOW, ewNoWait, ErrorCode)
    
          end;
      end;
    end;
  • 相关阅读:
    C#中使用MATLAB
    各种插值法及效果图对比
    Visual Studio中你所不知道的智能感知
    C#中使用Surfer
    XCode中连接使用GitHub
    个人作业Week1
    个人作业Week3
    个人作业Week2
    第一次作业——subway
    执行ajax加载页面中的js总结
  • 原文地址:https://www.cnblogs.com/oneivan/p/4263307.html
Copyright © 2020-2023  润新知