Discussion:
PtrToStructure() failing: "the structure must not be a value class
(too old to reply)
nickdu
2009-04-27 20:28:10 UTC
Permalink
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

***@community.nospam
remove "nospam" change community. to msn.com
a
2009-04-28 07:11:53 UTC
Permalink
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]);
}
Post by nickdu
[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
remove "nospam" change community. to msn.com
Jialiang Ge [MSFT]
2009-04-28 08:33:40 UTC
Permalink
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_REGISTRATION));
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 (***@online.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:
***@microsoft.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.
Ben Voigt [C++ MVP]
2009-04-28 17:21:28 UTC
Permalink
Post by Jialiang Ge [MSFT]
Hello Nick
[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_REGISTRATION));
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
Post by Jialiang Ge [MSFT]
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,
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
==================================================
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.
Loading...