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 / July 2004

Tip: Looking for answers? Try searching our database.

How to Marshal a Variable Length Structure

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Charles Law - 28 Jul 2004 16:49 GMT
Sorry for the cross post, but I have just realised that this might be a
better place for this question.

Can anyone suggest how I would marshal a variable length structure back from
an API call. Specifically, I am looking at the WaitForDebugEvent function,
which returns a DEBUG_EVENT structure.

However, the DEBUG_EVENT structure is defined as a union, and the size and
contents vary depending on the event code contained in the header.

typedef struct _DEBUG_EVENT {
 DWORD dwDebugEventCode;
 DWORD dwProcessId;
 DWORD dwThreadId;
 union {
   EXCEPTION_DEBUG_INFO Exception;
   CREATE_THREAD_DEBUG_INFO CreateThread;
   CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
   EXIT_THREAD_DEBUG_INFO ExitThread;
   EXIT_PROCESS_DEBUG_INFO ExitProcess;
   LOAD_DLL_DEBUG_INFO LoadDll;
   UNLOAD_DLL_DEBUG_INFO UnloadDll;
   OUTPUT_DEBUG_STRING_INFO DebugString;
   RIP_INFO RipInfo;
 } u;
} DEBUG_EVENT, *LPDEBUG_EVENT;

I can translate this to VB.NET, but the marshalling eludes me.

TIA

Charles
BMermuys - 29 Jul 2004 22:28 GMT
Hi,

> Sorry for the cross post, but I have just realised that this might be a
> better place for this question.
[quoted text clipped - 24 lines]
>
> I can translate this to VB.NET, but the marshalling eludes me.

<StructLayout(LayoutKind.Explicit)> _
Public Structure DebugEvent
   <FieldOffset(0)> Public uint DebugEventCode;
   <FieldOffset(4)> Public uint ProcessId;
   <FieldOffset(8)> Public uint ThreadId;
   <FieldOffset(12)> Public ExceptionDebugInfo Exception;
   <FieldOffset(12)> Public CreateThreadDebugInfo CreateThread;
   <FieldOffset(12)> Public CreateProcessInfo;
   ....
   ....
End Structure

+ Translate all child structures, use LayoutKind.Sequential for them.

<DllImport("kernel32.dll")>
Public Shared Function WaitForDebugEvent( ByRef debugEvent as DebugEvent,
uint MilliSeconds )
End Function

HTH,
greetings

> TIA
>
> Charles
Charles Law - 29 Jul 2004 22:37 GMT
Hi

Thanks for the reply. Funnily enough, I've had something similar suggested
in another group, which I have since tried. It does indeed work, but I have
now run into trouble with the definitions of the child structures.

The method you have shown works where the structure contains either only
value types or reference types. The two cannot be mixed. The
EXCEPTION_RECORD upsets this scheme, as it contains a fixed array that needs
to be marshalled as a reference type; unless you have any suggestions?

Charles

> Hi,
>
[quoted text clipped - 53 lines]
> >
> > Charles
BMermuys - 29 Jul 2004 23:47 GMT
> Hi
>
[quoted text clipped - 6 lines]
> EXCEPTION_RECORD upsets this scheme, as it contains a fixed array that needs
> to be marshalled as a reference type; unless you have any suggestions?

So _EXCEPTION_DEBUG_INFO  contains an embedded EXCEPTION_RECORD, not a
pointer, so that's not a problem :

<StructLayout(LayoutKind.Sequential)> _
Public Structure _ExceptionDebugInfo
 Public ExceptionRecord As _ExceptionRecord
 Public FirstChance As uint
End Structure

Now, EXCEPTION_RECORD has a pointer to other records, so declare it as an
IntPtr :

<StructLayout(LayoutKind.Sequential)> _
Public Structure _ExceptionRecord
 Public ExceptionCode As UInt32
 Public ExceptionFlags As UInt32
 Public pExceptionRecord As IntPtr        ' pointer to chained records
 Public pExceptionAddress As IntPtr
 Public NumberParameters As UInt32
 <MarshalAs(UnmanagedType.ByValArray, SizeConst:=15)> _
 Public ExceptionInformation() As IntPtr
End Structure

....
Dim de As New DebugEvent
WaitForDebugEvent( de, ... )
...
' Now if de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT,
' then you can read the first ExceptionRecord => de.Exception,
' but to get the chained Exceptions you need to do :

Dim p As IntPtr p = de.Exception.pExceptionRecord

