PDA

Показать полную графическую версию : Скрипты Inno Setup. Помощь и советы [часть 9]


Страниц : 1 2 3 4 5 6 7 8 9 [10] 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

TROY Diamond
30-12-2018, 18:54
Iska, с DLL-кой такое прокатит или принципиально 7za.exe?

Iska
30-12-2018, 19:17
Iska, с DLL-кой такое прокатит… »
Чтобы прокатило — пинайте коллегу El Sanchez на предмет данной темы, я Вам тут слабый помощник. Сегодня, кстати, 7-Zip обновился.

TROY Diamond
30-12-2018, 19:56
Iska, в 7-Zip, нет 7za.exe, есть DLL-ки и 7z.exe...

mwz
30-12-2018, 20:00
в 7-Zip, нет 7za.exe »

Есть.
Находится в 7z1806-extra, который также лежит на странице загрузок.

Iska
30-12-2018, 20:32
Iska, в 7-Zip, нет 7za.exe, »
Как уже сказал коллега mwz — есть. И Вам нужен именно 7za.exe, standalone-версия, уже статически слинкованная с потребными библиотеками (не 7z.exe).

TROY Diamond
31-12-2018, 02:54
Iska и mwz, я просто уточнил - спасибо за пояснения! Чтобы просто упаковать в обычный zip, нужны такие "заморочки" и "спец-файл"?

Iska
31-12-2018, 12:03
TROY Diamond, что подразумевается под «заморочками» и под «спец-файлом»?

TROY Diamond
31-12-2018, 18:42
Iska , смайлик забыл поставить - всё в порядке, спасибо!

Iska, mwz и El Sanchez, подскажите, пожалуйста:
1. Как во время архивирования файлов "заставить индикатор процесса двигаться" или хотя бы чтобы было написано создание файла и т.п. Идеально бы ещё с процентами соединить! НОВЫЙ липовый (НЕ настоящий) индикатор процесса НЕ нужен!
А то во время упаковки всё замирает, кнопка Отмена НЕ активна, конечный пользователь может решить что всё зависло, а создание некоторых больших архивов может занимает до 5-7 минут!

2. Как внести в список для деинсталляции, эти созданные архивы, установщик ведь о них НЕ знает, при удалении игры все архивы останутся в папки установки? Просто указать все архивы в [UninstallDelete]?

2.1. А если процесс установки, по какой-то причине, будет прерван, тут как сделать? Чтобы ВСЯ папка установки была удалена, если установка завершилась некорректно или вообще была переврана?

3. Есть ещё одна проблема - это те игры, которые хранят свои сейвы, файлы конфигурации и т.п. прям в папке установки, поэтому просто тупо удалить всю папку нельзя, нужно спросить пользователя "Оставить сохранения и т.п.?"

mwz
31-12-2018, 20:03
Чтобы ВСЯ папка установки была удалена, если установка завершилась некорректно или вообще была переврана? »

Как-то у одного знакомого пропало абсолютно всё на диске E:

Разборка с анализом протоколов и дальнейшим "опросом свидетелей" показала, что сын установил пиратскую игру, а затем деинсталлировал её. И всё бы ничего, но установил он её в корень диска Е, а деинсталятор запустил команду, которая в переводе на человеческий язык означала: "Удалить нахрен всю папку установки, и при удалении ни о чём не спрашивать".

С Наступающим!

Iska
01-01-2019, 09:48
TROY Diamond, вооот… Теперь Вы видите, что не всё так просто :)?

1. Как во время архивирования файлов "заставить индикатор процесса двигаться" или хотя бы чтобы было написано создание файла и т.п. Идеально бы ещё с процентами соединить! »
По-хорошему — никак. Это сторонние задачи, никоим образом не привязанные ни к объёму инсталляции, ни к индикатору процесса инсталляции (который определяется как раз её объёмом).

