Recent

Author Topic: Need help with ScrollWindowEx  (Read 4763 times)

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Need help with ScrollWindowEx
« on: February 23, 2023, 03:46:31 pm »
 
Code: Pascal  [Select][+][-]
  1. SendMessage(PageMemo.handle, WM_VSCROLL,  MakeLong(SB_THUMBPOSITION,  VrtBarPos));
  2.  

       The above function is what I have used for years.
       It works for the RUN test by the compiler. It also
       works if I put the compiled EXE into a new folder.

       But once WINDOWS realizes that I have done this,
       they block the SENDMESSAGE function; ie. it just
       won't scroll anymore. This has developed recently,
       and I think it is a security issue by WINDOWS.
       So I am trying to implement the ScrollInfo method.

       Below is the ScrollWindowEx function. It is supposed
       to work, but I am misunderstanding its parameters.
       I also can't find any Pascal explanations for it.

       Lower is a SynEdit application from its unit. The
       compiler does not like the coding. Thus I am trying
       to translate it for the compiler environment.

       Lower again is a C code example by Windows. Lazarus
       doesn't like any of that!

       Can anyone show me how I should actually load
       ScrollWindowEx? Windows tells me that everything
       but the HANDLE and SET_POSITIONS should be NULL.
       Then you call UpdateWindow to make it happen.

       I suspect that the @AreaRect entries are improper.
       I also haven't found any information on the FLAGS.

       // VARIABLES
       // VrtBarPos:= SetScrollPos(PageMemo.handle, SB_VERT, VrtBarPos, TRUE); // integer
       // var AreaRect: TRect;
       // GetVrtOK: boolean;
       // SetVrtPos: integer;

Code: Pascal  [Select][+][-]
  1.        AreaRect:= rect(null,null,null,null);
  2.        SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer
  3.  
  4.        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application
  5.                                   0,  // horizontal element
  6.                                   (VrtBarPos - SetVrtPos), // old and new positions
  7.                                   @AreaRect,
  8.                                   @AreaRect,
  9.                                   0,
  10.                                   @AreaRect,
  11.                                   2); // boolean
  12.  
  13.        GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute
  14.        end else showmessage('VRT-SCROLLBAR FAILED 17');
  15.  

       SynEdit Unit
       ScrollWindowEx (HWND=PageMemo.handle,
                       DX=0,
                       DY=(VrtBarPos - SetVrtPos),
                       PRCSCROLL=0x0,
                       PRCCLIP=0x0,
                       HRGNUPDATE=0,
                       PRCUPDATE=0x0,
                       FLAGS=2); // boolean

       Windows Example
       ScrollWindowEx(
       hWnd: HWND;
       dx: Integer;
       dy: Integer;
       prcScroll: PRect;
       prcClip: PRect;
       hrgnUpdate: HRGN;
       prcUpdate: PRect;
       flags: UINT
       ):Boolean;
       
       Scroll the window. The system repaints most of the
       client area when ScrollWindowEx is called; however, it is
       necessary to call UpdateWindow in order to repaint the
       rectangle of pixels that were invalidated.

       C CODE EXAMPLE:
