Jump to content

Berocoder

Members
  • Content Count

    93
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Berocoder


  1. I find a solution now. I have not done much of thread-handling before
    Here are the modified code:

    function TATMail.SendCloudMail(const aReceiver, aReplyTo, aCc, aSubject, aBody,
      aAttachments: string; ACallBack: TEMailCallBack; out AErrorMessage: string): Boolean;
    var
      oOutLook: TOutlookEmail;
    begin
      oOutLook := TOutlookEmail.Create(aReceiver, aReplyTo, aCc, aSubject, aBody, aAttachments, ACallBack);
      if not Assigned(ACallBack) then
      begin
        // Simulate blocking
        while oOutLook.EventSignal.WaitFor(100) = wrTimeout do
        begin
          CheckSynchronize(50);
        end;
    
        AErrorMessage := oOutLook.fMessage;
        Result := oOutLook.fSuccess;
      end
      else
        Result := True;  // Doesn't matter. None blocking code should never check result.
    end;

    I made 2 important changes
    1. Call SetEvent in the event that is called by FNC mailcomponent after mail was sent. I somehow thought that this happen automatically.
    2. In while loop compare with wrTimeOut instead of "<> wrSignaled". But when I think about it now maybe not so important...


  2. Normally a developer want to use async mode when send emails to make main thread more responsive.

    But I am in the situation to maintain an old ERP application. We use Delphi 11.3 for that.
    Currently it use 2 kind of email solutions.

    - SMTP. This contact an inhouse emailserver

    - SendGrid https://sendgrid.com

     

    There is now a request for a third email solution OutLook Azure from one big customer.

    So TMS FNC CloudPack component was bought.
    It was fairly easy to send emails once you get client id, secret etc correct.

    But the component only use asynchronous design which is correct from architecture point of view.
    The current code that use email method expect synchronous design.

     

    As long as emailing is working my current solution is ok.
    But there is no way to check and notify user in case of problem.
    It can be network or other reasons for error.
     

    To rewrite it require a major refactoring, that is also risky.
    So the most pragmatic solution would be to simulate blocking mode with FNC CloudPack if possible.

    So made 2 public methods in the mailing class.
    Send and SendWait. Send use asynchronous on places where it is possible and SendWait use synchronous.

    Current implementation

    function TATMail.SendCloudMail(const aReceiver, aReplyTo, aCc, aSubject, aBody,
      aAttachments: string; ACallBack: TEMailCallBack; out AErrorMessage: string): Boolean;
    var
      oOutLook: TOutlookEmail;
    begin
      oOutLook := TOutlookEmail.Create(aReceiver, aReplyTo, aCc, aSubject, aBody, aAttachments, ACallBack);
      if not Assigned(ACallBack) then
      begin
        while true do
        begin
          if oOutLook.Done then
            break;
    
          Application.ProcessMessages;
        end;
        TraceLog.Trace('After blocking');
        AErrorMessage := oOutLook.fMessage;
        Result := oOutLook.fSuccess;
      end
      else
        Result := True;  // Doesn't matter. None blocking code should never check result.
    end;

    I am aware that ProcessMessages is famous for cause random bugs and would prefer to no using it.
    I see that email component use CheckSynchronize to trigger the callback event. I tested 

    while event.Waitfor(100) <> wrSignaled do
    begin
      CheckSynchronize(50);
    end;

    I asked similar thing on Stack overflow https://stackoverflow.com/questions/79094352/how-can-i-convert-code-to-synkron-in-delphi
    And @Dalija Prasnikar suggested that. But CheckSynchronize is supposed to run in the background thread not in main thread ?
    Could be some misunderstanding. Anyway it didn't work.
    So I search for a solution in main thread that cooperate well when backgroud thread is calling CheckSynchronize.
    There is also some code on pastebin https://pastebin.com/EXsf4ywP
    Only as illustration. It won't compile

     


  3. Hi I want to know if anyone actually can debug a Delphi console program reliable?

    My setup is latest Delphi 12.1 on a Window 10 running in KVM. Host is Ubuntu 24.04.

    Sometimes it works to singlestep source but most of the time IDE just freeze and I have to kill it🙁

    I know 2 other developers with same experience as mine.

    I just don't understand how testing works at Embarcadero. This kinds of bugs must be catched before release!

     

    My report here https://embt.atlassian.net/servicedesk/customer/portal/1/RSS-1415


  4. 39 minutes ago, dummzeuch said:

    I'm not sure how efficient the implementation of IndexStr is. Assuming it's a linear search, the case statement is worse on two accounts:

    1. It more difficult to read and understand.

    2. It's a bit less efficient.

     

    On top of that this implementation is error prone. If somebody inserts a new string rather than appending it to the array the indices in the case statement will all have to be corrected.

     

    It has only one advantage: It's less to type. And of course, it looks cleaner.

     

    Some kind of sorted list or hash table storing the strings and an enum value would be more efficient and less error prone (edit: in short: a dictionary). Of course that list must be initialized before or can be used, preferably only once.

     

    People who are used to languages that support case statements with strings will of course laugh at that code anyway.

    I would prefer alternative 2. But you are right that it is error prone on change as it is harder to read.

    And as David said using enum would be best choice.

    Currently alternative 1 is used so I think I leave it as is for now 🙂

     


  5. What code to you prefer and why?

    Alternative 1

      if aMessageType = 'EXPREG' then
        DecodeExportReg(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPACC' then
        DecodeExportAcc(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPERR' then
        DecodeExportErr(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPREL' then
        DecodeExportRel(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPREF' then
        DecodeExportRef(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPREQ' then
        DecodeExportReq(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPINF' then
        DecodeExportInf(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPREJ' then
        DecodeExportRej(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPCLA' then
        DecodeExportCla(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPCON' then
        DecodeExportCon(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPAME' then
        DecodeExportAme(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPIRJ' then
        DecodeExportIrj(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPARJ' then
        DecodeExportArj(vDoc, aCdn, aRequestCorrelation, aMessageText)
      else if aMessageType = 'EXPHRT' then
        DecodeExportHrt(vDoc, aCdn, aRequestCorrelation, aMessageText)

     

    Alternative 2

      var Index := IndexStr(aMessageType, ['EXPREG', 'EXPACC', 'EXPERR', 'EXPREL', 'EXPREF', 'EXPREQ', 'EXPINF', 'EXPCLA', 'EXPCON', 'EXPAME', 'EXPIRJ', 'EXPARJ', 'EXPHRT']);
      case Index of
        0: DecodeExportReg(vDoc, aCdn, aRequestCorrelation, aMessageText);
        1: DecodeExportAcc(vDoc, aCdn, aRequestCorrelation, aMessageText);
        2: DecodeExportErr(vDoc, aCdn, aRequestCorrelation, aMessageText);
        3: DecodeExportRel(vDoc, aCdn, aRequestCorrelation, aMessageText);
        4: DecodeExportRef(vDoc, aCdn, aRequestCorrelation, aMessageText);
        5: DecodeExportReq(vDoc, aCdn, aRequestCorrelation, aMessageText);
        6: DecodeExportInf(vDoc, aCdn, aRequestCorrelation, aMessageText);
        7: DecodeExportRej(vDoc, aCdn, aRequestCorrelation, aMessageText);
        8: DecodeExportCla(vDoc, aCdn, aRequestCorrelation, aMessageText);
        9: DecodeExportCon(vDoc, aCdn, aRequestCorrelation, aMessageText);
        10: DecodeExportAme(vDoc, aCdn, aRequestCorrelation, aMessageText);
        11: DecodeExportIrj(vDoc, aCdn, aRequestCorrelation, aMessageText);
        12: DecodeExportArj(vDoc, aCdn, aRequestCorrelation, aMessageText);
        13: DecodeExportHrt(vDoc, aCdn, aRequestCorrelation, aMessageText);
      end;

     

    Regards

    Roland Bengtsson


  6. In our big ERP application we have always compiled it with Optimization off in compiler settings to production.

    Delphi 10.4 is used but plan is to switch to 11.3 during summer.

    With our biggest customer the volumes has increased and the application can sometimes feel slow.

     

    So I tried to compile it with Optimization on as that is a cheap way to increase performance. Everything seems to work fine.

    But there is one thing. Exceptions are logged to a textfile. Callstack/Stacktrace are also logged. We use JCL for that.

    It works fine before but now I see sometimes callstacks make no sense anymore.
    Obviously I suspect Optimization for that.

     

    So curious how other developers handle this case ?

    Is there other components like EurekaLog that handle optimization better and still can generate a reliable callstack ?

    Or maybe we have to choose between better performance or reliable callstack ?
     

    Regards

    Roland Bengtsson


  7. I am a bit confused of TestInsight. I am using version 1.2.0.1 with Delphi 11.2.


    image.png.a61d68c2bbd20c041cc246a160edf3d3.png
    I have marked my testproject 

    image.thumb.png.5325a67db7d220d45242a59be62c656a.png
    Discover tests find 34

     

    image.thumb.png.f6062880dd81ff6a3d6da92be8b79142.png
    I mark 2 tests and run selected with Shift+Alt+F9

    image.thumb.png.a78c25065e972a290efe69e1f8cefc46.png

    Now the strange case. I mark 2 new tests in skipped and run again with Shift+Alt+F9.
    The 2 already successful seems to run. Duration change. But not the new tests.
    I expect to see 4 success and 30 skipped now

    image.thumb.png.c313d18f5b93397c093372673d06bf64.png
    Now I uncheck the 2 tests at top and leave only 2 selected tests and run with Shift+Alt+F9.
    It seems to be ignored and none tests was executed.

     


    Did I do anything wrong or have I found a bug ?

     

    /Roland


  8. I have a problem that needs to be solved.
    I have an application written in Delphi 10.4. It is about 10 years old. It transform data from one database to another unsing Unidac drivers.
    Runs on a Windows 2008 R2 Server. As it is old it needs to be replaced by a new virtual server with Windows server 2019.
    Unfortunately my application don't works well. It runs for a while and just quit. Not an exception no sign of error at all before it dies.
    At the same time we setup more strict permissions in Windows. Thought that this was the reason.
    When I look in eventlog I see this:
     
    Faulting application name: DatapumpOCL.exe, version: 2022.10.200.3483, time stamp: 0x6358d093
    Faulting module name: KERNELBASE.dll, version: 10.0.17763.3532, time stamp: 0x95b80d84
    Exception code: 0x0eedfade
    Fault offset: 0x00125232
    Faulting process id: 0x237c
    Faulting application start time: 0x01d8f9bcde0671f6
    Faulting application path: C:\Ahola\AholaDaily\DatapumpOCL.exe
    Faulting module path: C:\Windows\System32\KERNELBASE.dll
    Report Id: 404588fe-4a1d-45a2-8c13-42a4b0136ced
    Faulting package full name:
    Faulting package-relative application ID:
    

     

    This is a 32-bit application. Windows Defender is running as antivirus. But Defender seems only have information as logs. No errors.
    I have tried to turn off everything in Exploit Protection just for this DatapumpOCL.exe. I have tried to turn on checks for Range, Overflow and IO in Delphi compiler settings but still the same.
    So out of ideas now :classic_mellow:
     
     

  9. Hi, I am using latest delphi with all patches. Delphi 11 Version 28.0.46141.0937

    When I debug my application by singlestep code with F7 or F8 sooner or later I cannot continue.
    IDE is still responsive but programcounter hang and singlestep code have no effect.

    I have seen this problem before also with previous 10.4.

    Anyone with similar experience ? What can I do as workaround except to restart my application and try again.
    It seems to be completely random...


  10. On 8/10/2022 at 9:01 AM, David Heffernan said:

    It sounded like you might be accessing an object after it has been destroyed which is obviously incorrect. 

    It is correct. Deleted is not the same as destroyed.
    A BoldObject is usually persisted in a database.

    Summary of lifecycle of such object:

    • Some code ask for the object. It is loaded from database to memory. A new instance in memory is created.
    • It can now be used as any normal object.
    • Some code call Delete method. The flag above BoldObjectIsDeleted is now true
    • Some code Synchronize memory with database. Objects that are changed will update rows in database.
      Objects that are deleted in memory will also be deleted in database.
    • The object will now be destroyed

     


  11. 8 hours ago, Uwe Raabe said:

    Thinking out of the box here:

    
    type
      TSupport = class helper for TObject
      public
        function Supports<T: class>(out ResObj: T): Boolean;
      end;
    
    function TSupport.Supports<T>(out ResObj: T): Boolean;
    begin
      ResObj := nil;
      if Self is T then
      begin
        if not ((Self is TBoldObject) and TBoldObject(Self).BoldObjectIsDeleted) then
          ResObj := T(Self);
      end;
      result := ResObj <> nil;
    end;

    Hm interesting idea 😀 Thanks!
    But that change how call the method. How will that look like ?

     

    Quote

     

     

×