НОВЫЙ липовый (НЕ настоящий) индикатор процесса НЕ нужен! »
Вообще-то — как раз нужен новый индикатор, в отдельном окне. А совсем правильно — новое окно для всех пакуемых архивов, плюс по ещё одному окну с индикатором упаковки каждого отдельного архива. Я так думаю.

А то во время упаковки всё замирает, кнопка Отмена НЕ активна, конечный пользователь может решить что всё зависло, а создание некоторых больших архивов может занимает до 5-7 минут! »
Функция exec() с параметром ewWaitUntilTerminated — она такая ;). Вы что-то запустили из кода и ждёте результата. И пока такая функция полностью не отработает — обновлять форму и обрабатывать приходящие для неё сообщения некому.

2. Как внести в список для деинсталляции, эти созданные архивы, установщик ведь о них НЕ знает, при удалении игры все архивы останутся в папки установки? Просто указать все архивы в [UninstallDelete]? »
Да. Имейте в виду, что они будут удалены на последнем шаге деинсталляции

2.1. А если процесс установки, по какой-то причине, будет прерван, тут как сделать? Чтобы ВСЯ папка установки была удалена, если установка завершилась некорректно или вообще была переврана? »
В общем и целом — сложно. Вы должны внутри процедуры Pack() анализировать код возврата 7za.exe, и при ненулевом коде возврата удалить все ранее созданные архивы.

3. Есть ещё одна проблема - это те игры, которые хранят свои сейвы, файлы конфигурации и т.п. прям в папке установки, поэтому просто тупо удалить всю папку нельзя, нужно спросить пользователя "Оставить сохранения и т.п.?" »
Ну, дык, спрашивайте. Pascal ждёт Вас. Вообще-то, нормальные игры давно уже не хранят пользовательские данные в каталоге установки, а только либо в пользовательском разделе реестре, либо в профиле пользователя.

mwz, пираты — они такие :). Любимое дело — попытаться забросить «свои» библиотеки в системный каталог, забросить «свои» шрифты в каталог со шрифтами, нимало не заботясь о том, что не токмо функционал каких-то сторонних приложений, но и сама операционная система от таких вывертов может накрыться медным тазом.

TROY Diamond
01-01-2019, 20:38
Iska, ну а липовый индикатор установки во время создания архивов как тогда сделать, или просто в момент создания архива, стандартную надпись "Копирование файлов", заменить на "Создание файла и т.п."?

Iska
02-01-2019, 00:04
Не надо липовый. Нужны отдельные и реальные. Как — надеюсь, коллеги Вам помогут.

El Sanchez
04-01-2019, 14:39
во время упаковки всё замирает, кнопка Отмена НЕ активна, конечный пользователь может решить что всё зависло, а создание некоторых больших архивов может занимает до 5-7 минут! »
TROY Diamond, ясно, так и знал, что по-простому не выйдет.

[Languages]
Name: ru; MessagesFile: compiler:Languages\russian.isl

[CustomMessages]
ru.SevenZipStatusPackFiles=Упаковка файлов из %1:
ru.SevenZipProgressCaptions=Прогресс:%nСкорость:%nПрошло:%nОсталось:
ru.SevenZipProgressInfo=%1%% (%2 из %3)%n%4%n%5%n%6
ru.SevenZipPackFailed=При создании архива %1 произошла ошибка. Код ошибки: %2
ru.UnableDeleteEmptyFolder=Не удалось удалить пустую папку %1. Код ошибки: %2 (%3)

[Files]
Source: 7-zip32.dll; Flags: dontcopy
#ifndef IS_ENHANCED
; http://restools.hanzify.org/inno/callbackctrl/InnoCallbackCtrl_V1.1.zip
Source: CallbackCtrl.dll; Flags: dontcopy
#endif
; {app}\data\test01
Source: {app}\test01\*; DestDir: {app}\data\test01; Flags: ignoreversion overwritereadonly recursesubdirs createallsubdirs sortfilesbyextension
Source: dummy; DestDir: {app}\data; AfterInstall: Pack(ExpandConstant('{app}\data\test01')); Flags: deleteafterinstall
; {app}\data\test02
Source: {app}\test02\*; DestDir: {app}\data\test02; Flags: ignoreversion overwritereadonly recursesubdirs createallsubdirs sortfilesbyextension
Source: dummy; DestDir: {app}\data; AfterInstall: Pack(ExpandConstant('{app}\data\test02')); Flags: deleteafterinstall