Code: Pascal  [Select][+][-]
  1.        ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
  2.                      (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
  3.                      SW_INVALIDATE);
  4.        UpdateWindow(hwnd);
  5.  
 
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2079
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Need help with ScrollWindowEx
« Reply #1 on: February 23, 2023, 03:56:16 pm »
I also can't find any Pascal explanations for it.
Since it is from the Windows API your only reference is the ScrollWindowEx and inside Windows SDK.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #2 on: February 23, 2023, 04:43:09 pm »
Quote
Code: Pascal  [Select][+][-]
  1. ScrollWindowEx (PageMemo.handle,

When you do that, you scroll the image on the screen. And that is all.

The memo never gets to know you did that. So once the memo repaints, it will paint the old content again.
You need to tell the memo, which line it should paint as the first visible line.


ScrollWindowEx is something you would use as part of your own custom control. When you implement the "paint" method yourself too.
ScrollWindowEx simply safes you from a full repaint, as it takes the pixels that are already painted, and moves those pixels. (Leaving it to you to update all internal states of the control)

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Need help with ScrollWindowEx
« Reply #3 on: February 23, 2023, 06:46:04 pm »
Martin_fr

Quote
The memo never gets to know you did that. So once the memo repaints, it will paint the old content again. You need to tell the memo, which line it should paint as the first visible line.

Leaving it to you to update all internal states of the control.

The (VrtBarPos - SetVrtPos) is what tells it to repaint as the first visible line. I am not changing the document. I am scrolling the document to match the setting I have installed on the ScrollBar. I may not understand what you are telling me ... but this function is updating the internal controls.

Rick
« Last Edit: February 23, 2023, 08:14:10 pm by rick2691 »
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #4 on: February 23, 2023, 07:53:50 pm »
If you get the memo's own scrollbar pos "...VrtPos", and that scrollbar has changed, then the memo should scroll on it's own => why do you need ScrollWindowEx at all?

ScrollWindowEx will only have an affect until the next paint event of the memo. It is a one time paint to the memos visible area on the screen. It does nothing else at all.

SO:
- if the memo does change (without ScrollWindowEx) what it will paint as first line => then the memo will paint that, an the only effect that ScrollWindowEx has, is that it gets painted a tiny bit earlier.
- if the memo does not change (without ScrollWindowEx) what it will paint as first line => then ScrollWindowEx will cause the memo to display its content "moved up/down" and a few milliseconds later will be completely undone by the next paint.

In other words ScrollWindowEx does nothing but at best flicker your display once.


rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Need help with ScrollWindowEx
« Reply #5 on: February 23, 2023, 08:28:16 pm »
Martin,

Setting the ScrollBar position does not change anything. ScrollWindowEx is basically what happens when you drag the ScrollBar button or click up/down buttons. My setting the position value does not trigger a scrolling action. Neither does ScrollWindowEx until I send GetVrtOK:= UpdateWindow(PageMemo.handle);

That scrolls the text. But what I need is to how to fill out the data list in ScrollWindowEx. So I am appealing to everyone who ever used the function. I have not been able to find any information that explains what each entry is doing. However, I have found that they should all be set to NULL.

In particular the settings that I have shown as @AreaRect, which was only a stab at making something happen. I am sure that @AreaRect is not what needs to happen. I stuck an @ on it because they want a pointer. I don't think that you can point to a variable, but I tried it. It doesn't work, but it did not cause an error message either.

Please don't try to get me to do something else. If you don't know how to fill in the data, please just wait for someone who does.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #6 on: February 26, 2023, 12:26:02 pm »
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-scrollwindowex

Mind on non-Win platforms (qt,gtk,cocoa) only subsets of the documented behaviour may be implemented.


IIRC (but not 100%) "prcScroll"  is the source rect.

The dest rect is then calculated by adding dx/dy. But any part of the dest rect that is outside "prcClip" is NOT painted.

hrgnUpdate => not sure. Some Windows thing, may not work on other platforms. Keep it nil.


prcUpdate : as it said, the invalidated rectangle.
Any part of the dest-rect for which there are no (valid) src pixels.  Could be scrolled in from outside the client area. Or could be scrolled in from an already invalidated area.
Usually not needed, rather set SW_INVALIDATE and there will be a paint event for this, after the scrolling.


SW_SCROLLCHILDREN if there are child windows (with a window handle, eg a panel / but must be children) in the rect, they will be moved.




So if you just set
- the handle
- dx / dy
- all else nil

then you will scroll the entire clientarea.

If not, then either
- you have the wrong handle
- the (entire) client area was invalidated (waiting for a paint)
- there is a paint event undoing the scroll, before you even can see it.

If the function returns an error =>
- on windows, check msdn website
- on other widgetset, check if ScrollWindowEx is implemented at all.




Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #7 on: February 26, 2023, 12:41:32 pm »
Please don't try to get me to do something else. If you don't know how to fill in the data, please just wait for someone who does.
Just for background: I wrote the code in SynEdit that calls ScrollWindowEx. And that works well. It does have a fallback to use paint, if for any reason the text can't be scrolled (e.g. is already invalidated, maybe because some other control painted on top of it).

Mind: At least on older Windows ScrollWindowEx can leave a ghost cursor (the text cursor / vertical blinking line). There is a comment towards that in the SynEdit Source.



In SynEdit, the code (SynEdit code, because ScrollWindowEx does none of those) that invokes ScrollWindowEx will set :
- the scrollbars to the correct new position
- The internal variable for "TopLine" that decides which line from the TextBuffer will be the first visible (otherwise SynEdit.Paint would undo the Scroll)
- Other internal values (such as the position of the text cursor)

Any Text that got "scrolled in" will be painted by SynEdit.Paint. SW_INVALIDATE is used for that.
« Last Edit: February 26, 2023, 12:46:21 pm by Martin_fr »

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Need help with ScrollWindowEx
« Reply #8 on: February 26, 2023, 06:05:00 pm »
Martin

Quote
Just for background: I wrote the code in SynEdit that calls ScrollWindowEx.
Yes, I had seen your name.

Meanwhile, I have changed the code to the following. It doesn't throw any errors, but it also does not scroll the screen.

Code: Pascal  [Select][+][-]
  1.        // var AreaRect: TRect;
  2.        AreaRect:= rect(0,0,0,0);
  3.        SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer
  4.  
  5.        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application
  6.                                   0,  // horizontal element
  7.                                   (VrtBarPos - SetVrtPos), // old and new positions
  8.                                   @AreaRect,
  9.                                   @AreaRect,
  10.                                   0,
  11.                                   @AreaRect,
  12.                                   SW_INVALIDATE); // boolean
  13.  
  14.        GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute
  15.        end else showmessage('VRT-SCROLLBAR FAILED 17');  

       The issue of setting those to nil, null, or zero is what I have been asking about. using the word "null' had thrown an error, and so had "nil", yet a zero was accepted. But with no functionality. So what would be the correct way of setting them.

