Jump to content

Der schöne Günther

  • Content Count

  • Joined

  • Last visited

  • Days Won


Der schöne Günther last won the day on January 22

Der schöne Günther had the most liked content!

Community Reputation

22 Excellent

Technical Information

  • Delphi-Version
    Delphi 10.0 Seattle

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Der schöne Günther

    IDE can not create ancestor TFrame

    I have never done that but thank you for encouraging me! I just found out that, at least in my special case, the IDE runs into this error when you Are using the form designer Edit -> Hide non-visual components (Ctrl+H) Close the project After that, the registry path HKEY_CURRENT_USER\Software\Embarcadero\BDS\17.0\Form Design has "Show NonVisual Components"="False" This appears to be deadly. Just setting this value back to "True" makes my RAD Studio work again. I am on Delphi 10.0 Seattle. Not sure if it also affects other versions.
  2. Der schöne Günther

    IDE can not create ancestor TFrame

    Can you still open the ancestor frame in the form designer? Several times a week, my IDE somehow corrupts itself so that the form designer does no longer work for inherited frames. I then load a backup of my registry for HKCU\Software\Embarcadero\BDS\17.0 and everything is fine again for the next few days. I'm on 10 Seattle. Apart from that, it sometimes also just corrupts the DFM files for a frame. Your version control should be able to show you what happened.
  3. Der schöne Günther

    track process execution

    Your question is relatively vague. I guess the technical definition of "programs executed" means "whenever the WinApi CreateProcess(..) routine is called"? In that case, the Microsoft or MahdiSafsafi libraries are probably the fastest way: https://github.com/MahdiSafsafi/DDetours https://github.com/microsoft/detours/wiki/Using-Detours
  4. Der schöne Günther

    Undocumented "Interface flag" for IInvokable?

    I wonder where this value actually comes from. I guess not from RTL code that exists as a .pas file?
  5. You can use the RTTI to evaluate certain properties of interace types. Please see the following snippet: program Project1; uses System.Rtti; var context: TRttiContext; rttiInterface: TRttiInterfaceType; begin context := TRttiContext.Create(); rttiInterface := context.GetType( TypeInfo(IInterface) ) as TRttiInterfaceType; rttiInterface.IntfFlags; // is [ifHasGuid] rttiInterface := context.GetType( TypeInfo(IInvokable) ) as TRttiInterfaceType; rttiInterface.IntfFlags; // is [3]. 3 is not a valid enum value end. You can put a breakpoint on both lines with a comment for evaluating the value of IntfFlags yourself. IInvokable (and every interface that derives from it) has an undocumented value of "3". What does it mean? I have not been able to find anything in the source code. Clearly, System.TypInfo.TIntfFlag is declared as TIntfFlag = (ifHasGuid, ifDispInterface, ifDispatch);
  6. Der schöne Günther

    Is it possible to know when a TObject is instanciated/freed?

    Maybe this could be related? http://blog.marcocantu.com/blog/2017-june-delphi-packages-creators-update.html
  7. Der schöne Günther

    RadStudio Roadmap 2019

    What's so interesting about that? I still don't get quite behind that language server thing. I see that they will be able to delegate things like Code Completion and Error Insight to some external process in the background. Is that also going to work the other way round? Will tools like VS Code be able to access Delphi's debugger? I am already looking forward to 10.4 because of High DPI. Maybe I will once again be able to use Delphi at home, not just at work.
  8. Der schöne Günther

    ITask.Wait() behaving differently when called multiple times

    Thank you for taking the time to explain. It sounds like a good point, although a bit artificial 😉 And I have trouble achieving just that. Even with something like procedure TForm1.Button1Click(Sender: TObject); var task: ITask; e: Exception; begin event := TSimpleEvent.Create(); task := TTask.Run( procedure() begin raise EProgrammerNotFound.Create(EmptyStr); end ); try try task.Wait(); finally task := nil; end; except e := Exception( AcquireExceptionObject() ); end; end; The task still lives. Maybe because the default thread pool still has a reference to it.
  9. Der schöne Günther

    ITask.Wait() behaving differently when called multiple times

    Thank you for replying. If that can happen, then yes, then that won't work. But right now, I have no idea how that could happen, to be honest. In order to catch the exception, I have to call .Wait() on the task - Meaning I have to have a reference to it. Meaning the task cannot be freed yet. What am I missing?
  10. Der schöne Günther

    ITask.Wait() behaving differently when called multiple times

    And because of that, it's even more important the exceptions do not get lost and you get a reliable and reproducible behaviour. 😎 As so often, it seems to be modelled after .NET. And what .NET does (raise the exception(s) every time you wait for the task) is perfectly achievable with Delphi. I just don't understand why they took this weird approach.
  11. Der schöne Günther

    ITask.Wait() behaving differently when called multiple times

    There is no need to change anything about raising exceptions or lifetime management of exceptions. It's just that an EAggregateException always owns the exception it refers to. I believe that should be optional. Raise the exception normally, or acquire ownership and free it later - It doesn't matter. As long as the task owns its exceptions, not the EAggregateException. You can do with the AggregateExcption whatever you like. It's not the same, but TThread is similar. It has a FatalException property you can query for the exception that happened in the thread. The exception is owned by the thread. It is there for as long as the thread object is alive. With the way tasks are implemented, the first one to call .Wait() on a task gets the exceptions - After that, they're gone. It makes no sense.
  12. Der schöne Günther

    ITask.Wait() behaving differently when called multiple times

    But "the exception" is an artificially generated EAggregateException that references exceptions that are already stored. The "true" exceptions have never been raised directly. There would be nothing wrong with raising an EAggregateException that does not own the exceptions it referred and instead the task can free those exceptions when it is destroyed. Which is what was suggested in https://quality.embarcadero.com/browse/RSP-9548. Wouldn't that solve all those problems?
  13. Der schöne Günther

    ITask.Wait() behaving differently when called multiple times

    Does that mean 10.3 raises an exception for both times? Because I accidentally typed it would raise an EOperationCancelled. It does, in fact, properly raise an EAggregateException. But just for the first time.
  14. Consider the following: uses System.Threading; procedure TForm1.Button1Click(Sender: TObject); var task: ITask; begin task := TTask.Run( procedure() begin raise EProgrammerNotFound.Create('test'); end ); try task.Wait(); // << raises EAggregateException except ShowMessage('ex'); end; task.Wait(); // no exception. returns true // task.Status is now TTaskStatus.Exception end; I find this irritating. Why does waiting for a task raise an exception one time, but not the other? Apart from the fact that the Embarcadero documentation on ITask.Wait(..) does not even mention an exception should be expected, I guess they (once again) modelled it after .NET's Task.Wait(..) method which clearly states an exception is to be expected if the task was cancelled or failed with an exception. Some fine gentleman even reported this to Embarcadero almost five years back: https://quality.embarcadero.com/browse/RSP-9548 But two years later, it was closed as "Works as expected". I still don't understand. Can someone elaborate? I believe the implementation is wrong.
  15. Der schöne Günther

    Is it possible to raise an aggregated exception?

    So far, the only solution I have come up with is ripping out the wanted exception with a class helper 🤷‍♂️ and then raise this exception instead. function EAggregateExceptionHelper.Extract(const index: NativeInt): Exception; var newArray: TArray<Exception>; arrayIndex: NativeInt; begin newArray := []; Result := nil; with self do begin for arrayIndex := Low(FInnerExceptions) to High(FInnerExceptions) do if(arrayIndex = index) then Result := FInnerExceptions[arrayIndex] else newArray := newArray + [FInnerExceptions[arrayIndex]]; FInnerExceptions := newArray; end; end;