Jump to content

aehimself

Members
  • Content Count

    1030
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by aehimself


  1. 7 hours ago, pcplayer99 said:

    So, I guess in Android, var T is a local variable and after exit Button1Click method, it was released by ARC.

     

    So I move var T: TMyThread declare to global variable at var Form1: TForm, and then delete Sleep(500) and then tested in Android, it works OK.

    However I have 0 experience in cross-platform, this sounds perfectly reasonable. My 2 cents are that if any object (TMyThread) need to live and be accessible throughout a method, define it's variable in the parent (TForm1), worst-case-scenario unit global. It makes sense to me like this and it seems the garbage collector thinks the same way.

     

    @David Heffernan

    My guess is that there is a reason for suspended creation, it is just not included in the example code above. What I try to say is, I always create TThreads suspended myself but mostly because I want to do stuff with them before the actual execution (e.g. .NameThreadForDebugging, etc.).


  2. 3 minutes ago, David Heffernan said:

    This looks a bit bogus to my eyes. Why would this change anything. Surely LoadFromFile use a file stream. 

    Code is from D7-era. Maybe it worked different back then...? In 10.2 .LoadFromFile effectively does the same (only without the .BeginUpdate and .EndUpdate).

    But I remember that I had to change due to insanely long loading times.


  3. Memo.Lines.LoadFromFile suffers from performance issues if the file is n x 10 MB, especially if it is on a network location. I changed most of my sensitive methods to use Streams instead:

      fs := TFileStream.Create('filename.txt', fmOpenRead + fmShareDenyNone);
      Try
       Memo.Lines.BeginUpdate;
       Memo.Lines.LoadFromStream(fs);
      Finally
       FreeAndNil(fs);
       Memo.Lines.EndUpdate;
      End;

     


  4. Afaik ShellExecute returns nothing, it does not even confirm if the command line was executed or not. By sticking to it you have no other options but command line parameters, best case scenario is to encrypt the password and decrypt it from the second app. You can check the running processes after ShellExecute and grab it's handle for data transfer but this introduces a lot of unnecessary checks, like timeout (don't wait for the second process until you can find it, what if it did not even launch), did it already initialize and ready to accept data?

     

    If you use CreateProcess and map the stdin and stdout, you can make your first application to "type in" the user name and password to the second one and read back the output to verify if authentication was successful.

     

    However if both applications are written and managed by you, move the worker method to a .DLL and make the first and the second application to load and use it. You also have to validate the legitimacy of the library, though. Or to a helper unit, and do not even include a secondary file.

     

    However, external files will always pose a major security risk, especially if they need to share sensitive information. It's really easy to put a malicious .EXE file in place of yours (even if it's running) just to steal the credentials.

    • Like 1

  5. You don't need a component for this. I'd proceed this way:

    - have a strict private DateTime variable. Upon form creation, set it to zero.

    - OnKeyDown / OnKeyPress handler of the ComboBox. If the key was pressed, and it's not a comma, set the above DateTime to zero. If it is, check if the value of the DateTime variable:

      - If the value equals zero, set it to Now

      - If it's not, check the seconds passed between that and Now (DateUtils.SecondsBetween):

        - If the difference is greater than 1 or 2, set the variable to Now

        - If the difference is less, execute your custom action.

     

    If you need more help let me know, I can make a quick demo, but my theory would be this.


  6. I wish I would be. I'd buy you a beer for closing the military industrial takeover topic 🙂

    Seriously though, my company is not paying for (or don't know about) these and it's a bit pricy for a simple person. There are people in my country who earn the price (or a fraction!) of a 1-day ticket per month.


  7. ...ooooor the focus actually stays on the button, it's just not redrawn properly. ActiveX controls work in strange ways (I still have active / not active issues with embedded MSTSC controls up to this day...)

    You can verify this by comparing form..ActiveControl with your button.


  8. You can actually reproduce the issue (on 10.2) by dialog.Visible := Not dialog.Visible. I suppose the issue is that since the window object is not actually closing (default closing action is to hide only), the preview is not getting refreshed automatically. If you really would like to keep it this way, use the MainFormOnTaskbar or the .Handle workaround which you discovered. I suspect this is only an other bug though.

     

    I agree with everyone else though - do not auto-create windows. If you want to load data only once, load it into an object in your main form (like a DataSet or a TStringList) and send that to your dialog form with a reintroduced .Create or an additional .Init method. As all forms of your application are running in the same thread, passing any object should be safe - if you are 100% sure that only one form is using them, at least, a time.


  9. 10 minutes ago, Kas Ob. said:

    %99 it was disk operation (save/load) caused by wrong permission or antivirus installed [...]

    I do not envy AV programmers. Most of us love to blame them for everything 😄

    • Like 1

  10. WM_SETREDRAW adds the WS_VISIBLE style, but this does not trigger the .Visible property to change. Since according to Delphi the window is not visible it does not even try to hide it - this is why the form stays visible forever.

     

    This is why I love to code, we always learn something new:

     

    image.thumb.png.1de747f102db941c64ef5018cf90d594.png

     

    During the OnCreate event the form is invisible. Forcing it visible without being fully created (property loading takes place in a later stage) seems to render it in an unusable state... like it does receive the enable redraw message, but omits it without processing... or something. Removing these calls from the OnCreate and OnClose method solves the issue completely.

     

    Verdict: do not use WM_SETREDRAW in any form during construction or destruction.

     

    I'll just stick to hiding it before the final expansion to eliminate the flicker, but it's good to know what we can and cannot do with WM_SETREDRAW.


  11. 1 hour ago, timfrost said:

    Have you tried setting caHide in the Action parameter in your FormClose method?

    No, I did not, as caHide is the default value of Action. The reason why the form pops back up can be found on MSDN: "If the application sends the WM_SETREDRAW message to a hidden window, the window becomes visible (that is, the operating system adds the WS_VISIBLE style to the window)."

     

    Maybe this is the reason why it fails to initialize in Modal...?


  12. Ooooooookay. Progress. I'm calling the expand logic upon creating and closing the form to set / reset the dimensions.

    Procedure TForm2.FormClose(Sender: TObject; Var Action: TCloseAction);
    Begin
     Self.Visible := False;
     SendMessage(Self.Handle, WM_SETREDRAW, Ord(False), 0);
     SendMessage(Self.Handle, WM_SETREDRAW, Ord(True), 0);
    End;
    
    procedure TForm2.FormCreate(Sender: TObject);
    begin
     SendMessage(Self.Handle, WM_SETREDRAW, Ord(False), 0);
     SendMessage(Self.Handle, WM_SETREDRAW, Ord(True), 0);
    end;

    If you execute this window with ShowModal, it will freeze upon opening. If you execute it with .Show, it will never disappear (despite having it's .Visible property at false) but remain unpainted for it's lifetime. The problem is calling these upon creating and closing the form.

    I just don't know why.

    Yet.

     

    Edit: The flicker is there because of the OnClose logic, as I was expanding the window and it popped full-size for a moment before disappearing. The whole story started there, and however it can be done by hiding it before the logic, it disturbs me A LOT on why this method is not working 🙂


  13. I know that FreeAndNil is unnecessary here, I just personally use it instead of .Free every single time. A few cycles here is better than a possible false Assigned check somewhere else 🙂

     

    I do use VCL Styles in my application, but starting with a fresh project and importing only the message dialog unit has the exact same results.

     

    I'll try to strip it down further, as unfortunately the window has to be resizable 😞


  14. Unfortunately no joy for me, window is still frozen on screen. All logic executes only once and goes in the SendMessage block on first try.

    This message box is displayed with .ShowModal, if that can affect the functionality.

     

    Edit: I also saw that 'ownerless' windows can behave like this; and my dialog is created from a class procedure:

    Class Procedure TMyDialogForm.ShowMe;
    Var
     mdf: TMyDialogForm;
    Begin
     mdf := TMyDialogForm.Create(nil);
     Try
      [...]
      mdf.ShowModal;
     Finally
      FreeAndNil(mdf);
     End;
    End;

    Unfortunately though, changing nil to Application.MainForm had no effect.


  15. 1 hour ago, dkprojektai said:

    Software runs on many PC's without any problems. This issue I have only on 1 PC. It's Windows 7 32bit.

    TJPEGImage is using external methods, like jpeg_CreateDecompress. I don't know if this is being supplied by the compiler or the OS the application is running on, but in this case I don't think it's an issue, as:

    - if it would be an issue with Win7 x86, it would have affected an awful lot of applications, including browsers too and would have quickly been patched

    - if the compiler is attaching these methods to the EXE, the application would fail everywhere.

     

    Is the application failing with all Win7 x86 OSes, or just one particular PC? If only one PC, is it failing constantly, or just from time to time?

    I'd look into the configuration of the machine. Ideas: AV locks the file to scan it before the DLL tries to access it; UAC blocking the placement of the file; worn hard drive; any other application hooking into yours / system calls, etc.


  16. 9 hours ago, Remy Lebeau said:

    What makes you think TJPEGImage creates invalid JPG files?

    My 2 cents are... not releasing write lock / not closing file, or improper flushing to disk. I personally never had any issues with TJPEGImage like this.

     

    @dkprojektai If you really want to make sure, try reloading the saved file with the same, TJPEGImage object and catch any exceptions. As I stated above though, I would be surprised if there would be any. I think @Remy Lebeau is on the right track here and the DLL is not handling the file correctly.

    At the end of the day it might be a special requirement in the header / pattern what we don't know about.


  17. Hello,

     

    I already used WM_SETREDRAW to disable flickering when resizing / loading components successfully, however today I faced an interesting issue. I created a TForm descendant (DoubleBuffered, if it makes any difference) with .BeginUpdate and .EndUpdate methods as follows:

    Procedure TMyForm.BeginUpdate;
    Begin
     SendMessage(Self.Handle, WM_SETREDRAW, Ord(False), 0);
    // LockWindowUpdate(Self.Handle);
    End;
    
    
    Procedure TMyForm.EndUpdate;
    Begin
     SendMessage(Self.Handle, WM_SETREDRAW, Ord(True), 0);
     Self.Repaint;
    // LockWindowUpdate(0);
    End;

    I am trying to create an "expandable" dialog box, where there is a button to show additional information about the message (if available). It looks like this:

     

    image.png.45b43eb52e720ac2fbf55e4cb8e2d097.png

     

    It contains three elements: a top panel with alTop (with the alLeft picture and a alClient caption), a bottom panel for buttons with alBottom and an alClient memo.

    Expanding / collapsing logic is:

      ExpandCollapseButton.Glyph.Assign(nil);
      If _expanded Then Begin
                        ImageList.GetBitmap(1, ExpandCollapseButton.Glyph);
                        Self.Constraints.MaxHeight := 0;
                        Self.Height := _savedheight;
                        Self.Constraints.MinHeight := Self.Height - ExtendedMessageMemo.Height + 21;
                        End
        Else Begin
             ImageList.GetBitmap(0, ExpandCollapseButton.Glyph);
             _savedheight := Self.Height;
             Self.Constraints.MinHeight := 0;
             Self.ClientHeight := TopMessagePanel.Height + ButtonsPanel.Height;
             Self.Constraints.MinHeight := Self.Height;
             Self.Constraints.MaxHeight := Self.Height;
            End;

    Everything works like a charm until I try to wrap this block in the .BeginUpdate / .EndUpdate method. The form is alive (reacts to keypresses; even expands itself if I assign the expand method to a keypress), but unclickable, unmovable... like if the ending WM_SETREDRAW would have never been called.

    Both SendMessage functions returns with success.

    Extra: if I swap the ending SendMessage with PostMessage, the form works normally, only the moving parts are not repainted (in my case the memo and the button panel); guess this is because the .Repaint is performed before the message is processed. I already tried sending a WM_PAINT, a simple .Invalidate instead of .Repaint, even repainting the whole screen without success.

     

    The question is obvious. What am I overlooking, why WM_SETREDRAW is working fine with everything else, but a form? 🙂

     

    Cheers!


  18. @Arnaud Bouchez I guess it all comes down to personal preference and possibility. There are cases when you are not allowed to choose the DB engine for your application, and there are cases when your application has to support some / most of them. My situation was exactly like this - someone decided to go with ONE DB engine only, and the whole software was built to use the engine-specific features. You don't necessarily have to agree with the design choices but you can only cook from what you have.

     

    As for preference I like the strict typing more but I can see the pros and opportunities of weak types (JSON is still the best for REST-like channels and local application settings store). I'll rather add a column to a database than to verify before each data access if the value exists, if it is a known (and accepted) type and if it has the information which I need. Especially if the user has the freedom or the possibility to access / change these objects (in my consideration if the software is running on their systems, they do).

     

    If you have the freedom and do not plan your database to grow too large - go for it. All I'm saying is that I already burned myself with this and therefore quickly became a no-go in future designs.

×