Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Автоматическая установка Windows » Автоматическая установка приложений » Скрипты Inno Setup. Помощь и советы [часть 6]

Закрытая тема
Настройки темы
Скрипты Inno Setup. Помощь и советы [часть 6]

Аватара для El Sanchez

Ветеран


Contributor


Сообщения: 1274
Благодарности: 1030


Конфигурация

Профиль | Отправить PM | Цитировать


Изменения
Автор: El Sanchez
Дата: 16-02-2015
Внимание! Данная тема предназначена только для обсуждения написания скриптов !
Остальные вопросы, а также последние версии компилятора в теме
Inno Setup. Прочие вопросы.


Показать/скрыть: Справка, руководство, примеры:
Показать/скрыть: Ссылки на примеры скриптов:
Показать/скрыть: Дополнительные программы для Inno Setup:
  • ISTool - неплохой редактор скриптов Inno Setup.
    Последняя версия: 5.3.0.1 [29.09.2009] - Скачать | зеркало;

  • Inno Script Generator - генератор скриптов Inno Setup. Обладает некоторыми полезными функциями, которых нет ни у самого Inno Setup, ни у ISTool.
    Последняя версия: 1.0.3.1 [23.03.2008] - Скачать | зеркало на русифицированную программу;
    Примечание: Родной сайт www.hisoft2000.de более недоступен, поэтому здесь расположены сторонние ссылки.

  • Inno Setup Form Designer - редактор страниц Inno Setup, можно создавать свои страницы.
    Последняя версия: 2.0.8 [12.11.2006] - Скачать;
    Примечание: Родной сайт http://isfd.kaju74.de/index.php?isfd более недоступен, поэтому здесь расположены сторонние ссылки.

  • Inno Setup GameScript Generator - программа генерирует скрипты для Inno Setup . С помощью GameScript Generator и Inno Setup вы сможете быстро создать простенький инсталляционный пакет для любой игры. В инсталлятор можно встроить музыку, слайдшоу и фоновый рисунок. Для специалистов созданный скрипт, возможно, будет неплохой заготовкой для дальнейшей модернизации;

  • ISSkin - Программа для создания и добавления в инсталлятор скинов. Инструкция.
    Последняя версия: 3.0.0.0 [19.01.2010] - Скачать;

  • ISSJoiner - Программа для объединения нескольких скриптов InnoSetup в один.
    Последняя версия: 3.0 [23.07.2009]

  • Converter - Программа конвертирует reg-файлы в формат *.iss (формат скриптов Inno Setup).
    Последняя версия: 0.1.4 [13.03.2010] - Скачать;


Предыдущие ветки обсуждения по ссылкам ниже и в прикреплённых архивах:

Отправлено: 19:06, 28-03-2013

 

Пользователь


Сообщения: 80
Благодарности: 3

Профиль | Отправить PM | Цитировать


Цитата Johny777:
Mat_y, вот накатал копирование файлов из папки куда-нибудь, возможностью перезаписи/пропуска и перемещения файлов в одной функции с опциональным отображением прогресса: »
Сломался на всем этом... пытался, но не осилил.

Отправлено: 15:23, 21-11-2013 | #1481



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Аватара для Johny777

Ветеран


Сообщения: 649
Благодарности: 444

Профиль | Отправить PM | Цитировать


Mat_y,
Цитата Mat_y:
Я попробовал оба варианта... все равно натыкается на существующий фаил и стопорится. »
Цитата Mat_y:
Сломался на всем этом... пытался, но не осилил. »
Кошмар!
Давай по порядку.
Функция вчера почти весь вечер, а ночью дописывалась, хотя это я мог бы и быстрее, но, тк цель одна - максимальная скорость, функциональность и качество,
в ней собственная система определения нужного файла для копирования - это вспомогательные функции из раздела "File Mask Works",
из которых непосредственно во время копирования работает только "ThatFile", для того чтобы найти и в последствии копировать в один цикл прохода по выбранной папке, чтоб
не насиловать ж. диск в количестве длиной с массив масок, как в коде у тебя из сообщения:
for i:=0 to GetArrayLength(MyFiles)-1 do ..., где MyFiles - массив строк (масок поиска)
Перед тем как выложить функцию я её протестировал, хотя составные её части тестировались ещё по мере написания, там где приписано "debug"
Но замечу: я её не перегружал (далее опишу чем), тк не знал насколько это может быть необходимо, тк думал, что тот код которым ты пользуешься не особо хорошо работает.
(не люблю я исправлять, мне проще переписать и потому код твой не брал. Только глянул в чём его назначение)
Те целью было рабочее копирование/перемещение!
"натыкается на существующий фаил и стопорится" может по двум известным мне причинам, если ты конечно папку винды не переносишь
1. у файла (который заменяем в папке назначения) свойство "Только чтение"
2. файл держит какой-то процесс
3. хз
эти 3 возможности в коде не учтены, как сказано выше
вывод: дело не в том коде, каким ты пользовался, а в тех самых файлах, которые есть только у тебя, так что нужно максимальное кол-во информации с твоей стороны!


