Inno Setup disable component selection when a specific component is selected

前端 未结 2 1127
天涯浪人
天涯浪人 2021-01-07 07:50

I would like to be able to disable the selection of a component based on a specific component being selected. I cannot do this through nesting of components, as the componen

相关标签:
2条回答
  • 2021-01-07 08:25

    The code I used in the end is based entirely on @TLama's code that he provided previously as this does not require the use of an external DLL.

    [Code]
    const
    //Define global constants
      CompIndexSync = 15;
      CompIndexSyncClient = 16;
      CompIndexSyncServer = 17;
    
    var
    //Define global variables
      CompPageVisited: Boolean;
      DefaultCompClickCheck: TNotifyEvent;
      DefaultCompTypeChange: TNotifyEvent;
    
    //Uncheck and set the enabled state of the Sync components based on whether the Client component is selected
    procedure UpdateComponents;
    begin
      with WizardForm.ComponentsList do
        begin
          if IsComponentSelected('Client') then
            begin
              CheckItem(CompIndexSync, coUncheck);
            end; 
          ItemEnabled[CompIndexSync] := not IsComponentSelected('Client');
          ItemEnabled[CompIndexSyncClient] := not IsComponentSelected('Client');
          ItemEnabled[CompIndexSyncServer] := not IsComponentSelected('Client');
          Invalidate; //required for text state to update correctly
        end;
    end;
    
    //Update the component states if the component states change and restore the original event handler procedures
    procedure ComponentsClickCheck(Sender: TObject);
    begin
      DefaultCompClickCheck(Sender);
      UpdateComponents;
    end;
    
    procedure ComponentsTypesComboChange(Sender: TObject);
    begin
      DefaultCompTypeChange(Sender);
      UpdateComponents;
    end;
    
    procedure InitializeWizard();
    begin
    //Store the original Components Page OnClickCheck and Types Combo Box OnChange event procedures and assign custom procedures
      DefaultCompClickCheck := WizardForm.ComponentsList.OnClickCheck;
      WizardForm.ComponentsList.OnClickCheck := @ComponentsClickCheck;
      DefaultCompTypeChange := WizardForm.TypesCombo.OnChange;
      WizardForm.TypesCombo.OnChange := @ComponentsTypesComboChange;
    end;
    
    procedure CurPageChanged(CurPageID: Integer);
    begin
    //Update the Components Page if entered for the first time
      if (CurPageID = wpSelectComponents) and not CompPageVisited then
        begin
          CompPageVisited := True;
          UpdateComponents;
        end;
    end;
    

    Although this and @RobeN's solutions both work, they both exhibit a graphical update issue i.e. when changing the status of the components from active to disabled and vice versa, the text doesn't automatically dim or undim until the scroll bar is dragged.

    Note that the refresh issue described above is resolved by adding an `Invalidate;' line. Code updated above with a comment to reflect this. See Inno Setup Components graphical refresh issue for further information. Thanks @TLama.

    0 讨论(0)
  • 2021-01-07 08:39

    You had TLama's solution which was probably better than the following, but still this code is also a way to achieve the goal (though you will need innocallback.dll):

    [Setup]
    AppName=My Program
    AppVersion=1.5
    DefaultDirName={pf}\My Program
    
    [Files]
    Source: ".\InnoCallback.dll"; DestDir: "{tmp}"; Flags: dontcopy nocompression
    
    [Components]
    Name: "Client"; Description: "Client"; Types: custom
    Name: "Sync"; Description: "Sync"; Types: custom
    
    [Code]
    var
    TimerID: Integer;
    
    type
    TTimerProc = procedure(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; 
    SysTime: DWORD);
    function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
    external 'wrapcallback@files:InnoCallback.dll stdcall';    
    function SetTimer(hWnd: HWND; nIDEvent, uElapse: UINT;
    lpTimerFunc: UINT): UINT; external 'SetTimer@user32.dll stdcall';
    
    function KillTimer(hWnd: HWND; uIDEvent: UINT): BOOL; 
    external 'KillTimer@user32.dll stdcall'; 
    
    procedure KillComponentsTimer;
    begin
      if TimerID <> 0 then 
        begin
          if KillTimer(0, TimerID) then
            TimerID := 1;
        end;
    end;
    
    procedure OnComponentsCheck(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; 
    SysTime: DWORD);
    begin
        if IsComponentSelected('Client') then begin
            WizardForm.ComponentsList.Checked[1] := False;
            WizardForm.ComponentsList.ItemEnabled[1] := False;
        end
        else begin
            WizardForm.ComponentsList.ItemEnabled[1] := True;
        end;    
        if IsComponentSelected('Sync') then begin
            WizardForm.ComponentsList.Checked[0] := False;
            WizardForm.ComponentsList.ItemEnabled[0] := False;
        end
        else begin 
            WizardForm.ComponentsList.ItemEnabled[0] := True;
        end;
    end;
    
    procedure ComponentsCheck();
    var
      TimerCallback: LongWord;
    begin
      TimerCallback := WrapTimerProc(@OnComponentsCheck, 4);
      TimerID := SetTimer(0, 0, 100, TimerCallback);
    end;
    
    procedure CurPageChanged(CurPageID: Integer);
    begin
    if CurPageID = wpSelectComponents then
      begin
        ComponentsCheck;
      end;
    if CurPageID = not wpSelectComponents then 
      begin
       KillComponentsTimer;
      end;
    end;
    
    0 讨论(0)
提交回复
热议问题