HighTechTalks DotNet Forums  

PtrToStructure() failing: "the structure must not be a value class

Dotnet Framework (Interop) microsoft.public.dotnet.framework.interop


Discuss PtrToStructure() failing: "the structure must not be a value class in the Dotnet Framework (Interop) forum.



Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old   
nickdu
 
Posts: n/a

Default PtrToStructure() failing: "the structure must not be a value class - 04-27-2009 , 04:28 PM






I've written the following methods:

[StructLayout(LayoutKind.Sequential)]
public struct TRACE_GUID_REGISTRATION
{
public IntPtr Guid;
public IntPtr RegHandle;
}

[DllImport("advapi32.dll")]
public static extern uint RegisterTraceGuids(WMIDPREQUEST request, IntPtr
context,
ref Guid controlGuid, uint guidCount, IntPtr traceGuidReg, string
mofImagePath,
string mofResourceName, out ulong session);

public static uint RegisterTraceGuids(WMIDPREQUEST request, IntPtr context,
ref Guid controlGuid, ref TRACE_GUID_REGISTRATION[] traceGuidReg, string
mofImagePath,
string mofResourceName, out ulong session)
{
if (traceGuidReg == null)
throw(new ArgumentNullException("traceGuidReg"));
if (traceGuidReg.Length == 0)
throw(new ArgumentException("traceGuidReg.Length cannot be zero."));

uint size = (uint) Marshal.SizeOf(typeof(TRACE_GUID_REGISTRATION));
IntPtr buffer = Marshal.AllocHGlobal((int) (size * traceGuidReg.Length));
try
{
for (int i = 0; i < traceGuidReg.Length; ++i)
{
Marshal.StructureToPtr(traceGuidReg[i], (IntPtr) ((uint) buffer + (i *
size)), false);
}

uint result = RegisterTraceGuids(request, context, ref controlGuid, (uint)
traceGuidReg.Length,
buffer, mofImagePath, mofResourceName, out session);
if (result != 0)
return result;

for (int i = 0; i < traceGuidReg.Length; ++i)
{
Marshal.PtrToStructure((IntPtr) ((uint) buffer + (i * size)),
traceGuidReg[i]);
}

return 0;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}


It appears calling my helper RegisterTraceGuids() works up until the point I
try to marshal the array back, from IntPtr to the managed array. Is there a
reason why I can't copy back into the array?

--
Thanks,
Nick

nicknospamdu (AT) community (DOT) nospam
remove "nospam" change community. to msn.com

Reply With Quote
  #2  
Old   
a
 
Posts: n/a

Default Re: PtrToStructure() failing: "the structure must not be a value class - 04-28-2009 , 03:11 AM






What error did you see?

Is the return of RegisterTraceGuids 0? If it's not 0, what does
GetLastError() return?

What's the symptom when it unmarshals the array?

for (int i = 0; i < traceGuidReg.Length; ++i)
{
Marshal.PtrToStructure((IntPtr) ((uint) buffer + (i * size)),
traceGuidReg[i]);
}



"nickdu" <nicknospamdu (AT) community (DOT) nospam> wrote

Quote:
I've written the following methods:

[StructLayout(LayoutKind.Sequential)]
public struct TRACE_GUID_REGISTRATION
{
public IntPtr Guid;
public IntPtr RegHandle;
}

[DllImport("advapi32.dll")]
public static extern uint RegisterTraceGuids(WMIDPREQUEST request, IntPtr
context,
ref Guid controlGuid, uint guidCount, IntPtr traceGuidReg, string
mofImagePath,
string mofResourceName, out ulong session);

public static uint RegisterTraceGuids(WMIDPREQUEST request, IntPtr
context,
ref Guid controlGuid, ref TRACE_GUID_REGISTRATION[] traceGuidReg, string
mofImagePath,
string mofResourceName, out ulong session)
{
if (traceGuidReg == null)
throw(new ArgumentNullException("traceGuidReg"));
if (traceGuidReg.Length == 0)
throw(new ArgumentException("traceGuidReg.Length cannot be zero."));

uint size = (uint) Marshal.SizeOf(typeof(TRACE_GUID_REGISTRATION));
IntPtr buffer = Marshal.AllocHGlobal((int) (size * traceGuidReg.Length));
try
{
for (int i = 0; i < traceGuidReg.Length; ++i)
{
Marshal.StructureToPtr(traceGuidReg[i], (IntPtr) ((uint) buffer + (i *
size)), false);
}

uint result = RegisterTraceGuids(request, context, ref controlGuid, (uint)
traceGuidReg.Length,
buffer, mofImagePath, mofResourceName, out session);
if (result != 0)
return result;

for (int i = 0; i < traceGuidReg.Length; ++i)
{
Marshal.PtrToStructure((IntPtr) ((uint) buffer + (i * size)),
traceGuidReg[i]);
}

return 0;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}


It appears calling my helper RegisterTraceGuids() works up until the point
I
try to marshal the array back, from IntPtr to the managed array. Is there
a
reason why I can't copy back into the array?

--
Thanks,
Nick

nicknospamdu (AT) community (DOT) nospam
remove "nospam" change community. to msn.com


Reply With Quote
  #3  
Old   
Jialiang Ge [MSFT]
 
Posts: n/a

Default RE: PtrToStructure() failing: "the structure must not be a value class - 04-28-2009 , 04:33 AM



Hello Nick

I can quickly reproduce the problem with this piece of test code:

[StructLayout(LayoutKind.Sequential)]
public struct TRACE_GUID_REGISTRATION
{
public IntPtr Guid;
public IntPtr RegHandle;
}
TRACE_GUID_REGISTRATION[] arr = new TRACE_GUID_REGISTRATION[2];
arr[0].Guid = (IntPtr)0x123;
arr[1].Guid = (IntPtr)0x456;
uint size = (uint)Marshal.SizeOf(typeof(TRACE_GUID_REGISTRATIO N));
IntPtr buffer = Marshal.AllocHGlobal((int)(size * arr.Length));
for (int i = 0; i < arr.Length; ++i)
{
Marshal.StructureToPtr(arr[i], (IntPtr)((uint)buffer + (i * size)),
false);
}
for (int i = 0; i < arr.Length; ++i)
{
Marshal.PtrToStructure((IntPtr)((uint)buffer + (i * size)), arr[i]);
}

The problem does nothing with the RegisterTraceGuids API.

According to the doc of Marshal.PtrToStructure(IntPtr, Object)
http://msdn.microsoft.com/en-us/library/30ex8z62.aspx
, it throws the ArgumentException that you saw when structure layout is not
sequential or explicit or structure is a boxed value type.

In this case, the structure is declared as sequential, however, the
elements in the array (traceGuidReg[i]) are boxed on the managed heap
because of the array object, thus you got the error "the structure must not
be a value class."

You would need to use the overload Marshal.PtrToStructure Method (IntPtr,
Type)
http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx
and assign the result of PtrToStructure to the array elements.


Regards,
Jialiang Ge (jialge (AT) online (DOT) microsoft.com, remove 'online.')
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msdnmg (AT) microsoft (DOT) com.

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

MSDN Managed Newsgroup support offering is for non-urgent issues where an
initial response from the community or a Microsoft Support Engineer within
2 business day is acceptable. Please note that each follow up response may
take approximately 2 business days as the support professional working with
you may need further investigation to reach the most efficient resolution.
The offering is not appropriate for situations that require urgent,
real-time or phone-based interactions. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.


Reply With Quote
  #4  
Old   
Ben Voigt [C++ MVP]
 
Posts: n/a

Default Re: PtrToStructure() failing: "the structure must not be a value class - 04-28-2009 , 01:21 PM





""Jialiang Ge [MSFT]"" <jialge (AT) online (DOT) microsoft.com> wrote

Quote:
Hello Nick

I can quickly reproduce the problem with this piece of test code:

[StructLayout(LayoutKind.Sequential)]
public struct TRACE_GUID_REGISTRATION
{
public IntPtr Guid;
public IntPtr RegHandle;
}
TRACE_GUID_REGISTRATION[] arr = new TRACE_GUID_REGISTRATION[2];
arr[0].Guid = (IntPtr)0x123;
arr[1].Guid = (IntPtr)0x456;
uint size = (uint)Marshal.SizeOf(typeof(TRACE_GUID_REGISTRATIO N));
IntPtr buffer = Marshal.AllocHGlobal((int)(size * arr.Length));
for (int i = 0; i < arr.Length; ++i)
{
Marshal.StructureToPtr(arr[i], (IntPtr)((uint)buffer + (i * size)),
false);
}
for (int i = 0; i < arr.Length; ++i)
{
Marshal.PtrToStructure((IntPtr)((uint)buffer + (i * size)), arr[i]);
}

The problem does nothing with the RegisterTraceGuids API.

According to the doc of Marshal.PtrToStructure(IntPtr, Object)
http://msdn.microsoft.com/en-us/library/30ex8z62.aspx
, it throws the ArgumentException that you saw when structure layout is
not
sequential or explicit or structure is a boxed value type.

In this case, the structure is declared as sequential, however, the
elements in the array (traceGuidReg[i]) are boxed on the managed heap
because of the array object, thus you got the error "the structure must
not
be a value class."
Elements of arrays are not boxed unless the array is of type object[]. The
problem is passing the argument in a parameter of type object, then it is
boxed.

Of course it could not work, because changes made to a value class passed by
value are lost.

Probably the next version of .NET should add an overload

PtrToStructure<T>(IntPtr, ref T) where T : struct

Quote:
You would need to use the overload Marshal.PtrToStructure Method (IntPtr,
Type)
http://msdn.microsoft.com/en-us/library/4ca6d5z7.aspx
and assign the result of PtrToStructure to the array elements.


Regards,
Jialiang Ge (jialge (AT) online (DOT) microsoft.com, remove 'online.')
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
msdnmg (AT) microsoft (DOT) com.

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

MSDN Managed Newsgroup support offering is for non-urgent issues where an
initial response from the community or a Microsoft Support Engineer within
2 business day is acceptable. Please note that each follow up response may
take approximately 2 business days as the support professional working
with
you may need further investigation to reach the most efficient resolution.
The offering is not appropriate for situations that require urgent,
real-time or phone-based interactions. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no
rights.


Reply With Quote
Reply




Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.