none
Marshaling arrays RRS feed

  • Question

  • hi there..

     

    i'm trying to call this simple win32 api function "GetVersionEx" that is suppose to tell me the version of the os..the function signature appears like that :

    BOOL WINAPI GetVersionEx(<br/>
     __inout OSVERSIONINFO VersionInfo<br/>
    );
    

     

    i've sucssufly translated the the unmanged signature of the function like that

     

    [DllImport("kernel32.dll", EntryPoint = "GetVersionExA")]
    static extern bool GetOSVersion(ref OSVersionInfo OsVersionInfoStruct);
    

     

    ===================================================================


    the function needs as a parameter a structure of the type "OSVERSIONINFO" that will cary the info about the os version and is declared like that

    struct _OSVERSIONINFO {
     DWORD dwOSVersionInfoSize;
     DWORD dwMajorVersion;
     DWORD dwMinorVersion;
     DWORD dwBuildNumber;
     DWORD dwPlatformId;
     TCHAR szCSDVersion[128];
    }
    


    the problem is about the last element szCSDVersion which as you can see is an array of the type TCHAR = byte(ansi version).
    i've sucssufly translated the the unmanged signature of the structure like that

    public struct OSVersionInfo
      {
        public Int32 dwOSVersionInfoSize;
        public Int32 dwMajorVersion;
        public Int32 dwMinorVersion;
        public Int32 dwBuildNumber;
        public Int32 dwPlatformId;
        public Byte[]szCSDVersion;
      }
    
    and then when i trys to call the function i redefine the array to be a 128 size array of bytes like that

        static void Main(string[] args)
        {
          OSVersionInfo osvi = new OSVersionInfo();
          osvi.szCSDVersion = new Byte [128];
    
          osvi.dwOSVersionInfoSize = 148;
    
          Boolean Result;
          Result = GetOSVersion(ref osvi);
          Console
          .WriteLine(Encoding.Default.GetString(osvi.szCSDVersion));
        }
    



    the problem is that i get the "protected memory error" when i trys to call the function ...

    i was told that i must use the "MarshalAs" attribute on the array and it worked ..!!! like that

      public struct OSVersionInfo
      {
        public Int32 dwOSVersionInfoSize;
        public Int32 dwMajorVersion;
        public Int32 dwMinorVersion;
        public Int32 dwBuildNumber;
        public Int32 dwPlatformId;
        [MarshalAs(UnmanagedType.ByValArray ,SizeConst = 128)]
        public Byte[]szCSDVersion;
      }
    


    why do i need to use the MarshalAs attribute ??
    when to use it ??

     

    Sunday, August 1, 2010 12:26 PM

Answers

  • When you declare a C struct containing an array, the array is allocated directly in the struct. This is not what happens when you declare a C# struct: by default the struct only contains a reference to a managed array that is allocated elsewhere (you need to allocate and size it explicitly). This would be as if the C struct were defined as:

    struct {
      ...
      TCHAR* array;
    }

    By using the MarshalAs attribute, you are providing the missing information so that the marshalling is now possible. Since 2.0, we also have the alternative of embedding the array in the struct:

    struct Foo {
      ...
      public fixed byte array [128];
    }

    The disadvantage of this approach, as compared to MarshalAs is that this only works in an unsafe context.

    HTH
    --mc

    • Marked as answer by Mostafaxx Sunday, August 1, 2010 2:30 PM
    Sunday, August 1, 2010 1:29 PM

All replies

  • Just one thing: if your real problem is that you want to get the OS version from .NET you should be using:

    Environment.OSVersion
    


    Zaiden http://zPod.com.ar
    Sunday, August 1, 2010 1:26 PM
  • When you declare a C struct containing an array, the array is allocated directly in the struct. This is not what happens when you declare a C# struct: by default the struct only contains a reference to a managed array that is allocated elsewhere (you need to allocate and size it explicitly). This would be as if the C struct were defined as:

    struct {
      ...
      TCHAR* array;
    }

    By using the MarshalAs attribute, you are providing the missing information so that the marshalling is now possible. Since 2.0, we also have the alternative of embedding the array in the struct:

    struct Foo {
      ...
      public fixed byte array [128];
    }

    The disadvantage of this approach, as compared to MarshalAs is that this only works in an unsafe context.

    HTH
    --mc

    • Marked as answer by Mostafaxx Sunday, August 1, 2010 2:30 PM
    Sunday, August 1, 2010 1:29 PM
  • thanks Mario Cossi now i know when to use the MarshalAs attribute

    but could you plz provide me with any topic or book that gives more info about the topic "how arrays in C structure are different from arrays in c#"

    in other way where did you read that ...

     

    thanks Zaiden i was asking about
     marshaling arrays

    Sunday, August 1, 2010 2:36 PM
  • Unfortunately I got to know how C structs work by programming in C, so I don't really have a book to advise.

    What gives away the difference, though is directly in the type declaration. Take for instance:

    // C
    struct foo {
      LONG quux;
      unsigned char bar [128];
    };

    // C#
    struct Foo {
      public int quux;
      public byte [] bar;
    }

    In the first case, the compiler has all the information it needs to calculate the size of the struct and it can safely assume that the size is never going to change. It can just allocate a block of 132 bytes (4 for the LONG + 128 for the array) and use it.

    The C# compiler has no such luxury: the size of the array cannot be inferred by the declaration and there is no guarantee that the size will be constant. The only option is to consider the struct as being composed of an int and a reference to a managed array. This is why I said that this is similar to the C struct:

    struct foo {
      int quux;
      unsigned char* bar;
    };

    It is by no accident that the alternative C# (unsafe) declaration that allows us to embed an array in a struct requires that we specify the array size:

    struct foo {
      public int quux;
      public fixed byte bar [128];
    }

    This is what allows the C# compiler to make the same assumption the C compiler makes, and behave accordingly.

    HTH
    --mc

    Sunday, August 1, 2010 4:08 PM