[Code]
#define A = (Defined UNICODE) ? "W" : "A"
const
WM_GETFONT = $0031;
WM_SETTEXT = $000C;
WM_USER = $0400;

PBM_SETPOS = WM_USER + 2;
PBM_SETRANGE32 = WM_USER + 6;

GWL_STYLE = -16;

WS_CLIPSIBLINGS = $04000000;
WS_VISIBLE = $10000000;
WS_CHILDWINDOW = $40000000;
SS_RIGHT = $2;

CP_ACP = 0;
CP_UTF8 = 65001;

FNAME_MAX32 = 512;
MAX_PATH = 260;

ARCEXTRACT_BEGIN = 0;
ARCEXTRACT_INPROCESS = 1;

type
{ 7-zip.dll. }
TExtractingInfo = record
szSourceFileName: PAnsiChar;
szDestFileName: PAnsiChar;
dwFileSize: DWORD;
szFileSize: PAnsiChar;
dwWriteSize: DWORD;
szWriteSize: PAnsiChar;
dwProgress: DWORD;
szSpeed: PAnsiChar;
szElapsed: PAnsiChar;
szRemain: PAnsiChar;
end;

{ User-defined data passed to callback. }
TArcParam = array of HWND;

#ifndef IS_ENHANCED
TPackCallbackProc = function (nState: UINT; var ExtInfo: TExtractingInfo; var ArcParam: TArcParam): BOOL;
#endif

// Unicode and Character Set Functions
function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD; lpWideCharStr: string; cchWideChar: Integer; lpMultiByteStr: AnsiString; cbMultiByte, lpDefaultChar: Integer; lpUsedDefaultChar: Longint): Integer; external 'WideCharToMultiByte@kernel32.dll stdcall';
function MultiByteToWideChar(CodePage: UINT; dwFlags: DWORD; lpMultiByteStr: AnsiString; cbMultiByte: Integer; lpWideCharStr: string; cchWideChar: Integer): Integer; external 'MultiByteToWideChar@kernel32.dll stdcall';
// Shell Lightweight Utility Functions
function PathCompactPath(hDC: THandle; lpszPath: string; dx: UINT): BOOL; external 'PathCompactPath{#A}@shlwapi.dll stdcall';
// Painting and Drawing Functions
function GetDC(hWnd: HWND): THandle; external 'GetDC@user32.dll stdcall';
// Device Context Functions
function ReleaseDC(hWnd: HWND; hDC: THandle): Integer; external 'ReleaseDC@user32.dll stdcall';
function SelectObject(hdc, hgdiobj: THandle): THandle; external 'SelectObject@gdi32.dll stdcall';
// Window Functions
function GetClientRect(hWnd: HWND; var lpRect: TRect): BOOL; external 'GetClientRect@user32.dll stdcall';
// Message Functions
function SendMessageString(hWnd: HWND; Msg: UINT; wParam: Longint; lParam: string): Longint; external 'SendMessage{#A}@user32.dll stdcall';
// Window Class Functions
function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Longint; external 'SetWindowLong{#A}@user32.dll stdcall';
// 7-zip.dll Functions
function SevenZip(const CmdLine: AnsiString; ArcProc: Longint; var LParam: TArcParam): Integer; external 'SevenZip@files:7-zip32.dll stdcall';
#ifndef IS_ENHANCED
// CallbackCtrl.dll Functions
function WrapPackProc(Callback: TPackCallbackProc; ParamCount: Integer): LongWord; external 'wrapcallbackaddr@files:callbackctrl.dll stdcall';
#endif

var
ProgressInfoContainer, ProgressInfo: TNewStaticText;
ArcProc: LongWord;

