Jump to content

PeterBelow

Members
  • Content Count

    468
  • Joined

  • Last visited

  • Days Won

    13

Posts posted by PeterBelow


  1. 7 hours ago, MathewV said:

    Is anyone else having issues where you step into a DLL function and all you get is the CPU screen?

     

    There are so many reasons why we want to move our 25 year Delphi project to D11, but this one is stopping us and there has been no traffic on the RSP that has been added (https://quality.embarcadero.com/browse/RSP-35879)

    I recorded a video here https://www.screencast.com/t/qEOV7MO00Jq and you can download the OP's sample project from the RSP. 

     

    If this is a user/setting error, please let me know! 

    I have not been working with DLL projects much in the past and never with 64 bit DLLs, but usually one had to debug the DLL project, set the host application to use in the Run -> Parameters dialog, set a breakpoint in the DLL funtion of interest, and then just run. Do the required actions in the host to end up in the DLL at the breakpoint.

    If you end up in the CPU view this means that the debugger cannot find the debug information for the code you stepped into. Make sure you build the DLL with debug information. 64-bit apps are debugged in a kind of remote debugger session since the IDE is a 32 bit process. So make sure you have enabled "include remote debug symbols" in the linker options.

    • Like 1

  2. 18 hours ago, Attila Kovacs said:

    This will only work if you have the sources for every components you are using and you also build them all at least once at building the release version aaaand your units will be found earlier than the dcu's in Delphi's lib directory.

     

    So it wasn't for me, I'm using this:

    ...

     

     

    Was it originaly from you @PeterBelow?  http://www.delphigroups.info/2/92/298063.html

     

    Yes. That was ages ago, makes me realize how old I've gotten now...

     

     

    • Like 1

  3. 8 hours ago, Remy Lebeau said:

    This is why you should configure your AntiVirus/AntiMalware to ignore compiler output folders as exceptions.

     

    If I only could; McAfee rermoved that ability some years ago, one can only exempt specific EXEs now, and that is automatically removed if the EXE changes. I would not recomment McAfee for developer PCs for this reason, although it is a good product otherwise, IMO (a bit pricey, though). I can live with it since I don't program for a living and these false detections are rare.


  4. 2 minutes ago, Dirk Janssens said:

    That is how it works for my simpel project, but for the more complex one I see not why it does not work.
    Can it be that the cause is that I name the unit "Consts.pas", and not "VCL.consts.pas" ? 

     

    Definitely. It will also not work if you build your project with runtime packages.


  5. 20 hours ago, stan rydzewski said:

    Greetings.  

     

    I briefly used Delphi at a job I had a few years ago.   Well just this week I had a desire to create some simple windows forms programs for personal use.  Seeking to avoid the overhead of .net,  I thought of Delphi. 

    I downloaded the community edition and created a quick 'hello world' sort of program as a proof of concept.  I made an exe of it which seems to run fine from explorer. 

     

    I went to send it to myself via gmail to see if I could run it on a machine that didn't have delphi installed.  gmail immediately flagged it as a virus! 

     

    I had a similar problem with Delphi Alexandria, McAfee would detect a freshly build Win32 debug EXE as virus and quarantine it before I could debug it under the IDE, but it would not flag the 32 bit release version of the same program and neither 64 bit debug or release versions.

    By the way: to send an EXE through a mail server put it into a ZIP file and password-protect that. The encryption done will make a virus scanner ignore it since it cannot identify the zipped file as executable. Some particularly paranoid mail servers will reject password-protected zip files for this reason, though.


  6. You can use the OnDrawCell event to draw the cell content yourself any way you like. The stringgrid.Canvas has a TextRect method that supports aligning the text in the way you want.

    • Like 1

  7. 3 hours ago, Nasreddine said:

    @FredS  @Remy Lebeau Thank you very much guys, I'm refactoring my code now to use MsgWaitForMultipleObjects and see the difference
     

    Remy Do you have an example how to pump the message queue in this case? I would like to compare when I'm done.

     

    Here is an example from my old threading library code. FSignal is a TSimpleEvent the thread will signal when it has finished its work.

     

    {! Wait for the call to complete. Optionally we can process a subset
      of messages during the wait. That complicates the timeout handling,
      though, since the wait can be interrupted by messages.}
    function TAsyncCall.WaitForCompletion(TimeoutMSecs: Cardinal;
      ProcessMessages: Boolean): TWaitResult;
    var
      TargetTime, CurrentTime: int64;
      H: THandle;
      Ret: DWORD;
    
      function TimeRemaining: DWORD;
      begin
        if TimeoutMSecs = INFINITE then
          Result := INFINITE
        else begin
          CurrentTime := ToInt64(GetTickCount());
          if CurrentTime > TargetTime then
            Result := 0
          else begin
            Result := TargetTime - CurrentTime;
            if Result > TimeoutMSecs then
              Result := 0;  // GetTickCount rolled over
          end;
        end;
      end;
    
      {! We want to block most user input here but allow paint messages
        to be processed and also non-client messages that relate to moving
        or minimizing the window to be acted upon. Timer messages are also
        processed! }
      procedure ProcessPendingMessages;
      var
        Msg: TMsg;
      const
        NSCMask = $FFF0;
      begin
        while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
          case Msg.message of
            WM_KEYFIRST..WM_KEYLAST, WM_MOUSEFIRST..WM_MOUSELAST: ; // swallow
            WM_NCMOUSEMOVE..WM_NCLBUTTONDBLCLK:
              case Msg.wParam of
                HTCAPTION, HTMINBUTTON: DispatchMessage(Msg);
              end; {case}
            WM_SYSCOMMAND:
              case Msg.wParam and NSCMask of
                SC_MINIMIZE, SC_RESTORE: DispatchMessage(Msg);
              end; {case}
          else
            DispatchMessage(Msg);
          end; {case}
      end;
    
    begin
      EnsureSignalIsCreated;
      if FCompleted then
        Result := wrSignaled
      else
        if ProcessMessages then begin
          TargetTime := ToInt64(GetTickCount()) + TimeoutMSecs;
          H:= FSignal.Handle;
          Result := wrAbandoned;
          repeat
            Ret := MsgWaitForMultipleObjectsEx(
              1, H, TimeRemaining, QS_ALLINPUT, 0);
            case Ret of
              WAIT_ABANDONED : Exit;
              WAIT_FAILED    : Result := wrError;
              WAIT_TIMEOUT   : Result := wrTimeout;
              WAIT_OBJECT_0  : Result := wrSignaled;
              WAIT_OBJECT_0+1: ProcessPendingMessages;
            end; {case }
          until Result <> wrAbandoned;
        end {if}
        else
          Result := FSignal.WaitFor(TimeoutMSecs);
    end;

     


  8. 20 hours ago, RaelB said:

    Thanks. So if a TForm is holding such a component, e.g. TVirtualStringTree, how can I write a method on the form, such that it will be receiving those scrolling messages from the VST?

    If the OnScroll event of the control is not sufficient for your need you have to subclass the control using its WindowProc property. Here is a short example using a TListbox filled with enough items to show a scrollbar as victim. The form also needs a TMemo to show the message traced.

    Note a few things regarding VCL subclassing:

    • You need to find a place where the control you want to subclass has been created and that will only execute once during form creation. I used an overloaded Loaded method.
    • The subclassing should be undone before the form is destroyed. A good place for that is an overloaded BeforeDestruction method.
    • The replacement windowproc must pass all unhandeled messages to the original or the control will stop working. Usually one also passes the message one wants to handle to the original proc, perhaps with modified message parameters.
    type
      TMainform = class(Tform)
        ListBox1: TListBox;
        Memo1: TMemo;
      private
        FListWndProc: TWndMethod;
        procedure NewListboxProc(var Message: TMessage);
      protected
        procedure Loaded; override;
      public
        procedure BeforeDestruction; override;
      end;
      
      ....
      
      function GetScrollCodeAsText(aScrollcode: Smallint): string;
    begin
      case aScrollcode of
        SB_LINEUP: Result := 'SB_LINEUP';
        SB_LINEDOWN: Result := 'SB_LINEDOWN';
        SB_BOTTOM: Result := 'SB_BOTTOM';
        SB_ENDSCROLL: Result := 'SB_ENDSCROLL';
        SB_PAGEUP: Result := 'SB_PAGEUP';
        SB_PAGEDOWN: Result := 'SB_PAGEDOWN';
        SB_THUMBPOSITION: Result := 'SB_THUMBPOSITION';
        SB_THUMBTRACK: Result := 'SB_THUMBTRACK';
        SB_TOP: Result := 'SB_TOP';
      else
        Result := 'unknown';
      end;
    end;
    
    
    procedure TMainform.BeforeDestruction;
    begin
      if Assigned(FListWndProc) and Assigned(ListBox1) then
        Listbox1.WindowProc := FListWndProc;
      inherited;
    end;
    
    procedure TMainform.Loaded;
    begin
      inherited;
      if Assigned(ListBox1) then begin
        FListWndProc := Listbox1.WindowProc;
        Listbox1.WindowProc := NewListboxProc;
      end;
    end;
    
    procedure TMainform.NewListboxProc(var Message: TMessage);
    begin
      try
        if Message.Msg = WM_VSCROLL then begin
          memo1.Lines.Add(
            Format('Scroll code: %d (%s), position: %d',
              [TWMVScroll(Message).ScrollCode,
               GetScrollCodeAsText(TWMVScroll(Message).ScrollCode),
               TWMVScroll(Message).Pos
               ]));
        end;
    
      finally
        FListWndProc(Message);
      end;
    end;

    A click on the scrollbar thump (still in the top position) results in three messages:

     

    Scroll code: 5 (SB_THUMBTRACK), position: 0
    Scroll code: 4 (SB_THUMBPOSITION), position: 0
    Scroll code: 8 (SB_ENDSCROLL), position: 0
    

     


  9. 17 hours ago, Lajos Juhász said:

    You can handle OnMessage for the Applicaton or simple use the OnScroll event of the component.

    OnMessage only triggers for posted messages (PostMessage), but WM_VSCROLL is send (SendMessage). Using an OnSCroll event, if the control offers one, is the preferred way, though.


  10. 3 hours ago, RaelB said:

    Hi,

    In a control with scrollbar, is it possible to detect when the user clicks down and then up on the middle scrollbar button (i.e. draggable part of the scrollbar)?

    Thanks

    Yes, in a VCL control, at least. The control wll receive WM_VSCROLL messages when the user manipulates the scrollbar. The message parameters tell you what has happened.


  11. 23 hours ago, HeartWare said:

    Is it possible to control the location of a Sub-Menu off a TPopupMenu? Ie. A TPopupMenu has an item that is a sub-menu with items. I want to control where this sub-menu pops up (normally, it pops up to the right, but I want it to pop up on the left due to screen design).

     

    Or is it possible to not have the sub-menu being auto-opened with mouse hover over the sub-menu item (ie. you have to click the sub-menu item in order to open the entire sub menu)?

    The position of the submenus is controlled by Windows (assuming we are talking about a VCL app), by default it pops up on the right side, unless there is insufficient space available on the screen on that side. I don't know of a way to control that.

    What you could do is to implement each submenu as a separate TPopupMenu and pop it up manually from the OnClick event of the "parent" menu item. Unfortunately it is not trivial to determine the screen position of an open menu item...


  12. 2 hours ago, David Schwartz said:

    I only wish it were easier to type in a bunch of property declarations that follow a simple pattern: a popup box that asks for the property name, its type, checkbox for read and write and whether they're a local var or a method. Is there anything that simple that doesn't require me to install a huge amount of other stuff at the same time? 

    Modelmaker CodeExplorer (MMX) offers that, and a lot of similar stuff for quickly adding methods etc. And it's free now. Could not live without it...

    • Like 2

  13. 57 minutes ago, David Schwartz said:

     

    Thanks!

     

    Well, I can plainly see that the Windows thread scheduler is failing to do what I want. The UI is locking-up after processing a couple of things, even though there's a 300ms timer being used to update it, so nothing further is visible to the user until the number of tasks left in the queue is less than the number of cores, at which point it's like dumping 10 gallons of water on someone all at once who was expecting to see one gallon per minute for 10 minutes. 

     

     

    Windows is not a real-.time OS, so you don't have any guarantee for defined thread execution times, and your program has to share the CPU resources with a few dozen OS processes. Anyway, your problem sounds like you flood your UI thread's message queue with update requests (you do Synchronize these request, I hope, and do not execute the background task's work in a syncronized method). These requests have a higher priority than the paint messages your changes to the UI cause to be added to the queue.

    If adding calls to a method like

    procedure ProcessPaintrequests;
    var
      Msg: TMsg;
    begin
      while PeekMessage(Msg, 0, WM_PAINT, WM_PAINT, PM_REMOVE) do
        DispatchMessage(Msg);
      while PeekMessage(Msg, 0, WM_NULL, WM_NULL, PM_REMOVE) do
        DispatchMessage(Msg);
    end;

    does not fix the problem you have to lower the priority of your worker threads to give the main thread more time to update the UI.


  14. 1 hour ago, roPopa said:

    I have the following logical problem developing an app.
    I need to do several key operations that need to be executed only once.
    Lets say I need to print something on a fiscal printer.
    I have several records stored on the database.
    I send one command to the printer and the result is ok (was printed successfully).
    I save on that specific line the fact that was printed ok, so if the program is somehow stopped, on resume that line is already printed and will be skipped from sent to printer.
    However if I cannot write in the database the answer (the program crash) on resume the line will be printed again.
    This operation is obvious not an atomic operation.

    So I need one protocol to ensure this functionality.
    Is there any?
    Many thanks

    A kind of transaction log saved to local storage (a file) may serve your purpose. You can write entries to a file using a write  followed by a flush operation (or a full open - write - close cycle) . While not very fast it will ensure the entry is either written completely or not all (if the PC suffers a power failure, for example).

    Your operation would then follow this scheme:

    • Write the intent to print, with the ID of the item to print, to the log
    • print the item
    • write the success of the operation to the log
    • save it to the database
    • write an end of transactio to the log or delete the log

    On (re)start the program can then look for a transaction log and analyse it to see how far it got on the last run.

     


  15. 24 minutes ago, CoeurdeLeon said:

    I attended DelphiCon 2021 and enjoyed it very much, however I cannot find any of the example projects.  Are the example projects published and if so where?

     

    Thank you

    Dick Maley

    At least one of the examples is on github: https://github.com/gustavomenabarreto/delphicon2021

    Perhaps you can find more in the replays on Youtube: DelphiCon 2021 Playlist

    It's probably up to the speakers to make the code for their talk available somewhere...


  16. 19 minutes ago, FPiette said:

    GPX file have very simple structure but there are tens of thousands of nodes (Example of GPX file). Before changing my code, I would profile it to know if the slowness comes from the XML parser our from my own code which is fully class oriented with generic TObjectList. I suspect this is much slower in my case compared to records and pre-allocated dynamic arrays. 

    Set the Capacity property of your list objects to a suitably high value before you start adding objects, that can greatly improve performance since it cuts down cases where the list has to grow its internal array.


  17. @David

    IMO you are mixing data with UI in a way that only causes problems. You should use a list class instance (nonvisual) to hold objects that represent a student, each of which holds a list of the classes taken with the score obtained. The list class can then have a method to compose the items for a listview you pass as parameter to the method. If you need that you can store the reference to the student object in the corresponding listitem's Data property, but the lifetime management of the objects is the duty of the list class, not that of the UI listview.

    • Like 5

  18. 1 hour ago, toufik said:

    @FPiette
    sorry for i was bit unclear and thanks for taking from your time ;;; 
    this what i was trying to do , i'm almost there  i just need to remove that 12 start from 00:00:00 not 12:00:00 any idea ?

    bandicam_2022-01-01_09-51-18-033.avi

    DecodeTime is the wrong method to use since it decodes a time point, not a time interval.

    The System.Diagnostics.TStopwatch record may be of more use for your problem.

     

    Add a private field

      FStopwatch: TStopwatch;

    to your form. In the OnCreate event you start the stopwatch with

    FStopwatch := TStopwatch.StartNew;

    When you want to know the elapsed time call FStopwatch.Stop first and then examine the Elapsed property. It returns a TTimespan record, which has properties to dissect the time interval into days, hours, minutes etc.

    • Thanks 1

  19. 18 hours ago, Hugo Bendtner said:

    Does anyone know if TControlLists can handle transparency? I would like to have a watermark underneath and whereas TPanels with clNone as their color are essentially transparent, the TControlList displays black. Messing around with ParentColor doesn't have desired results either.

    Tcontrollist inherits the ParentBackground property but does not publish it, it is protected. You can try to set it to true in code, using a cracker class:

     

    type
      TControllistCracker = class(TControllist);
      
    ...
    
     TControllistcracker(Controllist1).Parentbackground := true;
      

    Untested!


  20. 1 hour ago, Henry Olive said:

    I wish everyone a healthy day.

     

    Uses System.StrUtils;

    var

    S, FirstStr, SecStr : String,

    begin

      S := SqlQuery1.FieldByName ('RANGE').asString; // it is '5/10'

      FirstStr := SplitString(S, '/')[0];

      SecStr  := SplitString(S, '/')[1];

    end; 

     

    Above code works in Delphi-XE w/o any problem but

    i get   Not enough actual parameters err.msg in  Delphi 10.3

    What is wrong ?

     

    Thank You
     

     

     

    There is nothing wrong with the code you posted, other than the comma instead of semicolon after the "string" in the var section. Perhaps you have another SplitString function closer in scope than StrUtils.SplitString here. If you hover the mouse over SplitString, what does the code insight popup tell you where it's from?

×