Jump to content
John Gambler

Pointer variable erros

Recommended Posts

I'm having some difficulty using variables through their memory addresses. In the test below, the pointer of the ParamEmbeddedRec variable and the Params variable (inside ParamMaster) should be the same, so the value of PatchParam and Payload (inside ParamEmbeddedRec) are invalid. I think the syntax of line 47 (ParamMaster.Params := @ParamEmbedded) is not correct. Bellow, my code and an image of the debug,

 

My code:

 

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
  Type TParamMaster = Record
     Operacao : Smallint;
     Params   : Pointer;
   End;
   Var ParamMaster : ^TParamMaster;

   Type TParamEmbedded = Record
      PatchParam : String;
      Payload    : String;
   End;
   Var ParamEmbedded : ^TParamEmbedded;
   Var ParamEmbeddedRec : ^TParamEmbedded;
begin
   New(ParamMaster);
   New(ParamEmbedded);

   ParamEmbedded.PatchParam := 'somePatch';
   ParamEmbedded.Payload := '{"aooCode": "F60EB930-9B1B-11EF-9657-02240D86274B"}';

   ParamMaster.Operacao := 1;
   ParamMaster.Params := @ParamEmbedded;

   ParamEmbeddedRec := ParamMaster.Params;

   Dispose(ParamEmbedded);
   Dispose(ParamMaster);
end;

end.

 

Sem título.jpg

Share this post


Link to post
4 hours ago, John Gambler said:

I'm having some difficulty using variables through their memory addresses.

Because you are using it incorrectly.

4 hours ago, John Gambler said:

In the test below, the pointer of the ParamEmbeddedRec variable and the Params variable (inside ParamMaster) should be the same

They are the same address, but they are not the same type.  The Params is holding a ^^TParamEmbedded (a pointer to a pointer to a record), but ParamEmbeddedRec is a ^TParamEmbedded (pointer to a record) instead.  The only reason your code even compiles at all is because the Params is an untyped Pointer, so all type safety is out the window.

4 hours ago, John Gambler said:

so the value of PatchParam and Payload (inside ParamEmbeddedRec) are invalid. I think the syntax of line 47 (ParamMaster.Params := @ParamEmbedded) is not correct.

You are correct.  You are storing a ^^TParamEmbedded into the Params, and then accessing it back out as a ^TParamEmbedded instead, eg:

+------------+        +------------+
| Operacao   |        | PatchParam |
| Params     |---+    | Payoad     |
+------------+   |    +------------+
       ^         |          ^
       |         |          |
+-------------+  |   +---------------+     +------------------+
| ParamMaster |  +-->| ParamEmbedded |<----| ParamEmbeddedRec |
+-------------+      +---------------+     +------------------+

Get rid of the @, you don't need it since the ParamEmbedded variable is already a pointer, eg:

procedure TForm1.Button1Click(Sender: TObject);
Type
  TParamMaster = Record
    Operacao : Smallint;
    Params   : Pointer;
  End;
  TParamEmbedded = Record
    PatchParam : String;
    Payload    : String;
  End;
Var
  ParamMaster : ^TParamMaster;
  ParamEmbedded : ^TParamEmbedded;
  ParamEmbeddedRec : ^TParamEmbedded;
begin
  New(ParamMaster);
  New(ParamEmbedded);

  ParamEmbedded.PatchParam := 'somePatch';
  ParamEmbedded.Payload := '{"aooCode": "F60EB930-9B1B-11EF-9657-02240D86274B"}';

  ParamMaster.Operacao := 1;
  ParamMaster.Params := ParamEmbedded; // <-- NO @ HERE!

  ParamEmbeddedRec := ParamMaster.Params;

  ...

  Dispose(ParamEmbedded);
  Dispose(ParamMaster);
end;
+------------+        +------------+
| Operacao   |        | PatchParam |
| Params     |------->| Payload    |<----------+
+------------+        +------------+           |
       ^                    ^                  |
       |                    |                  |
+-------------+      +---------------+     +------------------+
| ParamMaster |      | ParamEmbedded |     | ParamEmbeddedRec |
+-------------+      +---------------+     +------------------+                                          

That being said, this example can be simplified by not using New/Dispose at all, in which case using @ does make sense, eg:

procedure TForm1.Button1Click(Sender: TObject);
Type
  TParamMaster = Record
    Operacao : Smallint;
    Params   : Pointer;
  End;
  TParamEmbedded = Record
    PatchParam : String;
    Payload    : String;
  End;
Var
  ParamMaster : TParamMaster;
  ParamEmbedded : TParamEmbedded;
  ParamEmbeddedRec : ^TParamEmbedded;
begin
  ParamEmbedded.PatchParam := 'somePatch';
  ParamEmbedded.Payload := '{"aooCode": "F60EB930-9B1B-11EF-9657-02240D86274B"}';

  ParamMaster.Operacao := 1;
  ParamMaster.Params := @ParamEmbedded; // <-- DO USE @ HERE!

  ParamEmbeddedRec := ParamMaster.Params;
  
  ...
end;
 ParamMaster       ParamEmbedded
+------------+     +------------+
| Operacao   |     | PatchParam |     +------------------+
| Params     |---->| Payload    |<----| ParamEmbeddedRec |
+------------+     +------------+     +------------------+

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post

Perfect.

 

I'm glad I didn't find this one in my attempts, otherwise I wouldn't have had access to such a comprehensive explanation.

 

I use this approach to access a DLL from my application. This DLL only exports one function, which receives a pointer and returns a pointer.

 

ParamMaster represents the generic parameter for the DLL. ParamMaster.Operation represents which service from the DLL I want to use and ParamMaster.Param represents the parameter used by this service.

 

The DLL returns a pointer that represents the response from this service.

 

Right after calling the service, the caller copies the response to internal variables and calls the DLL again to inform it that it no longer needs the response variable and the DLL calls a dispose for it. Right after, the caller disposes the parameter variable.

 

I don't know if I was clear. In any case, I'm satisfied with the quick and objective response.

 

Thank you.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×