UPD:
вот местами исправленный, улучшенный и дополненный код:

добавлена работа с файлами защиты от изменений ( Read only )
изменён прототип функции. Теперь туда отправляем флаги
SET_OVERWRITE_EXISTING_FILES = 2;
SET_MOVE_FILES = 4;
SET_PROCESS_READONLY_FILES = 8;

читать дальше »
Код: Выделить весь код
[Code]
/////////////////////////////////  File Mask Works ////////////////////////
const
    ALL_FILES = '*';
    BACKSLASH = '\';
type
    _FILE_MASK = record
        Parts: array of String;
        PartsCount: Integer;
    end;

    _FILES_MASKS_SHOBLA = record
        Masks: array of _FILE_MASK;
        MasksCount: Integer;
    end;
procedure Inc(var Int: Integer);
begin
    Int := Int + 1;
end;
procedure Dec(var Int: Integer);
begin
    Int := Int - 1;
end;
procedure IncEx(var Int: Extended; const Value: Extended);
begin
    Int := Int + Value;
end;
procedure DecEx(var Int: Extended; const Value: Extended);
begin
    Int := Int - Value;
end;
procedure AddFragmentToFileMask(const Fragment: String; var f: _FILE_MASK);
begin
    Inc(f.PartsCount);
    SetArrayLength(f.Parts, f.PartsCount);
    f.Parts[f.PartsCount-1] := Fragment;
end;
procedure SplitFileMask(const FileMask: String; out f: _FILE_MASK);
var
    i, Len: Integer;
    Fragment: String;
begin
    Len := Length(FileMask);    
    Fragment := '';
    for i := 1 to Len do
    begin
        if FileMask[i] = '*' then
        begin
            if Fragment <> '' then
            begin
                AddFragmentToFileMask(Fragment, f);
                Fragment := '';
            end;
            Continue;
        end;
        Fragment := Fragment + FileMask[i];
    end;
    if Fragment <> '' then AddFragmentToFileMask(Fragment, f);
end;
procedure SplitFilesMasks(const FilesMasks: array of String; var f: _FILES_MASKS_SHOBLA);
var
    i, Len: Integer;
begin
    Len := GetArrayLength(FilesMasks);
    for i := 0 to Len-1 do
    begin
        Inc(f.MasksCount);
        SetArrayLength(f.Masks, f.MasksCount);
        SplitFileMask(FilesMasks[i], f.Masks[f.MasksCount-1]);
    end;
end;
function ThatFile(const uFileName: String; const f: _FILES_MASKS_SHOBLA): Boolean;
var
    a, i: Integer;
begin
    for a := 0 to f.MasksCount-1 do
    begin
      Result := True;
      for i := 0 to f.Masks[a].PartsCount-1 do
          Result := Result and ( Pos(f.Masks[a].Parts[i], uFileName) <> 0 );
      if Result then Break;
    end;
end;
function AllFiles(const Masks: array of String): Boolean;
var
    Len: Integer;
begin
    Len := GetArrayLength(Masks);
    case Len of
        0: Result := True;
        1: Result := Masks[0] = ALL_FILES;
    else
        Result := False;
    end;
