A.M. Hoornweg
Members-
Content Count
473 -
Joined
-
Last visited
-
Days Won
9
Everything posted by A.M. Hoornweg
-
Records as TDictionary keys
A.M. Hoornweg replied to balabuev's topic in RTL and Delphi Object Pascal
Hey, that's actually really cool! -
You could put a tScrollbox on your form and put the rest of your components on top of that. The scrollbox can be larger than the form itself and you can simply use the scrollbars to scroll the components into view.
-
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg posted a topic in Delphi IDE and APIs
Hello all, I've noticed that an application I'm working on was behaving differently when compiled in Delphi 11 or 12. In Delphi 12 I was getting all sorts of overflows and unexpected behavior. It took me a while to figure out the cause. Now the surprising thing: The cause wasn't even in this executable I was working on, it was in a DLL that my program is using. This DLL was built with a previous version of Delphi. This particular DLL expects that a FP error such as a division by zero will throw an exception. A breaking change in Delphi 12 is that the executables it produces mask the FP exceptions. This change in behavior affects all code running in the process, including all DLLs. In other words, this DLL no longer threw exceptions where it was supposed to. My workaround was to re-enable FPU exceptions in the executable and the situation instantly went "back to normal". But it got me thinking, how does one write code that copes with both FP situations and can run safely with *any* Delphi version? Should I do something like this? Try c:=SomeHighlyComplexCalculation(); if IsNan (c) then raise eDivByZero.Create('Something went wrong'); except // the exception is triggered either automatically (Old Delphi version) or manually (New Delphi version) end; Currently, my gut feeling tells me to manually enable FPU exceptions in all my Delphi exe projects to prevent such nasty surprises in the future. I use tons of tried-and-tested DLLs written in Delphi and I really don't want them to break. -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
It would be a can of worms for me I'm afraid. I am thinking of all my Delphi COM DLL's that expose interfaces and class factories (see image). Each interface is basically an object that can have dozens of methods so we're not talking about just a few functions, it's more like hundreds of exposed methods. And many of these methods call each other, which complicates matters further because setfpcr/restorefpcr would have to support nesting. And multi-threading would make matters even more complicated. -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
"Take control on entry and restore on exit" would be very cumbersome in the case of DLL's written in Delphi. It would need to be done in every exposed function / method. (edit) or at least in every method that has to do with FP calculations. -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
OK, that massively simplifies matters. My fear was that the FPCR would be a shared resource among threads. -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
I have no way of knowing. In the distant past the FPU (80x87) used to be an expensive separate chip. I simply don't know if the fpu is now part of each cpu core. -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
That is not what I mean, since a "context switch" is done when the scheduler switches from one thread to another (so one is halted, its state is saved and the next thread resumes after its state was restored). My question is about threads literally running simultaneously on different CPU cores, does each core always have an independent FPU + FPCR so one thread cannot jeopardize another ? -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
Since threads run concurrently on multi-core systems, isn't the fp control state global to all threads? Or does every cpu core have its own fpu core? -
Disabled floating point exceptions are problematic for DLLs
A.M. Hoornweg replied to A.M. Hoornweg's topic in Delphi IDE and APIs
Sure it is documented. But it may be off the radar that existing binaries such as DLL's may suddenly behave differently if they were written in Delphi. I use some third-party DLL's that were written in Delphi. -
Offline Installer - GetIt doesn't work with msg JSON metadata not found ?
A.M. Hoornweg replied to Lars Fosdal's topic in Delphi IDE and APIs
As far as I can see you can't download from that site though. -
I am getting "Disconnected Session" all the time whilst working on a 64-bit project. Never had this problem in 12.0. The error dialog window contains this information: [69E0B1C0]{dbkdebugide290.bpl} Debug.TDebugKernel.msgBox (Line 5951, "Debug.pas" + 30) + $0 [2BCC6EB3]{bordbk290.dll} Unknown function at DllUnregisterServer + $5037 [2BD3B88C]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $619B4 [2BD3B90B]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $61A33 [2BD3C351]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $62479 [2BD3C5A1]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $626C9 [2BD6C3D3]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $924FB [69E0B6FD]{dbkdebugide290.bpl} Debug.TThread.DoGetCurAddr (Line 6080, "Debug.pas" + 1) + $4 [2BCD9D72]{bordbk290.dll} Unknown function at DllUnregisterServer + $17EF6 [2BD6A91D]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $90A45 [2BD3C577]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $6269F [2BD3C7E0]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $62908 [2BCC6A4B]{bordbk290.dll} Unknown function at DllUnregisterServer + $4BCF [2BD5AB32]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $80C5A [2BD5AB3C]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $80C64 [69E17AFD]{dbkdebugide290.bpl} Debug.GetNextEvent (Line 11764, "Debug.pas" + 1) + $24 [6DC6037A]{rtl290.bpl } System.@IsClass (Line 18904, "System.pas" + 1) + $8 [69E185E1]{dbkdebugide290.bpl} Debug.TDebugger.UpdateEventLog (Line 11776, "Debug.pas" + 9) + $1 [69E11931]{dbkdebugide290.bpl} Debug.TProcess.ntfyNewEventLogData (Line 9020, "Debug.pas" + 1) + $7 [2BD5B3A0]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $814C8 [2BD3B90B]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $61A33 [2BD3C577]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $6269F [2BD570FB]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $7D223 [2BD57136]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $7D25E [2BD6C4C7]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $925EF [2BCD9D72]{bordbk290.dll} Unknown function at DllUnregisterServer + $17EF6 [2BD3B8B0]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $619D8 [2BD3C7E0]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $62908 [2BCE4247]{bordbk290.dll} Unknown function at @isDbkLoggingOn$qv + $A36F [625AA5EA]{CnWizards_D120A.DLL} Unknown function at __dbk_fcall_wrapper + $788AA [6CB305FD]{vcl290.bpl } Vcl.Themes.TStyleHook.WndProc (Line 7733, "Vcl.Themes.pas" + 38) + $6 [6CC598FC]{vcl290.bpl } Vcl.Styles.TStyleEngine.HandleMessage (Line 3616, "Vcl.Styles.pas" + 20) + $C [6340DEA9]{mmx_bds23.dll} IDEEdtHooks.GetMessageHook (Line 66, "IDEEdtHooks.pas" + 7) + $12 [6279DE04]{CnWizards_D120A.DLL} Unknown function at INITWIZARD0001 + $17CC00 [6CB7392F]{vcl290.bpl } Vcl.Forms.TApplication.ProcessMessage (Line 13284, "Vcl.Forms.pas" + 25) + $1 [6CB73952]{vcl290.bpl } Vcl.Forms.TApplication.ProcessMessages (Line 13304, "Vcl.Forms.pas" + 1) + $4 [00487F2B]{bds.exe } AppMain.TAppBuilder.ApplicationActivated + $7 [6CBCD24F]{vcl290.bpl } Vcl.AppEvnts.TCustomApplicationEvents.DoActivate (Line 210, "Vcl.AppEvnts.pas" + 1) + $16 [6CBCD8ED]{vcl290.bpl } Vcl.AppEvnts.TMultiCaster.DoActivate (Line 438, "Vcl.AppEvnts.pas" + 5) + $10 [6CB72DD0]{vcl290.bpl } Vcl.Forms.TApplication.WndProc (Line 12854, "Vcl.Forms.pas" + 140) + $C [6DD8477C]{rtl290.bpl } System.Classes.StdWndProc (Line 19085, "System.Classes.pas" + 9) + $2 [6CB73927]{vcl290.bpl } Vcl.Forms.TApplication.ProcessMessage (Line 13282, "Vcl.Forms.pas" + 23) + $1 [6CB7396A]{vcl290.bpl } Vcl.Forms.TApplication.HandleMessage (Line 13312, "Vcl.Forms.pas" + 1) + $4 [6CB73CA9]{vcl290.bpl } Vcl.Forms.TApplication.Run (Line 13451, "Vcl.Forms.pas" + 27) + $3 [004D8AD2]{bds.exe } bds.bds + $DE
-
Do you need an ARM64 compiler for Windows?
A.M. Hoornweg replied to Lars Fosdal's topic in Cross-platform
There are ways to achieve that (passing an EMF cross-process) but yes, it would be ugly. It would be like re-inventing the RDP protocol. -
Do you need an ARM64 compiler for Windows?
A.M. Hoornweg replied to Lars Fosdal's topic in Cross-platform
If you'd ask me to attempt a thing like that, I'd first look for a suitable bidirectional RPC framework. Something having capabilities like COM. COM was used by IDE's such as Visual Basic to host (in-process) VBX controls but it works across processes as well. The "helper processes" would only need to contain the designtime part of the components, at runtime they do nothing. Such an approach would move the design time components out of the address space of the IDE. Also, the "bitness" of the helper processes and the IDE would be independent from each other. -
Do you need an ARM64 compiler for Windows?
A.M. Hoornweg replied to Lars Fosdal's topic in Cross-platform
My preference would be to have the component packages in separate helper processes. -
Do you need an ARM64 compiler for Windows?
A.M. Hoornweg replied to Lars Fosdal's topic in Cross-platform
Please remember that all installed design time packages (BPL files) and their associated runtime packages must be compiled to the same architecture and bitness as the IDE itself. BPLs are just DLLs and the IDE loads them directly, in-process. This means that moving away from 32-bit x86 would be a huge breaking change for the deployment of third party components. Frankly, I've never understood why the design time packages are hosted in the IDE process itself because bugs in components will affect the IDE. Many of us will know the phenomenon that the IDE may throw an AV exception in some BPL when you terminate Delphi. -
Simplified Debug Visualizers for all my TNullableTypes
A.M. Hoornweg replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Can't you make a read-only property out of it instead of a plain method? That way you could make it show up in the watch list of the debugger. -
A gem from the past (Goto)
A.M. Hoornweg replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
No need for this, the debugger has that functionality built-in: -Set a breakpoint on your corner case condition and wait until it fires -Right-click the line where you want to "go to" -Enter submenu "Debug" -Select menu item "Set next statement". The debugger will jump here when you single-step through your code. -
How do I terminate a thread that doesn't have an Execute method ?
A.M. Hoornweg replied to dormky's topic in Algorithms, Data Structures and Class Design
A thread using While not terminated do begin Dosomething; Sleep(xxx); end; is perfectly OK if the thread has to do something useful periodically and if xxx isn't a terribly small number. But if "Dosomething()" is merely polling for some state change to respond to, then it's rather inefficient to have this thread constantly wakeup, consume CPU time and sleep again. The "Sleep(xxx)" also limits the response time and the number of state changes that can be handled per second. For such a scenario it's much more efficient if you can wake up the thread "from the outside" ASAP when it has to react. This is where events really shine. -
Where to put an app in Windows startup and shutdown and sleep mode?
A.M. Hoornweg replied to JohnLM's topic in General Help
I would personally write such a program as a service application and let it monitor messages like WM_POWERBROADCAST to log the events. This way you can be sure that the application is always running and will capture the events when they happen. -
Delphi 12 IDE, auto-formatter mutilates generics
A.M. Hoornweg posted a topic in Delphi IDE and APIs
Hello all, I see that the Delphi 12 source code formatter (Ctrl-D) still mutilates generic class declarations, it inserts inappropriate line feeds between keywords and ruins indentation. Is there a way to set markers in the source code that tell the formatter to skip those areas from formatting? Or can you recommend a better code formatter that handles generics properly? Have a nice day! Arthur -
Create a new instance of a generic class
A.M. Hoornweg posted a topic in RTL and Delphi Object Pascal
Hello all, suppose I have a generic class that's going to be inherited. I want to give the base class a method that creates a new instance of the same object type (a class factory so to speak). How can I do that? I need to somehow tell the compiler which constructor to call. Type tSomeclass<T:iInterface>=CLass (tInterfacedObject, iSomeInterface<T>) //many methods here Procedure SomeMethod(intf: T); Function SomeFunction:T; Constructor Create(someparameters); Function CreateNewInstance:iSomeInterface<T>; end; ... Function tSomeclass<T>.CreateNewInstance:iSomeInterface<T> begin result:=Self.Classtype.Create(fSomeParameters); //Does not compile end; -
Create a new instance of a generic class
A.M. Hoornweg replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Thank you! That seems to work indeed ! -
Create a new instance of a generic class
A.M. Hoornweg replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
The reason I'm trying to achieve this is the following. I have made a generic tStreamableInterfaceList<T:iInterface> which is basically a managed Tlist<T> that implements iInterfacelist<T>. The elements are interfaces. This list object knows several special tricks such as saving its contents to XML and BSON. It can also load those elements back from such data files, which necessitates a virtual ClassFactory() method to create the correct objects "on the fly" based on the class names found in the data. So far, this all works very nicely. I wanted to enhance this list with a few LinQ-like methods such as: Function .Where(aCondition:tPredicate<T>):iInterfacelist<T>; Function .OrderBy(aCompare:tComparison<T>):iInterfacelist<T>; ... but in order to achieve that, the base class must be able to dynamically instantiate derived classes or else the resulting objects would have the base nonfunctional Classfactory() method. The "ugly" solution would be to put an abstract virtual Clone() method in the base class, but I'd very much like to avoid that. -
Create a new instance of a generic class
A.M. Hoornweg replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
That doesn't do the trick, because function TMyClass<T>.CloneObject: TMyClass<T>; ... will just construct an instance of the base class, I would have to re-implement that method in each derived class. With non-generic classes it is possible to achieve what I want (see below). With generics, the "class of..." syntax does not work. type SomeClassType = class of tSomeClass; tSomeClass = class protected SomeNumber: Integer; public constructor Create(aSomeNumber: Integer); virtual; function Copy: tSomeClass; procedure Whoami; end; tSomeClass2=Class(tSomeClass) End; tSomeClass3=Class(tSomeClass2) End; function tSomeClass.Copy: tSomeClass; var ctype: SomeClassType; begin ctype := SomeClassType(self.ClassType); result := ctype.Create(SomeNumber+1); end; constructor tSomeClass.Create(aSomeNumber: Integer); begin inherited Create; SomeNumber := aSomeNumber; end; procedure tSomeClass.Whoami; begin OutputDebugString(pchar( format('Class name = %s, number is %d',[self.classname,somenumber] ))); end; procedure TForm1.Button2Click(Sender: TObject); begin tSomeclass3.Create(1).Copy.Copy.Copy.Whoami; //yes, this test leaks some memory. end;