Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a Delphi Array of Fixed Sized Strings within a packed record in c#

I need to read a blob field from a database into a c# app.

However the blob field was written to the database by a Delphi App using the following method:

 procedure WriteABlob(Blob : TBlobField; var Buffer; size : integer);
 var 
     s : String;
 begin
     setlength(s,size);
     move(buffer,s[1],Size);
     Blob.Value := S;
 end;

The Structure written to the database is not a simple structure and contains things like

MyVariable : Array[0..3] of String[80];

or worse some of them contain

MyRecord = Packed Record
case byte of
    1: (
        iValue:Integer;
       )
    2: (
        cValue:Char;
       )
end;

I've been trying reading in the bytes from the database and then using

Marshal.PtrToStructure()

in order to move it into the struct

My Struct is defined as follows:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1, Size = 10710)]
    public struct MyBlobField
    {
        ...
        [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.AnsiBStr,SizeConst = SpecificArraySize)]
        public String[] ArrayofFixedLengthStrings;
        ...
    }

But i get an error when calling Marshal.PtrToStructure():

Cannot marshal field 'ArrayofFixedLengthStrings' of type 'MyBlobField': Invalid managed/unmanaged type combination (String[] must be paired with an ArraySubType of LPStr, LPWStr, BStr or LPTStr).

I was wondering if there was a attribute I could define on a CustomMarshaler which would accept a pairing with a String[]

Any ideas how I could read the contents of the blob into c#?

like image 612
James Barrass Avatar asked Feb 03 '10 16:02

James Barrass


1 Answers

Figured it out...

Declared a struct String20 as

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct String20
    {
        [MarshalAs(UnmanagedType.U1)]
        public byte StringSize;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public String Value;
    }

Apparently the string size identifier at the beginning of a fixed length string (i.e a delphi ShortString) is only 1 byte. Then changed the definition of header_identifiers to:

       [MarshalAs(UnmanagedType.ByValArray, SizeConst = max_header_identifiers)]
        public String20[] header_identifiers;

Also found that Delphi Packed Boolean need to be cast as

[MarshalAs(UnmanagedType.I1)]
public bool BooleanVar;
like image 187
James Barrass Avatar answered Sep 23 '22 11:09

James Barrass