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 2003

Tip: Looking for answers? Try searching our database.

Marshal.PtrToStructure Returns Garbage

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Charles Parker - 20 Aug 2003 15:05 GMT
I have a COM object that allocates and passes back a pointer to an array of
DATA_MAP structures. A test app written in C++ work correctly however a C#
.NET app returns garbage. In .NET the managed structure is defined as:

[StructLayout(LayoutKind.Sequential)]
public struct DATA_MAP
{
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=65)]
   public string szRegDB;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=65)]
   public string szTableName;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=65)]
   public string szColumnName;
   public int iRestrictAccess;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=1024)]
   public string szRestrictionText;
}

The code to retrieve the data is shown below:

// Retrieve the records
IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(DATA_MAP)) *
iRecordsReturned);
IData.GetDataAttr(sUserName, sbEncodedPwd.ToString(), iAppID, iConnectType,
iRecordsReturned, buffer);

pDataMapOut = new DATA_MAP[iRecordsReturned];
IntPtr iter = buffer;
for (int i=0; i<iRecordsReturned; i++)
{
   pDataMapOut[i] = (DATA_MAP)Marshal.PtrToStructure(iter,
typeof(DATA_MAP));
   iter = (IntPtr)((int)iter + Marshal.SizeOf(typeof(DATA_MAP)));
}

The first string in the returned structure is garbage while the remaing
strings are empty/blank. Debugging through the COM object data in the array
of structures is correct so the problem must be in the marshalling to the
managed structure. Any ideas on how to solve this problem would be greatly
appreciated. Thanks.

Charles...
Charles Parker - 20 Aug 2003 15:11 GMT
The COM structure is defined as follows:

typedef struct  _DATA_MAP
{
   unsigned char szRegDB[ 65 ];
   unsigned char szTableName[ 65 ];
   unsigned char szColumnName[ 65 ];
   int iRestrictAccess;
   unsigned char szRestrictionText[ 1024 ];
} DATA_MAP;

Charles...

> I have a COM object that allocates and passes back a pointer to an array of
> DATA_MAP structures. A test app written in C++ work correctly however a C#
[quoted text clipped - 38 lines]
>
> Charles...
Andrei Barborica - 21 Aug 2003 00:29 GMT
Well, Charles,
 I don't have yet a solution, but I can give you more information
regarding how the constructor for arrays of structures seems to be
working in C#. I have a similar problem:

[StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct MIXERCONTROLDETAILS_LISTTEXT
{
    public uint dwParam1;
    public uint dwParam2;
    [MarshalAs( UnmanagedType.ByValArray, SizeConst=64)]
    public char[] szName;
} ;

 When I use this structure to retrieve data from a COM object
(mixerXXX API in Windows Multimedia SDK), as is (no array), works
fine. The layout is as expected, folowing the sequential declarations
of the members.
  However, if I declare an array mxcd of
MIXERCONTROLDETAILS_LISTTEXT, I've found that the memory mapping of
the structures in the array is something like that:
  0-3: mxcd[0].dwParam1
  4-7: mxcd[0].dwParam2
  8-11: a 4-byte POINTER to another memory area holding
mxcd[0].szName (64 bytes long), not the actual string. <----- Here !
  12-15: mxcd[1].dwParam1
  16-19: mxcd[1].dwParam1
  20-23: a 4-byte POINTER to another memory area holding
mxcd[1].szName (64 bytes long), not the actual string. <----- Here !
   
 Apparently, when you call the constructor for the array, the base
types are left in place, where they were supposed to be, while the
strings (and other arrays) are created by allocating a different
memory area and inserting a pointer to it, where one would expect to
find the actual data.

I tried using explicit layout of the structure, but with no better
results. I even tried using the Size (Size=0x48) attribute for the
structure. The result was that instead of having the actual string at
the expected location, I got a pointer in the first 4 bytes, followed
by 60 bytes of unused space, but the szName string would still reside
somewhere else !

I hope this helps in figuring out the intricate mechanism of C#
memory allocation. I wish I had a solution as much as you do !

Can anyone HELP us ???? Please ???
  Andrei Barborica.

> The COM structure is defined as follows:
>
[quoted text clipped - 8 lines]
>
> Charles...
Charles Parker - 21 Aug 2003 12:37 GMT
Thanks for your candid help Andrei,
The strange part is the are occasions when I will get all the data back
except the first string in the [0] structure. It is always garbage, while
all other fields including the first string of structure [1], [2], [n]. This
is strange. Are you using .NET 1.1/Visual Studio .NET 2003? I am not, may
this problem was fixed in this version. Hopefully, someone from Microsoft
will see this thread and be able to help.

Thanks again.
Charles...

> Well, Charles,
>   I don't have yet a solution, but I can give you more information
[quoted text clipped - 57 lines]
> >
> > Charles...
Thomas Scheidegger [MVP] - 21 Aug 2003 07:11 GMT
Hi Charles

   > [StructLayout(LayoutKind.Sequential)]
   > public struct DATA_MAP
   > {
   >     [MarshalAs(UnmanagedType.ByValTStr, SizeConst=65)]
   >     public string szRegDB;

Just to be sure, add a 'CharSet' to your struct:
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]

   > I have a COM object that allocates and passes back a pointer to an array of
   > DATA_MAP structures.

This description doesn't match your actual code.
If the "...COM object allocates memory",
why does your C# client the same with AllocCoTaskMem?

Then for "passes back a pointer to...",
this would mean in managed code either an 'out'
or 'ref' parameter, but your C# client passes
the 'buffer' pointer 'by value'.

As I don't have any documentation to your COMponent,
there could be many problems...

But let's try something like:

 IntPtr pptr = Marshal.AllocCoTaskMem( IntPtr.Size );
 IData.GetDataAttr(  ....pptr )
 IntPtr buffer = Marshal.ReadIntPtr( pptr )
   ...use buffer & PtrToStructure - loop as before
   ... free the pptr, buffer according COMponent docu.

Signature

Thomas Scheidegger - MVP .NET - 'NETMaster'
http://www.cetus-links.org/oo_dotnet.html - http://dnetmaster.net/

Charles Parker - 21 Aug 2003 12:57 GMT
Thomas,

You have a point about allocating the IntPtr and passing it to
GetDataAttr(). However, the method signature does not want an out IntPtr
just and IntPtr. The IDL for this method is as follows:

[id(1), helpstring("method GetDataAttr. Retrieves User Attributes.")]
HRESULT GetDataAttr([in] BSTR bstUserName, [in] BSTR bstPassword, [in] int
iAppID, [in] int iConnType, [in] long lNoEntries, [out,
size_is(,lNoEntries)] DATA_MAP** ppDataMapOut);

This specifies the pointer to array of DATA_MAPs as an out parameter so I do
not no why the signature in the .NET app just wants a IntPtr and not out
IntPtr.

If I do not allocate the IntPtr and set it IntPtr.Zero before passing to
GetDataAttr() I get the following error when executing.
Additional information: The parameter is incorrect.

This is what I also observered.
The strange part is the are occasions when I will get all the data back
except the first string in the [0] structure. It is always garbage, while
all other fields including the first string of structure [1], [2], [n]. This
is strange.

Thanks,
Charles...

> Hi Charles
>
[quoted text clipped - 29 lines]
>     ...use buffer & PtrToStructure - loop as before
>     ... free the pptr, buffer according COMponent docu.
Charles Parker - 21 Aug 2003 13:05 GMT
Thomas,

The COM object is expecting a pointer to an array of structures. The array
of structures is allocated in the COM object and assigned to the pointer. I
would assume this is why the signature is not out. In the C++ app that uses
the COM object I just pass the pointer to the array of structures the that
COM object allocates and returns. This works as expected. The problems are
the .NET marshalling back the structure.

Thanks,
Charles...

> Hi Charles
>
[quoted text clipped - 29 lines]
>     ...use buffer & PtrToStructure - loop as before
>     ... free the pptr, buffer according COMponent docu.

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.