function UTF8Encode(const Value: string): AnsiString;
var
Len: Integer;
UTF16Buffer: string;
begin
if Value = '' then Exit;
#ifndef UNICODE
// на ANSI-версии компилятора сначала переводим строку в UTF-16LE (Unicode)
Len := MultiByteToWideChar(CP_ACP, 0, Value, -1, '', 0);
if Len = 0 then Exit;
UTF16Buffer := StringOfChar(#0, Len shl 1);
if MultiByteToWideChar(CP_ACP, 0, Value, -1, UTF16Buffer, Len) = 0 then Exit;
#else
UTF16Buffer := Value;
#endif
// перевод строки UTF-16LE (Unicode) в UTF-8
Len := WideCharToMultiByte(CP_UTF8, 0, UTF16Buffer, -1, '', 0, 0, 0);
if Len = 0 then Exit;
Result := StringOfChar(#0, Len - 1);
if WideCharToMultiByte(CP_UTF8, 0, UTF16Buffer, -1, Result, Len, 0, 0) = 0 then Exit;
end;

function UTF8Decode(const Value: AnsiString): string;
var
Len: Integer;
#ifndef UNICODE
UTF16Buffer: string;
#endif
begin
if Value = '' then Exit;
#ifndef UNICODE
// на ANSI-версии компилятора сначала переводим строку в UTF-16LE (Unicode)
Len := MultiByteToWideChar(CP_UTF8, 0, Value, -1, '', 0);
if Len = 0 then Exit;
UTF16Buffer := StringOfChar(#0, Len shl 1);
if MultiByteToWideChar(CP_UTF8, 0, Value, -1, UTF16Buffer, Len) = 0 then Exit;

// перевод строки UTF-16 в ANSI
Len := WideCharToMultiByte(CP_ACP, 0, UTF16Buffer, -1, '', 0, 0, 0);
if Len = 0 then Exit;
Result := StringOfChar(#0, Len - 1);
if WideCharToMultiByte(CP_ACP, 0, UTF16Buffer, -1, Result, Len, 0, 0) = 0 then Exit;
#else
// на Unicode-версии компилятора перевод строки UTF-8 в UTF-16LE (Unicode)
Len := MultiByteToWideChar(CP_UTF8, 0, Value, -1, '', 0);
if Len = 0 then Exit;
Result := StringOfChar(#0, Len - 1);
if MultiByteToWideChar(CP_UTF8, 0, Value, -1, Result, Len) = 0 then Exit;
#endif
end;

function PackCallbackProc(nState: UINT; var ExtInfo: TExtractingInfo; var ArcParam: TArcParam): BOOL;
var
S: string;
DC, SaveFont: THandle;
H: HWND;
R: TRect;
begin
{ Avoid call VCL methods or get/set properties. }
Result := True;
case nState of
ARCEXTRACT_BEGIN:
begin
H := ArcParam[0];
DC := GetDC(H);
try
SaveFont := SelectObject(DC, SendMessage(H, WM_GETFONT, 0, 0));
GetClientRect(H, R);
S := UTF8Decode(ExtInfo.szDestFileName);
PathCompactPath(DC, S, R.Right - R.Left);
SendMessageString(H, WM_SETTEXT, 0, S);
finally
if SaveFont <> 0 then
SelectObject(DC, SaveFont);
ReleaseDC(H, DC);
end;
end;
ARCEXTRACT_INPROCESS:
begin
H := ArcParam[1];
PostMessage(H, PBM_SETRANGE32, 0, 100);
PostMessage(H, PBM_SETPOS, ExtInfo.dwProgress, 0);
H := ArcParam[2];
S := FmtMessage(CustomMessage('SevenZipProgressInfo'), );
SendMessageString(H, WM_SETTEXT, 0, S);
end;
end;
end;

procedure Pack(const APath: string);
var
CmdLine: AnsiString;
ArcParam: TArcParam;
ResultCode: Integer;
begin
[i]{ Pack files. }
try
WizardForm.StatusLabel.Caption := FmtMessage(CustomMessage('SevenZipStatusPackFiles'), [ExtractFileName(APath)]);
ProgressInfoContainer.Show;
CmdLine := UTF8Encode(Format('a -tzip -sdel -y "%0:s.pk3" "%0:s\*"', [APath]));
SetLength(ArcParam, 3);
ArcParam[0] := WizardForm.FilenameLabel.Handle;
ArcParam[1] := WizardForm.ProgressGauge.Handle;
ArcParam[2] := ProgressInfo.Handle;
ResultCode := SevenZip(CmdLine, ArcProc, ArcParam);
if ResultCode <> 0 then
RaiseException(FmtMessage(CustomMessage('SevenZipPackFailed'), [ExtractFileName(APath), Format('0x%.8x', [ResultCode])]));
if not RemoveDir(APath) then
begin
ResultCode := DLLGetLastError;
RaiseException(FmtMessage(CustomMessage('UnableDeleteEmptyFolder'), [APath, ResultCode, SysErrorMessage(ResultCode)]));
end;
except
ShowExceptionMessage;
DelTree(ExtractFileDir(APath) + '\*.pk3', False, True, False); // Rollback if error occured.
finally
ProgressInfoContainer.Hide;
WizardForm.StatusLabel.Caption := SetupMessage(msgStatusExtractFiles);
WizardForm.FilenameLabel.Caption := '';
end;
end;

procedure CreateInstallingPage;
begin
{ ProgressInfoContainer. }
ProgressInfoContainer := TNewStaticText.Create(WizardForm);
with ProgressInfoContainer do
begin
Parent := WizardForm.InstallingPage;
Align := alBottom;
AutoSize := False;
Caption := CustomMessage('SevenZipProgressCaptions');
Height := Parent.ClientHeight - WizardForm.ProgressGauge.Top - WizardForm.ProgressGauge.Height - ScaleY(5);
end;

{ ProgressInfo. }
ProgressInfo := TNewStaticText.Create(WizardForm);
with ProgressInfo do
begin
Parent := ProgressInfoContainer;
Align := alRight;
AutoSize := False;
Width := Parent.ClientWidth div 2;
SetWindowLong(Handle, GWL_STYLE, WS_CHILDWINDOW or WS_VISIBLE or WS_CLIPSIBLINGS or SS_RIGHT);
end;
#ifdef IS_ENHANCED
ArcProc := CallbackAddr('PackCallbackProc');
#else
ArcProc := WrapPackProc(@PackCallbackProc, 3);
#endif
end;

procedure InitializeWizard;
begin
CreateInstallingPage;
end;

rashidzhan
06-01-2019, 06:44
Кто платно поможет мне создать инсталлятор?
https://i.ibb.co/LgSfC0N/Superinstall1.jpg
https://i.ibb.co/6vZmDx2/Superinstall2.jpg
1) Выбор языка установщика;
2) Проверка на новую версию установщика;
3) Установки некоторых файлов;
4) Тихая установка дополнительных программ и утилит;
5) Установка ярлыков;
6) Показывать описание в отдельной окошке;
7) Интерфейс как на скриншоте.

