Recent

Author Topic: (Solved?) Pointer to TForm.Caption (pass to procedure)  (Read 4962 times)

GreatCorn

  • New Member
  • *
  • Posts: 40
    • GreatCorn
(Solved?) Pointer to TForm.Caption (pass to procedure)
« on: July 29, 2020, 06:13:13 pm »
Let's say I have a TForm component and a procedure like this:
Code: Pascal  [Select][+][-]
  1. procedure SomeProcedure(outPointer: pointer);
  2. begin
  3.   PString(outPointer)^ := 'Stuff';
  4.   AnotherProcedure(outPointer);
  5. end;
I have to pass the TForm.Caption to SomeProcedure, but the Caption isn't a variable I guess. Parameters like Width and Height can be passed and used just fine. When trying to do this:
Code: Pascal  [Select][+][-]
  1. procedure SomeProcedure(var outPointer: string{or TCaption, whatever});
the compiler just says it "Can't take the address of constant expressions".
Can this somehow be done?
« Last Edit: July 30, 2020, 05:17:28 pm by GreatCorn »

Handoko

  • Hero Member
  • *****
  • Posts: 5538
  • My goal: build my own game engine using Lazarus
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #1 on: July 29, 2020, 06:38:37 pm »
Did you meant something like this:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, StdCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     procedure Button1Click(Sender: TObject);
  17.   end;
  18.  
  19. var
  20.   Form1: TForm1;
  21.  
  22. implementation
  23.  
  24. procedure ChangeCaption(var aForm: TForm1);
  25. begin
  26.   aForm.Caption:= 'Your lucky number is ' + Random(9).ToString;
  27. end;
  28.  
  29. {$R *.lfm}
  30.  
  31. { TForm1 }
  32.  
  33. procedure TForm1.Button1Click(Sender: TObject);
  34. begin
  35.   ChangeCaption(Self);
  36. end;
  37.  
  38. end.

eny

  • Hero Member
  • *****
  • Posts: 1665
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #2 on: July 29, 2020, 06:49:31 pm »
Or alternatively you could use a call back procedure or events.
All posts based on: Win11; stable Lazarus 4_4  (x64) 2026-02-12 (unless specified otherwise...)

Warfley

  • Hero Member
  • *****
  • Posts: 2058
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #3 on: July 29, 2020, 06:53:50 pm »
No, Caption is a property, it can either be implemented as getter and setter functions or as direct variable access. But from the outside you don't know. And without knowing that you can't implement a pointer based machanism

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #4 on: July 29, 2020, 06:55:33 pm »
Let's say I have a TForm component and a procedure like this:
Code: Pascal  [Select][+][-]
  1. procedure SomeProcedure(outPointer: pointer);
  2. begin
  3.   PString(outPointer)^ := 'Stuff';
  4.   AnotherProcedure(outPointer);
  5. end;
I have to pass the TForm.Caption to SomeProcedure, but the Caption isn't a variable I guess. Parameters like Width and Height can be passed and used just fine. When trying to do this:
Code: Pascal  [Select][+][-]
  1. procedure SomeProcedure(var outPointer: string{or TCaption, whatever});
the compiler just says it "Can't take the address of constant expressions".
Can this somehow be done?

Hi!

You are not allowed to use a property as a var parameter of a procedure.
Here you use the caption of the TForm.

You can get around that with a temporary variable:

Code: Pascal  [Select][+][-]
  1. procedure changeString (var s : String);
  2. .....
  3. .....
  4. var tmp: string ;
  5. ....
  6. tmp := {Form1.}.caption;
  7. changeString(tmp);
  8. {Form1}.caption := tmp;
  9. ....
  10.  
  11.  
Winni

GreatCorn

  • New Member
  • *
  • Posts: 40
    • GreatCorn
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #5 on: July 29, 2020, 09:53:59 pm »
Thank you all very much for your replies. However, I didn't quite elaborate on what I'm trying to achieve.
I have a dynamic array for pointers to different properties/variables (like the aforementioned Width and Height). I then use that array to assign the properties/variables that I need by something like this:
Code: Pascal  [Select][+][-]
  1. PString(SomeArray[i])^ := 'Stuff';
The code doesn't have access to the original objects and may need to change different properties without referring to them from the objects. AFAIK, a TForm's Width and Height are properties too and the code worked flawlessly with them... But, well, I'm comparing an Integer with a TCaption (still though, why did it work?).
By the way, the passing as var thing was a last resort attempt at making it work, I'd prefer doing it with pointers.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #6 on: July 29, 2020, 09:59:52 pm »
If it works with TForm.Height (passing as var param), then that is a bug in FPC. And it will get fixed, and your code will stop working.

Mind, that there was such a bug in an old version of fpc (not sure maybe 2.6), so if you are using that...

GreatCorn

  • New Member
  • *
  • Posts: 40
    • GreatCorn
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #7 on: July 29, 2020, 10:13:25 pm »
If it works with TForm.Height (passing as var param), then that is a bug in FPC. And it will get fixed, and your code will stop working.

Mind, that there was such a bug in an old version of fpc (not sure maybe 2.6), so if you are using that...
I didn't pass it as var param, sorry, wasn't clear again. I passed it as a Pointer just like so:
Code: Pascal  [Select][+][-]
  1. with component as TForm do
  2. begin
  3.   SomeProcedure(@Width);
  4.   SomeProcedure(@Height);
  5. end;
Checked FPC, it's 3.0.4, as far as I can tell...

