Wie wird 7zip ausgeführt, ohne die InnoSetup-Benutzeroberfläche zu blockieren?
Meine InnoSetup-GUI ist während des Entpackens eingefroren.
Ich habe eineprocedure DoUnzip(source: String; targetdir: String)
mit dem Kern
unzipTool := ExpandConstant('{tmp}\7za.exe');
Exec(unzipTool, ' x "' + source + '" -o"' + targetdir + '" -y',
'', SW_HIDE, ewWaitUntilTerminated, ReturnCode);
Diese Prozedur wird mehrmals aufgerufen und dasExec
ie @ -Operation blockiert die Benutzeroberfläche. Es gibt nur einen sehr kurzen Moment zwischen den Ausführungen, in dem die Inno-GUI zieh- / verschiebbar ist.
Ich weiß, dass es andere Optionen für @ giTExecWait
Anstatt vonewWaitUntilTerminated
, mögenewNoWait
undewWaitUntilIdle
, aber in diesem Fall sind sie leider nicht hilfreich. @ VerwendewNoWait
würde dazu führen, dass mehrere Entpackungsvorgänge gleichzeitig ausgeführt werden.
Ich suche nach einer Möglichkeit, einen externen Dekomprimierungsvorgang auszuführen und zu warten, bis er abgeschlossen ist, ohne jedoch die Benutzeroberfläche zu blockieren. Wie kann ich das umsetzen?
Hier sind meine Notizen und Ideen:
Warten, bis ein Prozess abgeschlossen ist, wird blockiert, es sei denn, Sie warten in einem anderen Thread als dem Hauptthread. Ich denke, dass eine Art Rückruf benötigt wird, der ausgeführt wird, wenn der Entpackvorgang abgeschlossen ist.
Ich bin mir bewusst, dass InnoSetup diese Funktion nicht sofort zur Verfügung stellt. Siehehttps: //github.com/jrsoftware/issrc/issues/14
ei der Suche nach verwandten Themen zu StackOverflow stellte sich die FragVerwenden eines Rückrufs zum Anzeigen von Dateinamen aus der externen Dekomprimierungs-DLL (Inno Setup), wo ich @ gefunden ha Mirals Antwort. Es verwendet InnoCallback in Kombination mit einer anderen DLL.
Ich denke, in meinem Fall könnte dies sein7zxa.dll
für den Entpackvorgang. Aber es akzeptiert keinen Rückruf. Der folgende Code ist also nur ein Konzept- / Ideenentwurf. Ein Problem ist, dass7zxa.dll
akzeptiert keinen Rückruf. Ein weiteres Problem ist, dass die 7zxa-API nicht wirklich zum Arbeiten einlädt.
[Code]
type
TMyCallback = procedure(Filename: PChar);
// wrapper to tell callback function to InnoCallback
function WrapMyCallback(Callback: TMyCallback; ParamCount: Integer): LongWord;
external 'WrapCallback@files:innocallback.dll stdcall';
// the call to the unzip dll
// P!: the 7zxa.dll doesn't accept a callback
procedure DoUnzipDll(Blah: Integer; Foo: String; ...; Callback: LongWord);
external 'DoUnzipDll@files:7zxa.dll stdcall';
// the actual callback action
procedure MyCallback(Filename: PChar);
begin
// refresh the GUI
end;
//-----
var Callback : LongWord;
// tell innocallback the callback procedure as 1 parameter
Callback := WrapMyCallback(@MyCallback, 1);
// pass the wrapped callback to the unzip DLL
DoUnzipDll(source, target, ..., Callback);
procedure DoUnzip(src, target : String);
begin
DoUnzipDll(ExpandConstant(src), ExpandConstant(target));
end;
Aktualisiere
ik schlug vor, die WinAPI-Funktion ShellExecuteEx () mit INFINITE WaitForSingleObject zu kombiniere
Ich habe diesen Ansatz implementiert und getestet. Der Code ist unten.
Das Entpacken funktioniert, aber das InnoSetup-Fenster kann zwischen den einzelnen Entpackvorgängen nur für einen kurzen Moment verschoben / gezogen werden. Während eines langen Entpackens reagiert die GUI nicht mehr - kein Ziehen / Abbrechen. Ich habe BringToFrontAndRestore () hinzugefügt, aber es scheint, dass der neue Prozess den Fokus hat.
const
WAIT_OBJECT_0 = $0;
WAIT_TIMEOUT = $00000102;
SEE_MASK_NOCLOSEPROCESS = $00000040;
INFINITE = $FFFFFFFF; { Infinite timeout }
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 'ShellExecuteEx{#AW}@shell32.dll stdcall';
function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD;
external '[email protected] stdcall';
function CloseHandle(hObject: THandle): BOOL; external '[email protected] stdcall';
procedure DoUnzip(source: String; targetdir: String);
var
unzipTool, unzipParams : String; // path to unzip util
ReturnCode : Integer; // errorcode
ExecInfo: TShellExecuteInfo;
begin
// source might contain {tmp} or {app} constant, so expand/resolve it to path name
source := ExpandConstant(source);
unzipTool := ExpandConstant('{tmp}\7za.exe');
unzipParams := ' x "' + source + '" -o"' + targetdir + '" -y';
ExecInfo.cbSize := SizeOf(ExecInfo);
ExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
ExecInfo.Wnd := 0;
ExecInfo.lpFile := unzipTool;
ExecInfo.lpParameters := unzipParams;
ExecInfo.nShow := SW_HIDE;
if not FileExists(unzipTool)
then MsgBox('UnzipTool not found: ' + unzipTool, mbError, MB_OK)
else if not FileExists(source)
then MsgBox('File was not found while trying to unzip: ' + source, mbError, MB_OK)
else begin
// ShellExecuteEx combined with INFINITE WaitForSingleObject
if ShellExecuteEx(ExecInfo) then
begin
while WaitForSingleObject(ExecInfo.hProcess, INFINITE) <> WAIT_OBJECT_0
do begin
InstallPage.Surface.Update;
//BringToFrontAndRestore;
WizardForm.Refresh();
end;
CloseHandle(ExecInfo.hProcess);
end;
end;
end;