Marshaling on Mac

View: New views
6 Messages — Rating Filter:   Alert me  

Marshaling on Mac

by silver83 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I am calling a Carbon MAC OS X API function using p/invoke :

[DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon", CharSet = CharSet.Ansi)]
internal static extern int FSGetVolumeInfo(
                                       short volume,
                                       uint volumeIndex,
                                       ref short actualVolume,
                                       uint whichInfo,
                                       ref FSVolumeInfo info,
                                       ref HFSUniStr255 volumeName,
                                       ref FSRef rootDirectory);

while the actual C prototype is :

OSErr FSGetVolumeInfo (
   FSVolumeRefNum volume,
   ItemCount volumeIndex,
   FSVolumeRefNum *actualVolume,
   FSVolumeInfoBitmap whichInfo,
   FSVolumeInfo *info,
   HFSUniStr255 *volumeName,
   FSRef *rootDirectory
);

I'm mostly interested in the info ref parameter, which is of type FSVolumeInfo*.

Here are the struct defs in C , and following are my C# marshaling targets :
C :

struct FSVolumeInfo {
   UTCDateTime createDate;
   UTCDateTime modifyDate;
   UTCDateTime backupDate;
   UTCDateTime checkedDate;
   UInt32 fileCount;
   UInt32 folderCount;
   UInt64 totalBytes;
   UInt64 freeBytes;
   UInt32 blockSize;
   UInt32 totalBlocks;
   UInt32 freeBlocks;
   UInt32 nextAllocation;
   UInt32 rsrcClumpSize;
   UInt32 dataClumpSize;
   UInt32 nextCatalogID;
   UInt8 finderInfo[32];
   UInt16 flags;
   UInt16 filesystemID;
   UInt16 signature;
   UInt16 driveNumber;
   short driverRefNum;
};

struct UTCDateTime {
   UInt16 highSeconds;
   UInt32 lowSeconds;
   UInt16 fraction;
};


C# :

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct FSVolumeInfo
    {
        public UTCDateTime createDate;
        public UTCDateTime modifyDate;
        public UTCDateTime backupDate;
        public UTCDateTime checkedDate;
        public UInt32 fileCount;
        public UInt32 folderCount;
        public UInt64 totalBytes;
        public UInt64 freeBytes;
        public UInt32 blockSize;
        public UInt32 totalBlocks;
        public UInt32 freeBlocks;
        public UInt32 nextAllocation;
        public UInt32 rsrcClumpSize;
        public UInt32 dataClumpSize;
        public UInt32 nextCatalogID;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]
        public byte[] finderInfo;
        public UInt16 flags;
        public UInt16 filesystemID;
        public UInt16 signature;
        public UInt16 driveNumber;
        public Int16 driverRefNum;
    };

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct UTCDateTime
    {
        public UInt16 highSeconds;
        public UInt32 lowSeconds;
        public UInt16 fraction;
    };

The invoking code looks something like this :

//other variable initialization...

FSVolumeInfo volInfo = new FSVolumeInfo();
int status = FSGetVolumeInfo(...ref volInfo.../*and some more params....*/);

//...some more code
//...print results in volInfo ...

I'm getting back garbage in volInfo.

I've compares the results of invoking this method via Mono (managed code) and the results when writing a native app in C which calls the same API method.

It seems like the entire FSVolumeInfo struct I'm getting back using Mono is garbage....
The values are all wrong and marshaling seems not to work.

I tried changing the UTCDateTime struct in c# to use explicit layout, as shown in the following :

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
    struct UTCDateTime
    {
        [FieldOffset(0)]
        public UInt16 highSeconds;
        [FieldOffset(2)]
        public UInt32 lowSeconds;
        [FieldOffset(6)]
        public UInt16 fraction;
    };

And this makes all the values in the FSVolumeInfo instance up until "byte[] finderInfo;" look OK, but the rest of the fields after that are garbage again.

*** Question number 1 : Why do I have to explicitly tell it the struct layout, it is pretty obviouse here isn't it ? shouldn't this just be simple blitting ? is it because of the fact that this is a struct being used under another struct ?

Moving on ...The only thing I could do to make it work is kind of "give up" on the automatic marshaling of the array, and instead of "byte[] finderInfo;" replace it with a manually-declared-size struct, which now looks something like this  :

    [StructLayout(LayoutKind.Sequential, Size = 32)]
    struct FinderInfoArrData
    {
        int values;
    }
   
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct FSVolumeInfo
    {
       //... same as before

         public FinderInfoArrData finderInfo;
     
       // ... the rest is same as before, and now the values here are OK too...
    }

Changing the entire FSVolumeInfo to be Explicitly defined with [FieldOffset] (in addition to UTCDateTime being explicit) also works. It seems too error-prone to me and I'm trying to avoid it.

My questions are :
1. Is it a mono issue that the simple struct-withing-struct scenario isn't blitted well ? or am I missing something while working against the Carbon libraries in terms of encoding/memory layout...
2. If it is, any knowledge of an open bug/fix planned in following release ?
3. Is it a mono issue that I have to either do fancy tricks and give up on auto-marshaling of the array in the middle, or set the Entire FSVolumeInfo struct layout to Explicit ?
4. [same as 2]


