Groups | Blog | Home
all groups > dotnet interop > april 2004 >

dotnet interop : unmanaged structs in managed code


MZK
4/14/2004 4:41:03 PM
I hope this is the right place to ask..

I have a VC++ 6 application that reads data from a legacy database. This database consists of 512 byte records, with the first 2 bytes determining the record type (eg 01 = record type 1, 999 = record type 99 etc). Each record type is structured differently, although they are all 512 bytes long

Now, my existing app contains struct definitions for each record type and I simply read each record into a buffer, check the record type, cast the buffer to the correct struct type and call a function which handles that record type

What I want to do now is port the app to .NET c#. From the information I've found so far, it doesn't appear possible to replicate fixed structured record types and cast from a byte buffer. However, what I have read suggests that I should be able to write the file access and record type casting code in unmanaged c++ and let the managed app call into the unmanaged code to retrieve the data as an unmanaged-code-defined structure (!!)

I thinks this means I can do something like..

// unmanaged cod

struct rec01
short rt
int f1
int f2
..
}

struct rec02
short rt
long f1
long f2
..
}

short ReadNextRecord()
// returns 0 on final read, or record type otherwis

GetRec01(rec01 *rec)
// return pointer to or copy of a rec01 struc

GetRec02(rec02 *rec)
// return pointer to or copy of a rec02 struc

// managed cod

while (rt = ReadNextRecord())
// call relevant record type handler, probably via function array lookup (delegate?) or one BIG switch ;


void HandleRec01(rec01 rec)
/


Firstly, is something like this possible ? If so, should it be via p/invoke ? Can the resultant unmanaged assembly be referenced in the managed project like any other assembly ? As all the structure members are blittable, does this help

Thanks in advanc

Mattias Sjögren
4/15/2004 2:40:12 AM

[quoted text, click to view]

Not true, you can do that alright. Something like

rec01 rec;
byte[] buffer = ...
fixed ( byte* p = buffer )
rec = *((rec*)p);



Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
MZK
4/15/2004 5:31:05 AM
Thanks for your response.

Can you clarify a couple of points:

1. are there any substantial performance penalties using this method - the DB I'm reading has about a million records, which all need processed.

2. am I right in thinking that the last line should be used as:
unsafe {
fixed (byte *p = buffer) {
rec = *((rec01*)p);
}
}

3. do I need to add an attribute to the struct definition to ensure that the structure is laid out in memory correctly for the
fixed/unsafe cast ?

Thanks again for your help

MZK
4/15/2004 8:16:07 AM
Mattias Sjögren
4/15/2004 3:54:23 PM

[quoted text, click to view]

Well pinning the byte array (which is what you are doing here with the
fixed statement) can have some negative affect on the GC efficiency.
But considering your options, I think this way is as good as any. As
always when it comes to performance; meaasure it!


[quoted text, click to view]

Same code, just more curly braces. :) But you're right that you need
an unsafe block around it somehow, yes.


[quoted text, click to view]

C# structs have sequential layout by default (as if you used
[StructLayout(LayoutKind.Sequential)]). If that's what you want (and
it usually is) then you don't need any extra attributes.



Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
AddThis Social Bookmark Button