我目前正在安装.NET Framework 4.6.2作为PreparetoInstall事件函数的先决条件,以便我可以获取退出代码,设置NeedsReboot状态,或者在安装失败时中止.我的代码在下面,这一切都正常.
var
  PreparetoInstallLabel: TNewStaticText;
  PreparetoInstallProgressBar: TNewProgressBar;
  intDotNetResultCode: Integer;
  CancelWithoutPrompt,AbortInstall: Boolean;

function InitializeSetup(): Boolean;
begin
  Result := True;
  OverwriteDB := False;
  CancelWithoutPrompt := False;
  AbortInstall := False;
end;

function PreparetoInstall(var NeedsRestart: Boolean): String;
var
  intResultCode: Integer;
  strInstallType: String;
begin
  if not IsDotNet45Installed and IsWindows7Sp1OrAbove then
    begin
      HidePreparetoInstallGuiControls;
      PreparetoInstallLabel.Caption := 'Installing Microsoft .NET Framework 4.6.2...';
      ShowPreparetoInstallGuiControls;
      ExtractTemporaryFile('NDP462-KB3151800-x86-x64-AllOS-ENU.exe');
      if WizardSilent = True then
        begin
          strInstallType := '/q';
        end
      else
        begin
          strInstallType := '/passive';
        end;
      Exec(ExpandConstant('{tmp}\NDP462-KB3151800-x86-x64-AllOS-ENU.exe'),strInstallType + ' /norestart','',SW_SHOW,ewWaitUntilTerminated,intDotNetResultCode);
      if (intDotNetResultCode = 0) or (intDotNetResultCode = 1641) or (intDotNetResultCode = 3010) then 
        begin
          Log('Microsoft .NET Framework 4.6.2 installed successfully.' + #13#10 + 'Exit Code: ' + IntToStr(intDotNetResultCode));
          CancelWithoutPrompt := False;
          AbortInstall := False;
        end
      else
        begin
          if WizardSilent = True then
            begin
              Log('Microsoft .NET Framework 4.6.2 Failed to install.' + #13#10 + 'Exit Code: ' + IntToStr(intDotNetResultCode) + #13#10 + 'Setup aborted.');
            end
          else
            begin
              MsgBox('Microsoft .NET Framework 4.6.2 Failed to install.' + #13#10 + #13#10 +
                'Exit Code: ' + IntToStr(intDotNetResultCode) + #13#10 + #13#10 +
                'Setup aborted. Click Next or Cancel to exit,or Back to try again.',mbCriticalError,MB_OK);
            end;
          PreparetoInstallProgressBar.Visible := False;
          PreparetoInstallLabel.Caption := 'Microsoft .NET Framework 4.6.2 Failed to install.' + #13#10 + #13#10 + 'Exit Code: ' + IntToStr(intDotNetResultCode) + #13#10 + #13#10 + 'Setup aborted. Click Next or Cancel to exit,or Back to try again.';
          CancelWithoutPrompt := True;
          AbortInstall := True;
          Abort;
        end;
    end;
end;

procedure InitializeWizard();
begin
//Define the label for the Preparing to Install page
  PreparetoInstallLabel := TNewStaticText.Create(WizardForm);
  with PreparetoInstallLabel do
    begin
      Visible := False;
      Parent := WizardForm.PreparingPage;
      Left := WizardForm.StatusLabel.Left;
      Top := WizardForm.StatusLabel.Top;
    end;
//Define Progress Bar for the Preparing to Install Page
  PreparetoInstallProgressBar := TNewProgressBar.Create(WizardForm);
  with PreparetoInstallProgressBar do
    begin
      Visible := False;
      Parent := WizardForm.PreparingPage;
      Left := WizardForm.ProgressGauge.Left;
      Top := WizardForm.ProgressGauge.Top;
      Width := WizardForm.ProgressGauge.Width;
      Height := WizardForm.ProgressGauge.Height;
      PreparetoInstallProgressBar.Style := npbstMarquee;
    end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep = ssInstall then
    begin
      if AbortInstall = True then
        begin
          Abort;
        end;
    end;
end;

目前,我使用/ q或/ passive将安装类型设置为静默或无人值守,以控制.NET Framework安装程序显示的可见GUI数量,具体取决于Inno安装程序的运行方式以及使用Marquee样式进度条表明事情正在发生.但是,从Microsoft文档here中可以看出,可以使用/ pipe开关让.NET Framework安装程序报告它的安装进度,这可能允许它以交互方式更新实际进度的正常样式进度条.这意味着.NET Framework安装程序可以完全隐藏,而Inno Setup用于指示相对进度,这是一个更加整洁的解决方案.不幸的是,我不知道C,我只是一个新手程序员.因此,任何人都可以确认是否可以使用Inno Setup,如果可以,可以尝试如何使用它?

解决方法

下面显示了Pascal Script实现的代码
How to: Get Progress from the .NET Framework 4.5 Installer
[Files]
Source: "NDP462-KB3151800-x86-x64-AllOS-ENU.exe"; Flags: dontcopy

[Code]

{ Change to unique names }    
const
  SectionName = 'MyProgSetup';
  EventName = 'MyProgSetupEvent';

const
  INFINITE = 65535;
  WAIT_OBJECT_0 = 0;
  WAIT_TIMEOUT = $00000102;
  FILE_MAP_WRITE = $0002;
  E_PENDING = $8000000A;
  S_OK = 0;
  MMIO_V45 = 1;
  MAX_PATH = 260;
  SEE_MASK_NOCLOSEPROCESS = $00000040;
  INVALID_HANDLE_VALUE = -1;
  PAGE_READWRITE = 4;
  MMIO_SIZE = 65536;

type
  TMmioDataStructure = record
    DownloadFinished: Boolean; { download done yet? }
    InstallFinished: Boolean; { install done yet? }
    DownloadAbort: Boolean; { set downloader to abort }
    InstallAbort: Boolean; { set installer to abort }
    DownloadFinishedResult: Cardinal; { resultant HRESULT for download }
    InstallFinishedResult: Cardinal; { resultant HRESULT for install }
    InternalError: Cardinal;
    CurrentItemStep: array[0..MAX_PATH-1] of WideChar;
    DownloadSoFar: Byte; { download progress 0 - 255 (0 to 100% done) }
    InstallSoFar: Byte; { install progress 0 - 255 (0 to 100% done) }
    { event that chainer 'creates' and chainee 'opens'to sync communications }
    EventName: array[0..MAX_PATH-1] of WideChar; 

    Version: Byte; { version of the data structure,set by chainer. }
                   { 0x0 : .Net 4.0 }
                   { 0x1 : .Net 4.5 }

    { current message being sent by the chainee,0 if no message is active }
    MessageCode: Cardinal; 
    { chainer's response to current message,0 if not yet handled }
    MessageResponse: Cardinal; 
    { length of the m_messageData field in bytes }
    MessageDataLength: Cardinal; 
    { variable length buffer,content depends on m_messageCode }
    MessageData: array[0..MMIO_SIZE] of Byte; 
  end;

function CreateFileMapping(
  File: THandle; Attributes: Cardinal; Protect: Cardinal;
  MaximumSizeHigh: Cardinal; MaximumSizeLow: Cardinal; Name: string): THandle;
  external 'CreateFileMappingW@kernel32.dll stdcall';

function CreateEvent(
  EventAttributes: Cardinal; ManualReset: Boolean; InitialState: Boolean;
  Name: string): THandle;
  external 'CreateEventW@kernel32.dll stdcall';

function CreateMutex(
  MutexAttributes: Cardinal; InitialOwner: Boolean; Name: string): THandle;
  external 'CreateMutexW@kernel32.dll stdcall';

function WaitForSingleObject(
  Handle: THandle; Milliseconds: Cardinal): Cardinal;
  external 'WaitForSingleObject@kernel32.dll stdcall';

function MapViewOfFile(
  FileMappingObject: THandle; DesiredAccess: Cardinal; FileOffsetHigh: Cardinal;
  FileOffsetLow: Cardinal; NumberOfBytesToMap: Cardinal): Cardinal;
  external 'MapViewOfFile@kernel32.dll stdcall';

function ReleaseMutex(Mutex: THandle): Boolean;
  external 'ReleaseMutex@kernel32.dll stdcall';

type
  TShellExecuteInfo = record
    cbSize: DWORD;
    fMask: Cardinal;
    Wnd: HWND;
    lpVerb: string;
    lpFile: string;
    lpParameters: string;
    lpDirectory: string;
    nShow: Integer;
    hInstApp: THandle;    
    lpIDList: DWORD;
    lpClass: string;
    hkeyClass: THandle;
    dwHotKey: DWORD;
    hMonitor: THandle;
    hProcess: THandle;
  end;

function ShellExecuteEx(var lpExecInfo: TShellExecuteInfo): BOOL; 
  external 'ShellExecuteExW@shell32.dll stdcall';

function GetExitCodeProcess(Process: THandle; var ExitCode: Cardinal): Boolean;
  external 'GetExitCodeProcess@kernel32.dll stdcall';

procedure copyPointerToData(
  var Destination: TMmioDataStructure; Source: Cardinal; Length: Cardinal);
  external 'RtlMoveMemory@kernel32.dll stdcall';

procedure copyDataToPointer(
  Destination: Cardinal; var Source: TMmioDataStructure; Length: Cardinal);
  external 'RtlMoveMemory@kernel32.dll stdcall';

var
  FileMapping: THandle;
  EventChaineeSend: THandle;
  EventChainerSend: THandle;
  Mutex: THandle;
  Data: TMmioDataStructure;
  View: Cardinal;

procedure LockDataMutex;
var
  R: Cardinal;
begin
  R := WaitForSingleObject(Mutex,INFINITE);
  Log(Format('WaitForSingleObject = %d',[Integer(R)]));
  if R <> WAIT_OBJECT_0 then
    RaiseException('Error waiting for mutex');
end;

procedure UnlockDataMutex;
var
  R: Boolean;
begin
  R := ReleaseMutex(Mutex);
  Log(Format('ReleaseMutex = %d',[Integer(R)]));
  if not R then
    RaiseException('Error releasing waiting for mutex');
end;

procedure ReadData;
begin
  copyPointerToData(Data,View,MMIO_SIZE);
end;

procedure WriteData;
begin
  copyDataToPointer(View,Data,MMIO_SIZE);
end;

procedure InitializeChainer;
var
  I: Integer;
begin
  Log('Initializing chainer');  

  FileMapping :=
    CreateFileMapping(
      INVALID_HANDLE_VALUE,PAGE_READWRITE,MMIO_SIZE,SectionName);
  Log(Format('FileMapping = %d',[Integer(FileMapping)]));
  if FileMapping = 0 then
    RaiseException('Error creating file mapping'); 

  EventChaineeSend := CreateEvent(0,False,EventName);
  Log(Format('EventChaineeSend = %d',[Integer(EventChaineeSend)]));
  if EventChaineeSend = 0 then
    RaiseException('Error creating chainee event'); 

  EventChainerSend := CreateEvent(0,EventName + '_send');
  Log(Format('EventChainerSend = %d',[Integer(EventChainerSend)]));
  if EventChainerSend = 0 then
    RaiseException('Error creating chainer event'); 

  Mutex := CreateMutex(0,EventName + '_mutex');
  Log(Format('Mutex = %d',[Integer(Mutex)]));
  if Mutex = 0 then
    RaiseException('Error creating mutex'); 

  View :=
    MapViewOfFile(FileMapping,FILE_MAP_WRITE,0);
  if View = 0 then
    RaiseException('Cannot map data view');
  Log('Mapped data view');

  LockDataMutex;

  ReadData;

  Log('Initializing data');  
  for I := 1 to Length(EventName) do
    Data.EventName[I - 1] := EventName[I];
  Data.EventName[Length(EventName)] := #$00;

  { Download specific data }
  Data.DownloadFinished := False;
  Data.DownloadSoFar := 0;
  Data.DownloadFinishedResult := E_PENDING;
  Data.DownloadAbort := False;

  { Install specific data }
  Data.InstallFinished := False;
  Data.InstallSoFar := 0;
  Data.InstallFinishedResult := E_PENDING;
  Data.InstallAbort := False;

  Data.InternalError := S_OK;

  Data.Version := MMIO_V45;
  Data.MessageCode := 0;
  Data.MessageResponse := 0;
  Data.MessageDataLength := 0;

  Log('Initialized data');  

  WriteData;

  UnlockDataMutex;

  Log('Initialized chainer');  
end;

var
  Progresspage: TOutputProgressWizardPage;

procedure InstallNetFramework;
var
  R: Cardinal;
  ExecInfo: TShellExecuteInfo;
  ExitCode: Cardinal;
  InstallError: string;
  Completed: Boolean;
  Progress: Integer;
begin
  ExtractTemporaryFile('NDP462-KB3151800-x86-x64-AllOS-ENU.exe');

  { Start the installer using ShellExecuteEx to get process ID }
  ExecInfo.cbSize := SizeOf(ExecInfo);
  ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
  ExecInfo.Wnd := 0;
  ExecInfo.lpFile := ExpandConstant('{tmp}\NDP462-KB3151800-x86-x64-AllOS-ENU.exe');
  ExecInfo.lpParameters := '/pipe ' + SectionName + ' /chainingpackage mysetup /q';
  ExecInfo.nShow := SW_HIDE;

  if not ShellExecuteEx(ExecInfo) then
    RaiseException('Cannot start .NET framework installer');

  Log(Format('.NET framework installer started as process %x',[ExecInfo.hProcess]));

  Progress := 0;
  { displaying indefinite progress while the framework installer is initializing }
  Progresspage.ProgressBar.Style := npbstMarquee;
  Progresspage.SetProgress(Progress,100);
  Progresspage.Show;
  try
    Completed := False;

    while not Completed do
    begin
      { Check if the installer process has finished already }
      R := WaitForSingleObject(ExecInfo.hProcess,0);
      if R = WAIT_OBJECT_0 then
      begin
        Log('.NET framework installer completed');
        Completed := True;
        if not GetExitCodeProcess(ExecInfo.hProcess,ExitCode) then
        begin
          InstallError := 'Cannot get .NET framework installer exit code';
        end
          else
        begin
          Log(Format('Exit code: %d',[Integer(ExitCode)]));
          if ExitCode <> 0 then
          begin
            InstallError :=
              Format('.NET framework installer Failed with exit code %d',[ExitCode]);
          end;
        end;
      end
        else
      if R <> WAIT_TIMEOUT then
      begin
        InstallError := 'Error waiting for .NET framework installer to complete';
        Completed := True;
      end
        else
      begin
        { Check if the installer process has signaled progress event }
        R := WaitForSingleObject(EventChaineeSend,0);
        if R = WAIT_OBJECT_0 then
        begin  
          Log('Got event from the installer');
          { Read progress data }
          LockDataMutex;
          ReadData;
          Log(Format(
            'DownloadSoFar = %d,InstallSoFar = %d',[
              Data.DownloadSoFar,Data.InstallSoFar]));
          Progress := Integer(Data.InstallSoFar) * 100 div 255;
          Log(Format('Progress = %d',[Progress]));
          UnlockDataMutex;
          { Once we get any progress data,switch to definite progress display }
          Progresspage.ProgressBar.Style := npbstnormal;
          Progresspage.SetProgress(Progress,100);
        end
          else
        if R <> WAIT_TIMEOUT then
        begin
          InstallError := 'Error waiting for .NET framework installer event';
          Completed := True;
        end
          else
        begin
          { Seemingly pointless as progress did not change,}
          { but it pumps a message queue as a side effect }
          Progresspage.SetProgress(Progress,100);
          Sleep(100);
        end;
      end;
    end;
  finally
    Progresspage.Hide;
  end;

  if InstallError <> '' then
  begin 
    { RaiseException does not work properly while TOutputProgressWizardPage is shown }
    RaiseException(InstallError);
  end;
end;

function InitializeSetup(): Boolean;
begin
  InitializeChainer;

  Result := True;
end;

procedure InitializeWizard();
begin
  Progresspage := CreateOutputProgresspage('Installing .NET framework','');
end;

您可以像下面一样使用它,也可以在安装程序进程的任何其他位置使用它.

function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;

  if CurPageID = wpReady then
  begin
    try
      InstallNetFramework;
    except
      MsgBox(GetExceptionMessage,mbError,MB_OK);
      Result := False;
    end;
  end;
end;

以下屏幕截图显示了Inno Setup中的“进度页面”如何链接到.NET框架安装程序(当然,.NET框架安装程序被/ q开关隐藏,它只是暂时显示以获取屏幕截图).

我已经成功测试了代码

> dotnetfx45_full_x86_x64.exe(.NET framework 4.5 – 离线安装程序)
> NDP462-KB3151800-x86-x64-AllOS-ENU.exe(.NET framework 4.6.2 – 离线安装程序)

请注意,代码仅考虑InstallSoFar,因为上面的两个安装程序都是脱机的.对于在线安装程序,也应考虑DownloadSoFar.实际上甚至离线安装程序也会下载一些东西.

ShellExecuteEx代码取自Inno Setup Exec() function Wait for a limited time.

inno-setup – Inno Setup从.NET Framework 4.5(或更高版本)安装程序获取进度以更新进度条位置的更多相关文章

  1. canvas中普通动效与粒子动效的实现代码示例

    canvas用于在网页上绘制图像、动画,可以将其理解为画布,在这个画布上构建想要的效果。本文详细的介绍了粒子特效,和普通动效进行对比,非常具有实用价值,需要的朋友可以参考下

  2. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. canvas学习和滤镜实现代码

    这篇文章主要介绍了canvas学习和滤镜实现代码,利用 canvas,前端人员可以很轻松地、进行图像处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  4. localStorage的过期时间设置的方法详解

    这篇文章主要介绍了localStorage的过期时间设置的方法详解的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. 详解HTML5 data-* 自定义属性

    这篇文章主要介绍了详解HTML5 data-* 自定义属性的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. HTML5 WebSocket实现点对点聊天的示例代码

    这篇文章主要介绍了HTML5 WebSocket实现点对点聊天的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. HTML5的postMessage的使用手册

    HTML5提出了一个新的用来跨域传值的方法,即postMessage,这篇文章主要介绍了HTML5的postMessage的使用手册的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. 教你使用Canvas处理图片的方法

    本篇文章主要介绍了教你使用Canvas处理图片的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  9. 关于h5中的fetch方法解读(小结)

    这篇文章主要介绍了关于h5中的fetch方法解读(小结),fetch身为H5中的一个新对象,他的诞生,是为了取代ajax的存在而出现,有兴趣的可以了解一下

  10. 浅谈HTML5 FileReader分布读取文件以及其方法简介

    本篇文章主要介绍了浅谈HTML5 FileReader分布读取文件以及其方法简介,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

随机推荐

  1. delphi – 主窗口按进程名称处理

    DelphiXe,Win7x64如何从进程名称(exe文件的完整路径)获取主窗口句柄,或至少一个类或窗口名称(如果该进程只有一个窗口).例:解决方法我同意Petesh的说法,你需要枚举顶级窗口并检查创建它的进程的模块文件名.为了帮助您开始枚举顶级窗口,这是一个delphi实现.首先,当你回调给你时,你需要一些与EnumWindows方法通信的方式.为此声明一条记录,该记录将保存您要查找的模块的文件

  2. 如何在Delphi中纯粹通过RTTI信息(即不使用任何实际对象实例)获取TObjectList的子项类型?

    我正在使用RTTI实现用于流式传输任意Delphi对象的通用代码,并且为了使其工作(更具体地说,为了使加载部分工作),我需要以某种方式获得TObjectList的子项类型<T>不使用任何实际对象实例的字段.要求不使用任何实际对象实例的明显原因是,在从流加载对象的情况下(仅基于要加载的对象的类类型的知识),我将不会有任何实例在加载完成之前完全可用–我宁愿只能访问相关类的纯RTTI数据.我希望能

  3. inno-setup – Inno Setup – 安装程序背景图片

    图像作为安装程序背景如何用inno5.5.9做到这一点?

  4. inno-setup – Inno Setup – 如何添加多个arc文件进行解压缩?

    使用InnoSetup解压缩弧文件.我希望有可能解压缩多个arc文件以从组件选择中安装文件(例如).但仍然显示所有提取的整体进度条.这可能吗?的回答的修改预备是相同的,参考其他答案.在ExtractArc中,为要提取的每个存档调用AddArchive.

  5. delphi – 如何在DataSet的帮助下在TAdvStringGrid中显示数据库中的BLOB图像

    解决方法CreateBlobStream正在创建一个TStream对象,而不是TMemoryStream.由于您不想将JPG写入数据库,因此应使用bmRead而不是bmReadWrite.我不习惯sqlite,但你必须确保使用合适的二进制日期类型.为了确保存储的图像真的是JPG,您应该编写JPG以进行测试,例如:

  6. inno-setup – 在Inno Setup的Code部分下载程序后运行程序

    如何运行我通过Internet下载的应用程序,在代码部分中使用,并等待该应用程序完成运行.我有,使用InnoTools下载程序,下载这两个文件,我想,在第二个完成下载后运行该下载,或jdk-8u111-windows-x64.exe,然后继续安装.解决方法使用其他下载插件,而不是ITD(请参阅下面的原因).例如,InnoDownloadPlugin.当您包含idp.iss时,它定义了一个全局IDP

  7. progress-bar – Inno Setup Run部分的简单进度页面

    我的安装程序非常简单,它基本上是:>欢迎页面>进展页面>最终页面欢迎页面和最终页面是标准页面.在Progress页面,我正在静默安装一堆其他程序.实际的脚本是在[Run]部分中安装每个程序.问题是酒吧达到100%然后停留在那里.我只能更改消息文本.我想要实现的是使用Pascal脚本显示进度,例如:这样我就可以显示更准确的进度条.这就是我所拥有的:问题是,当我构建安装程序时,它不显示欢迎页面.我做错了什么?

  8. delphi – 如何使“显示/隐藏桌面图标”设置生效?

    下面的代码调用SHGetSetSettings函数来隐藏桌面图标但它只是从视图菜单中取消选中“显示桌面图标”.我打电话给SHChangeNotify;更新桌面,但这不起作用?解决方法isa,要刷新桌面,您可以将F5键发送到progman窗口隐藏桌面图标的另一种方法是再次显示

  9. inno-setup – Inno Setup – 避免显示子安装程序的文件名

    我试图使用InnoSetup–Howtohidecertainfilenameswhileinstalling?(FilenameLabel)的想法Theonlysuresolutionistoavoidinstallingthefiles,youdonotwanttoshow,usingthe[Files]section.Installthemusingacodeinstead.UsetheEx

  10. inno-setup – Inno Setup磁力链接下载实施

    我目前正在使用InnoDownloadPlugin为我的安装程序下载文件,这个问题最大的问题是faila正确下载文件.因为连接不良等诸多原因.我想添加一种替代方法来下载文件,因此用户可以选择是否需要常规方式或torrent方式.我知道我可以使用aria2c.exe应用程序(https://aria2.github.io/),有人可以帮我实现它的inno设置代码吗?我需要的是使用torrent(ar

返回
顶部