[Mono-list] Marshaling on Mac

silver83 silver83 at gmail.com
Mon Aug 25 09:49:45 EDT 2008

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

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

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

It seems like the entire FSVolumeInfo struct I'm getting back using Mono is
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
        public UInt16 highSeconds;
        public UInt32 lowSeconds;
        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

*** 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

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.

View this message in context: http://www.nabble.com/Marshaling-on-Mac-tp19144208p19144208.html
Sent from the Mono - General mailing list archive at Nabble.com.

More information about the Mono-list mailing list