【问题标题】:CustomPage for Serial Number in Inno SetupInno 设置中序列号的自定义页面
【发布时间】:2012-05-10 05:58:55
【问题描述】:

如何在 Inno Setup 中创建带有序列号编辑框的 CustomPage? 例如。 6x5chars 还是 7x5chars?

脚本应在“下一步”按钮可用之前检查是否所有框都已填满。

如果剪贴板内容与序列号模式匹配,如果可以实现允许填充所有编辑框的复制/粘贴功能,那也是很好的。

【问题讨论】:

    标签: inno-setup


    【解决方案1】:

    这是一种使用创建单独编辑框的自定义页面的方法。您只需指定定义编辑框数量的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 'SetFocus@user32.dll stdcall';
    function OpenClipboard(hWndNewOwner: HWND): BOOL;
      external 'OpenClipboard@user32.dll stdcall';
    function GetClipboardData(uFormat: UINT): THandle;
      external 'GetClipboardData@user32.dll stdcall';
    function CloseClipboard: BOOL;
      external 'CloseClipboard@user32.dll stdcall';
    function GlobalLock(hMem: THandle): PAnsiChar;
      external 'GlobalLock@kernel32.dll stdcall';
    function GlobalUnlock(hMem: THandle): BOOL;
      external 'GlobalUnlock@kernel32.dll 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;
    

    下面是它的样子:

    【讨论】:

      【解决方案2】:

      您可以通过添加CheckSerial() 事件函数让 Inno 提示用户输入序列号。

      如果您想对页面进行更多控制,可以使用其中一个库存页面 (CreateInput...Page) 或设置向导中使用CreateCustomPage() 的自定义页面,并根据需要添加控件。

      请参阅 Inno 设置中包含的 codedlg.iss 示例。

      【讨论】:

        【解决方案3】:

        在名称和组织文本字段下方添加序列键框的最简单方法是将以下内容添加到您的 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}
        

        如果之前为安装输入了序列号,它将填写序列号。

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-11
        • 1970-01-01
        相关资源
        最近更新 更多