Jump to content

aehimself

Members
  • Content Count

    1030
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by aehimself


  1. 1 hour ago, Lars Fosdal said:

    @aehimself Just a thought. You may need to support "as" naming to handle duplicate field names in table joins or IsNull code. 

    
    select aStrField, IsNull(aIntField, 0) as aIntField from aTable

    Without the as - the aIntField will not be named in the result set - at least not for MS SQL.

     

    Then there is the question of count, max, min, and so forth...

    Once you open for custom queries - you basically open a can of feature requests 😉

    I'm not too worried about duplicate file names, as I'm planning to generate the query with TABLENAME.FIELDNAME all the times (thus the mapping) and if the output will show MyField and MyField_1 in the column header... then so be it.

    As for the IsNull you might be right but not during data display (my database component handles null values as 0, which is perfect in my case) but at WHERE clauses... I recall having an issue on MSSQL not returning correct rows as it handled NULL and 0 (or '', I don't remember exactly) differently. We will see how exactly it will turn out, especially with the "can" you are talking about 🙂

     

    As for the external components I think I will have to gather my strength and finalize my solution. After all it's less than 400 lines (only field mapping and the crawler until now, though) and does not increase the budget. Good news is that I'm either doing this or implementing the requested XML documentation commenting. And I rather code than to do documentation 😄


  2. On 1/15/2020 at 8:23 AM, haentschman said:

    Hi...:classic_cool:

    Imho is not a good idea to allow the end user to generate statements. Especially with an input in a TDEDIT. :classic_ninja:

    SQL injection: https://en.wikipedia.org/wiki/SQL_injection

     

    Good point, but the user is not allowed to write SQL queries at all 🙂 The method I'm working on / looking for is allowing the user to select (enter) field names, maps those to real fields in the database (attempted sql injection will fail at this level as '; DROP TABLE Users; will not map to any field in the database) and based on the mapped fields constructs a SELECT query with proper joins.

     

    Maybe I'm not viewing this scenario from all aspects, but I don't see the possibility of a vulnerability here.


  3. I also started to use %USERPROFILE% and %APPDATA% as local data storages. If people want to exchange their information, they can export and import; but not necessarily everyone wants to see the same information.

     

    Just imagine your application running on a terminal server used by 100+. They will surely want to separate their data.


  4. Hi all,

     

    I have an application where I would like the user to be able to "build" what data he wants to see. As I can not expect the user to be an expert in SQL, I need to have an interface where he can just check (or enter) the fields, my program will parse it, generate the necessary SQL query (with proper joins and such), executes it and returns the data.

    I wrote a small program to "design" the database of the application - it is generating SQL scripts and the code for my custom table-as-an-object implementation - so I have access to all the field and relational information and can output it in any format needed.

     

    I already have a prototype which can judge which field in which table to select and a crawler (path finder, basically) which can determine the shortest route between two tables. They seem to be working fine but there's still a lot of work with it (optimizations, beautifying - the usual) which I am soooooo unwilling to do at the moment.

     

    So my question is - do I really have to reinvent the wheel? Is there a framework available which can do this for me?

     

    And yes, I really hate to redesign working prototypes to production-ready implementations 🙂


  5. 17 hours ago, PeterPanettone said:

     

    
    function TformMain.SaveShortcutShellLinkAsAdministrator(const AFile: string; AShellLink: JclShell.TShellLink): Boolean;
    begin
     [...]
      else
      begin
        MessageDlg('Could not create a temporary ShellLink Shortcut', mtError, [mbOK], 0);
        EXIT;
      end;
      [...]
      if not Result then EXIT;
      [...]
      if not FileExists(AFile) then EXIT;
      [...]
    end;

     

     

    On 12/20/2019 at 10:29 AM, PeterPanettone said:

    I have found a new DEFINITION of "Early Return":

     

    "STUPIDITY TRYING TO LOOK SMART"

    Jokes aside 🙂

    A couple of questions popped up in my mind:

    - Are you sure that "RunAs" is an allowed verb for ShellExecute? https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutea does not seem include it, only https://docs.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-shellexecuteinfoa (JCL's ShellExecAndWait is using the Ex version, so the code itself is good, it's only a misleading comment)

    - Tip: If the file exists but corrupted (hashes do not match) delete the target file as its useless anyway; but...

    - Why are you comparing the hashes before and after moving? Did you experience corruption in any occasion? I'm only asking because I personally never met this before.

    - A little bit more resource friendly way of verification might be to check the exit code of move. I'd say might, because as it never failed on me I don't know what exit code it returns if it corrupted the data. So take this with a grain of salt.


  6. Yes, that was my fear too. Solution is rather easy though - don't use overloads 🙂 I started to experiment and came to the realization that Self can be used in a class function / procedure. It only won't reference an instance, only the class of the calling object - even if it is a child. The below works perfectly:

    TBase = Class
    strict protected
     Function GetAsJSON: String; Virtual;
     Procedure SetAsJSON(inJSONString: String); Virtual;
    public
     Var1: Integer;
     Class Function New(inJSONString: String): TBase;
     Class Function New2(inInteger: Integer): TBase; Virtual;
     Property AsJSON: String Read GetAsJSON Write SetAsJSON;
    End;
    
    TChild = Class(TBase)
    strict protected
     Function GetAsJSON: String; Override;
     Procedure SetAsJSON(inJSONString: String); Override;
    public
     Var2: String;
     Class Function New2(inInteger: Integer; inString: String): TChild; ReIntroduce;
    End;
    
    //
    
    Class Function TBase.New(inJSONString: String): TBase;
    Begin
     Result := Self.Create;
     Result.AsJSON := inJSONString;
    End;
    
    Class Function TBase.New2(inInteger: Integer): TBase;
    Begin
     Result := Self.Create;
     Result.Var1 := inInteger;
    End;
    
    Class Function TChild.New2(inInteger: Integer; inString: String): TChild;
    Begin
     Result := TChild(inherited New2(inInteger));
     Result.Var2 := inString;
    End;

    I don't like that there are two "New" methods now, but it feels a lot more clean.


  7. On 12/31/2019 at 12:15 PM, Stefan Glienke said:

    That code would not even compile as the two New overloads in TBase don't differ from each other parameter wise.

    Did not pay enough attention when writing the example 🙂 Let me correct myself:

    TBase = Class
    public
     Var1: Integer;
     Class Function New(inJSONString: String): TBase; Overload; Virtual;
     Class Function New(inVar1: Integer): TBase; Overload; Virtual;
    End;
    
    TChild = Class(TBase)
    public
     Var2: String;
     Class Function New(inJSONString: String): TChild; ReIntroduce; Overload;
     Class Function New(inVar1: Integer; inVar2: String): TChild; ReIntroduce; Overload;
    End;

  8. I think the answer is no but maybe I just did not find the correct way - yet.

     

    Imagine the following:

    TBase = Class
    public
     Var1: String;
     Class Function New(inJSONString: String): TBase; Overload; Virtual;
     Class Function New(inVar1: String): TBase; Overload; Virtual;
    End;
    
    TChild = Class(TBase)
    public
     Var2: Integer;
     Class Function New(inJSONString: String): TChild; ReIntroduce; Overload;
     Class Function New(inVar1: String; inVar2: Integer): TChild; ReIntroduce; Overload;
    End;

    When I type TChild.New, all four variants are accessible. So the question is: is it possible to completely reintroduce the base classes all overloaded methods, so in the child only the newly declared are accessible?


  9. Killing a thread is not a good idea in about 99% of the times 🙂 The best case is that it will leak memory and / or abandon TCP connections.

    Worst case? It can leave corrupted temporary files around, render your application unusable and requiring a restart or even leave the system in an unbootable state (depending what it is doing which gets forcefully interrupted).

     

    Sometimes you have no other option though... 

     

     

    There are some REALLY good advices there. Maybe you can launch the image processing in a child process - in regards to the host applications state killing a process can be less painful than a killing a thread.

    • Like 1

  10. 1 minute ago, PeterPanettone said:

    That's not a definition. Try harder.

    There you go, I found it: https://dictionary.cambridge.org/us/dictionary/english/sarcasm

     

    I'll try to act like an adult and stop this discussion right here. If you would like to learn more about coding styles, Google is - as always - your friend. In the mean time, please learn how not to get offended when people say their favorite color is not the same as yours.

    • Like 2

  11. 4 minutes ago, PeterPanettone said:

    That's not an "experience" but a FALSE ASSUMPTION.

    No, it's not. @Anders Melander said: "It's based on the experience that unnecessary nesting makes the code harder to read." which is not false and not an assumption. It's a general statement.

    I only can quote myself. Don't get offended. We are talking about personal preferences here.

    • Like 1

  12. 5 hours ago, Anders Melander said:

    It's a refactoring; It improves the readability of the code without changing the functionality.

    I'm a fan of early returns, I use them all the times. For me it does improve readability but my colleagues complain that it makes it harder for them.

    This is a matter of preference IMO, nothing else.

    • Like 1

  13. 16 minutes ago, David Heffernan said:

    Actually it's a really bad idea. Cross process window parenting relationships just don't work out. Don't even think about it. 

    I respectfully disagree. I had issues with focus and modals not being true modals but otherwise it's working pretty all right. I have to admit that I docked quite simple applications (like PUTTY) until now, though.


  14. 11 minutes ago, Soji said:

    Application.ProcessMessages is not a solution I am fond of. I wanted to avoid that and came into the peekmessage option.

    Well, you are effectively - almost - doing the same 🙂

     

    12 minutes ago, Soji said:

    But it is a big overhaul and in sustain mode, it is not allowed to do that overhaul.

    This is a difference in point of views by different coders / companies. Sustain mode means only to fix critical bugs for me. Main window is frozen? Live with it; it's only visual, not critical.


  15. 5 hours ago, Rollo62 said:

    Have you considered to call several EXE files in the umbrella app ?

    They seem not be related much yet, so that could be a way to be faster.

    This is actually a really good idea. Call the .EXE's and dock their window into your application, like a new tabsheet. And until the clients are happy, you can work on the refactoring 🙂


  16. What you see is how a specific operating system is handling unresponsive windows. It's not only your program, it's all which are freezing the main thread (therefore blocks message processing).

     

    If you don't mind getting your hand dirty by writing REALLY BAD code you can get away with periodically calling Application.ProcessMessages during your long operation:

    Procedure StartLongOperaton;
    Begin
     Operation1;
     Application.ProcessMessages;
     Operation2;
     Application.ProcessMessages;
    End;

    or

    Procedure WorkWithDataSet(inDataSet: TDataSet);
    Begin
     inDataSet.First;
     While Not inDataSet.Eof Do
      Begin
       DoSomethingWithRecord;
       inDataSet.Next;
       Application.ProcessMessages;
      End;
    End;

    ...but if you don't know what you are doing, you'll quickly face more issues than just a frozen window.

     

    PeekMessage works, because it is forcing the processing of windows messages, therefore your form will APPEAR not frozen. Application.ProcessMessages does the same, it's basically a better wrapper for it.

     

    The real solution is... well, you guessed it: threads. There is no such thing as a method is "not possible to put in a thread".


  17. When I reached a point like this in the past I always went for a full refactor. It's painful, it's slow, adding no new features at all (maybe even removing some...?) but you always can reuse chunks of code to help to finish faster.

    In the end it worths the effort, trust me.

     

    I had an application I was maintaining for 10 years (7 threads plus VCL logic written in Unit1.pas, with names like Button1 or Thread1) when I decided that it was too messy. It took about 3 months to rewrite the whole thing from scratch but implementing proper class inheritance and separation of data access, business logic and UI. Adding a new feature in the past took days or weeks, now it is a matter of hours. As an addition, I cannot tell how many bugs were fixed just by cleaning the code up.

     

    It's a tremendous and scary job. But knowing the result I'd definitely do it again.


  18. Soooo... the bad thing is that without major changes the original project started to work correctly and I don't know why!!!

     

    Especially since the raw DBGrid seems to have this issue and I don't remember fixing anything in my descendant...


  19. Yes, original code was without .Lock and .Unlock but since it started to glitch out I decided to include it (and it remained). As for the Mod 2 it is no mystery, only my mistake: took the shots before changing the value - was experimenting with a lot of things before asking.
    Invalidating after a column drag will not be the solution - as this is only the sample code, and this is how I could recreate the issue. In the original project some lines are drawn correctly, some are in black (no matter that the color is set to red), some does not appear at all even without dragging involved.


  20. Hello,

     

    In Delphi 10.3.3 I have a DBGrid component with the following handler:

    procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState);
    Var
     r: TRect;
    begin
     If ZQuery1.RecNo Mod 2 = 0 Then Begin
                                     r := Rect;
                                     InflateRect(r, -1, -1);
                                     DBGrid1.Canvas.Lock;
                                     Try
                                      DBGrid1.Canvas.Pen.Color := clRed;
                                      DBGrid1.Canvas.Pen.Width := 2;
                                      DBGrid1.Canvas.MoveTo(r.Left, r.Top);
                                      DBGrid1.Canvas.LineTo(r.Right, r.Top);
                                     FInally
                                      DBGrid1.Canvas.Unlock;
                                     End;
                                     End;
    end;

    Everything works fine:

     

    DBGrid_Unstyled_OK.PNG.34da0626bda8fa11700cb7925fb35fcd.PNG

     

    Until the moment when I enable VCL Styles. At first, it appears okay:

     

    DBGrid_Styled_OK.PNG.5660e2b8296fc25b3a7718acb7056ea9.PNG

     

    But if you start to click (especially try to drag and drop column headers) things start to fall apart:

     

    DBGrid_Styled_NOK.PNG.29703ad5d8e9e82e71b036ce8f668fc7.PNG

     

    This does not seem to happen when there are no Styles enabled. Anyone has an idea on what is this and how to fix it?

     

    Thanks!

×