end;
////////////////////////////////////////////////////////////////////////////////////////////
 const
    COPY_COLLECTING_INFO = 0;
    COPY_IN_PROGRESS = 1;
    COPY_FINISHED = -1;
     
    SET_OVERWRITE_EXISTING_FILES = 2;
    SET_MOVE_FILES = 4;
    SET_PROCESS_READONLY_FILES = 8;
    
    UNDEF_INT = -1;

    COPY_BLOCK_SIZE = 65536;
    
type
    _FILE_INFO = record
        FilePath: String;
        Size: Extended;
    end;
    _FILE_CALLBACK =
    function
    (
        const Msg: Integer; //сообщение статуса копирования
        const srcFilePath: String; //путь к текущему исходному файлу
        const dstFilePath: String; //путь к текущему файлу назначения
        const FileBytes: Extended; //размер текущего файла в байтах
        const FileBytesCopied: Extended; //сколько байт текущего файла скопировано
        const OverallBytes: Extended; //размер всех файлов в байтах
        const OverallBytesCopied: Extended //сколько байт всех файлов скопировано
    ): Boolean; //чтоб отменить копирование нужно вернуть False
    
function QuadPart(const HighPart: Longint; const LowPart: DWORD): Extended;
begin
    Result := HighPart * $80000000{2^32} + LowPart;
end;
procedure AddFileInfo
(
    const uFileInfo: TFindRec;
    const uFilePath: String;
    var Files: array of _FILE_INFO;
    var FilesCount: Integer
);
begin
    Inc(FilesCount);
    SetArrayLength(Files, FilesCount);
    Files[FilesCount-1].FilePath := uFilePath + uFileInfo.Name;
    Files[FilesCount-1].Size := QuadPart(uFileInfo.SizeHigh, uFileInfo.SizeLow);
end;
procedure FindFiles
(
    const srcFolder: String;
    const f: _FILES_MASKS_SHOBLA;
    const FindAll: Boolean;
    var Files: array of _FILE_INFO;
    var FilesCount: Integer;
    var Canceled: Boolean;
    const CallBack: _FILE_CALLBACK
);
var
    FileInfo: TFindRec;
begin
    if FindFirst(srcFolder + ALL_FILES, FileInfo) then
    try
        repeat
            if Canceled then Break;
        
            if (FileInfo.Name <> '.') and (FileInfo.Name <> '..') then
            begin
                if FileInfo.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
                begin

                    if FindAll then
                    begin
                        AddFileInfo(FileInfo, srcFolder, Files, FilesCount);
                        if CallBack <> nil then
                          if not CallBack
                          (
                              COPY_COLLECTING_INFO,
                              Files[FilesCount-1].FilePath,
                              '',
                              Files[FilesCount-1].Size,
                              UNDEF_INT,
                              UNDEF_INT,
                              UNDEF_INT
                          ) then
                          begin
                              Canceled := True;
                              Break;
                          end;
                    end
                    else if ThatFile(FileInfo.Name, f) then
                    begin
                        AddFileInfo(FileInfo, srcFolder, Files, FilesCount);
                        if CallBack <> nil then
                          if not CallBack
                          (
                              COPY_COLLECTING_INFO,
                              Files[FilesCount-1].FilePath,
                              '',
                              Files[FilesCount-1].Size,
                              UNDEF_INT,
                              UNDEF_INT,
                              UNDEF_INT
                          ) then
                          begin
                              Canceled := True;
                              Break;
                          end;
                    end;

                end else if FileInfo.Attributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY then
                  FindFiles(
                      srcFolder + FileInfo.Name + BACKSLASH,
                      f,
                      FindAll,
                      Files,
                      FilesCount,
                      Canceled,
                      CallBack
                  );
            end;
        until not FindNext(FileInfo);

    finally
        FindClose(FileInfo);
    end;
end;
function CountFilesSize(const Files: array of _FILE_INFO; const FilesCount: Integer): Extended;
var
    i: Integer;
begin
    Result := 0;
    for i := 0 to FilesCount-1 do IncEx(Result, Files[i].Size);
end;
function GetNewFilePath(
    const srcFolder: String; 
    const dstFolder: String;
    const srcFilePath: String
): String;  // returns dstFilePath
var
    BuffFilePath: String;
begin
    BuffFilePath := srcFilePath;
    StringChange(BuffFilePath, srcFolder, '');
    Result := dstFolder + BuffFilePath;
