CustomPage для серийного номера в Inno Setup

17

Как создать CustomPage в Inno Setup с помощью Edit Boxes для серийного номера? Например. 6x5chars или 7x5chars?

Скрипт должен проверить, заполнены ли все поля до появления следующей кнопки.

Было бы хорошо, если бы была реализована функция Copy / Paste, которая позволила бы заполнить все поля редактирования, если содержимое буфера обмена соответствует шаблону серийного номера.     

задан RobeN 30.04.2012 в 16:22
источник

3 ответа

33

Вот один из подходов, который использует настраиваемую страницу, где создаются отдельные поля редактирования. Вам нужно указать значение константы SC_EDITCOUNT , где указано количество полей ввода, а SC_CHARCOUNT - количество символов, которое можно ввести в эти поля редактирования. Если вы находитесь в первом окне редактирования, вы можете вставить весь серийный номер, если он находится в формате по шаблону, ограниченному символом - (здесь функция TryPasteSerialNumber ). Чтобы получить серийный номер из полей редактирования, достаточно вызвать GetSerialNumber , где вы также можете указать разделитель для выходного формата (при необходимости).

[Setup]
AppName=Serial number project
AppVersion=1.0
DefaultDirName={pf}\Serial number project

[code]
function SetFocus(hWnd: HWND): HWND;
  external '[email protected] stdcall';
function OpenClipboard(hWndNewOwner: HWND): BOOL;
  external '[email protected] stdcall';
function GetClipboardData(uFormat: UINT): THandle;
  external '[email protected] stdcall';
function CloseClipboard: BOOL;
  external '[email protected] stdcall';
function GlobalLock(hMem: THandle): PAnsiChar;
  external '[email protected] stdcall';
function GlobalUnlock(hMem: THandle): BOOL;
  external '[email protected] stdcall';

var
  SerialPage: TWizardPage;
  SerialEdits: array of TEdit;

const
  CF_TEXT = 1;
  VK_BACK = 8;
  SC_EDITCOUNT = 6;
  SC_CHARCOUNT = 5;
  SC_DELIMITER = '-';

function IsValidInput: Boolean;
var
  I: Integer;
begin
  Result := True;
  for I := 0 to GetArrayLength(SerialEdits) - 1 do
    if Length(SerialEdits[I].Text) < SC_CHARCOUNT then
    begin
      Result := False;
      Break;
    end;
end;

function GetClipboardText: string;
var
  Data: THandle;
begin
  Result := '';
  if OpenClipboard(0) then
  try
    Data := GetClipboardData(CF_TEXT);
    if Data <> 0 then
      Result := String(GlobalLock(Data));
  finally
    if Data <> 0 then
      GlobalUnlock(Data);
    CloseClipboard;
  end;
end;

function GetSerialNumber(ADelimiter: Char): string;
var
  I: Integer;
begin
  Result := '';
  for I := 0 to GetArrayLength(SerialEdits) - 1 do
    Result := Result + SerialEdits[I].Text + ADelimiter;
  Delete(Result, Length(Result), 1);
end;

function TrySetSerialNumber(const ASerialNumber: string; ADelimiter: Char): Boolean;
var
  I: Integer;
  J: Integer;
begin
  Result := False;

  if Length(ASerialNumber) = ((SC_EDITCOUNT * SC_CHARCOUNT) + (SC_EDITCOUNT - 1)) then
  begin
    for I := 1 to SC_EDITCOUNT - 1 do
      if ASerialNumber[(I * SC_CHARCOUNT) + I] <> ADelimiter then
        Exit;

    for I := 0 to GetArrayLength(SerialEdits) - 1 do
    begin
      J := (I * SC_CHARCOUNT) + I + 1;
      SerialEdits[I].Text := Copy(ASerialNumber, J, SC_CHARCOUNT);
    end;

    Result := True;
  end;
end;

function TryPasteSerialNumber: Boolean;
begin
  Result := TrySetSerialNumber(GetClipboardText, SC_DELIMITER);
end;

procedure OnSerialEditChange(Sender: TObject);
begin
  WizardForm.NextButton.Enabled := IsValidInput;
end;

procedure OnSerialEditKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  Edit: TEdit;
  EditIndex: Integer;
begin
  Edit := TEdit(Sender);
  EditIndex := Edit.TabOrder - SerialEdits[0].TabOrder;
  if (EditIndex = 0) and (Key = Ord('V')) and (Shift = [ssCtrl]) then
  begin
    if TryPasteSerialNumber then
      Key := 0;
  end
  else
  if (Key >= 32) and (Key <= 255) then
  begin
    if Length(Edit.Text) = SC_CHARCOUNT - 1 then
    begin
      if EditIndex < GetArrayLength(SerialEdits) - 1 then
        SetFocus(SerialEdits[EditIndex + 1].Handle)
      else
        SetFocus(WizardForm.NextButton.Handle);
    end;
  end
  else
  if Key = VK_BACK then
    if (EditIndex > 0) and (Edit.Text = '') and (Edit.SelStart = 0) then
      SetFocus(SerialEdits[EditIndex - 1].Handle);
