2

I'm trying to use the scroll bar position code from this article to get the scroll bar position of a TNewCheckListBox object I have defined.

It seems like the handle parameter is not accessible.

I want to be able to adjust the related hover message according to the scroll position. Currently when a user scrolls down, the hover message stays relative to the first x elements of the TNewCheckListBox.

    procedure OnScrollPosition(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; SysTime: DWORD);
    var
      ScrollInfo: TScrollInfo;
    begin
      ScrollInfo.cbSize  := SizeOf(ScrollInfo);
      ScrollInfo.fMask    := SIF_RANGE or SIF_POS or SIF_PAGE;
         if GetScrollInfo(WizardForm.LicenseMemo.Handle, SB_VERT, ScrollInfo) then
                       // Above ^ WizardForm.LicenceMemo.Handle needs to be the
                       // handle for my TNewCheckListBox object!
          if ScrollInfo.nPos = ScrollInfo.nMax - ScrollInfo.nPage then
            begin
              WizardForm.LicenseAcceptedRadio.Enabled := True;
              WizardForm.LicenseNotAcceptedRadio.Enabled := True;
            end;
    end;

Any help / ideas would be much appreciated!

Here's the full code...

    [Setup]
    AppName=MyProg
    AppVersion=1.0
    CreateAppDir=No
    LicenseFile=Licence.rtf

    [Files]
    Source: Message1.rtf;  Flags: dontcopy;
    Source: Message2.rtf;  Flags: dontcopy;
    Source: Message3.rtf;  Flags: dontcopy;
    Source: Message4.rtf;  Flags: dontcopy;
    Source: Message5.rtf;  Flags: dontcopy;
    Source: Message6.rtf;  Flags: dontcopy;
    Source: Message7.rtf;  Flags: dontcopy;
    Source: Message8.rtf;  Flags: dontcopy;
    Source: Message9.rtf;  Flags: dontcopy;
    Source: Message10.rtf; Flags: dontcopy;
    Source: Message11.rtf; Flags: dontcopy;
    Source: Message12.rtf; Flags: dontcopy;
    Source: Message13.rtf; Flags: dontcopy;
    Source: Message14.rtf; Flags: dontcopy;
    Source: Message15.rtf; Flags: dontcopy;
    Source: Message16.rtf; Flags: dontcopy;
    Source: Message17.rtf; Flags: dontcopy;
    Source: Message18.rtf; Flags: dontcopy;
    Source: Message19.rtf; Flags: dontcopy;


    ;-- Window API .dll and Timer functions .dll
    Source: user32.dll;       Flags: dontcopy;
    Source: InnoCallback.dll; Flags: dontcopy; 

    [Code]

    //---------------------------------------------------------------------------
    // Setup for Windows API functions
    //---------------------------------------------------------------------------
    const
      SB_VERT   = 1;  // Indicate we want to know about the vertical bar (0 or 1)
      SIF_RANGE = 1;  // Copy the range of the scroll bar to nMin and nMax (0 or 1)
      SIF_POS   = 4;
      SIF_PAGE  = 2;

    type
      TScrollInfo = record
        cbSize   : UINT;
        fMask    : UINT;
        nMin     : Integer;
        nMax     : Integer;
        nPage    : UINT;
        nPos     : Integer;
        nTrackPos: Integer;
      end;


    var
      Page      : TWizardPage;
      ListBox   : TNewCheckListBox;
      Memo      : TRichEditViewer;
      CheckLabel: TLabel;
      MouseY    : integer;

    type
      TTimerProc = procedure(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; SysTime: DWORD);

    //---------------------------------------------------------------------------
    // Define Windows API functions
    //---------------------------------------------------------------------------
    function GetScrollInfo(hWnd: HWND; BarFlag: Integer; var ScrollInfo: TScrollInfo): BOOL;
              external 'GetScrollInfo@user32.dll stdcall';

    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';


    //---------------------------------------------------------------------------
    // Functions for checking scroll position via Windows API
    //---------------------------------------------------------------------------
    procedure OnScrollPosition(Wnd: HWND; Msg: UINT; TimerID: UINT_PTR; SysTime: DWORD);
    var
      ScrollInfo: TScrollInfo;
    begin
      ScrollInfo.cbSize  := SizeOf(ScrollInfo);
      ScrollInfo.fMask    := SIF_RANGE or SIF_POS or SIF_PAGE;
        if GetScrollInfo(WizardForm.LicenseMemo.Handle, SB_VERT, ScrollInfo) then
          if ScrollInfo.nPos = ScrollInfo.nMax - ScrollInfo.nPage then
            begin
              WizardForm.LicenseAcceptedRadio.Enabled := True;
              WizardForm.LicenseNotAcceptedRadio.Enabled := True;
            end;
    end;

    procedure ScrollPosition();
    var
      TimerCallback: LongWord;
      TimerID: UINT_PTR;
    begin
      TimerCallback := WrapTimerProc(@OnScrollPosition, 4);
      TimerID := SetTimer(0, 0, 500, TimerCallback);
    end;

    //---------------------------------------------------------------------------
    // Define what happens when a certain page is selected
    //---------------------------------------------------------------------------
    procedure CurPageChanged(CurPageID: Integer);
    var
      ScrollInfo: TScrollInfo;
    begin 

    if CurPageID = wpLicense then
      WizardForm.LicenseAcceptedRadio.Enabled := False;
      WizardForm.LicenseNotAcceptedRadio.Enabled := False;
      ScrollPosition
    end;

    //---------------------------------------------------------------------------
    // Functions to show hover messages and check boxes
    //---------------------------------------------------------------------------
    function CheckedBox(ItemNumber: integer): Boolean;
    begin                                    
      Result:= ListBox.Checked[ItemNumber]; 
    end;
    procedure CheckOnClick (Sender: TObject);
    begin
      if MouseY < ListBox.Items.Count then
        begin 
          ListBox.Checked[MouseY]:= Not(ListBox.Checked[MouseY]);
        end;
    end;

    procedure CheckMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    begin 
      MouseY:= Y/ScaleY(16);
      if MouseY < ListBox.Items.Count then
        begin
          Memo.RTFText:= TStrings(ListBox.ItemObject[MouseY]).Text;
        end;
    end;

    //---------------------------------------------------------------------------
    // Program entry point...
    //---------------------------------------------------------------------------
    procedure InitializeWizard();
    var
      Index: Integer;
    begin
      ExtractTemporaryFile('Message1.rtf'); 
      ExtractTemporaryFile('Message2.rtf');
      ExtractTemporaryFile('Message3.rtf');
      ExtractTemporaryFile('Message4.rtf'); 
      ExtractTemporaryFile('Message5.rtf');
      ExtractTemporaryFile('Message6.rtf');
      ExtractTemporaryFile('Message7.rtf'); 
      ExtractTemporaryFile('Message8.rtf');
      ExtractTemporaryFile('Message9.rtf');
      ExtractTemporaryFile('Message10.rtf'); 
      ExtractTemporaryFile('Message11.rtf');
      ExtractTemporaryFile('Message12.rtf');
      ExtractTemporaryFile('Message13.rtf'); 
      ExtractTemporaryFile('Message14.rtf');
      ExtractTemporaryFile('Message15.rtf');
      ExtractTemporaryFile('Message16.rtf'); 
      ExtractTemporaryFile('Message17.rtf');
      ExtractTemporaryFile('Message18.rtf');
      ExtractTemporaryFile('Message19.rtf');

      WizardForm.LicenseAcceptedRadio.Enabled := False;
      WizardForm.LicenseNotAcceptedRadio.Enabled := False;

      Page:=CreateCustomPage(wpLicense, 'A Page', 'This is a custom page with hover functionality.')

      ListBox:= TNewCheckListBox.Create(Page); 
      with ListBox do
        begin
          Left   := 15
          Top    := 0
          Width  := 200
          Height := 149
          Parent := Page.Surface
          AddCheckBox('Check Box Group Item', '', 0, True, True, True, True, TStringList.Create);
          AddCheckBox('Check Box Item 1', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 2', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 3', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 4', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 5', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 6', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 7', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 8', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 9', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 10', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 11', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 12', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 13', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 14', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 15', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 16', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 17', '', 1, True, True, False, True, TStringList.Create);
          AddCheckBox('Check Box Item 18', '', 1, True, True, False, True, TStringList.Create)

          TStrings(ItemObject[0]).LoadFromFile(ExpandConstant('{tmp}\Message1.rtf'));
          TStrings(ItemObject[1]).LoadFromFile(ExpandConstant('{tmp}\Message2.rtf'));
          TStrings(ItemObject[2]).LoadFromFile(ExpandConstant('{tmp}\Message3.rtf'));
          TStrings(ItemObject[3]).LoadFromFile(ExpandConstant('{tmp}\Message4.rtf'));
          TStrings(ItemObject[4]).LoadFromFile(ExpandConstant('{tmp}\Message5.rtf'));
          TStrings(ItemObject[5]).LoadFromFile(ExpandConstant('{tmp}\Message6.rtf'));
          TStrings(ItemObject[6]).LoadFromFile(ExpandConstant('{tmp}\Message7.rtf'));
          TStrings(ItemObject[7]).LoadFromFile(ExpandConstant('{tmp}\Message8.rtf'));
          TStrings(ItemObject[8]).LoadFromFile(ExpandConstant('{tmp}\Message9.rtf'));
          TStrings(ItemObject[9]).LoadFromFile(ExpandConstant('{tmp}\Message10.rtf'));
          TStrings(ItemObject[10]).LoadFromFile(ExpandConstant('{tmp}\Message11.rtf'));
          TStrings(ItemObject[11]).LoadFromFile(ExpandConstant('{tmp}\Message12.rtf'));
          TStrings(ItemObject[12]).LoadFromFile(ExpandConstant('{tmp}\Message13.rtf'));
          TStrings(ItemObject[13]).LoadFromFile(ExpandConstant('{tmp}\Message14.rtf'));
          TStrings(ItemObject[14]).LoadFromFile(ExpandConstant('{tmp}\Message15.rtf'));
          TStrings(ItemObject[15]).LoadFromFile(ExpandConstant('{tmp}\Message16.rtf'));
          TStrings(ItemObject[16]).LoadFromFile(ExpandConstant('{tmp}\Message17.rtf'));
          TStrings(ItemObject[17]).LoadFromFile(ExpandConstant('{tmp}\Message18.rtf'));
          TStrings(ItemObject[18]).LoadFromFile(ExpandConstant('{tmp}\Message19.rtf'));
        end;

      Memo:= TRichEditViewer.Create(Page); 
      with Memo do
        begin
          Left        := ListBox.Left + ListBox.Width + 8;
          Top         := ListBox.Top;
          Width       := ListBox.Width;
          Height      := ListBox.Height;
          Color       := clBtnFace;
          Enabled     := False;
          BorderStyle := bsNone;
          Parent      := Page.Surface;
        end;

      CheckLabel:= TLabel.Create(Page); 
      with CheckLabel do
        begin
          Width       := ListBox.Width;
          Height      := ListBox.Height;
          Autosize    := False;
          Transparent := True;
          OnMouseMove := @CheckMouseMove;
          OnClick     := @CheckOnClick;
          Parent      := ListBox;
          Cursor      := 1;
        end;
    end;