Do While ( Not p.Equals( IntPtr.Zero) )
   Dim ex As _ExceptionRecord = _
       CType(Marshal.PtrToStruct( p, GetType(_ExceptionRecord)),
_ExceptionRecord)

  ' use ex  here  (or store it for later use)

   ' get next pointer
   p = ex.pExceptionRecord
Loop

' You can also use Marshal.PtrToStruct on ExceptionInformation(x) if it's a
pointer to struct or use ExceptionInformation(x).ToInt32() if the pointer is
used as a value.

HTH,
greetings

> Charles
>
[quoted text clipped - 57 lines]
> > >
> > > Charles
Charles Law - 30 Jul 2004 00:09 GMT
It's the EXCEPTION_RECORD that is the problem. This is what it doesn't like

>   <MarshalAs(UnmanagedType.ByValArray, SizeConst:=15)> _
>   Public ExceptionInformation() As IntPtr

The application compiles, but when I call a method containing

> Dim de As New DebugEvent

I get the follwoing exception

<Exception>
An unhandled exception of type 'System.TypeLoadException' occurred in
Unknown Module.

Additional information: Could not load type union from assembly MyAssembly,
Version=1.0.1671.41486, Culture=neutral, PublicKeyToken=null because it
contains an object field at offset 4 that is incorrectly aligned or
overlapped by a non-object field.
</Exception>

I never even get into the method.

Do you have this scenario running?

Charles

> > Hi
> >
[quoted text clipped - 124 lines]
> > > >
> > > > Charles
BMermuys - 30 Jul 2004 03:37 GMT
Hi,

> It's the EXCEPTION_RECORD that is the problem. This is what it doesn't like
>
[quoted text clipped - 6 lines]
>
> I get the follwoing exception

Yes there seems to be some problems.  A possible workaround is to avoid the
use of a union:

<StructLayout(LayoutKind.Sequential)> _
Public Structure DebugEventHdr
   Public DebugEventCode As UInt32
   Public ProcessId As UInt32
   Public ThreadId As UInt32
End Structure

<DllImport("kernel32.dll")>
Public Shared Function WaitForDebugEvent( pDebugEvent As IntPtr,
MilliSeconds As UInt32 )
End Function

Usage :

Dim pDebugEvent As IntPtr = Marshal.AllocHGlobal(96)

WaitForDebugEvent ( pDebugEvent, Convert.ToUInt32(0) )
Dim hdr As DebugEventHdr =
CType(Marshal.PtrToStruct(pDebugEvent,GetType(DebugEventHdr)),DebugEventHdr)

IntPtr pEventData = new IntPtr( pDebugEvent.ToInt32() + 12 )

Select Case (Convert.ToInt32(hdr.DebugEventCode))
   Case Is = 1 'EXCEPTION_DEBUG_EVENT
       Dim edi As _ExceptionDebugInfo
       edi = CType(Marshal.PtrToStructure(pEventData,
GetType(_ExceptionDebugInfo)), _ExceptionDebugInfo)

   Case Is = 2 ' CREATE_THREAD_DEBUG_EVENT
       Dim ctde As _CreateThreadDebugInfo
       ctde = CType(Marshal.PtrToStructure(pEventData,
GetType(_CreateThreadDebugInfo)), _CreateThreadDebugInfo)

    ...
End Select
Marshal.FreeHGlobal( pDebugEvent )

Another workaround is to flatten the array inside EXCEPTION_RECORD.

HTH,
greetings

> <Exception>
> An unhandled exception of type 'System.TypeLoadException' occurred in
[quoted text clipped - 145 lines]
> > > > >
> > > > > Charles
Charles Law - 30 Jul 2004 09:21 GMT
I could flatten the array, in this case, as it only has 15 elements, but in
the general case ...

I have ended up making EXCEPTION_DEBUG_EVENT a special case, as you suggest,
and have removed it from the union. It all seems to work now.

Thanks again.

Charles

> Hi,
>
[quoted text clipped - 31 lines]
> WaitForDebugEvent ( pDebugEvent, Convert.ToUInt32(0) )
> Dim hdr As DebugEventHdr =

CType(Marshal.PtrToStruct(pDebugEvent,GetType(DebugEventHdr)),DebugEventHdr)

> IntPtr pEventData = new IntPtr( pDebugEvent.ToInt32() + 12 )
>
[quoted text clipped - 173 lines]
> > > > > >
> > > > > > Charles

Rate this thread:







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.