end;

procedure CreateSerialNumberPage;
var
  I: Integer;
  Edit: TEdit;
  DescLabel: TLabel;
  EditWidth: Integer;
begin
  SerialPage := CreateCustomPage(wpWelcome, 'Serial number validation',
    'Enter the valid serial number');

  DescLabel := TLabel.Create(SerialPage);
  DescLabel.Top := 16;
  DescLabel.Left := 0;
  DescLabel.Parent := SerialPage.Surface;
  DescLabel.Caption := 'Enter valid serial number and continue the installation...';
  DescLabel.Font.Style := [fsBold];

  SetArrayLength(SerialEdits, SC_EDITCOUNT);
  EditWidth := (SerialPage.SurfaceWidth - ((SC_EDITCOUNT - 1) * 8)) div SC_EDITCOUNT;

  for I := 0 to SC_EDITCOUNT - 1 do
  begin
    Edit := TEdit.Create(SerialPage);
    Edit.Top := 40;
    Edit.Left := I * (EditWidth + 8);
    Edit.Width := EditWidth;
    Edit.CharCase := ecUpperCase;
    Edit.MaxLength := SC_CHARCOUNT;
    Edit.Parent := SerialPage.Surface;
    Edit.OnChange := @OnSerialEditChange;
    Edit.OnKeyDown := @OnSerialEditKeyDown;
    SerialEdits[I] := Edit;
  end;
end;

procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = SerialPage.ID then
    WizardForm.NextButton.Enabled := IsValidInput;  
end;

procedure InitializeWizard;
begin
  CreateSerialNumberPage;
end;

И вот как это выглядит:

    
ответ дан TLama 01.05.2012 в 02:12
источник
  • Спасибо. TLama - первые тесты положительные. Я вернусь с последними комментариями после тестов в пятницу. –  RobeN 01.05.2012 в 06:59
  • +1! и к моим фаворитам. –  kobik 01.05.2012 в 17:17
  • Кажется, что PChar вызывает проблему, так как вызывает ошибку Неизвестного типа. Не могли бы вы помочь? Я изменил небольшую секцию, которая отвечает за следующее: Активное / Неактивное состояние следующей кнопки: если Length (SerialEdits [I] .Text) <5, то это вызывает следующую кнопку Неактивно, пока все поля редактирования не будут заполнены 5 символами. В вашей версии один символ в каждом окне редактирования делает следующую кнопку активным. –  RobeN 07.05.2012 в 09:41
  • Исправлено. Теперь он должен быть ANSI и Unicode дружественным; И я удалил формат буфера обмена CF_UNICODETEXT, это была моя ошибка, нет необходимости получать данные для этого формата. Я добавил также улучшение от вашего последнего комментария к сообщению :-) –  TLama 07.05.2012 в 12:27
  • Отлично! Теперь функция Copy / Paste работает по назначению! –  RobeN 07.05.2012 в 12:46
Показать остальные комментарии
7

Вы можете заставить Inno запросить пользователя для серийного ключа, добавив функцию CheckSerial() .

Если вам нужно больше контролировать страницу, вы можете использовать одну из страниц запаса ( CreateInput...Page ) или пользовательскую страницу в мастере настройки с помощью CreateCustomPage() и добавление элементов управления по мере необходимости.

См. пример codedlg.iss , включенный в установку Inno.

    
ответ дан Deanna 30.04.2012 в 16:31
источник
  • И +1 здесь тоже! :) –  kobik 01.05.2012 в 17:21
2

Самый простой способ добавить поле «Серийный ключ» под текстовыми полями «Имя» и «Организация» - добавить в ваш файл iss что-то вроде следующего.

[Code]

  function CheckSerial(Serial: String): Boolean;
  begin
  // serial format is XXXX-XXXX-XXXX-XXXX
  Serial := Trim(Serial);
  if Length(Serial) = 19 then
    result := true;
 end;

Это может быть полезно сочетать с

[Setup]
DefaultUserInfoSerial={param:Serial}

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

    
ответ дан s01ipsist 10.03.2014 в 23:30
источник
  • ... как уже говорила Динна ... –  TLama 11.03.2014 в 11:36
  • Где добавить валидацию к серийному ключу ??? –  Shashishekhar Hasabnis 15.05.2017 в 06:24
  • stackoverflow.com/questions/11246105/... –  Shashishekhar Hasabnis 15.05.2017 в 07:30