Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / August 2006

Tip: Looking for answers? Try searching our database.

structure size calculation problem

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
ps - 10 Aug 2006 15:36 GMT
Hi all,
I'm trying to make a pinvoke call to a legacy c dll. One method has a
structure as input.
The managed structure looks like this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Info
{
    public Version cryptokiVersion;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string manufacturerID;
    public uint flags;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string libraryDescription;
    public Version libraryVersion;
}

the inner Version structure:
public struct Version
{
    public byte major;
    public byte minor;
}

I need this structure to have exactly 72 bytes, as this is the size of the c
counterpart. On the first look, it should have 72 bytes (2 bytes for Version
x 2 + 32 bytes for the two ansi strings x 2 + 4 bytes uint = 72).
Unfortunately, Marshal.SizeOf calculates the size of this structure as 76,
although SizeOf applied to the individual members returns the correct,
expected values...

If I remove the uint, the size from Marshal.SizeOf suddenly drops to 68,
which is equal to the manualy calculated one. A uint takes up 4 bytes though
(Marshal.SizeOf confirms this), so why did the size drop by 8 bytes, not 4?.

If I replace the uint with two shorts (which are equal in size to one uint),
the size from Marshal.SizeOf is now correctly 72 (68 + 2x2).
Is this a bug in the framework (2.0.50727), or am I doing something wrong?

Thanks in advance for any insights...

Signature

PS

TDC - 10 Aug 2006 16:32 GMT
You are having problems because of the 4-byte alignment used in
structures.

The structure legacy C dll uses a structure that has members that
stradle that alignment in several places, which leads to pad bytes
getting created.

What you really have right now is:

public Version cryptokiVersion;
PadByte1
PadByte2
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string manufacturerID;
public uint flags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string libraryDescription;
public Version libraryVersion;
PadByte3
PadByte4

Tom

> Hi all,
> I'm trying to make a pinvoke call to a legacy c dll. One method has a
[quoted text clipped - 35 lines]
>
> Thanks in advance for any insights...
TDC - 10 Aug 2006 16:45 GMT
I just checked and the default in .NET is actually a Pack of 8 bytes,
not 4.

In any case, if specifiy a Pack of 1 in your StructLayoutAttribute then
it should solve your problem.

(There are few other solutions as well).

Let us know how you make out.

Tom

> You are having problems because of the 4-byte alignment used in
> structures.
[quoted text clipped - 58 lines]
> >
> > Thanks in advance for any insights...
ps - 10 Aug 2006 17:41 GMT
Thanks a lot, adding of the Pack property fixed my problem completely!

Just a few questions if I may... Why is it that this value only gets applied
only if there is a int or uint, but in the two shorts case? Also, is there
any relation to the fact that it only gets applied after the two nested
structures?

Thanks a lot again for that, I've spent a lot of time investigating this
already, and you saved yet a lot more of it :)
Signature

PS

„TDC" napísal (napísala):

> I just checked and the default in .NET is actually a Pack of 8 bytes,
> not 4.
[quoted text clipped - 70 lines]
> > >
> > > Thanks in advance for any insights...
TDC - 10 Aug 2006 19:14 GMT
I'm not exactly sure how the embedded structures get treated (though
I'm curious and I may have to run a test to find out exactly).

As for the Uint vs 2 Shorts, it is understandable that the smaller
types yeild less padding, because there is les chance of the
"straddling" a boundry.  It would only be possible if you had an odd
length and in your case all the lengths are even.

As an aside, I'm pretty sure that my previous description of exactly
where in the structre the padding was taking place, so don't ocde
relying on that.  The important thing is knowing that padding is going
on.

Tom

> Thanks a lot, adding of the Pack property fixed my problem completely!
>
[quoted text clipped - 84 lines]
> > > >
> > > > Thanks in advance for any insights...
TDC - 10 Aug 2006 20:47 GMT
I wrote a quick test...the padding is as follows

       public Version cryptokiVersion;   <--- bytes 0,1
       public string manufacturerID;       <--- bytes 2 thru 33 (the
last being a trailing null)
       PAD               <--- bytes 34, 35 pad so that flags can start
on a 4-byte boundry
       public uint flags;      <--- bytes 36, 37, 38, 39
       public string libraryDescription;    <--- bytes 40 thru 71 (the
last being a trailing null)
       public Version libraryVersion;   <--- bytes 72,73
       PAD     <--- bytes 74, 75 pad to fill a full upto the next 4
byte boundry

Hope that helps!
Tom

> I'm not exactly sure how the embedded structures get treated (though
> I'm curious and I may have to run a test to find out exactly).
[quoted text clipped - 99 lines]
> > > > >
> > > > > Thanks in advance for any insights...
ps - 11 Aug 2006 16:32 GMT
Thank you very much,
This solved my problem and the issue is a lot clearer now.

Signature

PS

„TDC" napísal (napísala):

> I wrote a quick test...the padding is as follows
>
[quoted text clipped - 116 lines]
> > > > > >
> > > > > > Thanks in advance for any insights...
ps - 10 Aug 2006 16:52 GMT
Hi,
thanks for the quick reply!

I think you are right, as it would exactly correspond to the shift in bytes
i perceive when the structure gets filled by the legacy component. There is a
two byte shift in the manufacturerID, and the other one possibly at the end.

Why aren't the pad bytes there if I replace the uint with two shorts though?
Is there any way to tell when they will be there and at what positions? Is
there any reason for them to be there at all? :)
Are there any workarounds except the one I mentioned (the replacement works
ok, but now the structure has one more field, that is just the placeholder
for the two bytes)

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Info
{
    public Version cryptokiVersion;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string manufacturerID;
    public short flags;
    private short x; // dummy placeholder for 2 bytes
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string libraryDescription;
    public Version libraryVersion;
}

Signature

PS

„TDC" napísal (napísala):

> You are having problems because of the 4-byte alignment used in
> structures.
[quoted text clipped - 58 lines]
> >
> > Thanks in advance for any insights...

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.