Thanks, Yoni.S.


Re: Marshaling on Mac

by Robert Jordan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

silver83 wrote:
> *** Question number 1 : Why do I have to explicitly tell it the struct
> layout, it is pretty obviouse here isn't it ? shouldn't this just be simple
> blitting ? is it because of the fact that this is a struct being used under
> another struct ?

No. It's because UTCDateTime is defined within a `#pragma options
align=mac68k' section in its C header file.

This means it doesn't have a default structure packing. IIRC,
"mac68k" packing means a packing of one, so your managed UTCDateTime
struct must be declared with:

[StructLayout(LayoutKind.Sequential, Pack = 1)]


> My questions are :
> 1. Is it a mono issue that the simple struct-withing-struct scenario isn't
> blitted well ? or am I missing something while working against the Carbon
> libraries in terms of encoding/memory layout...

See above.

> 3. Is it a mono issue that I have to either do fancy tricks and give up on
> auto-marshaling of the array in the middle, or set the Entire FSVolumeInfo
> struct layout to Explicit ?

Check and adjust the packing of all other structs you're planning to
use. It should fly then.

Robert

_______________________________________________
Mono-list maillist  -  Mono-list@...
http://lists.ximian.com/mailman/listinfo/mono-list

Re: Marshaling on Mac

by silver83 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Seems like you nailed it on the head, thanks a million !
Small follow ups :
1. Is this the case for all / most of Carbon APIs ?
2. Is there a concentrated reference to find out the Packing value per "#pragma options
align" setting ? tried to google around to find out without much luck...

Robert Jordan wrote:
No. It's because UTCDateTime is defined within a `#pragma options
align=mac68k' section in its C header file.

This means it doesn't have a default structure packing. IIRC,
"mac68k" packing means a packing of one, so your managed UTCDateTime
struct must be declared with:

[StructLayout(LayoutKind.Sequential, Pack = 1)]

Robert

_______________________________________________
Mono-list maillist  -  Mono-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-list

Re: Marshaling on Mac

by Andreas Färber :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Am 26.08.2008 um 10:19 schrieb silver83:

> 1. Is this the case for all / most of Carbon APIs ?

Mac68K seems to apply to ppc only, so no. To find out where it's  
necessary, check the header files on your system.

> 2. Is there a concentrated reference to find out the Packing value per
> "#pragma options
> align" setting ?

See the architecture-specific ABI documentation:
http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Articles/32bitPowerPC.html#/ 
/apple_ref/doc/uid/TP40002438-DontLinkElementID_1

Andreas

> Robert Jordan wrote:
>>
>> No. It's because UTCDateTime is defined within a `#pragma options
>> align=mac68k' section in its C header file.
>>
>> This means it doesn't have a default structure packing. IIRC,
>> "mac68k" packing means a packing of one, so your managed UTCDateTime
>> struct must be declared with:
>>
>> [StructLayout(LayoutKind.Sequential, Pack = 1)]
>>
>> Robert

_______________________________________________
Mono-list maillist  -  Mono-list@...
http://lists.ximian.com/mailman/listinfo/mono-list

Re: Marshaling on Mac

by Robert Jordan :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Andreas,

Andreas Färber wrote:
> Am 26.08.2008 um 10:19 schrieb silver83:
>
>> 1. Is this the case for all / most of Carbon APIs ?
>
> Mac68K seems to apply to ppc only, so no. To find out where it's  
> necessary, check the header files on your system.

It actually applies to all architectures.

It means "use the same packing as we used a decade ago on a Mac68K
under Mac OS 9". All Carbon headers exhibit this pragma.

Robert

_______________________________________________
Mono-list maillist  -  Mono-list@...
http://lists.ximian.com/mailman/listinfo/mono-list

Re: Marshaling on Mac

by Andreas Färber :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

Am 27.08.2008 um 16:07 schrieb Robert Jordan:

> Andreas Färber wrote:
>> Am 26.08.2008 um 10:19 schrieb silver83:
>>
>>> 1. Is this the case for all / most of Carbon APIs ?
>>
>> Mac68K seems to apply to ppc only, so no. To find out where it's
>> necessary, check the header files on your system.
>
> It actually applies to all architectures.
>
> It means "use the same packing as we used a decade ago on a Mac68K
> under Mac OS 9". All Carbon headers exhibit this pragma.

Hm, in the ABI docs its alignment rules are only listed for ppc, not  
ppc64 or IA-32...

Mac68K differs from Packed encoding there, so Pack=1 would not seem to  
be the ultimate solution in all cases. Pack=2 might work better,  
except for vector (16), not sure how char (1) fits into this. In the  
worst case a custom helper for mashalling IntPtr <-> struct via Mac68K  
might need to be implemented?

Andreas

_______________________________________________
Mono-list maillist  -  Mono-list@...
http://lists.ximian.com/mailman/listinfo/mono-list
LightInTheBox - Buy quality products at wholesale price!