Jump to content
Jenifer

How to calculate class size using TMemoryStream.size?

Recommended Posts

Hello,

 

I am trying to find size of built-in classes for an example TControl,TWinControl etc.Tried with InstanceSize() which in turn might not add size of few types considering them as references.

Found an interesting stack-overflow thread talking about TMemoryStream to find out class size:https://stackoverflow.com/questions/8782518/getting-the-size-of-a-class-or-object-in-the-same-format-as-a-file-size.I couldn't get much info on how to use TMemoryStream to figure out class size,can i get assistance regarding this?

 

Thanks,

Jenifer

Share this post


Link to post

This is very complex. The answer you link to is the size when serialized. But that bears no real relation to the memory used by the class at runtime. Also there are the system resources that are used.

 

The real question though is what you are planning to use this value for. Knowing that would allow us to understand better how you might solve this. 

Share this post


Link to post

Thanks @David Heffernan

 

Yeah better let me put my use case first:

  •  I want to capture properties of delphi UI controls starting with base controls TControl,TWinControl.
  • Have my own rough structures for TControl/TWinControl(in C programming), but those sizes aren't matching with controls of Delphi 10.4(3) versions.
  • So wanted to check sizes of those in-built control classes, tried with InstanceSize() which doesn't seem to be returning actual size
  • I got to know about TMemoryStream while searching for a solution

Any efficient/working solution would be great!!!:-)

Share this post


Link to post

You don't need to know the size of anything to persist properties. The way to do that is to use the streaming framework. There are many example codes on the web. You are probably making a mistake in believing that you need to copy a block of memory. That's not how to do persistence of complex structures. 

Edited by David Heffernan

Share this post


Link to post
Guest

The life is not very fair, with anyone!

Share this post


Link to post
4 hours ago, Jenifer said:

I want to capture properties of delphi UI controls starting with base controls TControl,TWinControl.

You do know that the RTL has its own native streaming framework for that exact purpose, don't you?  It is called a DFM.  It is not just for designing Forms at design-time.  It can be used by anyone to stream any TPersistent-derived class, which includes UI controls.  Look at the TStream.WriteComponent() and TStream.ReadComponent() methods.

4 hours ago, Jenifer said:
  • Have my own rough structures for TControl/TWinControl(in C programming), but those sizes aren't matching with controls of Delphi 10.4(3) versions.

