Jump to content

luebbe

Members
  • Content Count

    117
  • Joined

  • Last visited

Posts posted by luebbe


  1. Hi Folks,

    I've come across a strange bug with string literals in Delphi. I am in the process of moving from Delphi 11.3 to 12.1 and suddenly one of our tests fails. I could narrow it down to a combination of the less equal or greater equal unicode characters in combination with a tab in the string.

     

    Here's the definition:

    const
      cExpected: array [0 .. 4] of string = (
        '1 Line with <= and no tab',
        '2 Line with ≤ and no tab',
        #9'3 Line with ≤ and a',
        #9'4 Line with ≥ and a tab',
        #9'5 Line with >= and a tab');
    

    On the left side of the screenshot is the result of the misinterpretation. You see that somehow the first characters of the last line that didn't contain a tab *and* a greater equal/less equal character overwrite the first characters of the lines that contain both. I've never seen this before.

    WrongStringLiteral.thumb.png.f4dd072dff8e545760c09aac3dfab8bd.png

     

    Does anyone have an idea what is going on here?

     

    Delphi 11 handled it correctly. Originally it was one const separated by sLineBreak instead of a const array of string.

    This combination also damages TestCase() Attributes in DUnitX. They also get misinterpreted.


  2. 3 minutes ago, Anders Melander said:

    You need to have someone compile and run your project with 10.4.2 in order to conclude that.

    Right now you only know that your exe reproduces the problem and that an exe produced by one other person doesn't.

    We know the following:

    • An exe produced by someone else with 10.2 is ok
    • An exe produced by me with 10.4.2 is not ok
    • An exe produced by someone else with 11.3 is ok
    • An exe produced by me with 11.3 is ok (tested it in the mean time)

    Open question:

    • An exe produced by someone else with 10.4.2 is ???

  3. Hi Folks,

    I've come across a problem with VCL styled applications. Some controls (not all) continuously fire WM_SETCURSOR messages, when the mouse cursor is stationary over a scrollbar and VCL styles are active.
    When the standard Windows style is used, everything works as expected. There are a few WM_SETCURSOR messages and they stop coming, when the mouse stops moving.
    This may not sound like a big deal, but on my PC the CPU load goes up from 1% to 15%..20% (one core almost at 100%) when this happens. We have a timing critical application, where the timing goes haywire, when the mouse is over a scrollbar of a TListView or a TScrollBox.

    At least ListView and ScrollBox exhibit this behaviour. EasyListView and VirtualStringTree don't.

     

    I haven't found the source of the problem yet, so help is greatly appreciated.

    Attached you will find an example with a TListView that exhibits the behaviour. Included is an .exe, compiled with Delphi 10.4.2.
    So if this doesn't happen with a newer compiler, we have a big incentive to upgrade 🙂


    StyledWMSetCursor.zip
     

    Cheers & thanks

    Lübbe


  4. I deleted the Parnassus registry keys from "SOFTWARE\Embarcadero\BDS\21.0\Experts" and now the 10.4.2 IDE starts again. Getit still thinks the parnassus plugins are installed, but uninstalled them via getit and it seems ok now.

    I then let the 11.2 installer delete all 11.x registry keys and it looks like it will now proceed successfully.

     

    So it looks like I could solve the problem.


  5. Not a good experience for me so far. I had installed 11.1 alongside 10.4.2 without any problems. I always install from ISO with local admin privileges. Getit packages are installed later, normally without admin privileges.

    I let the 11.2 installer uninstall the previous version keeping the registry keys. It removes getit packages, finishes installing the core and then crashes with the following error:

     

    image.png.a2ec214ee95a3167206d8b61840e52fe.png

     

    Running the 11.2 installer again yields the same result.

     

    Worst of all, when I now start Delphi 10.4.2 it also crashes with almost the same exception:

     

    image.png.5190f8ccef83996685553a690cb7d5fe.png

     

    So the 11.2 installer managed to destroy two installations in one go.

     

    But the parnassus dlls seem to be in place:
    image.thumb.png.352b9b03bb89fcfdd946db9997894701.png

     

    How can I recover from this situation? Probably there are some registry keys which I should delete and then reinstall again, but which registry keys?

     

     


  6. 7 hours ago, Stefan Glienke said:

    The Eurekalog call stack makes zero sense compared to the code on github. Either you are using some outdated code or modified something yourself. There is nothing monitor in TThreadSafeQueue.Enqueue. It is using a critical section

    You're right, the call stack doesn't make sense. I'm using my own fork of loggerpro (https://github.com/luebbe/loggerpro.git) and made two PRs with additional functionality in the original, but I didn't modify any of the queuing code.

    We're using a very old version (6.x) of Eurekalog. Perhaps this is reason for the wrong stack trace, but still I wouldn't expect any exception to happen here.


  7. 15 hours ago, PeterBelow said:

    As far as I can see this function does not wait at all, it just checks the task value and returns. Or does the getter for FTask.Value wait?

    FTask is an IFuture, so yes, it should wait. I just mentioned this fact but didn't show any code. Here it is:


     

    procedure TUpdater.UpdateIndex(const ASearchPathList: string; AForceUpdate: boolean);
    begin
    
      ... cancel running tasks etc ...
      
      FTask := TTask.Future<TLoadStatus>(
        function: TLoadStatus
        begin
          Update;
          Result := FStatus;
        end);
    end;

     


  8. Hi Folks,

     

    in one ouf our projects I'm using @Daniele Teti 's loggerpro library (https://github.com/danieleteti/loggerpro) instead of a homebrew logging solution. A few weeks after switching to loggerpro, a first Eurekalog bug report came in with the message:
    "EMonitorLockException in ThreadSafeQueueU.pas: {ThreadSafeQueueU}TThreadSafeQueue<LoggerPro.TLogItem>.Enqueue, Zeile 157 (0)". This exception is clearly raised inside loggerpro.

    I have already asked at GitHub (https://github.com/danieleteti/loggerpro/issues/53), but have received no reply yet.

    Every month or so, another of these bug reports comes in. The problem is:

    - I cannot reproduce/trigger it on my development PC, even though I think I can locate exactly, where and under which circumstances it happens

    - I don't see any obvious error in the loggerpro code

    - I don't see any obvious error in my code

    which is why I'm asking for help here. Maybe I have missed something obvious in my code...


    We have the following scenario: The main thread starts a background task (IFuture), which builds up an index of files for later use. Both, main and background task log their status with LoggerPro.

     

    The index updater:

    procedure TUpdater.Update;
    var
      LXxxFiles, LYyyFiles: TFileList;
    begin
      if FStatus = stNotLoaded then
        begin
          Log.Debug('Renewing Index', 'INDEX');
    
          LXxxFiles := TFileList.Create;
          LYyyFiles := TFileList.Create;
          try
            FStatus := stLoading;
    
            ... Prepare XXX and YYY lists ...
            
            Log.Info('Check %d Xxx Files', [LYyyFiles.Count], 'INDEX');
            Log.Info('Check %d Yyy Files', [LXxxFiles.Count], 'INDEX');
    
            // Check existing files and index their content
            if FStatus <> stCanceled then
              if Process(LXxxFiles) and Process(LYyyFiles) then
                FStatus := stLoaded;
    
            if FAutoSave then
              FIndex.Save;
    
            FIndex.LogStats;
            Log.Debug('Status - ' + TRttiEnumerationType.GetName<TLoadStatus>(FStatus), 'INDEX');
    
          finally
            LXxxFiles.Free;
            LYyyFiles.Free;
          end;
        end;
    end;

    If the main task needs the index, it calls the following routine:

    function TUpdater.WaitForCompletion: boolean;
    begin
      Log.Enter('Updater.WaitForCompletion', 'INDEX');
      // Waits until the IFuture task is finished and returns its status
      // The calling thread is blocked while waiting
      Result := (FTask.Value = stLoaded);
      Log.Exit('Updater.WaitForCompletion', 'INDEX');
    end;
    

    Log.Enter and Log.Exit are just two wrapper functions around Log.Debug that I have added to LoggerPro. The Exception occurs on the `Log.Exit` call

     

    Here are the relevant lines of the Eurekalog report:

    EMonitorLockException Object lock not owned.
    
    |005B7380|Application.exe|ThreadSafeQueueU.pas         |{ThreadSafeQueueU}TThreadSafeQueue<LoggerPro |TLogItem>.Enqueue                |157[0]   |
    |005B61B5|Application.exe|LoggerPro.pas                |TLogWriter                                   |Log                              |557[5]   |
    |0110346B|Application.exe|System.Generics.Defaults.pas |                                             |                                 |39[0]    |
    |010FF5A2|Application.exe|Update.Index.pas             |TUpdater                                     |WaitForCompletion                |845[4]   |
    |010FF560|Application.exe|Update.Index.pas             |TUpdater                                     |WaitForCompletion                |841[0]   |
    
    

    Normally the update task takes some time, so the typical log output is:

    2022-04-21 15:22:13:937  [TID    16780][INFO   ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\#####
    2022-04-21 15:22:13:937  [TID    16780][DEBUG  ] [INDEX ] --> Updater.StopUpdate
    2022-04-21 15:22:13:937  [TID    16780][DEBUG  ] [INDEX ] <-- Updater.StopUpdate
    2022-04-21 15:22:13:987  [TID    16780][INFO   ] [INDEX ] Contains 240 Files
    2022-04-21 15:22:13:987  [TID    16780][INFO   ] [INDEX ] Contains 4931 Entries
    2022-04-21 15:22:13:987  [TID     3280][DEBUG  ] [INDEX ] Renewing Index
    2022-04-21 15:22:13:987  [TID    16780][DEBUG  ] [INDEX ] --> Updater.WaitForCompletion
    2022-04-21 15:22:14:080  [TID     3280][INFO   ] [INDEX ] Remove 0 Files
    2022-04-21 15:22:14:080  [TID     3280][INFO   ] [INDEX ] Check 238 xxx Files
    2022-04-21 15:22:14:080  [TID     3280][INFO   ] [INDEX ] Check 2 yyy Files
    2022-04-21 15:22:14:242  [TID     3280][INFO   ] [INDEX ] Contains 240 Files
    2022-04-21 15:22:14:242  [TID     3280][INFO   ] [INDEX ] Contains 4931 Entries
    2022-04-21 15:22:14:242  [TID     3280][DEBUG  ] [INDEX ] Updater.Status - stLoaded
    2022-04-21 15:22:14:242  [TID    16780][DEBUG  ] [INDEX ] <-- Updater.WaitForCompletion
    ... Normal work continues here
    

     

    In some cases (no search paths defined or search paths empty), there's "nothing" to do, which results in the following log output:

    2022-04-21 14:18:14:972  [TID    22208][INFO   ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\#####
    2022-04-21 14:18:14:972  [TID    22208][DEBUG  ] [INDEX ] --> Updater.StopUpdate
    2022-04-21 14:18:14:972  [TID    22208][DEBUG  ] [INDEX ] <-- Updater.StopUpdate
    2022-04-21 14:18:14:973  [TID    22208][INFO   ] [INDEX ] Contains 0 Files
    2022-04-21 14:18:14:973  [TID    22208][INFO   ] [INDEX ] Contains 0 Entries
    2022-04-21 14:18:14:974  [TID    14984][DEBUG  ] [INDEX ] Renewing Index
    2022-04-21 14:18:14:974  [TID    14984][INFO   ] [INDEX ] Remove 0 Files
    2022-04-21 14:18:14:974  [TID    14984][INFO   ] [INDEX ] Check 0 xxx Files
    2022-04-21 14:18:14:974  [TID    14984][INFO   ] [INDEX ] Check 0 yyy Files
    2022-04-21 14:18:14:977  [TID    14984][INFO   ] [INDEX ] Contains 0 Files
    2022-04-21 14:18:14:977  [TID    14984][INFO   ] [INDEX ] Contains 0 Entries
    2022-04-21 14:18:14:977  [TID    14984][DEBUG  ] [INDEX ] Updater.Status - stLoaded
    2022-04-21 14:18:14:979  [TID    22208][DEBUG  ] [INDEX ] --> Updater.WaitForCompletion
    2022-04-21 14:18:14:979  [TID    22208][DEBUG  ] [INDEX ] <-- Updater.WaitForCompletion
    ... Normal work continues here
    

    Note that in this case the updater was finished (stLoaded) before WaitForCompletion was called. The Log.Enter "--> Updater.WaitforCompletion" line may occur anywhere between the lines of the background thread (TID 14984 in this case).


    This is the LoggerPro output matching the bug report. The `EMonitorLockException` occured on the `Log.Exit` call in `TUpdater.WaitForCompletion` and this line is missing from the log:

    2022-04-21 14:42:03:003  [TID    20620][INFO   ] [INDEX ] Updater.Update in: C:\Users\Public\Documents\#####
    2022-04-21 14:42:03:003  [TID    20620][DEBUG  ] [INDEX ] --> Updater.StopUpdate
    2022-04-21 14:42:03:003  [TID    20620][DEBUG  ] [INDEX ] <-- Updater.StopUpdate
    2022-04-21 14:42:03:004  [TID    20620][INFO   ] [INDEX ] Contains 0 Files
    2022-04-21 14:42:03:004  [TID    20620][INFO   ] [INDEX ] Contains 0 Entries
    2022-04-21 14:42:03:004  [TID     3312][DEBUG  ] [INDEX ] Renewing Index
    2022-04-21 14:42:03:004  [TID     3312][INFO   ] [INDEX ] Remove 0 Files
    2022-04-21 14:42:03:004  [TID     3312][INFO   ] [INDEX ] Check 0 xxx Files
    2022-04-21 14:42:03:004  [TID     3312][INFO   ] [INDEX ] Check 0 yyy Files
    2022-04-21 14:42:03:008  [TID    20620][DEBUG  ] [INDEX ] --> Updater.WaitForCompletion
    2022-04-21 14:42:03:008  [TID     3312][INFO   ] [INDEX ] Contains 0 Files
    2022-04-21 14:42:03:008  [TID     3312][INFO   ] [INDEX ] Contains 0 Entries
    2022-04-21 14:42:03:008  [TID     3312][DEBUG  ] [INDEX ] Updater.Status - stLoaded
    ... Normal work continues here
    
    

    Note that the updater was still working (on nothing ;-)) when WaitForCompletion was called. It looks like Log.Exit('WaitForCompletion') and Log.Debug('Updater.Status - stLoaded') happen in the same millisecond, so I assume that thread 3312 still held the lock, when exception thread 20620 called `Log.Exit`.

    But I see this all the time (finish/exit happens in the sme millisecond) when I run the code on my PC and never get an EMonitorLock exception.

     

    Is there something we are doing wrong or have we come across a race condition in LoggerPro or the Delphi locking implementation?

     

     

     


  9. Hi Folks,
     

    I'm stuck with the problem that I want to prevent a grid to act on the mouse wheel events.

    The UI layout is the following:

    • On a TFrame (created at runtime) I have a TCategoryPanelGroup.
    • As the application is receiving data in different formats, for each data package a new TCategoryPanel is created at runtime and placed on the TCategoryPanelGroup.
    • Each TCategoryPanel contains two grids who are adjusted to fit the data. The heights of the grids and the TCategoryPanel are adjusted so that in >90% of the cases the grids won't have a scrollbar.

     

    Now when I use the mouse wheel over a grid, the grid catches the wheel and happily acts on it, which is not what I want. If the grid has a scrollbar (rare case), the user shall use the scrollbar to scroll the grid.

    My goal is to always scroll the TCategroyPanelGroup when the mouse wheel is used over one of the grids or a TCategorypanel so the user can quickly flip through the categories.

    How can I make the grids and the TCategoryPanel "ignore" or "pass up" the mouse wheel events so that the TCategoryPanelGroup receives them and can act on them?

     

    Would a different structure of UI elements be a better approach? I'm actually quite happy with the category panels, because the data inside can be clearly identified via their header and they can be collapsed when I don't want to see all different data sets at the same time.

     

    I've attached a stripped example of the UI structure that just catches the mouse wheel events for the controls and outputs them in a memo.

    MouseScroll.zip


  10. 21 hours ago, dummzeuch said:

    The "General" tab should now also look OK. Just don't move the dialog between high DPI and 96 DPI monitors. If you do that, the form gets wider and wider and the font size grows. Not sure whether that's a GExperts or VCL problem.

    Probably a rounding problem? @pyscripter has created a dpi aware base form which IIRC uses muldiv to adjust to dpi changes.
    Enjoy your vacation!


  11. Thanks Stefan,

    in the debugger I saw in ItemCallback(..) that the addresses of FItem and AItem were similar but not equal, so I suspected that there was something wrong with the interface being passed around instead of the object.

     

    I put a breakpoint on the first line of

    procedure TestIntfItem.ItemCallback(AItem: IMyIntfItem);
    begin
      Assert.IsNotNull(AItem);
      FCallbackResult := AItem.Caption;
    end;
    
    

    with TOnMyIntfItemSelected<T: IMyIntfItem> = procedure(AItem: T) of object; I see:

    Name    Wert
    Self    (TMyIntfItemA<List.Intf.IMyIntfItem>($3AA2840) as IMyIntfItem, '')
    AItem    Pointer($3AA2828) as IMyIntfItem
    

    This told me that something was wrong, but I couldn't understand what.

     

    with TOnMyIntfItemSelected<T: IMyIntfItem> = procedure(AItem: IMyIntfItem) of object; I see:

    Name    Wert
    Self    (TMyIntfItemA<List.Intf.IMyIntfItem>($3AC38D8) as IMyIntfItem, '')
    AItem    TMyIntfItemA<List.Intf.IMyIntfItem>($3AC38D8) as IMyIntfItem
    

    That's an evil trap. Thanks for shedding light on it. So if something is wrong I have to watch out for $18 byte address offsets 😉

×