PascalDragon

  • Hero Member
  • *****
  • Posts: 6395
  • Compiler Developer
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #8 on: July 29, 2020, 10:43:29 pm »
If it works with TForm.Height (passing as var param), then that is a bug in FPC. And it will get fixed, and your code will stop working.

Mind, that there was such a bug in an old version of fpc (not sure maybe 2.6), so if you are using that...
I didn't pass it as var param, sorry, wasn't clear again. I passed it as a Pointer just like so:
Code: Pascal  [Select][+][-]
  1. with component as TForm do
  2. begin
  3.   SomeProcedure(@Width);
  4.   SomeProcedure(@Height);
  5. end;
Checked FPC, it's 3.0.4, as far as I can tell...

This is not supposed to work for properties and will be fixed in the future.

jamie

  • Hero Member
  • *****
  • Posts: 7707
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #9 on: July 29, 2020, 10:52:41 pm »
If it works with TForm.Height (passing as var param), then that is a bug in FPC. And it will get fixed, and your code will stop working.

Mind, that there was such a bug in an old version of fpc (not sure maybe 2.6), so if you are using that...
I didn't pass it as var param, sorry, wasn't clear again. I passed it as a Pointer just like so:
Code: Pascal  [Select][+][-]
  1. with component as TForm do
  2. begin
  3.   SomeProcedure(@Width);
  4.   SomeProcedure(@Height);
  5. end;
Checked FPC, it's 3.0.4, as far as I can tell...

This is not supposed to work for properties and will be fixed in the future.

If you change that then I have code that will stop working..
it maybe a hack but if the property returns an entity that has no getter but direct access to the field  you are able to gain access to it to make changes.
 
 I have code that does this because there is no other way to change one of the fields in an exiting class in the libraries, at least not without rewriting a large chuck of code.

 True, it maybe a hack and one that may not be well known but I feel that I am not the only one using it because it was introduced to me from one of the well known coders here.

 Also, I need to check Delphi because it seems to me I've seen that hack used there too somewhere.

The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 6395
  • Compiler Developer
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #10 on: July 29, 2020, 10:58:44 pm »
Also, I need to check Delphi because it seems to me I've seen that hack used there too somewhere.

I just rechecked the following test with Delphi:

Code: Pascal  [Select][+][-]
  1. program tprop;
  2.  
  3. {$ifdef fpc}
  4. {$mode objfpc}{$H+}
  5. {$endif}
  6.  
  7. type
  8.  
  9.   { TTest }
  10.  
  11.   TTest = class
  12.   private
  13.     fField: LongInt;
  14.     function GetIndirect: LongInt;
  15.     procedure SetIndirect(AValue: LongInt);
  16.   public
  17.     property Direct: LongInt read fField write fField;
  18.     property Indirect: LongInt read GetIndirect write SetIndirect;
  19.   end;
  20.  
  21. function TTest.GetIndirect: LongInt;
  22. begin
  23.   Result := fField;
  24. end;
  25.  
  26. procedure TTest.SetIndirect(AValue: LongInt);
  27. begin
  28.   fField := AValue;
  29. end;
  30.  
  31. procedure Test(aArg: PLongInt);
  32. begin
  33.   Writeln(HexStr(aArg));
  34. end;
  35.  
  36. var
  37.   t: TObject;
  38. begin
  39.   t := TTest.Create;
  40.   Test(@TTest(t).Direct);
  41.   Test(@TTest(t).Indirect);
  42.   with t as TTest do begin
  43.     Test(@Direct);
  44.     Test(@Indirect);
  45.   end;
  46. end.

The pointers to Indirect lead to compile errors, the Direct ones work in both Delphi and FPC. So there isn't anything that needs to be changed afterall... *shrugs*

Please note however that such code will fail to compile if a property getter used in that way should be changed from a field to a method.

Bart

  • Hero Member
  • *****
  • Posts: 5721
    • Bart en Mariska's Webstek
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #11 on: July 29, 2020, 10:59:53 pm »
It actually compiles and runs in fpc 3.2.0.
If you then alter the referenced value in SomeProcedure, it changes the value of FWidht and FHeight respectively, which of course will not later the width/height of the form, but may create havoc later on.

It won't compile for properties that have a getter for the property.

Should this (that it allows it at all) be reported as a bug?

Bart

[ETA]PascalDragon answered that while I was typing ...
[/ETA]
« Last Edit: July 29, 2020, 11:01:30 pm by Bart »

jamie

  • Hero Member
  • *****
  • Posts: 7707
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #12 on: July 29, 2020, 11:00:58 pm »
Yes, verified

Any property that has access to the field via a READ in the property without a Function getter will resolved the address and thus you can make changes to the field..

 Of course this only works for Properties that has no GETTER function and I've seen this in the past used in Delphi but I never used it myself until someone here on the boards showed it to me.

  In this related case I believe there are many properties that have no getter function but direct access to the fields..

 Grant you that it should only be used under extreme conditions where there is no other way around it short of major rewriting of code.


 
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 7707
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #13 on: July 29, 2020, 11:03:22 pm »
My Delphi works this way so why change it ?
The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 6395
  • Compiler Developer
Re: Pointer to TForm.Caption (pass to procedure)
« Reply #14 on: July 29, 2020, 11:04:38 pm »
Changing a property's value in that way will also lead to circumventing a potential setter which in turn might lead to the class not correctly updating its internal state. As properties are supposed to be black boxes it's highly recommended not to write to properties in this way.

 

TinyPortal © 2005-2018