Need help with ScrollWindowEx lazarus / 34-Windows ---------------------------------------------------------------------- rick2691 · 2023-02-23 14:46 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SendMessage(PageMemo.handle, WM_VSCROLL,  MakeLong(SB_THUMBPOSITION,  VrtBarPos));         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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        AreaRect:= rect(null,null,null,null);       SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                @AreaRect,                                  @AreaRect,                                  0,                                @AreaRect,                                  2); // boolean      GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute       end else showmessage('VRT-SCROLLBAR FAILED 17');         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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,                   (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,                   SW_INVALIDATE);       UpdateWindow(hwnd); ---------------------------------------------------------------------- KodeZwerg · 2023-02-23 14:56 Quote from: rick2691 on February 23, 2023, 03:46:31 pmI 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. ---------------------------------------------------------------------- Martin_fr · 2023-02-23 15:43 QuoteCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i 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 · 2023-02-23 17:46 Martin_fr QuoteThe 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 ---------------------------------------------------------------------- Martin_fr · 2023-02-23 18:53 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 · 2023-02-23 19:28 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 ---------------------------------------------------------------------- Martin_fr · 2023-02-26 11:26 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 · 2023-02-26 11:41 Quote from: rick2691 on February 23, 2023, 08:28:16 pmPlease 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. ---------------------------------------------------------------------- rick2691 · 2023-02-26 17:05 Martin QuoteJust 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        // var AreaRect: TRect;       AreaRect:= rect(0,0,0,0);       SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                @AreaRect,                                  @AreaRect,                                  0,                                @AreaRect,                                  SW_INVALIDATE); // boolean        GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute       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 ---------------------------------------------------------------------- Martin_fr · 2023-02-26 18:19 Quote from: rick2691 on February 26, 2023, 06:05:00 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                nil,  // or clientrect                                nil,  // or clientrect                                  0,   // EDIT:  definitely passing 0 here                                  nil, // EDIT: nil or pointer to rect that will be written to                                SW_INVALIDATE); // boolean ---------------------------------------------------------------------- Martin_fr · 2023-02-26 18:27 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 ---------------------------------------------------------------------- Martin_fr · 2023-02-26 18:36 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean; {$IFDEF IF_BASE_MEMBER}virtual;{$ENDIF}  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 · 2023-02-26 18:44 QuoteCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  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 · 2023-02-27 10:51 Martin Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,                   (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,                   SW_INVALIDATE);       UpdateWindow(hwnd); QuoteAre 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SendMessage(PageMemo.handle, WM_VSCROLL,  MakeLong(SB_THUMBPOSITION,  VrtBarPos)); Rick ---------------------------------------------------------------------- Martin_fr · 2023-02-27 11:15 Quote from: rick2691 on February 27, 2023, 11:51:34 amCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute Everything that I have read says that you must call UpdateWindow immediately after calling ScrollWindowEx. From the msdn page I linked earlier: QuoteThe 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. QuoteThis is how it is done with C code. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,                   (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,                   SW_INVALIDATE);       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? ---------------------------------------------------------------------- KodeZwerg · 2023-02-27 11:16 Did you tried to cast to LPARAM() WPARAM() that it work on Windows? At least I do it when I call SendMessage(). ---------------------------------------------------------------------- rick2691 · 2023-02-27 12:04 Martin QuoteBut then I don't understand why you don't let the memo do the job anyway? Why do you have it in SynEdit? I have previously used the SB_THUMBPOSITION method because it is smooth and elegant. The screen just stays where it is upon your exiting the search, instead popping to a new placement. Rick ---------------------------------------------------------------------- rick2691 · 2023-02-27 12:15 Martin Quoteor retrieves the WM_PAINT message from the application queue. What is the code that used in SynEdit to do "the latter," as you cited. I would like to give it a try. Rick ---------------------------------------------------------------------- rick2691 · 2023-02-27 12:27 KodeZwerg QuoteDid you tried to cast to LPARAM() WPARAM() that it work on Windows? No. It had not needed them. Can you post your code for those operations? I will try them out. Rick ---------------------------------------------------------------------- Martin_fr · 2023-02-27 14:05 Quote from: rick2691 on February 27, 2023, 01:15:17 pmQuoteor retrieves the WM_PAINT message from the application queue. What is the code that used in SynEdit to do "the latter," as you cited. I would like to give it a try. SynEdit simply exits from the event handler. Then the message queue is automatically processed by the LCL. Your code normally runs in an event (OnClicked, OnIdle, On....) and as soon as your code returns (exits the event handler) the LCL continues with the message queue. And that will include WM_Paint events. Afaik paint events are done with the lowest priority. So if you keep receiving other events, and take long enough to handle them so more can queue up, then paint can be deferred. However usually in that case you want to at least skip a handful paint events, before doing them in one combined sweep. However if you don't run any data processing loops in your code, then there should be no speed/delay issues. You can always check in the debugger, by setting breakpoints in the relevant paint events (unless its an OS painted widget, and there is no paint event in the LCL / though even then there should be low level lcl code that can be used to set a breakpoint / richmemo likely has its own Paint method). Make the breakpoint "not breaking" (remove the checkmark in the options of the breakpoint), and then in the breakpoint window you can watch the hitcount. Or you can use normal breakpoints (actually pause at the breakpoint). So you can see the effect of ScrollWindowEx, and what the paint handler outputs as separate steps. Of course for that you need to make sure nothing overlaps the richmemo, and it is **always** in view. Not hidden by the IDE, not hidden by any other app. At least on Windows (tested Win10 64bit scrolling SynEdit): When you set a breakpoint, an step over ScrollWindowEx, the effect is immediate. You can see it happen on the screen. Of course at that time any "scrolled in" content is not yet there, and the old content still visible. The "scrolled in" is handled in the paint event. (Just test it with a SynEdit, by finding the ScrollWindowEX in SynEdit... / and then also break in the paint method. Note that you can pause at the begin of the paint method, but the effect will only be visible when you run the app again, and it returns to "TWindowProcHelper.SendPaintMessage" in the list of callers / It may be immediate if you switch of double buffering, not tested) ---------------------------------------------------------------------- rick2691 · 2023-02-27 14:16 Marti QuoteSynEdit simply exits from the event handler. I had already tried it with UpdateWindow removed ... so it just exited the handler. Did not help. Rick ---------------------------------------------------------------------- Martin_fr · 2023-02-27 15:23 Quote from: rick2691 on February 23, 2023, 03:46:31 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        AreaRect:= rect(null,null,null,null);       SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                @AreaRect,                                  @AreaRect,                                  0,                                @AreaRect,                                  2); // boolean  I assume "SetVrtPos" means "currently set/applied". IMHO misleading, maybe name it "CurrentVrtPos". But that is just a personal hint/opinion offtopic to the issue. Where does "VrtBarPos" (the new pos to which you want to scroll?) come from? And most important: How to you tell the memo, that it got scrolled to "VrtBarPos". Because as I mentioned: "ScrollWindowEx" does not tell the memo (100% sure). And neither does "UpdoteWindow". Have you single stepped the code? Does something happen on the screen, when you call ScrollWindowEx? (When you step over (F8) it). Mind, I don't know RichMemo. Maybe it uses child windows, and the content you want to scroll is in an altogether different childwindow, and you are passing the wrong handle? I must say, that IMHO this is highly UNLIKELY. But when nothing works, consider the unlikely. ---------------------------------------------------------------------- rick2691 · 2023-02-27 16:16 Martin Here is the code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TCmdForm.btnFindExitClick(Sender: TObject);  // was BtnFndEscClickvar //PageStat:boolean;    OldSelStart, OldSelLength: integer;    HrzBarPos, VrtBarPos, SetVrtPos, SetHrzPos, TmpPos: integer;    HrzBarFnd, VrtBarFnd, GetVrtOK, GetHrzOK: boolean;    AreaRect: TRect;begin  try  //PageMemo.Lines.BeginUpdate; // suspend screen update    FindPanel.visible:= false;    FindActive:= false;     OldSelStart:= PageMemo.SelStart;    OldSelLength:= PageMemo.SelLength;     //TmpPos:= GetScrollPos(PageMemo.handle,SB_VERT);  // for pop-up report     VrtBarFnd:= Is_ScrollBar_Visible(PageMemo.Handle, SB_VERT); // boolean    HrzBarFnd:= Is_ScrollBar_Visible(PageMemo.Handle, SB_HORZ);     //  *** SetScrollPos Method *** serves all methods    if VrtBarFnd then VrtBarPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer    if HrzBarFnd then HrzBarPos:= GetScrollPos(PageMemo.handle,SB_HORZ);     if VrtBarPos>0 then GetVrtOK:= TRUE else GetVrtOK:= FALSE;    if HrzBarPos>0 then GetHrzOK:= TRUE else GetHrzOK:= FALSE;     {  // *** ScrollInfo Method ***  // Get_Scroll_Info is identical to GetScrollInfo    if VrtBarFnd then                // being duplicated in order to make it editable     GetVrtOK:= Get_Scroll_Info(PageMemo.Handle, SB_VERT, VrtScrollData) //: Boolean;       else GetVrtOK:= false;     if HrzBarFnd then       GetHrzOK:= Get_Scroll_Info(PageMemo.Handle, SB_HORZ, HrzScrollData) //: Boolean;       else GetHrzOK:= false;    }     //PageStat:= PageWideStat.checked; // STORE STAT    FormResize(Self);    if AppSize=CmdForm.Width       then PageWideStat.checked:= true       else PageWideStat.checked:= false;  //PageWideStat.checked:= PageStat; // RESET STAT     RichMemoHighlightReset(PageMemo);     PageMemo.SelStart:= OldSelStart;    PageMemo.SelLength:= OldSelLength;   // was := OldSelLength; *or* 0 //=======================================    // *** C Code ScrollWindowEx example ***  // DO NOT ATTEMPT TO ACTIVATE THIS CODE    {    ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,                  (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,                  SW_INVALIDATE);     UpdateWindow(hwnd);    }//=======================================    // *** SB_THUMBPOSITION Method ***    (*    if GetVrtOK then       begin       SendMessage(PageMemo.handle, WM_VSCROLL, // vertical                 MakeLong(SB_THUMBPOSITION, VrtBarPos), 0);       VrtBarPos:= SetScrollPos(PageMemo.handle, SB_VERT, VrtBarPos, TRUE); //*GOOD*     end; // else showmessage('VRT-SCROLLBAR FAILED 17');     if GetHrzOK then       begin       SendMessage(PageMemo.handle, WM_HSCROLL, // horizontal                   MakeLong(SB_THUMBPOSITION, HrzBarPos), 0);       HrzBarPos:= SetScrollPos(PageMemo.handle, SB_HORZ, HrzBarPos, TRUE); //*GOOD*       end; // else showmessage('VRT- SCROLLBAR FAILED 17');     showmessage('SB_THUMBPOSITION DONE');    *)//=======================================    // *** ScrollWindowEx method ***    //(*    if GetVrtOK then       begin       AreaRect:= rect(0,0,0,0);       SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                @AreaRect,                                  @AreaRect,                                  0,                                @AreaRect,                                  SW_INVALIDATE); // boolean        GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute       end else showmessage('VRT-SCROLLBAR FAILED 17');        showmessage('ScrollWindowEx DONE');    //*)//======================================      finally    PageMemo.SelStart:= OldSelStart;    PageMemo.SelLength:= OldSelLength;   // was := OldSelLength; *or* 0    PagePassive:= false;  //PageMemo.Lines.EndUpdate;  end;end; The GET and SET are equivalent to READ and WRITE as they were applied prior to trying to use ScrollWindowEx. ---------------------------------------------------------------------- Martin_fr · 2023-02-27 16:57 First of all: If "VrtBarFnd" will be false, then "VrtBarPos" will not be initialized, and "GetVrtOK" will also not be initialized. So the condition at the end, may be true at random. I might have missed something, but I assume that between Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  if VrtBarFnd then VrtBarPos:= GetScrollPos(PageMemo.handle,SB_VERT); Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT);The Scrollbar will actually change? Otherwise you always scroll by 0 pixel. I don't see what changes it. Have you debugged and checked that the 2 values are different? Also what changes the scrollbar pos, and why does whatever that is not actually do the scrolling? E.g. if at some point (that I have not spotted), you set the Selection to a different location, and the memo scrolls to that different location (thereby updating the scrollbars), then why would you still need to scroll it, if it already did scroll? If of course the 2 lines that set the selection to OldSelStart/Length are undoing the scroll, then ... Well then SetVrtPos will be the same as VrtBarFnd, and DY will be 0. ... But then, even if you get SetVrtPos before you undo the scroll (reset the old selection), ScrollWindowEx will not fix the issue. It will move the pixels, but the memo will eventually get a paint event, and jump back to where it was. In any case: "@AreaRect" (all 3 occurrences) should be "nil". Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i       GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                NIL,                                  NIL,                                  0,                                NIL,                                  SW_INVALIDATE); // boolean If you hand in a pointer, then Windows will always read the rect at the pointer, and restrict scrolling to the rect given. In your case: zero pixel width, zero pixel height => nothing is scrolled). If you pass in nil, the entire clientrect will be scrolled. If you pass in "nil", and the 2 values from above are different (dy <> 0) and you set a breakpoint and step over the "ScrollWindowEx" call then you should see the pixels on the screen move to the new location. (This happens immediately during the call / if on Windows) Mind, this is trying to make the ScrollWindowEx actually do something (which in order to see it, you may have to watch in the debugger). If that solves whatever needs to be solved is another question.... ---------------------------------------------------------------------- rick2691 · 2023-02-27 17:20 QuoteHave you debugged and checked that the 2 values are different?Yes, they are different, and they are absolute pixel counts. QuoteIf "VrtBarFnd" will be false, then "VrtBarPos" will not be initialized, and "GetVrtOK" will also not be initialized. So the condition at the end, may be true at random. Good point. They had been globals, and were initiated elsewhere. Here, they are locals, and placed as such to make sure nothing is interfering with the data ... but I forgot to initiate them. I'll fix that and get back to you. ---------------------------------------------------------------------- rick2691 · 2023-02-27 17:37 This has the initiated variables. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TCmdForm.btnFindExitClick(Sender: TObject);  // was BtnFndEscClickvar //PageStat:boolean;    OldSelStart, OldSelLength: integer;    HrzBarPos, VrtBarPos, SetVrtPos, SetHrzPos, TmpPos: integer;    HrzBarFnd, VrtBarFnd, GetVrtOK, GetHrzOK: boolean;    AreaRect: TRect;begin  try  //PageMemo.Lines.BeginUpdate; // suspend screen update    FindPanel.visible:= false;    FindActive:= false;     OldSelStart:= PageMemo.SelStart;    OldSelLength:= PageMemo.SelLength;     VrtBarFnd:= false;    HrzBarFnd:= false;    VrtBarPos:= 0;    HrzBarPos:= 0;    SetVrtPos:= 0;    SetHrzPos:= 0;  GetVrtOK:= false;    GetHrzOK:= false;     //TmpPos:= 0;    //TmpPos:= GetScrollPos(PageMemo.handle,SB_VERT);  // for pop-up report     VrtBarFnd:= Is_ScrollBar_Visible(PageMemo.Handle, SB_VERT); // boolean    HrzBarFnd:= Is_ScrollBar_Visible(PageMemo.Handle, SB_HORZ);     //  *** SetScrollPos Method *** serves all methods    if VrtBarFnd then VrtBarPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer    if HrzBarFnd then HrzBarPos:= GetScrollPos(PageMemo.handle,SB_HORZ);     if VrtBarPos>0 then GetVrtOK:= TRUE else GetVrtOK:= FALSE;    if HrzBarPos>0 then GetHrzOK:= TRUE else GetHrzOK:= FALSE;     {  // *** ScrollInfo Method ***    if VrtBarFnd then       GetVrtOK:= Get_Scroll_Info(PageMemo.Handle, SB_VERT, VrtScrollData) //: Boolean;       else GetVrtOK:= false;     if HrzBarFnd then       GetHrzOK:= Get_Scroll_Info(PageMemo.Handle, SB_HORZ, HrzScrollData) //: Boolean;       else GetHrzOK:= false;    }     //PageStat:= PageWideStat.checked; // STORE STAT    FormResize(Self);    if AppSize=CmdForm.Width       then PageWideStat.checked:= true       else PageWideStat.checked:= false;    //PageWideStat.checked:= PageStat; // RESET STAT     RichMemoHighlightReset(PageMemo);     PageMemo.SelStart:= OldSelStart;    PageMemo.SelLength:= OldSelLength;   // was := OldSelLength; *or* 0 //=======================================    // *** C Code ScrollWindowEx example ***    {    ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,                  (CONST RECT *) NULL, (HRGN) NULL, (PRECT) NULL,                  SW_INVALIDATE);     UpdateWindow(hwnd);    }//=======================================    // *** SB_THUMBPOSITION Method ***    (*    if GetVrtOK then       begin       SendMessage(PageMemo.handle, WM_VSCROLL, // vertical                 MakeLong(SB_THUMBPOSITION, VrtBarPos), 0);       VrtBarPos:= SetScrollPos(PageMemo.handle, SB_VERT, VrtBarPos, TRUE); //*GOOD*       end; // else showmessage('VRT-SCROLLBAR FAILED 17');   if GetHrzOK then       begin       SendMessage(PageMemo.handle, WM_HSCROLL, // horizontal                   MakeLong(SB_THUMBPOSITION, HrzBarPos), 0);       HrzBarPos:= SetScrollPos(PageMemo.handle, SB_HORZ, HrzBarPos, TRUE); //*GOOD*       end; // else showmessage('VRT-SCROLLBAR FAILED 17');     showmessage('SB_THUMBPOSITION DONE');    *)//=======================================    // *** ScrollWindowEx method ***    //(*    if GetVrtOK then       begin       AreaRect:= rect(0,0,0,0);       SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer        GetVrtOK:= ScrollWindowEx (PageMemo.handle,  // RichMemo application                                0,  // horizontal element                                (VrtBarPos - SetVrtPos), // old and new positions                                @AreaRect,                                  @AreaRect,                                  0,                                @AreaRect,                                  SW_INVALIDATE); // boolean result        GetVrtOK:= UpdateWindow(PageMemo.handle); // must execute       end else showmessage('VRT-SCROLLBAR FAILED 17');      showmessage('ScrollWindowEx DONE');    //*)//======================================   finally    PageMemo.SelStart:= OldSelStart;    PageMemo.SelLength:= OldSelLength;   // was := OldSelLength; *or* 0    PagePassive:= false;  //PageMemo.Lines.EndUpdate;  end;end;  RichMemo is a container that is placed in the Control Form. Its controls are buttons, menus, pop-ups, and short-cut key strokes. Its only children are the scrollbars and PageTabControl. I have just made a test run, and it still has the same behaviour. ---------------------------------------------------------------------- Martin_fr · 2023-02-27 17:59 Did you try to 1) replace "@AreaRect" with "nil" 2) debug with a breakpoint before ScrollWindowEx, and then use "F8" until you stepped over it? Debug in such a way that the RichMemo is at no time hidden, and you can always see it? If in that case, at the end of stepping the content in the memo moved, then ScrollWindowEx did work. (It does not solve your issue, but it works as documented / You asked, just to make ScrollWindowEx work....). ---------------------------------------------------------------------- rick2691 · 2023-02-27 18:10 Martin QuoteI might have missed something, but I assume that between      if VrtBarFnd then VrtBarPos:= GetScrollPos(PageMemo.handle,SB_VERT);     SetVrtPos:= GetScrollPos(PageMemo.handle,SB_VERT); The Scrollbar will actually change? Otherwise you always scroll by 0 pixel. It does a form resize (FormResize), and clears highlighting (RichMemoHighlightReset) from the document. FormResize checks to see if you have manually changed the size of the form. If you have, it resizes all the panels, toolbars, and pop-ups so they can seen and accessed when they become active. I have not been changing the form size. RichMemoHighlightReset iterates through document and removes any highlighting that the word search would have generated. Yes, highlighting has been properly removed, and both functions are finished before I have hit the EXIT button that activates this section of code. Rick ---------------------------------------------------------------------- rick2691 · 2023-02-27 18:25 Martin Quote1) replace "@AreaRect" with "nil" We have answered this issue before ... Lazarus will not accept the word "nil" for a Pointer RECT function. Quote2) debug with a breakpoint before ScrollWindowEx, and then use "F8" until you stepped over it? No. I have never used the debugger. I have forgotten all of the "machine code" I had ever learned, so I can't read its reports. I just layout a bunch of showmessage('STAGE 1'); 2, 3, etc. to watch what happens. But I have not done that exhaustively, as you are suggesting. But I can attempt that, and get back to you. I was typing while you had sent those questions, so I have posted an updated procedure just prior to this post. You should look at it. Rick ---------------------------------------------------------------------- Martin_fr · 2023-02-27 18:43 Quote from: rick2691 on February 27, 2023, 07:25:16 pmQuote1) replace "@AreaRect" with "nil"We have answered this issue before ... Lazarus will not accept the word "nil" for a Pointer RECT function. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses windows, LCLIntf; procedure TForm1.FormCreate(Sender: TObject);begin  windows.ScrollWindowEx(Handle, 0, 10, nil, nil, 0, nil, SW_INVALIDATE);  LCLIntf.ScrollWindowEx(Handle, 0, 10, nil, nil, 0, nil, SW_INVALIDATE);end;  There is a ScrollWindowEx in unit LCLIntf (which has compatible implementation for other Widgedsets; and in unit windows (which goes directly to the win API). Both of them compile with nil, as given above. QuoteQuote2) debug with a breakpoint before ScrollWindowEx, and then use "F8" until you stepped over it? No. I have never used the debugger. I have forgotten all of the "machine code" I had ever learned, so I can't read its reports. I just layout a bunch of showmessage('STAGE 1'); 2, 3, etc. to watch what happens. But I have not done that exhaustively, as you are suggesting. But I can attempt that, and get back to you. I was typing while you had sent those questions, so I have posted an updated procedure just prior to this post. You should look at it. The debugger in Lazarus works directly with Pascal code. Menu: Project > Project Options - Compilation and linking: set optimization to either "none" or "O1" - Debugging: Enable "Generate info for debugger" and set the "type of debug info" to "dwarf with sets" In the source-editor either click (left mouse button) the empty space before the line-number to set a breakpoint (a red dot should appear). Or use F5 to set the breakpoint while the text cursor is at that line. Then run with F9. The debugger should pause at the breakpoint (a green arrow in the breakpoint appears). Now use F8 (several times), it will go to each line with the arguments, and in between to the line with "ScrollWindowEx". Eventually it goes to the statement after. At that time the scrolling should have happened. While paused you can hover over variables, or use "view > debug windows > ..." for much more info. ---------------------------------------------------------------------- rick2691 · 2023-02-27 20:39 Martin, I did the showmessages. The first position (VrtBarPos) is 18116. The highlighting was removed. The second position (SetVrtPos) is 18376 ... lower in the document. ScrollWindowEx did not throw an error. UpdateWindow did not throw an error. The window did not scroll. I saw your post and used windows.ScrollWindowEx(Handle, 0, (VrtBarPos - SetVrtPos), nil, nil, 0, nil, SW_INVALIDATE); windows.ScrollWindowEx(PageMemo.Handle, 0, (VrtBarPos - SetVrtPos), nil, nil, 0, nil, SW_INVALIDATE); Then I did windows.ScrollWindowEx(Handle, 0, -80, nil, nil, 0, nil, SW_INVALIDATE); windows.ScrollWindowEx(PageMemo.Handle, 0, -80, nil, nil, 0, nil, SW_INVALIDATE); Then I repeated all of them again with LCLIntf.ScrollWindowEx. Then again without the windows prefix nor the LCLIntf. I guess something got fixed in the process, but I had never tested "nil" again. All of these, however, have performed the same as my own was performing: no errors nor scrolling. Are you using a Windows 11 operating system? I think that Windows 11 just won't let programed scrolling happen. I can RUN the code with my original: SendMessage(PageMemo.handle, WM_VSCROLL, MakeLong(SB_THUMBPOSITION, VrtBarPos), 0);  The RUN function makes the scrolling happen. I can compile as an EXE, paste it to my operating folder, and it won't scroll. I can make a new folder, launch it from there, and it will scroll. But few days later it won't scroll either. I think it is a Windows security action. Automated scrolling is considered a hack. Rick ---------------------------------------------------------------------- Martin_fr · 2023-02-27 21:25 I am using Win 10. I did just test on Win11 too, works exactly as expected (as I expect it, and as I read the msdn documentation). Drop a button and a memo on a form, and add a button-click Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Button1Click(Sender: TObject);begin  ScrollWindowEx(Memo1.Handle, 0, 10, nil, nil, 0, nil, SW_INVALIDATE);end;  On both Win 10/11, this will "scroll" the memo's visible content. But as soon as the memo paints again (e.g. you click the memo, or press a key while it has focus) it will reset to where it was. If unlucky such a paint event may happen within micro seconds after the "scroll". I do quote "scroll" in the above, because it is not what you expect "scroll" to be. When the memo paints, it outputs the text that it has to the screen. The text is output as pixel patterns. And those pixels are stored in the graphic memory as a bitmap. The computer has a bitmap that contains each pixel visible on the screen/monitor. This bitmap does not belong to the memo, it represents the screen content. ScrollWindowEx "scrolls" (or moves) the pixel in that screen bitmap. And only those. And nothing else. Especially ScrollWindowEx - does not tell the memo that it has done something or even was called - does not even tell anything to the application owning the memo. It only returns a result to your code, and if request invalidates some content, and sends a paint message. (Such invalidation can also happen by many other causes, so the memo can not tell anything from that). Therefore for the memo the scroll has never happened, and when the memo paints again, it will paint the unscrolled content. And if that is a full repaint / not just a partial paint, then any moved pixels are overpainted. (After the scrollWindoEx it only does a partial paint, so some moved pixels remain on the screen) And that is all there is. I've tried to point that out before. ---------------------------------------------------------------------- rick2691 · 2023-02-28 12:26 Martin I have understood what you have been saying ... the screen is a tablet that gets painted. It isn't a scroll like you have with a rolled up document. Its a simulation. However, this painting is what happens when I use my mouse wheel or click and drag the elevator cabin in the scroll bar. That is the scroll that I want and expect. Have you been saying anything different from that? The actual mechanics of the simulation are buried in the operating system. Yet I expect the ScrollWindowEx function to make that available to me. Moreover, that is exactly what my SendMessage(PageMemo.handle, WM_VSCROLL, MakeLong(SB_THUMBPOSITION, VrtBarPos), 0) function had already been providing me with. I need to have its functionality returned to me. I am going to try your Button1Click procedure. It looks the same as what I have already tested. But since you have proven that it works with Windows 10 & 11, and if it doesn't on my computer, then I will have to track down what is boogering everything on my side. I will get back to you. I would also like to say that I appreciate all that you been doing for me. Rick ---------------------------------------------------------------------- rick2691 · 2023-02-28 13:07 Martin Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TCmdForm.Button1Click(Sender: TObject);begin  ScrollWindowEx(PageMemo.Handle, 0, 100, nil, nil, 0, nil, SW_INVALIDATE);  UpdateWindow(PageMemo.Handle);end;  I put this into my existing procedure, and it temporarily moved the scroll bar, but not the document (by all appearances). So I made an independent button and procedure, and it painted with the prescribed offset. Likewise, when I moved my cursor back to the window, it triggered a MouseEnter function that repainted the screen with its old data ... offset gone! However, I had included the UpdateWindow(PageMemo.Handle) function in my code, and it had done nothing at all. So you are correct, a double paint had been messing things up. But the UpdateWindow function hasn't painted anything. If I can't get it to perform as expected, then I need to find another function that will. Moreover, I think it might help if I managed the RECT areas that ScrollWindowEx wants me to assign. Rick ---------------------------------------------------------------------- Martin_fr · 2023-02-28 13:12 Quote from: rick2691 on February 28, 2023, 01:26:37 pmMartin I have understood what you have been saying ... the screen is a tablet that gets painted. It isn't a scroll like you have with a rolled up document. Its a simulation. However, this painting is what happens when I use my mouse wheel or click and drag the elevator cabin in the scroll bar. That is the scroll that I want and expect. Not exactly the same.... Well, it is possible that the memo (upon receiving a scrollbar action) actually calls ScrollWindowEx (so that part is the same). But the Scrollbar action does more. In my example (form, memo, button, buttonClick event) ScrollWindowEx scrolls the content (except for a small area at the top or bottom, depending on direction). But in that example that scroll is temporary. It gets undone by the next paint. If the memo text is Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i line 1line 2line 3... And the memo gets a WM_paint event, then the memo does - what is my internal value for the first line to show.   -- That value will at some time before have been taken from the scrollbar.   -- Or it will have been changed by the use of cursor keys (a memo can scroll, even without scrollbars) - The memo will then paint all pixels according to that internal value.    If the memo thinks "line 2" is first to be shown, it will show "line 2". ScrollWindowEx is not informing the memo. So the internal value is not changed. That is ok, if the memo itself did call ScrollWindowEx, because then the memo knows to update its internal value. But if you call ScrollWindowEx, the memo does not know. So if you call ScrollWindowEx, then "line 3" may be at the top. But the memo still believes it is "line 2", and in the next paint event it will undo the scroll. Also (and you can see that with the example I described), ScrollWindowEx  does not fill the "scrolled in" area => the memo does in a paint event. But the memo fills it with what it thinks should be there (and that is the unscrolled content). --- You can call ScrollWindowEx on a TButton. And it will work. And the image of the button (not the button, only the image of the button) will be moved on the screen. Of course a button has no concept of being scrolled. You would not expect the button to know when it has been scrolled. QuoteHave you been saying anything different from that? The actual mechanics of the simulation are buried in the operating system. Yet I expect the ScrollWindowEx function to make that available to me. No, ScrollWindowEx is not the mechanics of the memo's scrolling. It is just a tool that the memo can use as part of its internal mechanics. But it is just a small part. And if you execute it without the other parts then it will not to the full job. Equally TextOutA https://learn.microsoft.com/en- us/windows/win32/api/wingdi/nf-wingdi-textouta may be part of what the memo uses (this or some equal function). But if you do a TextOutA on the memos HDC (can be derived from the handle, IIRC), then that will not have a lasting effect. It will maybe draw something on the screen, but the next wm_paint will overpaint it. Because the memo never knew you put something there. QuoteMoreover, that is exactly what my SendMessage(PageMemo.handle, WM_VSCROLL, MakeLong(SB_THUMBPOSITION, VrtBarPos), 0) function had already been providing me with. I need to have its functionality returned to me. But that is a message that goes to the Memo. The memo will know that this happened (if it works). And so the memo will do all the parts of scrolling. Including updating its internal values. Unfortunately I do not know why it does not always work. Or if it is meant to work that way. QuoteI am going to try your Button1Click procedure. It looks the same as what I have already tested. But since you have proven that it works with Windows 10 & 11, and if it doesn't on my computer, then I will have to track down what is boogering everything on my side. It works as in "It does temporarily scroll the image". It does not do what you want it to do. It can not do what you want it to do. It is not meant to do that. After this post Quote from: rick2691 on February 23, 2023, 08:28:16 pmPlease 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. I tried to show you "how to fill in the data". Despite knowing that it wont help you. Despite that filling in the data correctly will simply not do what you want to be done. ---------------------------------------------------------------------- Martin_fr · 2023-02-28 13:14 Quote from: rick2691 on February 28, 2023, 02:07:59 pmthen I need to find another function that will. Yes. ---------------------------------------------------------------------- Martin_fr · 2023-02-28 13:34 Ok no idea if that has any influence.... (I do not even know, if that way works at all..., never tried myself) I just read up on https://learn.microsoft.com/en- us/windows/win32/controls/wm-vscroll QuoteSB_THUMBPOSITION    The user has dragged the scroll box (thumb) and released the mouse button. The HIWORD indicates the position of the scroll box at the end of the drag operation. In your code, in the comment is Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i        SendMessage(PageMemo.handle, WM_VSCROLL, // vertical                 MakeLong(SB_THUMBPOSITION, VrtBarPos), 0);       VrtBarPos:= SetScrollPos(PageMemo.handle, SB_VERT, VrtBarPos, TRUE); //*GOOD* But if SB_THUMBPOSITION is sent after the mouse button was released, maybe the "SetScrollPos" needs to be done first? Maybe do your own WM_VSCroll handler on a component with scrollbar. And observe which message come, and what values the scrollbar has at the time? Then at least you would know if your simulation is correct. Another idea... (And again, no idea if it will help) try PostMessage instead. Then it goes via the message queue. It may be that all your changes to the selection and what else you do, have already placed messages to that memo. If then you put yours first, the pre-existing messages may just override the effect of yours. ---------------------------------------------------------------------- rick2691 · 2023-03-02 14:00 Martin and all Here is my alternative code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TCmdForm.btnFindExitClick(Sender: TObject);  // was BtnFndEscClickvar OldSelStart, OldSelLength: longint;    HrzBarPos, VrtBarPos, VrtBarTgt: longint;    HrzBarFnd, VrtBarFnd, GetVrtOK, GetHrzOK: boolean;begin  try  PageMemo.Lines.BeginUpdate; // suspend screen update    FindPanel.visible:= false;    FindActive:= false;    PagePassive:= false;     OldSelStart:= PageMemo.SelStart;    OldSelLength:= PageMemo.SelLength;     VrtBarFnd:= false;    HrzBarFnd:= false;     VrtBarPos:= -1;    HrzBarPos:= -1;    VrtBarTgt:= -1;     GetVrtOK:= false;    GetHrzOK:= false;     VrtBarFnd:= Is_ScrollBar_Visible(PageMemo.Handle, SB_VERT); // boolean    HrzBarFnd:= Is_ScrollBar_Visible(PageMemo.Handle, SB_HORZ);     if VrtBarFnd then VrtBarPos:= GetScrollPos(PageMemo.handle,SB_VERT); // integer    if HrzBarFnd then HrzBarPos:= GetScrollPos(PageMemo.handle,SB_HORZ);     if VrtBarPos>-1 then GetVrtOK:= TRUE else GetVrtOK:= FALSE;    if HrzBarPos>-1 then GetHrzOK:= TRUE else GetHrzOK:= FALSE;     If GetVrtOK then VrtBarTgt:= GetScrollPos(PageMemo.handle,SB_VERT);     FormResize(Self);  // resizes and positions work panels    if AppSize=CmdForm.Width  // resets Form to PageWide width       then PageWideStat.checked:= true       else PageWideStat.checked:= false;     RichMemoHighlightReset(PageMemo);  // removes document highlighting //=======================================    // *** SB_THUMBPOSITION Method ***         {        SendMessage(PageMemo.Handle,                    WM_VSCROLL,                  MakeWParam(SB_THUMBPOSITION, VrtBarPos),                    0);         SB_BOTTOM   Scrolls to the lower right.        SB_ENDSCROLL   Ends scroll.        SB_LINEDOWN   Scrolls one line down.        SB_LINEUP   Scrolls one line up.        SB_PAGEDOWN    Scrolls one page down.        SB_PAGEUP   Scrolls one page up.      SB_THUMBPOSITION   The user has dragged the scroll box (thumb) and                         released the mouse button. The HIWORD indicates                           the position of the scroll box at the end of the                           drag operation.        SB_THUMBTRACK   The user is dragging the scroll box. This message is                      sent repeatedly until the user releases the mouse                      button. The HIWORD indicates the position that the                      scroll box has been dragged to.        SB_TOP   Scrolls to the upper left.        } //=======================================    // *** KeyInput Method ***     if GetVrtOK then       begin       PageMemo.SetFocus;       VrtBarPos:= GetScrollPos(PageMemo.handle,SB_VERT);        if VrtBarPos>=VrtBarTgt then  // scrolls document to last cursor position          Begin                    // as per its previous screen view          while (VrtBarTgt<=GetScrollPos(PageMemo.handle,SB_VERT)) do                 begin                 PageMemo.SetFocus;                  //KeyInput.Apply([ssCtrl]);   // use to include CtrlKey               KeyInput.Press(VK_UP);  // simulate press of F1 function key               KeyInput.Up(VK_UP);    // simulate release of UpArrow key               //KeyInput.Unapply([ssCtrl]);  // use to release CtrKey                // Alternative to KeyInput.Press(VK_UP):                 // SendMessage(PageMemo.handle, WM_VSCROLL, MAKELONG(SB_LINEUP, 1), longint(0));                 end;          PageMemo.SelStart:= OldSelStart;          PageMemo.SelLength:= OldSelLength;          end else              Begin              while (VrtBarTgt>=GetScrollPos(PageMemo.handle,SB_VERT)) do                   begin                     PageMemo.SetFocus;                      //KeyInput.Apply([ssCtrl]);   // use to include CtrlKey                   KeyInput.Press(VK_DOWN);  // simulate press of F1 function key                   KeyInput.Up(VK_DOWN);    // simulate release of UpArrow key                     //KeyInput.Unapply([ssCtrl]);  // use to release CtrKey                      // Alternative to KeyInput.Press(VK_DOWN):                     // SendMessage(PageMemo.handle, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 1), longint(0));                     end;              PageMemo.SelStart:= OldSelStart;              PageMemo.SelLength:= OldSelLength;            end;  // end of else       end;  // end of GetVrtOK //======================================   finally    PageMemo.SelStart:= OldSelStart;    PageMemo.SelLength:= OldSelLength;  PageMemo.Lines.EndUpdate;  end;end;  I tried to use GetFirstVisibleLine, but it is disfunctional. I am told that it has worked since Windows XP. So I resorted to a funky mechanical method that should work with any system and version. It works with mine. It isn't as smooth as the SB_THUMBPOSITION, but it doesn't work for me at this point. It could involve the double painting, but I attempted to make it work in an isolated condition and its behavior had not changed. This current method only come short because it makes a major blink when it is done, and I don't think there is any way to that. It is apparently an original RichEdit oversight. Thanks for the help. Rick ---------------------------------------------------------------------- KodeZwerg · 2023-03-02 15:03 I would replace this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     if VrtBarPos>-1 then GetVrtOK:= TRUE else GetVrtOK:= FALSE;    if HrzBarPos>-1 then GetHrzOK:= TRUE else GetHrzOK:= FALSE;with something like that Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     GetVrtOK := (VrtBarPos > -1);    GetHrzOK := (HrzBarPos > -1); I guess many things could be optimized there, but that one really hurt my eyes ---------------------------------------------------------------------- rick2691 · 2023-03-02 16:19 KodeZwerg I can understand that. I have been moving quickly with things, and as it is, it is self initiating GetVrtOK. I am sure that all of my code could be more elegant. But you should have seen the mess that was generated by my having to test and reject so many other things that failed their worth. Rick ---------------------------------------------------------------------- rick2691 · 2023-03-04 12:31 I have found one short coming by using either of the WM_VSCROLL or KeyInput methods: both can round out and go one line over or one line under its target. I haven't found any way to avoid that. Rick ---------------------------------------------------------------------- rick2691 · 2023-03-04 14:11 I have found a better method. By being in the btnExit procedure there was always a second paint by either subroutines or Mouse and Key events. Too hard to track down, and is probably vital to other routines. So I decided to build an independent procedure that btnExit can call. As it turns out it is one of the Scrollbar functions, and the simplest to use; plus it has a high precision; no over and under issues. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TCmdForm.ScrollMemo(TempMemo:TRichMemo; BarType:string; BarTgt:longint);//  TempMemo: RichMemo Document * Bartype: 'Vrt' or 'Hrz' * BarTgt: ScrollBar Position//  example ScrollMemo(PageMemo, 'VRT', 12452);var BarPos: LongInt;beginif upcase(BarType)='VRT' then  // vertical   begin   BarPos:= GetScrollPos(TempMemo.handle,SB_VERT);    if BarPos>BarTgt then  // scrolls document to last cursor position      Begin                    // as per its previous screen view      while (BarTgtGetScrollPos(TempMemo.handle,SB_VERT)) do                 begin                 TempMemo.VertScrollBar.Position:= TempMemo.VertScrollBar.Position + 1;                 end;          end;  // end of else   end; // end VERTICAL BarType if upcase(BarType)='HRZ' then  // horizontal   begin   BarPos:= GetScrollPos(TempMemo.handle,SB_HORZ);    if BarPos>BarTgt then  // scrolls document to last cursor position      Begin                    // as per its previous screen view      while (BarTgtGetScrollPos(TempMemo.handle,SB_HORZ)) do                 begin                 TempMemo.HorzScrollBar.Position:= TempMemo.HorzScrollBar.Position + 1;                 end;          end;  // end of else   end; // end HORIZONTAL BarTypeend;  Rick ---------------------------------------------------------------------- rick2691 · 2023-03-05 16:56 Et. Al. What bothers me is that I can do Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TempMemo.VertScrollBar.Position:= TempMemo.VertScrollBar.Position - 1; creeping up one pixel at a time to BarTgt, and it is perfect, but I cannot do Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TempMemo.VertScrollBar.Position:= BarTgt; It is evidence of severe disfunction, because it does nothing.