Скрин я сильно фотошопил.

TROY Diamond
10-01-2019, 15:20
Цитата El Sanchez:
El Sanchez »
ясно, так и знал, что по-простому не выйдет.1. El Sanchez, пожалуйста, будьте любезны, можно ПОЛНЫЙ скрипт, а также указать какую версию (и где взять) CallbackCtrl.dll и Inno Setip - вы использовали, что-то не получается! ((( То не пакует нормально, то архивы получаются битые, то папка не удаляется сразу после создания архива и перед распаковкой новой... Несколько раз компилировал, каждый раз по новому получалось...

2. Также подскажите, пожалуйста, как в этот скрипт добавить проверку ранее установленного приложения, например, по секции Uninstall, по названию и т.п., НО только с предупреждением, что приложение уже было установлено, БЕЗ запрета устанавливать "поверх"!
ПРОБЛЕМА В ТОМ, ЧТО ПРИЛОЖЕНИЕ МОЖЕТ НАЗЫВАТЬСЯ ПО РАЗНОМУ и в секции Uninstall, оно может быть в различных разделах! Я готов указать в скрипте ВСЕ ВОЗМОЖНЫЕ варианты, только скажите, куда и как это сделать?

El Sanchez
11-01-2019, 11:12
можно ПОЛНЫЙ скрипт, а также указать какую версию (и где взять) CallbackCtrl.dll и Inno Setip - вы использовали, что-то не получается! »
TROY Diamond, пример и так полный, только без секции Setup и с тестовыми папками test01, test02 и файлом-пустышкой dummy в Files. Работает в обычной и в расширенной версиях. Ссылка на CallbackCtrl.dll приведена в Files.
Также подскажите, пожалуйста, как в этот скрипт добавить проверку ранее установленного приложения, например, по секции Uninstall, по названию и т.п., НО только с предупреждением, что приложение уже было установлено, БЕЗ запрета устанавливать "поверх"!
ПРОБЛЕМА В ТОМ, ЧТО ПРИЛОЖЕНИЕ МОЖЕТ НАЗЫВАТЬСЯ ПО РАЗНОМУ и в секции Uninstall, оно может быть в различных разделах! Я готов указать в скрипте ВСЕ ВОЗМОЖНЫЕ варианты, только скажите, куда и как это сделать? »
TROY Diamond,

function InitializeSetup: Boolean;
var
UninstallSubKeyName: string;
begin
UninstallSubKeyName := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\';
if RegKeyExists(HKLM, UninstallSubKeyName + 'AIMP') or
RegKeyExists(HKLM, UninstallSubKeyName + '{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}') or
RegKeyExists(HKLM, UninstallSubKeyName + 'Axialis IconWorkshop_is1') then
MsgBox('Я никому не нужное информационное сообщение.', mbInformation, MB_OK);
end;

TROY Diamond
11-01-2019, 15:32
El Sanchez вместо "AIMP" и "{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}" - писать все возможные варианты?
А в MsgBox - написать что приложение уже было ранее установлено?

А как соединить с тем скриптом правильно?

El Sanchez
11-01-2019, 17:34
вместо "AIMP" и "{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}" - писать все возможные варианты? »
TROY Diamond, да. Я ж не знаю ваших вариантов.
А в MsgBox - написать что приложение уже было ранее установлено? »
TROY Diamond, угу.
А как соединить с тем скриптом правильно? »
TROY Diamond, копировать-вставить. Только я забыл в теле InitializeSetup строку Result := True; добавить, а то форму не увидите.

TROY Diamond
11-01-2019, 18:49
El Sanchez, так вот добавить?

function InitializeSetup(): Boolean;
begin
Result:= True;
var
UninstallSubKeyName: string;
begin
UninstallSubKeyName := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\';
if RegKeyExists(HKLM, UninstallSubKeyName + 'AIMP') or
RegKeyExists(HKLM, UninstallSubKeyName + '{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}') or
RegKeyExists(HKLM, UninstallSubKeyName + 'Axialis IconWorkshop_is1') then
MsgBox('Я никому не нужное информационное сообщение.', mbInformation, MB_OK);
end;

2. Соединить коды: 1-й со 2-м, сразу поле procedure InitializeWizard;
begin
CreateInstallingPage;
end;в первом коде вставить второй код?

3. Вы знали, наверное что будет это вопрос? ))) Как теперь подкорректировать размер свободного места на ЖД, который требует установщик? В нём ведь скомпилированы распакованные архивы и он считает их вес, а папки ведь поочередно удаляются после создания архивов, места нужно раза в 2 меньше, чем он хочет!

Iska
12-01-2019, 05:12
Как теперь подкорректировать размер свободного места на ЖД, который требует установщик? »
А куда он, простите, будет извлекать Ваши пока ещё не-архивы?!




© OSzone.net 2001-2012