Rick
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #9 on: February 26, 2023, 07:19:09 pm »
Code: Pascal  [Select][+][-]
  1.        AreaRect:= rect(0,0,0,0);
That is a rectangle with zero content. So nothing will be scrolled.

You could use the memos height/width in that rectangle, or probably just memo.clientrect.

But you don't need to.

I haven't checked the pascal definition (for nil versu 0).... But like this.

Code: Pascal  [Select][+][-]
  1. ScrollWindowEx (PageMemo.handle,  // RichMemo application
  2.                                   0,  // horizontal element
  3.                                   (VrtBarPos - SetVrtPos), // old and new positions
  4.                                   nil,  // or clientrect
  5.                                   nil,  // or clientrect
  6.                                   0,   // EDIT:  definitely passing 0 here
  7.                                   nil, // EDIT: nil or pointer to rect that will be written to
  8.                                   SW_INVALIDATE); // boolean
  9.  
« Last Edit: February 26, 2023, 07:38:03 pm by Martin_fr »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #10 on: February 26, 2023, 07:27:13 pm »
About passing a parameter for "hrgnUpdate" (where you passed @AreaRect):

This is of type HRGN  (handle to region), as is documented on the page I linked. This is not a rect. Regions are to be created using specific functions.... So unless you want a long read on msdn, and writing code for Windows only, then I suggest to set it to nil.


EDIT: I got the wrong order....

You passed 0 for the region => and that is ok.

You can pass nil at @SomeRect for prcUpdate. And you did pass @AreaRect => Which means AreaRect will be updated. Only in your case it will be updated to 0,0,0,0
« Last Edit: February 26, 2023, 07:34:04 pm by Martin_fr »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #11 on: February 26, 2023, 07:36:24 pm »
About nil vs zero. (null is msdn talk and in pascal it is nil or 0 )

You can look up the definition of the pascal function for the LCL (which on Windows gets then handed to the Window kernel)
Code: Pascal  [Select][+][-]
  1. function ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}
  2.  