end;

#ifdef UNICODE
    #define A "W"
#else
    #define A "A"
#endif
function SetFileAttributes(lpFileName: String; dwFileAttributes: DWORD): BOOL; external 'SetFileAttributes{#A}@kernel32.dll stdcall';
function GetFileAttributes(lpFileName: PAnsiChar): DWORD; external 'GetFileAttributes{#A}@kernel32.dll stdcall';

function CopyFiles(
    const srcFolder: String; //путь, откуда копировать
    const dstFolder: String; //путь, куда откуда копировать
    const Masks: array of String; //массив масок файла, например: ['*Soft*.exe', '*Soft*a*.exe', 'Valve*.*', '*.e*', '*.exe']
    const dwOptions: DWORD;
    const CallBack: _FILE_CALLBACK //указатель на функцию обратного вызова _FILE_CALLBACK или nil
): Boolean;
var
    Files: array of _FILE_INFO;
    f: _FILES_MASKS_SHOBLA;
    FilesCount: Integer;
    CopyAll: Boolean;
    
    Canceled: Boolean;
    ReadOnlyOff, ReadOnlyFile: Boolean;

    OverallBytes, OverallBytesCopied: Extended;

    srcFileStream, dstFileStream: TFileStream;
    dstFilePath, srcFilePath: String;
    i, CopyBytes, BytesLeft: Integer;
    
    CurrentFileDir: String;
begin
    Result := False;
    
    if not DirExists(srcFolder) then Exit;
    
    Canceled := False;
    ReadOnlyFile := False;

    CopyAll := AllFiles(Masks);
    if not CopyAll then SplitFilesMasks(Masks, f);

    FilesCount := 0;
    FindFiles
    (
        AddBackslash(RemoveBackslash(srcFolder)),
        f,
        CopyAll,
        Files,
        FilesCount,
        Canceled,
        CallBack
    );
    if (FilesCount = 0) or Canceled then Exit;
    
    if CallBack <> nil then
    begin
        OverallBytes := CountFilesSize(Files, FilesCount);
        OverallBytesCopied := 0;
    end;
    
    for i := 0 to FilesCount-1 do
    begin
        if Canceled then Break;
        
        srcFilePath := Files[i].FilePath;
        dstFilePath := GetNewFilePath(srcFolder, AddBackslash(RemoveBackslash(dstFolder)), srcFilePath);

        if dwOptions and SET_OVERWRITE_EXISTING_FILES = 0 then
         if FileExists(dstFilePath) then Continue;
         
        if dwOptions and SET_PROCESS_READONLY_FILES = SET_PROCESS_READONLY_FILES then
          if FileExists(dstFilePath) then
            if (GetFileAttributes(dstFilePath) and FILE_ATTRIBUTE_READONLY) = FILE_ATTRIBUTE_READONLY then
            begin
                ReadOnlyFile := True;
                ReadOnlyOff := SetFileAttributes(dstFilePath, FILE_ATTRIBUTE_NORMAL);
                if not ReadOnlyOff then
                begin
                    Canceled := True;
                    Break;
                end;
            end;
        
        if not ForceDirectories(ExtractFilePath(dstFilePath)) then
        begin
            Canceled := True;
            Break;
        end;

        srcFileStream := TFileStream.Create(srcFilePath, fmOpenRead);
        dstFileStream := TFileStream.Create(dstFilePath, fmCreate);
        
        BytesLeft := srcFileStream.Size - srcFileStream.Position;
        CopyBytes := COPY_BLOCK_SIZE;
        try
            while BytesLeft > 0 do
            begin
                if BytesLeft < COPY_BLOCK_SIZE then CopyBytes := BytesLeft;
                
                dstFileStream.CopyFrom(srcFileStream, CopyBytes);
                
                BytesLeft := srcFileStream.Size-srcFileStream.Position;

                IncEx(OverallBytesCopied, CopyBytes);
                if CallBack <> nil then
                  if not CallBack
                  (
                      COPY_IN_PROGRESS,
                      srcFilePath,
                      dstFilePath,
                      Files[i].Size,
                      Files[i].Size - BytesLeft,
                      OverallBytes,
                      OverallBytesCopied
                  ) then
                  begin
                      Canceled := True;
                      Break;
                  end;
            end;
        finally
            srcFileStream.Free;
            dstFileStream.Free;

            if ReadOnlyFile then
            begin
                ReadOnlyOff := not SetFileAttributes(dstFilePath, FILE_ATTRIBUTE_READONLY);
                if ReadOnlyOff then
                  Canceled := True
                else
                  ReadOnlyFile := False;
            end;
            
            if Canceled then
              DeleteFile(dstFilePath);

            if dwOptions and SET_MOVE_FILES = SET_MOVE_FILES then
            begin
                DeleteFile(srcFilePath);
                CurrentFileDir := ExtractFilePath(srcFilePath); 
                if CurrentFileDir <> srcFolder then
                  RemoveDir(CurrentFileDir); // removes dir if it is empty
            end;
        end;
    end;

    Result := not Canceled;
    if Result then
      if CallBack <> nil then
        CallBack(COPY_FINISHED, '', '', UNDEF_INT, UNDEF_INT, UNDEF_INT, UNDEF_INT);
