Jump to content

Johan Bontes

  • Content Count

  • Joined

  • Last visited

Posts posted by Johan Bontes

  1. 14 hours ago, jbg said:

    This assertion is thrown when the debugger's CreateProcess() call to start the application fails. I think it would be better to tell the user what the problem is (RaiseLastOSError) instead of showing the informationless "apiOK" message box.


    Unfortunately I can't reproduce this bug with the projects I have.


    Let me try and see if I can reproduce this error with a simple sample project. and post that here later.

  2. 10 minutes ago, miab said:

    How is it that one independent programmer has to improve Delphi IDE for over 10 years?
    Basically hacking them without access to sources?
    Delphi which subsequent versions are released for a large amount of money at least every year.

    As has been clarified by Hick Hodges a few times before (when he was working for Emba), all is exactly as Andy wants it.

    And he does have access to the source as per agreement.

    And no he does not get paid (as far as we know) and (as far as we know) that's how he wants it.

    This point keep coming up again and again and it's getting rather old, just be happy with the work Andy is doing and take your blessings where you can get them.


    Yes Emba should do more, better, faster etc but it is as it is.

    • Thanks 1

  3. @jbg

    Hi Andy,


    I'm getting an error when compiling my project after installing the Delphi fix pack in Rio Community edition version:

    Embarcadero® Delphi 10.3 Version 26.0.32429.4364


    Compiler Speed Pack x86 6.4 for Delphi 10.3


    Windows 10 version 10.0 Build 17134 64-Bit edition


    When I run a 64-bit application under the debugger (F9) the following error pops up:


    Debugger Assertion Failure "apiOK"

    in ..\win32src\w64mgr.cpp at Line 79

    [203B7664]{dbkdebugide260.bpl} Debug.TDebugKernel.msgBox (Line 5945, "Debug.pas" + 30) + $0
    [2DFB6EB3]{bordbk260.dll} Unknown function at DllUnregisterServer + $5037
    [2DFD37D6]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $98FE
    [2E067FC9]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $9E0F1
    [2DFCA660]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $788
    [2DFCA6DB]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $803
    [2E0617AD]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $978D5
    [189FB134]{bordbk260N.dll} Unknown function at @isDbkLoggingOn$qv + $302BC
    [189CDBB5]{bordbk260N.dll} Unknown function at @isDbkLoggingOn$qv + $2D3D
    [18A01FB3]{bordbk260N.dll} Unknown function at POSTEDHOOKPROC + $113F
    [18A0176F]{bordbk260N.dll} Unknown function at POSTEDHOOKPROC + $8FB
    [50067E99]{rtl260.bpl  } System.@IntfCopy (Line 38197, "System.pas" + 6) + $0
    [2E070CC5]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $A6DED
    [2DFB908C]{bordbk260.dll} Unknown function at DllUnregisterServer + $7210
    [2E06F91B]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $A5A43
    [2E06214A]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $98272
    [2E062AA4]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $98BCC
    [2E0628D3]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $989FB
    [2E062033]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $9815B
    [2E061999]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $97AC1
    [2E061521]{bordbk260.dll} Unknown function at @isDbkLoggingOn$qv + $97649
    [2DFB7AEC]{bordbk260.dll} Unknown function at DllUnregisterServer + $5C70
    [203B6357]{dbkdebugide260.bpl} Debug.TDebugKernel.CreateProcess (Line 5464, "Debug.pas" + 17) + $63
    [0B6AE315]{IDEFixPack.dll} DbkCreateProcessWithRelHostApp.TDebugKernel_CreateProcessHook (Line 46, "DbkCreateProcessWithRelHostApp.pas" + 4) + $23
    [203BDD5C]{dbkdebugide260.bpl} Debug.TProcess.CreateProcess (Line 9037, "Debug.pas" + 1) + $2D
    [203C4D51]{dbkdebugide260.bpl} Debug.TDebugger.DoCreateProcess (Line 11959, "Debug.pas" + 74) + $24
    [203C4EF8]{dbkdebugide260.bpl} Debug.TDebugger.CreateProcess (Line 11986, "Debug.pas" + 7) + $2F
    [203C5A27]{dbkdebugide260.bpl} Debug.TDebugger.Run (Line 12395, "Debug.pas" + 23) + $33
    [203C675C]{dbkdebugide260.bpl} Debug.TDebugger.Run (Line 12759, "Debug.pas" + 164) + $4D
    [203C062E]{dbkdebugide260.bpl} Debug.TDebugger.Run (Line 10370, "Debug.pas" + 0) + $2
    [20866811]{coreide260.bpl} DebuggerMgr.TDebuggerMgr.Run (Line 2067, "DebuggerMgr.pas" + 21) + $5
    [004AE277]{bds.exe     } AppMain.TAppBuilder.RunRun (Line 3386, "AppMain.pas" + 1) + $3
    [5017361B]{rtl260.bpl  } System.Classes.TBasicAction.Execute (Line 17028, "System.Classes.pas" + 7) + $3
    [50CCDE62]{vcl260.bpl  } Vcl.ActnList.TCustomAction.Execute (Line 261, "Vcl.ActnList.pas" + 19) + $35
    [0B6A880E]{IDEFixPack.dll} RefactoringActionUpdateFix.CustomActionExecute (Line 87, "RefactoringActionUpdateFix.pas" + 4) + $0
    [50173483]{rtl260.bpl  } System.Classes.TBasicActionLink.SetAction (Line 16939, "System.Classes.pas" + 0) + $3
    [50CE54EC]{vcl260.bpl  } Vcl.Controls.TControl.Click (Line 7501, "Vcl.Controls.pas" + 7) + $7
    [50D644BC]{vcl260.bpl  } Vcl.ComCtrls.TToolButton.Click (Line 21635, "Vcl.ComCtrls.pas" + 0) + $0
    [50CE59B7]{vcl260.bpl  } Vcl.Controls.TControl.WMLButtonUp (Line 7642, "Vcl.Controls.pas" + 7) + $6
    [50CE4FAA]{vcl260.bpl  } Vcl.Controls.TControl.WndProc (Line 7387, "Vcl.Controls.pas" + 91) + $6
    [5005FE07]{rtl260.bpl  } System.TObject.Dispatch (Line 18332, "System.pas" + 11) + $0
    [09918E3E]{themeloader260.bpl} Idetheme.Vclstylehooks.TIDEStyleHook.WndProc + $7A
    [50067E88]{rtl260.bpl  } System.@IntfClear (Line 38150, "System.pas" + 10) + $0
    [099188F7]{themeloader260.bpl} Idetheme.Vclstylehooks.TIDEStyleHook.HandleMessage + $B7
    [50067E88]{rtl260.bpl  } System.@IntfClear (Line 38150, "System.pas" + 10) + $0
    [500640D8]{rtl260.bpl  } System.@FinalizeArray (Line 32811, "System.pas" + 144) + $0
    [50CE4BE4]{vcl260.bpl  } Vcl.Controls.TControl.Perform (Line 7165, "Vcl.Controls.pas" + 10) + $8
    [50CE926E]{vcl260.bpl  } Vcl.Controls.GetControlAtPos (Line 9967, "Vcl.Controls.pas" + 4) + $75
    [50CE9336]{vcl260.bpl  } Vcl.Controls.TWinControl.ControlAtPos (Line 9990, "Vcl.Controls.pas" + 13) + $E
    [50CE4BE4]{vcl260.bpl  } Vcl.Controls.TControl.Perform (Line 7165, "Vcl.Controls.pas" + 10) + $8
    [50CE9404]{vcl260.bpl  } Vcl.Controls.TWinControl.IsControlMouseMsg (Line 10014, "Vcl.Controls.pas" + 15) + $29
    [50CE9A0C]{vcl260.bpl  } Vcl.Controls.TWinControl.WndProc (Line 10191, "Vcl.Controls.pas" + 112) + $6
    [50D665E9]{vcl260.bpl  } Vcl.ComCtrls.TToolBar.UpdateButtonState (Line 22913, "Vcl.ComCtrls.pas" + 11) + $27
    [50D6662A]{vcl260.bpl  } Vcl.ComCtrls.TToolBar.UpdateButtonStates (Line 22924, "Vcl.ComCtrls.pas" + 3) + $4
    [50D69060]{vcl260.bpl  } Vcl.ComCtrls.TToolBar.WndProc (Line 24514, "Vcl.ComCtrls.pas" + 104) + $6
    [50CE9178]{vcl260.bpl  } Vcl.Controls.TWinControl.MainWndProc (Line 9944, "Vcl.Controls.pas" + 3) + $6
    [50174370]{rtl260.bpl  } System.Classes.CalcJmpOffset (Line 17554, "System.Classes.pas" + 0) + $0
    [50E3E7A7]{vcl260.bpl  } Vcl.Forms.TApplication.ProcessMessage (Line 10724, "Vcl.Forms.pas" + 23) + $1
    [50E3E7EA]{vcl260.bpl  } Vcl.Forms.TApplication.HandleMessage (Line 10754, "Vcl.Forms.pas" + 1) + $4
    [50E3EB1D]{vcl260.bpl  } Vcl.Forms.TApplication.Run (Line 10892, "Vcl.Forms.pas" + 26) + $3
    [00517FFA]{bds.exe     } bds.bds (Line 214, "" + 7) + $7

    Uninstalling the IDE-fix pack (ouch, that hurts) resolves the issue.

  4. I have the following code (Delphi Berlin):

      TSliver = record
        case integer of
          8: (Data8: int64);
      TSlice = record
        FData: array [0..63] of byte;
      TSliverHelper = record helper for TSliver
        class function NS(const North, South: TSlice; out Changed: TSliverChanges): TSliver; static; inline;
      {$L 'C:\mydir\AVXGenerate.o'}  //imported assembly generated by lazarus.
      procedure AVXGENERATE_TSLIVERHELPER_NS; external name 'AVXGENERATE_$$_TSLIVERHELPER_NS'; //no parameters for simplicity.
    class function TSliverHelper.NS(const North, South: TSlice; out Changed: TSliverChanges): TSliver; {inline;}
      //RCX =North: PSlice
      //RDX =South: PSlice
      //R8 = Changed: PSliverChanges ((scUnchanged=0, scChanged=1, scInvalid=3));
      //RAX = Result: TSliver (as Int64)

    The asm method works correctly, the inlined method does not. If we look at the generated code it's easy to see why this happens.


        a:= TSliver.NSTest(N,S,statusA);
        //a = -1
        UnitTests.pas.877: b:= TSliver.NS(N,S, statusB);
        00000000009A77CE 488D8C2480000000 lea rcx,[rsp+$0080]
        00000000009A77D6 488D542440       lea rdx,[rsp+$40]
        00000000009A77DB 4C8D44242E       lea r8,[rsp+$2e]         
        00000000009A77E0 E82B5E0100       call TSliverHelper.NS
        00000000009A77E5 4889442430       mov [rsp+$30],rax      //b = 7 why?
        //Let's see what's happening in the inlined method.
        class function TSliverHelper.NS(const [ref] N,S: TBigRec; out status: TEnumRec): UInt64_Rec;
        Unit2.pas.4360: begin
        00000000009BD610 55               push rbp
        00000000009BD611 4883EC30         sub rsp,$30
        00000000009BD615 488BEC           mov rbp,rsp
        00000000009BD618 E833350000       call AVXGENERATE_TSLIVERHELPER_NS  //external asm procedure with no declared params.
        Unit2.pas.4362: end;              //At this point RAX = result = -1, all OK
        00000000009BD61D 488B4528         mov rax,[rbp+$28]   //Oops, RAX gets overwritten, why?  <<<<???????????????????????
        00000000009BD621 488D6530         lea rsp,[rbp+$30]
        00000000009BD625 5D               pop rbp
        00000000009BD626 C3               ret

    Why does the compiler insert an assignment to RAX? I have not instructed it to do anything of the sort.

    Compiling this code also does not issue a warning that Result might be unassigned.


    Why does the compiler do this?

    (I know I can fix this by declaring the external proc as a function, but that's beside the point).




    When we redefine the external proc as a function and change the inline method as shown below, correct code gets generated. It also gives some insight what is going on:


    Unit2.pas.4360: begin
    00000000009BD610 55               push rbp
    00000000009BD611 4883EC30         sub rsp,$30
    00000000009BD615 488BEC           mov rbp,rsp
    Unit2.pas.4361: Result:= AVXGENERATE_TSLIVERHELPER_NS;
    00000000009BD618 E833350000       call AVXGENERATE_TSLIVERHELPER_NS
    00000000009BD61D 48894528         mov [rbp+$28],rax                  //pointless stack trashing
    Unit2.pas.4362: end;
    00000000009BD621 488B4528         mov rax,[rbp+$28]                  //the exit code expects Result to be in the stackframe.
    00000000009BD625 488D6530         lea rsp,[rbp+$30]
    00000000009BD629 5D               pop rbp
    00000000009BD62A C3               ret

    The compiler is just copy pasting its exit code, regardless of the actual code in the body.

    Note that I've compiled the code with no stackframes



  5. 1 hour ago, Tommi Prami said:

    More than less general. Any syntax basically...  

    What does that mean? Do you want a Pascal parser, or an any/all language parser?

    The former exists, the latter does not.

    Obviously there are parsers for other languages, just not one parser for every language.


    There is however Langserver   you might want to have a look at that.

  6. @Tommi Prami That's easy: https://github.com/RomanYankovsky/DelphiAST 


    You might want to try the version with all my patches in it: https://github.com/JBontes/DelphiAST 


    It seems Roman Yankovsky has not had time to integrate all my issues yet. 


    It **is** a very mature library and using it will serve you well. If you want to change the code, grokking the

    calls between the different parser levels does take some getting used to. I suggest first reading up on the difference

    between a parser and a lexer if you want to do that.


    PS don't be put off by the XML output, that's just a cheap trick to display the contents of the tree. You don't need it to work with DelphiAST.

    • Like 3
    • Thanks 3

  7. I'm not sure this is the right place for feature requests, but here goes:


    A: hide signature lines

    Would it be possible to have the option to hide signature lines? I find them to be such a distraction.

    Of course it would be even better IMO if signature lines were not allowed at all, but at least the option to hide them would help a lot.

    Just found the "hide all signatures" option at https://en.delphipraxis.net/settings/signature/



    B: inline code

    I would really like to be able to have inline code in a line. A `monospace` button (in addition to bold, italic, etc would do the trick nicely.


    C: Disable animating emoji 

    Animation of any kind just sucks, enough said.


    D: position replies indented relative to the original post

    If I reply to a post, then that post just goes to the bottom. I can quote part or all of it, but that's a bit of a

    waste as it just repeats the content, which is often (not always) just noise. It would be great to have a threaded view

    where replies are underneigh the original post and indented (with a stop if the nesting gets too deep).


    Overall the forum works kind of nice, it does take up a **lot** of space relative to G+, but it works smooth enough.

    Thanks for making this available on such sort notice.


      TX = record
        class var x: integer;
        Fdata: integer;
        class operator Add(a,b: TX): TX;

    I love how the code formatter knows about post-1980 language features, unlike the one stackoverflow uses.

  8. 18 hours ago, Attila Kovacs said:

    @Johan Bontes if x() is just an example and not part of the problem. It could be xres := x(s,s).

    And in your y() example I can't see any danger. Result is a separate string which will be copied /(or assigned its pointer?) to S at the end. Which means, the same performance or worse as omitting 'const' in my original post.

    In that case can you please explain what the nature of your (time)bomb is? I thought it was the issue that the const input got changed by the proc, but that does not seem to be your problem.

    • Like 1

  9. The way to deal with this is to have a function return a string whenever possible, that

    way it is clear in the calling code that `S` is being overwritten.

    Never output the same managed type of data that you allow as input in a var or out parameter.


    function y(const input: string; out Success: boolean): string;
      Result:= input + '1';
    status:= x(S,S);    //Looks harmless
    S:= y(S, status);   //The danger is clearly visible in the calling code

    Alternatively he compiler could issue a warning when a const parameter is also passed as a var/out parameter.


    also this code does not make a whole lot of sense:


    if x(S,S) then ....
    ////hiding dangerous -work- stuff with side-effects in an if statement.

    You should never do unconditional work inside an if statement. That's too unexpected.

    • Like 2

  10. 11 minutes ago, Markus Kinzler said:

    The type is missing and has to be guessed.

    No the type does not have to be guessed, it is a `TInterfacedObject`. As is stated in the create statement.


    What would be great though is to have static methods for interfaces:


    class function IMyInterface.Create: IMyInterface; static;
    //or even better
    constructor IMyInterface.Create;

    Obviously internally the constructor would translate to a static class function returning the interface.

    We can already do this by wrapping interfaces inside records and using implicit operator overloads, but that's a lot of typing.

    There is nothing stopping the compiler from helping us here, it's just a bit of syntactic sugar.

    Then we can just write


    var IMyInf:= IMyInterface.Create;

    Just like we can do in Java 8. (Yes, I dislike java just as much as everyone else, but static interface methods are a pretty cool feature.)

  11. 1 hour ago, Dalija Prasnikar said:

    This is truly great and long missed feature. Truly great. 


    But... I hate buts... there are things to watch out. Namely, type inference breaks reference counting. It is one of those don't mix objects and interfaces pitfalls. Should I say that this works perfectly on ARC compiler 🙂


    If you have reference counted class, you cannot rely on type inference, you have to specify the interface type.


    // broken
    var Instance := TInterfacedObject.Create;
    // not broken
    var Instance: IInterface := TInterfacedObject.Create;


    This was already the case with normal var declarations. Obviously if you want the var to be a different type than the R-value then you'll have to declare that type.

    In your own code you can fix this by declaring class functions like so:


      TMyClass = class(TInterfacedObject, IMyIntf)
        class function CreateIntf: IMyInf;
      class function TMyClass.CreateIntf: IMyInf;
        Result:= TMyClass.Create;
    //Now type inference works just fine.
    //Alternatively perhaps typecasting works?
    var IMyVar := IMyInf(TMyClass.Create);


    • Like 1

  12. A while ago I did some development using DelphiAST. 

    I've since added a symbol table and a writer that writes out Delphi code.

    This allows me to do something really cool: read in Delphi(like) code and output transformed code.


    One of the things this allows is new operators like


    +=, /= etc.


    It also allows for the new


    for var i: integer:= 0 to 10 do ...

    syntax to be ported. I simply read in the new syntax and output the old, taking care to resolve any name clashes.

    Obviously this also requires me to rewrite the syntax highlighter, which I have not done so far, because this is a bit harder, still I think it would make

    an interesting project and help with the adaptation of the new language features.


    Is there documentation regarding the new language features in Rio? I cannot seem to find more than a few still shots from David's presentation?