The 3 rectangles expect: "PRect" => and so that is "nil"

hrgnUpdate is HRGN => a handle (you can follow it to the declaration). A handle takes 0 (while on msdn it will again be null).

In the end nil/null/zero all have an ordinal value of zero.
But in pascal they nil and 0 are of different types. And we got strict type checking.


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #12 on: February 26, 2023, 07:44:01 pm »
Quote
Code: Pascal  [Select][+][-]
  1.  GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute

Are you by any chance running code in a loop? Blocking the normal message queue?

Because this will fore a paint message, even if your app is still busy (similar to Application.ProcessMessages, but more restricted).

---
If you are not running in a loop, and your app returns to idle after this code block, then that call should not be needed.

rick2691

  • Sr. Member
  • ****
  • Posts: 444
Re: Need help with ScrollWindowEx
« Reply #13 on: February 27, 2023, 11:51:34 am »
Martin

Code: Pascal  [Select][+][-]
  1. GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute
  2.  
Everything that I have read says that you must call UpdateWindow immediately after calling ScrollWindowEx.

This is how it is done with C code.
Code: Pascal  [Select][+][-]
  1. ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
  2.                      (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
  3.                      SW_INVALIDATE);
  4.        UpdateWindow(hwnd);

Quote
Are you by any chance running code in a loop?

No. I have just finished a search routine. I want to return the screen to the same lines that it started with ... as if nothing has happened. The default action is to pop the last cursor position up to the top line. It make my eyes jitter. The action by ScrollWindowEx should create a soft return.

I have used the following to do the same until now ... Windows is currently blocking its use.

Code: Pascal  [Select][+][-]
  1. SendMessage(PageMemo.handle, WM_VSCROLL,  MakeLong(SB_THUMBPOSITION,  VrtBarPos));

Rick
« Last Edit: February 27, 2023, 12:03:22 pm by rick2691 »
Windows 11, LAZ 2.0.10, FPC 3.2.0, SVN 63526, i386-win32-win32/win64, using windows unit

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9900
  • Debugger - SynEdit - and more
    • wiki
Re: Need help with ScrollWindowEx
« Reply #14 on: February 27, 2023, 12:15:59 pm »
Code: Pascal  [Select][+][-]
  1. GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute
  2.  
Everything that I have read says that you must call UpdateWindow immediately after calling ScrollWindowEx.

From the msdn page I linked earlier:
Quote
The area is not updated until the application calls the UpdateWindow function, calls the RedrawWindow function (specifying the RDW_UPDATENOW or RDW_ERASENOW flag), or retrieves the WM_PAINT message from the application queue.

SynEdit does the last one, and it works.

There are a few reasons for calling one of the listed functions, some are:
- Your app is busy, and will for a long time not process the message queue.
- Your app is too slow, and processes too many other events before the paint event. In that case you can force painting, but scrolling will likely stutter.


Quote
This is how it is done with C code.
Code: Pascal  [Select][+][-]
  1. ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
  2.                      (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,
  3.                      SW_INVALIDATE);
  4.        UpdateWindow(hwnd);
Well, that translates to nil and zero instead of null.
If you are on Windows, it will lead to the same call to the Windows API.

As I still don't see what (or how) exactly you want to do, I can't really do much more that give you the info that Microsoft documented (and how I found it working in SynEdit).
As I said (just reworded / sorry about the repeat):
- ScrollWindowEx will move the pixels in the graphic-buffer of your graphic card. Those are the pixels that the memo has at some point painted to the screen.
- ScrollWindowEx will not scroll the memo itself. When the memo receives it next wm_paint event (from the queue, or through UpdateWindow, either way) it will paint whatever it (the memo) believes to be right.

Neither the memo, nor it's scrollbar will receive any info that ScrollWindowEx has been called.

If of course you did scroll according to the memos internal scrollbar (and that scrollbar had been changed), then you are updating the graphic-buffer to match what the memo will paint anyway. But then I don't understand why you don't let the memo do the job anyway?

 

TinyPortal © 2005-2018