end;

////////////////////////////////////////////  demo //////////////////////////////////////////////////////////////////
var
    MainCopyPrgBar,FileCopyPrgBar: TNewProgressBar;
    
    function ____________________
    (
        const Msg: Integer;
        const srcFilePath: String;
        const dstFilePath: String;
        const FileBytes: Extended;
        const FileBytesCopied: Extended;
        const OverallBytes: Extended;
        const OverallBytesCopied: Extended
    ): Boolean;
    begin
        case Msg of
            COPY_IN_PROGRESS:
            begin
                WizardForm.Caption := FloatToStr(FileBytes) + #32#32 + FloatToStr(FileBytesCopied);

                FileCopyPrgBar.Position := Round( (100*FileBytesCopied) / FileBytes );
                MainCopyPrgBar.Position := Round( (100*OverallBytesCopied) / OverallBytes );
            end;
            COPY_FINISHED: MsgBox('Finish! :)', mbInformation, MB_OK);
        end;
        
        Application.ProcessMessages;
        
        Result := not Application.Terminated;
    end;
    

    

procedure ButtonClick(Sender: TObject);
begin
    CopyFiles('C:\src\', 'C:\test',['*'], SET_PROCESS_READONLY_FILES or SET_OVERWRITE_EXISTING_FILES, @____________________);
end;

procedure InitializeWizard();
begin
    WizardForm.OuterNotebook.Hide;
    WizardForm.Canvas.Brush.Style := bsClear;
    MainCopyPrgBar := TNewProgressBar.Create(nil);
    with MainCopyPrgBar do
    begin
        Parent:= WizardForm;
        SetBounds(ScaleX(5), ScaleY(5), WizardForm.ClientWidth-10, ScaleY(20));
    end;
    FileCopyPrgBar := TNewProgressBar.Create(nil);
    with FileCopyPrgBar do
    begin
        Parent:= WizardForm;
        SetBounds(ScaleX(5), ScaleY(30), WizardForm.ClientWidth-10, ScaleY(20));
    end;

    with TButton.Create(WizardForm) do
    begin
        Parent:= WizardForm;
        Left := ScaleX(0);
        Top := ScaleY(200);
        Width := ScaleY(150);
        Caption:='Copy';
        OnClick:=@ButtonClick;
    end;
end;


пробуй!

Последний раз редактировалось Johny777, 21-11-2013 в 19:30.


Отправлено: 17:54, 21-11-2013 | #1482


Новый участник


Сообщения: 11
Благодарности: 0

Профиль | Сайт | Отправить PM | Цитировать


Всем привет ребята помогите выдаёт ошибкуhttp://forum.oszone.net/attachment.p...3&d=1385054354

Последний раз редактировалось dima.dmitrienko.71@fb, 28-11-2013 в 20:36.


Отправлено: 21:19, 21-11-2013 | #1483


Пользователь


Сообщения: 75
Благодарности: 6

Профиль | Отправить PM | Цитировать


Джони ну помоги пожалуйста,на прошлой стр описал проблемки. Или ткни носом,может уже решение было проблем таких.

Последний раз редактировалось FX-DENIS, 21-11-2013 в 22:10.


Отправлено: 21:29, 21-11-2013 | #1484


Аватара для nik1967

Старожил


Сообщения: 440
Благодарности: 251

Профиль | Сайт | Отправить PM | Цитировать


Цитата Dinvin4ester:
А мне не поможете ? »
Всё отображается.

-------
Если сообщение оказалось полезным для Вас, то помимо спасибо, можно нажать на "Полезное сообщение".


Отправлено: 22:54, 21-11-2013 | #1485


Аватара для habib2302

Ветеран


Сообщения: 862
Благодарности: 102

Профиль | Отправить PM | Цитировать


доброе время суток. как сделать если отсутствует какой-то компонент например DirectX была снята галка с компонента и был не активным

-------
Помог? От "Полезное сообщение" не откажусь!!!


Отправлено: 14:18, 22-11-2013 | #1486


Аватара для Dinvin4ester

Старожил


Сообщения: 229
Благодарности: 0

Профиль | Отправить PM | Цитировать


nik1967,
Отображается если использовать сторонние архиваторы , а я использую только средства инно . Понимаю что так не получится , но мне бы прикрутить стандартный прогресс бар .

Последний раз редактировалось Dinvin4ester, 23-11-2013 в 23:35.


Отправлено: 16:55, 22-11-2013 | #1487


Аватара для El Sanchez

Ветеран


Contributor


Сообщения: 1274
Благодарности: 1030

Профиль | Отправить PM | Цитировать


Цитата FX-DENIS:
Совместил фри арк и скрипт процентов и размера который мне давал Serega.Но вот беда,прогресс бар не отображается »
FX-DENIS, скажите сначала что нужно на этапе ssInstall (или ssPostInstall) делать. Словами, без кода.

Цитата FX-DENIS:
прогресс бар инно именно инно ,не фри арка,показывается 103% а не 100,как это исправить? »
FX-DENIS, это не исправить, в 5 класс школы уже не вернуться. Ищите в скрипте формулу, по которой проценты вычисляются.

Цитата FX-DENIS:
Третья проблемка инно не учитывает архивы фри арк и пишет размер только инно,как заставить писать размер места для установки правильно?Смысл тогда в строке #define NeedSize "5000000000" ? »
FX-DENIS, используется, например, так:
Код: Выделить весь код
#define NeedSize "5000000000"

[Setup]
#ifdef NeedSize
ExtraDiskSpaceRequired={#NeedSize}
#endif
Это сообщение посчитали полезным следующие участники:

Отправлено: 21:58, 22-11-2013 | #1488


Новый участник


Сообщения: 11
Благодарности: 0

Профиль | Сайт | Отправить PM | Цитировать


Помогите решить проблему Файл 107162

Последний раз редактировалось dima.dmitrienko.71@fb, 28-11-2013 в 20:36.


Отправлено: 23:08, 22-11-2013 | #1489


Аватара для El Sanchez

Ветеран


Contributor


Сообщения: 1274
Благодарности: 1030

Профиль | Отправить PM | Цитировать


Цитата dima.dmitrienko.71@fb:
Помогите решить проблему ffff.png »
dima.dmitrienko.71@fb, где-то выше не закрытый end-ом begin.
Это сообщение посчитали полезным следующие участники:

Отправлено: 23:15, 22-11-2013 | #1490



Компьютерный форум OSzone.net » Автоматическая установка Windows » Автоматическая установка приложений » Скрипты Inno Setup. Помощь и советы [часть 6]

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Скрипты Inno Setup. Помощь и советы [часть 5] El Sanchez Автоматическая установка приложений 1999 28-03-2013 19:09
Скрипты Inno Setup. Помощь и советы [часть 4] El Sanchez Автоматическая установка приложений 2099 22-05-2012 23:16
Скрипты Inno Setup. Помощь и советы [часть 3] Serega Автоматическая установка приложений 3755 26-10-2011 17:58
[архив] Скрипты Inno Setup. Помощь и советы [часть 2] Serega Автоматическая установка приложений 2651 08-11-2010 18:34
Скрипты Inno Setup Compiler QAZAK Автоматическая установка приложений 7 15-01-2007 17:59




 
Переход