現在、PrepareToInstall
イベント関数の前提条件として.NET Framework 4.6.2をインストールしています。これにより、終了コードを取得し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;
現時点では、Inno Setupの実行方法に応じて、/q
または/passive
.NET Frameworkインストーラーが表示する表示GUIの量を制御するために、インストールタイプをサイレントまたは無人に設定しています。マーキースタイルのプログレスバーを使用して、何かがハプニング。ただし、ここにあるMicrosoftのドキュメントから、.NET Frameworkインストーラーを取得して、インストールの進行状況を報告することができるようです。/pipe
スイッチ。これにより、実際の進行状況で通常のスタイルの進行状況バーをインタラクティブに更新できる場合があります。これは、.NET Frameworkインストーラーを完全に非表示にし、Inno Setupを使用して相対的な進行状況を示すことができることを意味します。これは、はるかにきちんとしたソリューションです。残念ながら、私はC ++を知らず、初心者のプログラマーにすぎません。したがって、これがInno Setupで可能かどうか、もしそうなら、どのように試みることができるかを誰かが確認できますか?
The following shows Pascal Script implementation of the code from
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 '[email protected] stdcall';
function CreateEvent(
EventAttributes: Cardinal; ManualReset: Boolean; InitialState: Boolean;
Name: string): THandle;
external '[email protected] stdcall';
function CreateMutex(
MutexAttributes: Cardinal; InitialOwner: Boolean; Name: string): THandle;
external '[email protected] stdcall';
function WaitForSingleObject(
Handle: THandle; Milliseconds: Cardinal): Cardinal;
external '[email protected] stdcall';
function MapViewOfFile(
FileMappingObject: THandle; DesiredAccess: Cardinal; FileOffsetHigh: Cardinal;
FileOffsetLow: Cardinal; NumberOfBytesToMap: Cardinal): Cardinal;
external '[email protected] stdcall';
function ReleaseMutex(Mutex: THandle): Boolean;
external '[email protected] 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 '[email protected] stdcall';
function GetExitCodeProcess(Process: THandle; var ExitCode: Cardinal): Boolean;
external '[email protected] stdcall';
procedure CopyPointerToData(
var Destination: TMmioDataStructure; Source: Cardinal; Length: Cardinal);
external '[email protected] stdcall';
procedure CopyDataToPointer(
Destination: Cardinal; var Source: TMmioDataStructure; Length: Cardinal);
external '[email protected] 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, 0, PAGE_READWRITE, 0, MMIO_SIZE, SectionName);
Log(Format('FileMapping = %d', [Integer(FileMapping)]));
if FileMapping = 0 then
RaiseException('Error creating file mapping');
EventChaineeSend := CreateEvent(0, False, False, EventName);
Log(Format('EventChaineeSend = %d', [Integer(EventChaineeSend)]));
if EventChaineeSend = 0 then
RaiseException('Error creating chainee event');
EventChainerSend := CreateEvent(0, False, False, EventName + '_send');
Log(Format('EventChainerSend = %d', [Integer(EventChainerSend)]));
if EventChainerSend = 0 then
RaiseException('Error creating chainer event');
Mutex := CreateMutex(0, False, EventName + '_mutex');
Log(Format('Mutex = %d', [Integer(Mutex)]));
if Mutex = 0 then
RaiseException('Error creating mutex');
View :=
MapViewOfFile(FileMapping, FILE_MAP_WRITE, 0, 0, 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;
You can use it like below, or on any other place of your installer process.
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;
The following screenshot shows how the "progress page" in Inno Setup is linked to the .NET framework installer (of course the .NET framework installer is hidden by the /q
switch, it was just temporarily shown for purposes of obtaining the screenshot).
I've successfully tested the code on
Note that the code takes into account the InstallSoFar
only as both installers above are off-line. For on-line installers, DownloadSoFar
should be taken into account too. And actually even off-line installers do sometime download something.
The ShellExecuteEx
code taken from Inno Setup Exec() function Wait for a limited time.
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
来年は、スペースオペラの最も壮大で野心的なメディアシリーズの50周年を迎えます。しかし、スタートレックはその誇り高い遺産に沿って50歳の誕生日を迎えますか?スタートレックの誕生日を祝う方法はたくさんあります。
(画像提供:ゲッティイメージズ)ドナルド・トランプは、アメリカ合衆国大統領の立候補者となる比類のない外交的洞察力を示し、何百万人もの人々を怒らせ、彼の時代遅れの客体化に対する評価の主要な情報源を失いました。彼が立候補を発表し終える前にパレード。トランプ氏は演説の中で、この国で最も高い役職に選出された場合、米国との南の国境に壁を建設すると述べた一連の声明を発表した。
オンラインデートに関しては、船長、ベーコン愛好家、ポットヘッド向けに作られたサイトなど、長年にわたって選択できるニッチなサイトがたくさんあります。今、ディズニーファンは彼ら自身のマッチメイキングサイトを通して愛を見つけることができます。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。