This implies to me that you are probably using overlay classes in C++ (C doesn't have classes) to access private members of those UI classes, by aligning members of the overlay class to coincide with the members of the UI classes.  You should not be doing that.  But even if you were, there are better ways to access private members, such as this template trick (and this follow-up).

4 hours ago, Jenifer said:
  • So wanted to check sizes of those in-built control classes, tried with InstanceSize() which doesn't seem to be returning actual size

Yes, it does.  It just doesn't report the size you are thinking of.  It only reports the size of the class itself (same as sizeof() does in C/C++), but it does not account for any additional memory that members of that class allocate dynamically for themselves internally (strings, lists, buffers, etc).

4 hours ago, Jenifer said:
  • I got to know about TMemoryStream while searching for a solution

That only works if you are serializing a class into a stream.  You are getting the total flat size of the data the class wrote to the stream, not the size of the class itself.

 

  • Thanks 1

Share this post


Link to post
8 hours ago, Arnaud Bouchez said:

Asking the very same question here and in SO is not very fair.

:classic_rolleyes:,due to urgency I had posted there as well, based on responses will stick to one going further.

  • Confused 1

Share this post


Link to post
On 12/7/2020 at 4:56 AM, Remy Lebeau said:

You do know that the RTL has its own native streaming framework for that exact purpose, don't you?  It is called a DFM.  It is not just for designing Forms at design-time.  It can be used by anyone to stream any TPersistent-derived class, which includes UI controls.  Look at the TStream.WriteComponent() and TStream.ReadComponent() methods.

This implies to me that you are probably using overlay classes in C++ (C doesn't have classes) to access private members of those UI classes, by aligning members of the overlay class to coincide with the members of the UI classes.  You should not be doing that.  But even if you were, there are better ways to access private members, such as this template trick (and this follow-up).

Yes, it does.  It just doesn't report the size you are thinking of.  It only reports the size of the class itself (same as sizeof() does in C/C++), but it does not account for any additional memory that members of that class allocate dynamically for themselves internally (strings, lists, buffers, etc).

That only works if you are serializing a class into a stream.  You are getting the total flat size of the data the class wrote to the stream, not the size of the class itself.

 

Thanks a lot for your detailed answer. The way we capture UI control properties is bit different via C programming, hence I doubt if I could go with DFM approach. My premier requirement here is finding basic control's memory offsets of various members, so that capture can go smooth.

Share this post


Link to post
33 minutes ago, Jenifer said:

Thanks a lot for your detailed answer. The way we capture UI control properties is bit different via C programming, hence I doubt if I could go with DFM approach. My premier requirement here is finding basic control's memory offsets of various members, so that capture can go smooth.

It seems like you might have asked the wrong question. It doesn't sound as though the size is that important. What you seem to be after is to capture the control's properties. Is that correct?

Share this post


Link to post
2 minutes ago, David Heffernan said:

It seems like you might have asked the wrong question. It doesn't sound as though the size is that important. What you seem to be after is to capture the control's properties. Is that correct?

We have framework to capture Delphi application control properties, it is that there are some issues related to 10.4 version. More related to memory offset, there came the question about size of basic Control classes like TControl/TWinControl.

Share this post


Link to post
4 hours ago, Jenifer said:

The way we capture UI control properties is bit different via C programming, hence I doubt if I could go with DFM approach. My premier requirement here is finding basic control's memory offsets of various members, so that capture can go smooth.

The offsets of members should not matter, unless you are doing something low-level to access the underlying raw memory data directly.  You are going to have to provide more detailed information about what you are really trying to accomplish.  Right now, it is very confusing to understand without seeing exactly what you are working with.

3 hours ago, Jenifer said:

We have framework to capture Delphi application control properties, it is that there are some issues related to 10.4 version. More related to memory offset, there came the question about size of basic Control classes like TControl/TWinControl.

Is it a 3rd party framework that we can see online, or is it something custom you developed for yourself?  What issues is it having in 10.4 that it doesn't have in previous versions?

Share this post


Link to post

@Remy Lebeau,Thanks for your reply.

 

  • Yes, it is our own custom library that we had developed.
  • From the window of Delphi application, I am trying to read Delphi object & its properties.
  • We do maintain our own structures for TControl & TWinControl etc.
  • Facing access violation issue on trying to read text from the UI control like panel via sending message.
  • Just wondering it might be due to structural change in Delphi UI control classes after 2006(That was the last developed/modified one)

Thanks,

Jenifer

Share this post


Link to post
19 minutes ago, Jenifer said:

From the window of Delphi application, I am trying to read Delphi object & its properties.

You don't need direct access to an object's raw memory in order to do that.  Use RTTI instead, that is what it is meant for.

19 minutes ago, Jenifer said:
  • We do maintain our own structures for TControl & TWinControl etc.

Why?

19 minutes ago, Jenifer said:
  • Facing access violation issue on trying to read text from the UI control like panel via sending message.

That is certainly a risk when you assume a certain memory layout, and then that layout changes between compiler/RTL versions.

19 minutes ago, Jenifer said:
  • Just wondering it might be due to structural change in Delphi UI control classes after 2006(That was the last developed/modified one)

That is quite likely.  As new features get added over time, new members are added, existing members get moved around, etc.

Share this post


Link to post
2 minutes ago, David Heffernan said:

Does your code run in the same process as the Delphi program whose properties you are trying to inspect?

Nope,those are of separate process

Edited by Jenifer

Share this post


Link to post
Just now, Jenifer said:

Nopethose are of separate process

Kind of an important detail that you slipped in there.

 

I'm going to be blunt here. The process of trying to offer help whereby you provide minimal details and then we try to piece together your environment with a game of 20 questions. Well, it's not productive. You haven't had a whole lot of success in this thread because you have been so economical with these details.

 

Until you address this lack of detail, I predict nothing will change.

Share this post


Link to post
21 minutes ago, Remy Lebeau said:

You don't need direct access to an object's raw memory in order to do that.  Use RTTI instead, that is what it is meant for.

Why?

That is certainly a risk when you assume a certain memory layout, and then that layout changes between compiler/RTL versions.

That is quite likely.  As new features get added over time, new members are added, existing members get moved around, etc.

  • Pseudo might be like this:
  • It is something like we would get Window(HWnd), object from an application.
  • Cast that object to TControl*(which is own own structure in C),so that we can retrieve properties
  • No issues till now but when i try to retrieve a text from control via WM_GETTEXT is what i am facing issue with.

Thanks for your time, appreciate it!!

Share this post


Link to post

Hopefully I had cleared the air with recent reply!!Let me rephrase my question probably.

 

Assuming TControl,TWinControl have class members starting as below:

 

{$IF DEFINED(CLR)}
  TControl = class(TComponent, IControl)
{$ELSE}
  TControl = class(TComponent)
{$ENDIF}
  public
    FParent: TWinControl;
    FWindowProc: TWndMethod;
    FLeft: Integer;
    FTop: Integer;
    FWidth: Integer;
    FHeight: Integer;
    FControlStyle: TControlStyle;
    FControlState: TControlState;
    FDesktopFont: Boolean;
    FVisible: Boolean;
    FEnabled: Boolean;

 

{$IF DEFINED(CLR)}
  TWinControl = class(TControl, IWinControl)
  strict private
    class var
      FPendingParentWindow: HWND;
{$ELSE}
  TWinControl = class(TControl)
{$ENDIF}
  private class var
    RM_AsyncMessage: Cardinal;
  private
    FAlignControlList: TList;
    FAlignLevel: Word;
    FBevelEdges: TBevelEdges;
    FBevelInner: TBevelCut;
    FBevelOuter: TBevelCut;
    FBevelKind: TBevelKind;
    FBevelWidth: TBevelWidth;
    FBorderWidth: TBorderWidth;
    FPadding: TPadding;
    FBrush: TBrush;
    FDockClients: TList;

 

How do we know the offset of each member in TControl/TWinControl class? For an example offset of FParent,FWidth like that.

I had to dive into disassembly to figure out the offset values ,but i could find offsets of few members only not for all.

Any suggestions?

 

Thanks,

Jenifer

Share this post


Link to post

For methods that are readily accessible you can use the idea given here (Delphi: Offset of record field - Stack Overflow), although in that Q it's in the context of records.

 

Your TControl in the previous message has public methods, so that's easy. Your TWinControl has private methods so you'd need some form of cracker to gain access to the private methods. If it were me I'd copy the VCL unit, add it to my project, and add some code in the implementation section to dump out the info you require.

 

Of course, the TControl that you quote here isn't the real TControl since the fields in the real one are private not public. So who knows what is really going on. Perhaps you are posting code from some experiment you are working on.

 

Also, casting an HWND to a TControl* doesn't get you anywhere. They are not the same thing.

  • Thanks 1

Share this post


Link to post
7 minutes ago, David Heffernan said:

For methods that are readily accessible you can use the idea given here (Delphi: Offset of record field - Stack Overflow), although in that Q it's in the context of records.

 

Your TControl in the previous message has public methods, so that's easy. Your TWinControl has private methods so you'd need some form of cracker to gain access to the private methods. If it were me I'd copy the VCL unit, add it to my project, and add some code in the implementation section to dump out the info you require.

 

Of course, the TControl that you quote here isn't the real TControl since the fields in the real one are private not public. So who knows what is really going on. Perhaps you are posting code from some experiment you are working on.

 

Also, casting an HWND to a TControl* doesn't get you anywhere. They are not the same thing.

  • No,I didn't mean casting HWND to TControl*.It is the Delphi object we will retrieve from the application Window.
  • Yes, of course am playing around the VCL unit code, had pasted those ones for reference.(So no public fields even from TControl :-))

Thanks

Share this post


Link to post
2 hours ago, Jenifer said:

How do we know the offset of each member in TControl/TWinControl class?

Enhanced RTTI provides that information.  See Working with RTTI, TRttiType.GetFields(), and TRttiField.Offset.

2 hours ago, Jenifer said:

For an example offset of FParent,FWidth like that.

For example:

var
  Ctx: TRttiContext;
  Offset: Integer;
  
Offset := Ctx.GetType(TControl).GetField('FParent').Offset;

But why do you need to access the FParent and FWidth member directly?  Why can't you use the TControl's public Parent and Width properties instead?

  • Thanks 1

Share this post


Link to post
1 hour ago, Remy Lebeau said:

Enhanced RTTI provides that information.  See Working with RTTI, TRttiType.GetFields(), and TRttiField.Offset.

For example:


var
  Ctx: TRttiContext;
  Offset: Integer;
  
Offset := Ctx.GetType(TControl).GetField('FParent').Offset;

But why do you need to access the FParent and FWidth member directly?  Why can't you use the TControl's public Parent and Width properties instead?

@Remy read up to the part where all this happens in another process with, presumably, ReadProcessMemory. 

Share this post


Link to post
2 hours ago, David Heffernan said:

@Remy read up to the part where all this happens in another process with, presumably, ReadProcessMemory. 

Thanks, I missed that part.  In which case, this issue just got a whole lot more dangerous.  Manipulating the RTL/VCL's data members directly, behind the RTL/VCL's back, is a HUGE risk.  Without intimate and explicit knowledge of the exact version of Delphi the other process is using, you can't hope to access its private data SAFELY, for the very reason I stated earlier - data members can and do change between versions.

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

×