Discussion:
Would some throw this together for me?
(too old to reply)
T
2022-11-29 06:08:21 UTC
Permalink
Hi All,

Windows 11 Pro 22H2

I program in Raku and can barely read C++

I pulled this off an M$ Forum. The idea was
to give you the size of a structure in bytes
of a structure:


This is the structure:

C++
typedef struct _WTS_SESSION_INFOA {
DWORD SessionId; # 4 bytes
LPSTR pWinStationName; # 4 or 8 bytes
WTS_CONNECTSTATE_CLASS State; # 4 bytes
} WTS_SESSION_INFOA, *PWTS_SESSION_INFOA;



This is the result:


int nSize1 = sizeof WTS_SESSION_INFOA; // 12 in x86, 24 in x64
// x64

int nSize1 = sizeof WTS_SESSION_INFOA; // 24
int nOffset1 = offsetof(WTS_SESSION_INFOA, SessionId); // 0
int nOffset2 = offsetof(WTS_SESSION_INFOA, pWinStationName); // 8
int nOffset3 = offsetof(WTS_SESSION_INFOA, State); // 16


I need these sizes to user Raku's NativeCall.

Would someone please throw together the C++ code
so I can duplicate it? (And use it for other
structure in the future.)

Also, when you do and if you have access to 32 bit
Windows, I need those results too (I have no
32 bit Windows at the moment.)

Many thanks,
-T
R.Wieser
2022-11-29 07:04:54 UTC
Permalink
T,
...
Post by T
I need these sizes to user Raku's NativeCall.
That won't be possible I'm afraid. "sizeof" and "offsetoff" are
pseudo-commands, resolved at compile, not runtime.

Regards,
Rudy Wieser
T
2022-11-29 07:27:54 UTC
Permalink
Post by R.Wieser
T,
...
Post by T
I need these sizes to user Raku's NativeCall.
That won't be possible I'm afraid. "sizeof" and "offsetoff" are
pseudo-commands, resolved at compile, not runtime.
Regards,
Rudy Wieser
How'd he come up with them?

I do not care if the compilers tells me or
if a running program prints it out. Either
gives me the information I need.
R.Wieser
2022-11-29 08:46:35 UTC
Permalink
T,
Post by T
How'd he come up with them?
"Them" ? I'm not sure what you are referring to.

If you mean the lines you posted as "the result", than you should know its a
misnomer. Its not the *result*, its just how you ask for those (already
existing!) constants.

Take a look

typedef struct _WTS_SESSION_INFOA {
DWORD SessionId; # 4 bytes
LPSTR pWinStationName; # 4 or 8 bytes
WTS_CONNECTSTATE_CLASS State; # 4 bytes
}

(assuming that you are on a 32-bit machine that LPSTR is going to be 32 bit
too)

You can go thru the offsets and sizes yourself :

The first field thats declared is "SessionId", of type DWORD, which is 4
bytes. As its the first field its located at offset 0.

The second field thats declared is "pWinStationName", of type LPSTR, which
is (also) 4 bytes. Its offset is the previous fields offset plus its size*,
being 0 + 4, so its at offset 4.

The third field is "State" of type WTS_CONNECTSTATE_CLASS. Now it gets
tricky, as you have to find that type back somewhere (in the multitude of
*.h (header files) ) and figure out what its size is. Lets assume 4 bytes
(its just a DWORD in disguise). Its offset is again the previous fields
offset plus its size, being 4 + 4, so its at offset 8.

The size of the whole structure is ofcourse (again) the offset of the last
field plus its size, being 8 + 4, so it is 12 bytes long.

And that matches the comment after the first line in the result : "12 in
x86"


But remember that "*" that I tagged onto that "plus its size" ? Yeah, here
is the thing: machines are a fussy about where start of its data pieces
should be. There is a thing called "alignment".

Lets again take a look and assume we are now on a 64-bit machine. It
expects an alignment of 8. The "SessionId" field will still be just 4
bytes. So, how is it that the "pWinStationName" field after it is at
offset 8 ? Thats where padding comes in : it just fills out the space until
the next allowed offset :

On a 64-bit machine :

(best viewed with a fixed width font. Copy it into notepad ?)

typedef struct _WTS_SESSION_INFOA {
DWORD SessionId; # 4 bytes - padding needed
DWORD ? // the padding. Unnamed, unused
LPSTR pWinStationName; # 8 bytes - No padding
WTS_CONNECTSTATE_CLASS State; # 4 bytes - padding needed
DWORD ? // the padding. Unnamed, unused
}

And now the structure matches the comments in the "result" in its full,
including the "24 in x64" remark from the first line. :-)


Mind you, not all functions expect the data to be aligned. But for those
who do the above is how it works. And by the way, although it was not
relevant to the above structure (it fits just fine) the x86 has an alignment
of 4. IOW, if the first field would have been a byte it would be followed
by, on an x86 machine, a padding of 3 bytes

Hope that helps.

... but you still need to do all that work by hand - or put the structure in
a compiler and let it output those values ofcourse.

Regards,
Rudy Wieser

