Jump to content

aehimself

Members
  • Content Count

    1030
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by aehimself


  1. Quote

     

    Unofficial, programmers love Pascal/Delphi/Free Pascal/Lazarus-IDE, but Official, they never confess that use that technologies and they shame of that.

    Pascal/Delphi programmer never put that information in CV that he love or use Pascal/Delphi.

    Delphi/Pascal programmers shame of Delphi/Pascal, and put in CV that use Microsoft C#, Python, PHP or something cool and very popular today.

     

    Wtf...?

     

    Btw I never experienced random crashes of my applications, not one since Windows 2000. I mean of course I did, but all of them was the fault of my code, not the OS silently attempting to kill it. And I would be REALLY surprised if it was true (especially now since Embarcadero / Idera has MS links if I'm not mistaken).

    • Like 1

  2. 1 hour ago, Wagner Landgraf said:

    Thank you very much for the feedback. Since you mentioned you just "gave it a try", you are not using it anymore, and/or didn't use it in production?

    I'm also interested in knowing how it is (and the other mentioned tools) when it comes to performance and stability, since I intend to use it in server applications.

    I had ~2 releases with DebugEngine, then I switched back to MadExcept. It's stack traces are less messed up when packed with UPX. I'd personally prefer DebugEngine as it is not installing hooks (thus - not having the issues I mentioned) getting stack traces is it's main purpose.

     

    Performance wise - you won't feel a difference tbh. None of these tools will make your application less stable or significantly slower.

    • Thanks 1

  3. I gave DebugEngine a try and it is very good. Sometimes it provides stack traces strange (method where exception happened, two inner methods of DebugEngine and then the real stack trace) but it's really easy to install and use. It is also unaffected by the two issues I have with MadExcept (TThread.FatalException and Exception.InnerException is rendered useless).

     

    It comes with a utility to attach the map (or it's own compressed smap) format to the .EXE itself, however the final executable is larger than with MadExcept (guess the .map compression is not that advanced in DebugEngine than in MadExcept).

     

    I don't have much experience with JclDebug... I tried it once, and I disliked every bit of it. Only to be able to see stack traces I had to include ~30 extra files in my project and the stack traces were not accurate.; so I gave up on it.

    If you can fit into the free usage conditions of MadExcept I'd say go with that. Otherwise, DebugEngine (or a license for MadExcept) would be my choice.

     

    P.s.: keep in mind that also MadExcept and DebugEngine is known to have stack issues if the .exe is packed with UPX.

    • Like 1
    • Thanks 1

  4. This question is way too broad to be able to be answered correctly. In general, have Try..Except blocks.

    What you do inside the exception handler completely depends on the kind of application you are writing.

     

    If you don't want your application to crash / misbehave after an exception happened you have to make sure you "reset it to a default state". Roll back transactions, close datasets, free up objects, closing TCP connections, etc. You might want to make a note of it too for debugging purposes so write details to a log file and let your user know that something went south.

    It's also good to have stack traces so look into MadExcept / DebugEngine - both are really easy to install and can be used for free - with restrictions of course.

    • Like 2

  5. Thank you for the explanation, it all makes sense now. I don't really need workarounds; if this area will be touched it will be properly changed instead to use a hack-of-a-hack...

     

    Don't get me wrong - I know this should not be done because it won't work; this is why I was this surprised that it does in our case. The sole purpose of this topic was for me to understand why it does, when it should not 🙂


  6. Update: wrong. #0s are not present.

     

    Var
     ss: TStringStream;
     s: TStream;
     tb: TBytes;
    begin
     ss := TStringStream.Create('Árvíztűrő tükörfúrógép');
     Try
      s := ss;
    
      SetLength(tb, s.Size);
      s.Read(tb, Length(tb));
      
      ShowMessage(TEncoding.Default.GetString(tb));
     Finally
      FreeAndNil(ss);
     End;

    Lossy conversion as you mentioned, though.


  7. 36 minutes ago, Remy Lebeau said:

    Most likely, that code predated the shift to Unicode in Delphi 2009.

    Not most likely, it does. Was Delphi 6 or 7, way before I joined the company.

    36 minutes ago, Remy Lebeau said:

    This is exactly why you SHOULD NOT put binary data into a UnicodeString.

    I know, this is why I was really surprised that it actually works like this. We are just lucky with our locale it seems 🙂

    36 minutes ago, Remy Lebeau said:

    Doesn't work.  It fills only 1/2 of the UnicodeString's memory with the non-textual binary (because SizeOf(WideChar) is 2, so the SetLength() is allocating twice the number of bytes as were read in), then converts the entire UnicodeString (including the unused bytes) from UTF-16 to ANSI producing complete garbage, and then writes that garbage as-is to file.  So yes, the same number of bytes MAY be written as were read in (but that is not guaranteed), but those bytes are useless.

    First one was only a demonstration; I knew it won't work. I found it strange that the output byte count is the same as the input (because of the double size as you pointed out) though. Guess I was lucky with the random choice of exe.

    36 minutes ago, Remy Lebeau said:

    That code is copying the binary as-is into an AnsiString of equal byte size, converting that AnsiString to a UTF-16 UnicodeString using the user's default locale, then converting that UnicodeString from UTF-16 back to ANSI using the same locale.  Depending on the particular locale used, that MAY be a lossy conversion, you MIGHT end up with the same bytes that you started with, or you MIGHT NOT.

    So if I get it right... we read the binary data, doubling it's size as we pad each character with a #0 during AnsiString -> String conversion?

    The real code is creating a TStringStream out of this and passing it as a parameter of a method, which is expecting a stream. That method will access the contents with .Seek and .Read I suppose.

    I didn't test this, but am I safe to assume that this would include the extra #0s, causing the binary data to be corrupted?


  8. While digging in the depths of a legacy application I was shocked to see that a binary data received through the network is stored and handled as a String.

    And it works.

     

    Imagine the following code:

    procedure TForm1.Button1Click(Sender: TObject);
    Var
     tb: TBytes;
     s: String;
    begin
     tb := TFile.ReadAllBytes('C:\temp\Project1.exe');
    
     SetLength(s, Length(tb));
     Move(tb[0], s[1], Length(tb));
    // If CompareMem(@tb[0], @s[1], Length(tb)) Then ShowMessage('Contents are the same');
    
     TFile.WriteAllText('C:\temp\project2.exe', s, TEncoding.Default);
    end;

    Fails. Produces the same amount of bytes, but it doesn't work.

     

    However, just by introducing a string casting:

    procedure TForm1.Button1Click(Sender: TObject);
    Var
     tb: TBytes;
     s: String;
     ans: AnsiString;
    begin
     tb := TFile.ReadAllBytes('C:\temp\Project1.exe');
    
     SetLength(ans, Length(tb));
     Move(tb[0], ans[1], Length(tb));
     s := String(ans);
    
     TFile.WriteAllText('C:\temp\Project2.exe', s, TEncoding.Default);
    end;

    output executable is... well, executable.

     

    My bet is on some pointer magic Delphi is doing in the background, but can someone please explain WHY this works?!


  9. Hello,

     

    I'm wondering how it is possible to achieve. Let's say I have an object:

    TMyObject = Class(TObject)
    strict private
     _status: String;
    strict protected
     Property Status: String Read _status Write _status;
    End;

    All fine, but how can I publish the same, Status property as public, read-only? In theory I could do (untested, only theory)...

    TMyObject2 = Class(TMyObject)
    strict private
     Function GetStatus: String;
    public
     Property Status: String Read GetStatus;
    End;
    
    Function TMyObject2.GetStatus: String;
    Begin
     Result := inherited Status;
    End;

    and from within TMyObject2's descendants I could say

    inherited Status := 'MyStatus';

    to set the status. Now, can it be achieved that from within the thread I simply say Status := 'MyStatus' and everyone else can access this as a read-only property from the outside?


  10. program Project2;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    Const
     MAX_NUMBER = 1000;
     CYCLECOUNT = Integer.MaxValue;
    
    Var
     numbers: Array[0.. MAX_NUMBER - 1] Of Integer;
     a, min, max: Integer;
    
    begin
     Randomize;
    
     For a := Low(numbers) to High(numbers) Do
      numbers[a] := 0;
    
     For a := 1 To CYCLECOUNT Do
      Inc(numbers[Random(MAX_NUMBER)]);
    
     min := CYCLECOUNT;
     max := 0;
    
     For a := Low(numbers) To High(numbers) Do
      Begin
       If numbers[a] < min Then min := numbers[a]
         Else
       If numbers[a] > max Then max := numbers[a];
      End;
    
     WriteLn('After ' + CYCLECOUNT.ToString + ' cycle(s), minimum amount of occurrences of the same number is ' + min.ToString + ', maximum is ' + max.ToString);
     ReadLn;
    end.


    After 2147483647 cycle(s), minimum amount of occurrences of the same number is 2144157, maximum is 2150811

    That means, the luckiest random number was hit 6654 times more than the least lucky one (from more than 2 billion attempts!).

     

    Delphi's internal random number generator has a healthy dispersion. It's not perfect, but it is more than enough for average use.

×