2012-04-30 41 views
17

如何在Inno Setup的创建CustomPage与编辑框的序列号? 例如6x5chars或7x5chars?CustomPage在Inno Setup的序列号

脚本应该检查是否可用Next按钮之前所有的箱子都装满。

这将是还不错,如果有可能复制/粘贴功能来实现,如果剪贴板内容的序列号模式相匹配,将允许以填补所有的编辑框。

回答

33

下面是一个使用在其中创建单独的编辑框自定义页面的一种方法。您只需指定定义编辑框数量的SC_EDITCOUNT常量的值,并且SC_CHARCOUNT可以输入到这些编辑框的字符数是多少。如果你在第一个编辑框中,你可以粘贴整个序列号,如果它的格式是由- char(这里的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; 

这里是它的样子:

enter image description here

+2

谢谢TLama - 第一次测试是积极的。最迟在星期五进行测试后,我会回复最后的评论。 – RobeN

+2

+1!和我的最爱。 – kobik

+0

似乎是PChar导致的问题,因为它会调用未知类型的错误。你能帮忙吗? 我已经改变一点点部,负责下一个按钮激活/非作用状态: '如果长度(SerialEdits [I]。文本)<5 then' 这会导致下一个按钮是无效,直到所有的编辑框充满5个字符。在您的版本中,每个编辑框中的单个字符使下一个按钮处于活动状态 – RobeN

7

您可以通过创新科技添加CheckSerial()事件功能提示输入序列密钥的用户。

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

参见随创新安装的codedlg.iss例子。

+0

And +1 here here also! :) – kobik

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} 

如果之前的安装进入,这将在串行填被有效地结合起来。

+0

... ['作为迪安娜已经说过]'(http://stackoverflow.com/a/10385420/960757)... – TLama

+0

在哪里添加验证的串行密钥? –

+0

http://stackoverflow.com/questions/11246105/how-can-i-set-the-serial-for-this-serial-form-inno-setup –