Community
  • 1
  • 1
Tom Clarke
  • 118
  • 8
  • What are *"objects not created by WizardForm"* ? Or what is the problem you're trying to resolve ? Are you asking how to get scroll info for your `TNewCheckListBox` ? Btw. do not include user32.dll library into your setup. – TLama Sep 19 '14 at 11:30
  • Sorry, yes that is exactly what I am asking. Thanks for notifying me not to include user32.dll too. What is the best way I can get access to the Windows API? – Tom Clarke Sep 19 '14 at 11:41
  • Ok, I see. Well, you have declared your object as a global variable `ListBox` (which is a must for methods to *see* your object), so let's just pass `ListBox.Handle` instead of `WizardForm.LicenseMemo.Handle`. To your question about Windows API, Windows API functions are part of the user's system and are built in the libraries from which you're importing them (just like you've imported `GetScrollInfo` from `user32.dll`), so there is no *best* way. There is just one way; the way you are doing that. You were just including user32.dll in your setup, which would not be used anyway. – TLama Sep 19 '14 at 11:53
  • Thanks a lot for your quick responses. I did first try to reference the `ListBox` object via `Page.ListBox.Handle` so that's where I was going wrong. I have also tried including the user32.dll library by using `Source: "{sys}\user32.dll;"` as the path but Inno doesn't seem to recognise the Constant and instead uses the path to the setup folder with the source path appended to it. Do I pass the 'external' flag to the file? – Tom Clarke Sep 19 '14 at 12:57
  • No no. If you look closely to function imports, you will see the major difference. The `GetScrollInfo` function (which is Windows API) has a tail like `@user32.dll` whilst `WrapTimerProc` (which is a function from custom library) uses `@files:InnoCallback.dll`. That `files:` prefix instructs Inno Setup to extract the `InnoCallback.dll` from the `[Files]` section and so this library must be included there. The `GetScrollInfo` function import has no such prefix and as such is searched by [`these rules`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms682586(v=vs.85).aspx)... – TLama Sep 19 '14 at 13:02
  • ...in the system. Do not include `user32.dll` in your setup. It is part of the system. So just remove the `user32.dll` entry from your `[Files]` section. It's not been used anyway. – TLama Sep 19 '14 at 13:03
  • Thank you for clearing that up. – Tom Clarke Sep 19 '14 at 13:05

0 Answers0