P.s.
That alignment also means that your structure-storage needs to be placed at
a multiple of that alignment value. If you don't the function trying to use
will just throw an "bad argument" error. Don't ask me how I know that. :-)
T
2022-11-29 09:12:14 UTC
Permalink
Post by R.Wieser
T,
Post by T
How'd he come up with them?
"Them" ? I'm not sure what you are referring to.
If you mean the lines you posted as "the result", than you should know its a
misnomer. Its not the *result*, its just how you ask for those (already
existing!) constants.
Take a look
typedef struct _WTS_SESSION_INFOA {
DWORD SessionId; # 4 bytes
LPSTR pWinStationName; # 4 or 8 bytes
WTS_CONNECTSTATE_CLASS State; # 4 bytes
}
(assuming that you are on a 32-bit machine that LPSTR is going to be 32 bit
too)
The first field thats declared is "SessionId", of type DWORD, which is 4
bytes. As its the first field its located at offset 0.
The second field thats declared is "pWinStationName", of type LPSTR, which
is (also) 4 bytes. Its offset is the previous fields offset plus its size*,
being 0 + 4, so its at offset 4.
The third field is "State" of type WTS_CONNECTSTATE_CLASS. Now it gets
tricky, as you have to find that type back somewhere (in the multitude of
*.h (header files) ) and figure out what its size is. Lets assume 4 bytes
(its just a DWORD in disguise). Its offset is again the previous fields
offset plus its size, being 4 + 4, so its at offset 8.
The size of the whole structure is ofcourse (again) the offset of the last
field plus its size, being 8 + 4, so it is 12 bytes long.
And that matches the comment after the first line in the result : "12 in
x86"
But remember that "*" that I tagged onto that "plus its size" ? Yeah, here
is the thing: machines are a fussy about where start of its data pieces
should be. There is a thing called "alignment".
Lets again take a look and assume we are now on a 64-bit machine. It
expects an alignment of 8. The "SessionId" field will still be just 4
bytes. So, how is it that the "pWinStationName" field after it is at
offset 8 ? Thats where padding comes in : it just fills out the space until
(best viewed with a fixed width font. Copy it into notepad ?)
typedef struct _WTS_SESSION_INFOA {
DWORD SessionId; # 4 bytes - padding needed
DWORD ? // the padding. Unnamed, unused
LPSTR pWinStationName; # 8 bytes - No padding
WTS_CONNECTSTATE_CLASS State; # 4 bytes - padding needed
DWORD ? // the padding. Unnamed, unused
}
And now the structure matches the comments in the "result" in its full,
including the "24 in x64" remark from the first line. :-)
Mind you, not all functions expect the data to be aligned. But for those
who do the above is how it works. And by the way, although it was not
relevant to the above structure (it fits just fine) the x86 has an alignment
of 4. IOW, if the first field would have been a byte it would be followed
by, on an x86 machine, a padding of 3 bytes
Hope that helps.
... but you still need to do all that work by hand - or put the structure in
a compiler and let it output those values ofcourse.
Regards,
Rudy Wieser
P.s.
That alignment also means that your structure-storage needs to be placed at
a multiple of that alignment value. If you don't the function trying to use
will just throw an "bad argument" error. Don't ask me how I know that. :-)
Thank you!

I plan on printing out the contents of the structure
byte by byte and see what I find. I will presalt
the result with 0xFF and see what agets changed.
R.Wieser
2022-11-29 09:51:17 UTC
Permalink
T,
Post by T
Thank you!
You're welcome. :-) And I assume that was the information you wher
missing
Post by T
I plan on printing out the contents of the structure
byte by byte and see what I find. I will presalt
the result with 0xFF and see what agets changed.
Good idea.

A suggestion though : first look at the structures bytes when you have not
given the fields a value. If you get anything else than a single byte value
back than "memfill" the whole structure with a certain value first, and only
than put stuff ito the fields (possibly also memfill-ing each of them,
preferrably with a different value. Makes it easier to see where one field
ends and the padding or the next field starts).

Regards,
Rudy Wieser
T
2022-11-29 10:19:40 UTC
Permalink
Post by R.Wieser
T,
Post by T
Thank you!
You're welcome. :-) And I assume that was the information you wher
missing
Post by T
I plan on printing out the contents of the structure
byte by byte and see what I find. I will presalt
the result with 0xFF and see what agets changed.
Good idea.
A suggestion though : first look at the structures bytes when you have not
given the fields a value. If you get anything else than a single byte value
back than "memfill" the whole structure with a certain value first, and only
than put stuff ito the fields (possibly also memfill-ing each of them,
preferrably with a different value. Makes it easier to see where one field
ends and the padding or the next field starts).
Regards,
Rudy Wieser
The variable I am sending will be created with
backfill:

my $SessionArray = CArray[BYTE].new( 0xFF xx $Length );

Means $SessionArray will be $Length Bytes long
and each byte will be filled with 0xFF

Then I see what gets overwritten.
R.Wieser
2022-11-29 12:30:26 UTC
Permalink
T,
Post by T
The variable I am sending will be created with
my $SessionArray = CArray[BYTE].new( 0xFF xx $Length );
Ah yes. You're not creating the structure itself, you create some space for
it and than cast that $SessionArray pointer to a WTS_SESSION_INFOA one (so
you can access its fields).

That works too. :-)

Is that stil C, or Raku ?

Regards,
Rudy Wieser
T
2022-11-29 12:33:49 UTC
Permalink
Post by R.Wieser
T,
Post by T
The variable I am sending will be created with
my $SessionArray = CArray[BYTE].new( 0xFF xx $Length );
Ah yes. You're not creating the structure itself, you create some space for
it and than cast that $SessionArray pointer to a WTS_SESSION_INFOA one (so
you can access its fields).
That works too. :-)
Is that stil C, or Raku ?
Regards,
Rudy Wieser
it is Raku attempting to call a C API

Loading...