A.M. Hoornweg
Members-
Content Count
473 -
Joined
-
Last visited
-
Days Won
9
Everything posted by A.M. Hoornweg
-
COM is not the problem, I've been implementing COM objects for years. My question is really specific about the correct use and usefulness of tAggregatedObject and tContainedObject, because as far as I can see they are not needed at all to build aggregates, tInterfacedobject can already do so using ordinary tObjects. So I'm probably missing something essential about their use and usefulness! For example, this aggregate uses a tAggregatedObject: type iHello = interface ['{58AD07B9-FCE5-494A-94B2-E1CAF7D05B1D}'] procedure Hello; end; iGoodbye = interface ['{35079C32-AF3D-4E9D-808C-6A6DDED38663}'] procedure Goodbye; end; tAggregate = class(taggregatedobject, iHello) procedure Hello; end; tCompositeObject1 = class(tinterfacedobject, iHello, iGoodbye) protected ainner: tAggregate; function GetInner: iHello; public procedure Goodbye; destructor Destroy; override; property Inner: iHello read GetInner implements iHello; end; procedure tAggregate.Hello; begin messagebox(0, pchar('Hello'), pchar('Hello'), mb_ok); end; destructor tCompositeObject1.Destroy; begin messagebox(0, pchar('Destructor'), pchar('tCompositeObject1'), mb_ok); ainner.free; inherited; end; function tCompositeObject1.GetInner: iHello; begin if not assigned(ainner) then ainner := tAggregate.create(self); result := ainner; end; procedure tCompositeObject1.Goodbye; begin messagebox(0, pchar('Goodbye'), pchar('Goodbye'), mb_ok); end; procedure TestCode1; var Hello: iHello; Goodbye: iGoodbye; begin Goodbye := tCompositeObject1.create; Goodbye.Goodbye; Hello := Goodbye as iHello; Hello.Hello; end; ... and this one does the very same thing using a plain vanilla tObject: type iHello = interface ['{58AD07B9-FCE5-494A-94B2-E1CAF7D05B1D}'] procedure Hello; end; iGoodbye = interface ['{35079C32-AF3D-4E9D-808C-6A6DDED38663}'] procedure Goodbye; end; tSimpleObject = class procedure Hello; end; tCompositeObject2 = class(tinterfacedobject, iHello, iGoodbye) protected ainner: tSimpleObject; function GetInner: tSimpleObject; public procedure Goodbye; destructor Destroy; override; property Inner: tSimpleObject read GetInner implements iHello; end; procedure tSimpleObject.Hello; begin messagebox(0, pchar('Hello'), pchar('Hello'), mb_ok); end; destructor tCompositeObject2.Destroy; begin messagebox(0, pchar('Destructor'), pchar('tCompositeObject2'), mb_ok); ainner.free; inherited; end; function tCompositeObject2.GetInner: tSimpleObject; begin if not assigned(ainner) then ainner := tSimpleObject.create; result := ainner; end; procedure tCompositeObject2.Goodbye; begin messagebox(0, pchar('Goodbye'), pchar('Goodbye'), mb_ok); end; procedure TestCode2; var Hello: iHello; Goodbye: iGoodbye; begin Hello := tCompositeObject2.create; Hello.Hello; Goodbye := Hello as iGoodbye; Goodbye.Goodbye; end So is there any advantage in using tAggregatedObject / tcontainedobject at all ? I currently see more advantages in using tObject, because that allows me to take an existing class and encapsulate it inside a wrapper class whenever I want it to be interface based. For example, these few lines of code make a tStringlist interface-based, expose the methods add, get and put and make the whole thing reference counted: type // Just expose a selected bunch of methods of tStrings iStrings = interface ['{242798EB-0A53-4284-BA16-306FF354E2AC}'] function Add(const S: string): Integer; function Get(Index: Integer): string; procedure Put(Index: Integer; const S: string); property Strings[index: Integer]: string read Get write Put; default; end; tInterfacedStrings = class(tinterfacedobject, iStrings) protected fList: tStringlist; function getList: tStringlist; public destructor Destroy; override; property list: tStringlist read getList implements iStrings; end; destructor tInterfacedStrings.Destroy; begin fList.free; inherited; end; function tInterfacedStrings.getList: tStringlist; begin if not assigned(fList) then fList := tStringlist.create; result := fList; end;
-
Hello all, when I deploy a FMX application to Ubuntu (in this case the "Screenshot" fmx demo) the Delphi 10.4 debugger hangs totally. My Windows and Linux machines are both VMWare VM's. I can see that the freshly compiled executable appears in the home/PAServer/scratch-dir/myname/Screenshot directory. The message log in the Delphi IDE gives a warning "Local file \Redist\libfmux.so not found. Skipping deployment." The executable is not started on the Linux system by PAServer. I am able to start the executable manually, so the executable itself must be OK. But Delphi hangs so thoroughly that I can't debug it. I can only terminate Delphi in the task manager. Am I doing something wrong?
-
Sydney, debugger not working on Ubuntu LTS 20.04
A.M. Hoornweg replied to A.M. Hoornweg's topic in Cross-platform
I have re-installed Delphi 10.4 after thoroughly cleaning my hard drive and registry from older Delphi 10.x leftovers and now it works. -
Hello all, I'm totally new to Android, and so far I'm having zero success getting Embarcadero's sample programs to run on Android. I am running Delphi 10.4 inside a VMWare VM. On my host machine, I have the Bluestacks 4.215.0.1019 emulator running, with ADB debugging enabled. Connection details: I am aware that Bluestacks only binds to localhost (127.0.0.1) so I have setup a port forwarding on the host (netsh interface portproxy add v4tov4 listenport=5556 connectaddress=127.0.0.1 connectport=5555) so that I can connect to the emulator from external IP addresses through TCP port 5556. I have enabled both ports 5555 and 5556 in the firewall. I have tested this setup and I can successfully connect to the emulator from my Delphi VM ("adb connect ip-address:5556") and send adb commands to it. I had expected this connectivity to be the biggest hurdle but it worked immediately. I have cloned Embarcadero's official sample repository from github (https://github.com/Embarcadero/RADStudio10.4Demos.git) and now I'm trying to compile and run the application in "Samples\Object Pascal\Multi-Device Samples\User Interface\Forms". I've activated the Android 32-bit target (guessing that Bluestacks emulates a 32 bit device) and the Delphi IDE "sees" the device without problems (see screenshot), it's called "SM-G973F". Since this is an "official" demo application, I was hoping things would work out of the box so I could use it as a starting point! But when I press F9, Delphi does a lengthy compiling act, and then throws the following errors: [PAClient Error] Error: E2312 Unable to execute '"C:\Users\Public\Documents\Embarcadero\Studio\21.0\PlatformSDKs\android-sdk-windows\build-tools\28.0.2\Aapt.exe" package -f -M "C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\AndroidManifest.xml" -F "C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\bin\Forms-unsigned.apk" -I "C:\Users\Public\Documents\Embarcadero\Studio\21.0\PlatformSDKs\android-sdk-windows\platforms\android-26\android.jar" -S "C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\res" -A "C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\assets" "C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\library" "C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\classes"' (Error 1) [PAClient Error] Error: E2312 C:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples\Object Pascal\Multi-Device Samples\User Interface\Forms\Android\Debug\Forms\AndroidManifest.xml:21: error: No resource identifier found for attribute 'requestLegacyExternalStorage' in package 'android' The error messages aren't helpful at all, what the heck is "Error 1" supposed to mean? Can anyone point me to a solution? Thanks in advance, Arthur
-
Cannot run sample programs on Android
A.M. Hoornweg replied to A.M. Hoornweg's topic in Cross-platform
It wouldn't work. I have de-installed Delphi Sydney and deleted all Embarcadero folders and registry keys plus everything that had to do with Java and Android. Then I re-installed Delphi and now the compiler deploys the executable as expected. The executable won't start on Bluestacks 4 (screen stays black), however, so I'll try a hardware device next. -
Cannot run sample programs on Android
A.M. Hoornweg replied to A.M. Hoornweg's topic in Cross-platform
I would be totally grateful if you'd tell me how to do that! I'm an absolute beginner with Android. -
Cannot run sample programs on Android
A.M. Hoornweg replied to A.M. Hoornweg's topic in Cross-platform
Deleting the xml file makes no difference. It gets re-created, yes, and then I get the exact same error messages as before. And then Delphi hangs completely, I have to shoot it down in the task manager. All in all, deploying to Android seems unfunctional. -
After installing "Rad Studio 10.4 Patch (Patch Tool) Test 1.0" which recently appeared in GetIt package manager, DUnitX has disappeared from my system. How do I get it back?
-
Hello all, does anyone know if Delphi 10.4 can co-exist peacefully with 10.3 Rio on the same system without one breaking the other, and can I un-install Rio later without damaging the Sydney installation? Especially if one intends to do some multi-platform (Android/Linux) work?
-
Thank you all! So I'll backup my VM, enlarge the C partition and install Sydney. At a later point in time I'll uninstall Rio to free up space.
-
App tethering? http://docwiki.embarcadero.com/RADStudio/Rio/en/Sharing_Data_with_Remote_Applications_Using_App_Tethering
-
It happens to me about 3 times a day that when I press F9 in Delphi Rio that the IDE reports "Disconnected Session" and then just hangs. I have to kill it using the task manager. It is very irritating, what can be the cause of this?
-
I wonder about sendmessage being executed in the context of the calling thread. Is that documented somewhere? The HWnd could be in an entirely different process, so there must be some kind of marshaling in between.
-
How do you deal with deprecated symbols in backwards compatible code?
A.M. Hoornweg replied to dummzeuch's topic in RTL and Delphi Object Pascal
I also usually use class helpers, that implement the new methods for the old Delphi versions. Not the other way around! -
The interfaces in Delphi are bad?
A.M. Hoornweg replied to Jacek Laskowski's topic in RTL and Delphi Object Pascal
You shouldn't, because the component's owner manages its lifetime. Refcounted objects do not have an owner, they manage their own lifetime. Freeing an object twice is a really bad idea. -
The interfaces in Delphi are bad?
A.M. Hoornweg replied to Jacek Laskowski's topic in RTL and Delphi Object Pascal
I use interfaces all the time, and there are simple ways to make existing classes support interfaces with or without reference counting, without having to derive from a common base class like tInterfacedObject. If I want to modify any class in such a way that it supports interfaces without reference counting, I simply add dummy methods _AddRef, _Release, and QueryInterface: Type tNewObject = class(TOldObject, IInterface) protected // IInterface function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; function tNewObject._AddRef: Integer; begin Result := -1; end; function tNewObject._Release: Integer; begin Result := -1; end; function tNewObject.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE; end; And similarly, it is possible to make any existing class support interfaces with reference counting, it just takes a few more methods: TNewObject = class(TOldObject, IInterface) protected FRefCount: Integer; function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; public procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override; property RefCount: Integer read FRefCount; end; procedure TNewObject.AfterConstruction; begin // Release the constructor's implicit refcount InterlockedDecrement(FRefCount); Inherited; end; procedure TNewObject.BeforeDestruction; begin if RefCount <> 0 then Error(reInvalidPtr); Inherited; end; // Set an implicit refcount so that refcounting // during construction won't destroy the object. class function TNewObject.NewInstance: TObject; begin Result := inherited NewInstance; TNewObject(Result).FRefCount := 1; end; function TNewObject.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TNewObject._AddRef: Integer; begin Result := InterlockedIncrement(FRefCount); end; function TNewObject._Release: Integer; begin Result := InterlockedDecrement(FRefCount); if Result = 0 then Destroy; end; -
Is a standard comment before each procedure implementation useful?
A.M. Hoornweg replied to dummzeuch's topic in GExperts
I don't know. But I wouldn't rely on the absence of blank lines because there are several other code formatters around. For example, I need to maintain some source code that must remain compatible with Delphi XE. The built-in source code formatter of XE doesn't know how to format anonymous methods properly, so I use CNPack's formatter there. -
Is a standard comment before each procedure implementation useful?
A.M. Hoornweg replied to dummzeuch's topic in GExperts
Lately I've been switching to this style: Function tMyClass.GetCustomerName(CustomerID:tGuid; OUT CustomerName:String):Integer; {Retrieves the name of a customer. Exceptions:None; Result<>0 means error. See table ### for a list of possible errors} Begin Result:=0; Try .... read customer name Except Result:=DetailedError; End; End; My reason for putting the comment inside the method is that the comments will fold out of view along with the method body when I use the folding feature of the IDE. If I want to know what a method does exactly, I simply unfold that single method and the first thing I see is the comments. This way I can have the documentation where I prefer to have it (near the code) and keep it out of view most of the time. I chose a light gray font for the comments to make them as un-obtrusive as possible. An additional advantage of having the comments inside the method body is that it prevents tools such as MMX, Cnpack, GExperts etc from inadvertently separating the comment from the method it belongs to. -
Hello all, I'd like to know if it is possible to activate the FastMM4 Option "AlwaysClearFreedMemory" temporarily/on demand in code? The reason being that some of my routines work with confidential passwords/hashes. Delphi often uses temporary "hidden" strings and interfaces (for example when concatenating strings) so there's the risk of legible stuff remaining in RAM when such a routine exits.
- 5 replies
-
- fastmm4
- alwaysclearfreedmemory
-
(and 3 more)
Tagged with:
-
Using Delphi in Virtual machine for a month
A.M. Hoornweg replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
A lot can be accelerated by changing some Windows 10 settings inside the VM: Control panel -> System -> Advanced system settings -> Advanced -> Performance settings -> Adjust for best performance. Then re-enable only the absolute minimum : ("show window contents while dragging" + "smooth edges of screen fonts") -
FastMM4 and option "AlwaysClearFreedMemory"
A.M. Hoornweg replied to A.M. Hoornweg's topic in General Help
My application needs to call sp_setapprole on MS SQL Server which requires a user name and password. So for a brief time I need these in cleartext form. They are currently stored in an AES encrypted file and I decrypt them on the fly when I need them, using Turbopower Lockbox 2.09. I have no way of knowing if its decryption engine leaves any decoded text in freed blocks on the heap so I thought it would be great if I could simply instruct the heap manager to wipe whatever memory is released. This would prevent the password from appearing in a memory dump. Edit: The actual SQL Query is executed using connection.execute(format('exec sp_setapprole ''%s'', {Encrypt N ''%s''}, ''odbc''', [Approle, Approlepassword])); so I cannot exclude the possibility that the "execute" and the "format" commands might put temporary stuff on the heap as well. [edit] the GitHub feature request you mentioned was mine...- 5 replies
-
- fastmm4
- alwaysclearfreedmemory
-
(and 3 more)
Tagged with:
-
Hello all, my most important application, a big beast I've been working on for almost two decades and which I must maintain/support indefinitely, is an MDI application. The program offers 50+ different views and editors and the users (working on oil rigs) usually have a handful of these MDI child windows open simultaneously. The program can optionally run in SDI mode but nobody does that - it only clutters their desktop and they must have other applications (such as Word and Excel) open at the same time. A MDI window also has the advantage that you can quickly drag the whole thing (with all child windows) to a different monitor if it gets in the way. It is currently built using Delphi XE. I already had high-dpi awareness V2 working usably (don't ask - it took tons of hacks and sleepless nights) but since I expected native high-dpi support to come to Delphi some day, all those hacks can be automatically disabled with an IFDEF. So now I'm trying to migrate this application from Delphi XE to Delphi Rio. I can compile and run it successfully, but unfortunately Embarcadero chose to not support high-DPI in MDI applications and the visual result is really disappointing. MDI child windows are now unusably small on a high-resolution monitor. I can't force the SDI application model through my users' throats so I must either get this DPI awareness to work properly on Rio or stick with Delphi XE. Sure I could write some flags into the Windows 10 registry to make the whole application non-DPI aware, but that's not a satisfactory solution. I had DPI-awareness working and now I'm losing that. Any ideas on how to solve this?
-
This looks promising. My current situation looks very much like this. Users have many views and editors open simultaneously and entering data in one view can change the graphic output in another view:
-
Hmmm. I have a subscription to both LMD VCL Complete and Finalbuilder. Though I love Finalbuilder, the docking solution it uses is unsuitable for my own application. Finalbuilder is basically an IDE, I love it, but the actual fiddling with action properties is done with modal dialog windows son one can only fiddle with one thing simultaneously. And re-arranging docked panels is by no means trivial. You see, once you detach a panel it has to fit into a rectangular space somewhere. You can't just place the panel anywhere you like, it's not like other panels will intelligently move out of the way if you want to drop one somewhere. When I try, I find myself dragging a panel around, hoping it will snap in somewhere suitable. So once I have a usable layout, I simply try not to break it! MDI may not be the prettiest solution but it actually solves a ton of problems. Open a dozen views or editors at once? Check. Auto-align them all? Check. Want to maximize one of them? It takes just one click. Restore the previous situation? One click.
-
"Docking" is a paradigm that lets the users assemble a view layout that is not supposed to change often (because docking is awkward). In my case that won't work. There are over 50 scalable views in my application and the user needs most of them on a daily basis. And often there will be multiple instances of the same view type open, to compare data from the oil well with older reference wells nearby.