?
Solved

Converting an array of struct objects to an IntPtr

Posted on 2006-05-28
9
Medium Priority
?
832 Views
Last Modified: 2009-07-29
I have 2 structs.  One contains an array of objects (instances of the other) like so:

[StructLayout(LayoutKind.Sequential)]
public struct IniData
{
  public int     DisEnumsCount;
  public IntPtr DisEnums;  // want this to point to a DisEnum []
}

[StructLayout(LayoutKind.Sequential)]
public struct DisEnum
{
  public int field1;
  public int field2;
  // etc.
}


In my application I construct an array of DisEnums (i.e. DisEnum []).  I want to convert this array to a valid IntPtr, namely the "public IntPtr DisEnums" member of the IniData struct.  Thanks!
0
Comment
Question by:DiamonDogX
  • 5
  • 4
9 Comments
 
LVL 12

Expert Comment

by:sumix
ID: 16784455
I suppose you want to send this type of objects to some unmanaged code. You can use GCHandle structure, which cand be used for accessing managed objects from unmanaged methods. For example:
   
   DisEnum[] de = new DisEnum[2];
   GCHandle gh = GCHandle.Alloc(de);
   IniData id = new IniData();
   id.DisEnums = (IntPtr)gh;

 You should read about GCHandle for details about how it should be used (http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemRuntimeInteropServicesGCHandleClassTopic.asp)
0
 

Author Comment

by:DiamonDogX
ID: 16785302
Tried doing that... like your snippet above, but when I try to get the first data element back from the array it looks messed up (weird characters, etc.):

DisEnum d = new DisEnum();
Marshal.PtrToStructure( id.DisEnums, d );  // d doesn't look correct after this call


One thing that did work, however, was this:

            DisEnum [] disEnumArray = new DisEnum[ 2 ];   // pretend it is populated with data

            int iPtr = (int) id.DisEnums;

            for( int i = 0; i < 2; i++ )
            {
                Marshal.StructureToPtr( disEnumArray[i], (IntPtr) iPtr, false );
                iPtr += Marshal.SizeOf( typeof( DisEnum ) );
            }
0
 
LVL 12

Expert Comment

by:sumix
ID: 16785768

you can create a pinned handle
   DisEnum[] de = new DisEnum[2];
   GCHandle gh = GCHandle.Alloc(de,GCHandleType.Pinned);
   IniData id = new IniData();
   id.DisEnums = gh.AddrOfPinnedObject();

and retrieve the first element the way you tried first:
   DisEnum d = new DisEnum();
   d = (DisEnum) Marshal.PtrToStructure( id.DisEnums, typeof(DisEnum));  

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:DiamonDogX
ID: 16786364
I get an error: "Object contains non-primitive or non-blittable data"

on this call: GCHandle gh = GCHandle.Alloc(de,GCHandleType.Pinned);
0
 
LVL 12

Expert Comment

by:sumix
ID: 16787391
That is probably because of the DisEnum structure. It works with a DisEnum struct that contains two integer members, this is how I tested it..
0
 

Author Comment

by:DiamonDogX
ID: 16794597
The DisEnum struct looks like this:

[StructLayout( LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi )]
    public struct DisEnum
    {
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.4 )]
        public string kind;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.4 )]
        public string domain;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.6 )]
        public string country;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.4 )]
        public string category;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.4 )]
        public string subcategory;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.4 )]
        public string specific;
        [MarshalAs( UnmanagedType.ByValTStr, SizeConst = InputDataConstants.4 )]
        public string extra;

        public byte accept;

        public DisEnum()
        {
        }
}


Know what the problem could be?
0
 
LVL 12

Expert Comment

by:sumix
ID: 16797353
Indeed, 'string' is not a blittable type (it does not have the same internal representation in managed and unmanaged code) - http://msdn2.microsoft.com/en-us/library/75dwhxf7.aspx 
 You could try using Marshal class, this is easy for an object that represents a DisEnum structure (Marshal.StructureToPtr method). Marshaling arrays is a little more difficult (http://msdn2.microsoft.com/en-us/library/z6cfh6e6.aspx).
0
 

Author Comment

by:DiamonDogX
ID: 16798780
I think I'll just stick with the code I got to work, unless you see any potential problems with it:

DisEnum [] disEnumArray = new DisEnum[ 2 ];   // pretend it is populated with data

            int iPtr = (int) id.DisEnums;

            for( int i = 0; i < 2; i++ )
            {
                Marshal.StructureToPtr( disEnumArray[i], (IntPtr) iPtr, false );
                iPtr += Marshal.SizeOf( typeof( DisEnum ) );
            }
0
 
LVL 12

Accepted Solution

by:
sumix earned 200 total points
ID: 16798987
I suppose it is ok, you should alloc the neccesary memory for disEnumArray and save the address in id.DisEnums, than marshal each element the way you did. I tried this complete solution and it worked:

int sz = Marshal.SizeOf(typeof(DisEnum));
id.DisEnums = Marshal.AllocHGlobal(sz * disEnumArray.Length);
int iPtr = id.DisEnums.ToInt32();
for (int i = 0; i < disEnumArray.Length; i++)
{
    Marshal.StructureToPtr(disEnumArray[i], new IntPtr(iPtr), true);
    iPtr += sz;
}

// now, retrieve the elements
iPtr = id.DisEnums.ToInt32();
for (int i = 0; i < disEnumArray.Length; i++)
{
    DisEnum d = new DisEnum();
    d = (DisEnum)Marshal.PtrToStructure(new IntPtr(iPtr), typeof(DisEnum));
    disEnumArray[i] = d;
    iPtr += sz;
}

Anyway the solution is more yours..
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an anti-spam), the admin…
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
Suggested Courses

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question