Passing a structure with arrays of fixed length strings to a DLL

Hi,

I need to be able to pass a structure to a DLL that has arrays of fields of fixed length in it.

In old VB6 this could be done by having types with types

type repeatingRecord
field1 as string * 2
field2 as string * 5
end type

type maintype
field1 as string * 7
records(10) as repeatingRecord
end type

In .NET types become structures and fixed length strings no longer exist. However the attributes 'VBFixedString' and MarshalAs will solve this problem for simple structures.

However it still does not solve my problem for arrays. .NET will not allow fixed length arrays ......

How do I pass the equivalent in .NET to unmanaged code in a DLL

Regards

Michael



Answer this question

Passing a structure with arrays of fixed length strings to a DLL

  • alok ranjan

    The VBFixedString and VBFixedArray are meant to be used with VB File IO routines (FileOpen, FilePut, etc).

    For passing structures with fixed size strings through P/Invoke (Declare statement method) you probably need to use the ByValTStr type on the marshalas attribute instead of ByValArray:

    MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr,sizeconst:=5)

    I don't really remember if the Ansi vs Unicode definition on declares affects the size of the characters here - you may also need to add a StructLayoutAttribute to the structure if you can't get the correct Char size.



  • Malla

    Hi,

    ByValTStr does not work - this is as per the Microsoft Press VB6 to .NEt upgrade book. My testing supports this - changing the strings to char arrays and using the VBFixedString attribute worked.

    Regards

    Michael Green


  • alan_k

    My test dll relevant code:

    struct repeatingRecord
    {
    char field1[2];
    char field2[5];
    };
    struct C1
    {
    char field1[7];
    repeatingRecord records[10];
    };
    extern "C"
    {
    TESTDLL_API
    int fnTestDLL(C1 arg);
    }

    TESTDLL_API int fnTestDLL(C1 arg)
    {
    MessageBoxA(0,arg.field1,
    "Title1", MB_OK);
    MessageBoxA(0,arg.records[9].field1 ,
    "Title2", MB_OK);
    MessageBoxA(0,arg.records[9].field2 ,
    "Title3", MB_OK);
    return 42;
    }

    On the vb side:

    Imports System.Runtime.InteropServices
    Module Module1

    Structure
    repeatingRecord
    <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=2)>
    Dim field1 As String
    <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=5)> Dim field2 As String
    End Structure

    Structure maintype
    <MarshalAs(UnmanagedType.ByValTStr, sizeconst:=7)>
    Dim field1 As String
    <MarshalAs(UnmanagedType.ByValArray, sizeconst:=10)> Dim records() As repeatingRecord
    End Structure

    Declare Ansi Function fnTestDLL Lib "C:\Documents and Settings\amoura\My Documents\Visual Studio 2005\Projects\TestDLL\debug\testdll.dll" (ByVal arg As maintype) As Integer

    Sub Main()
    Dim c As maintype
    c.field1 =
    "123456"
    c.records = New repeatingRecord(10) {}
    For i As Integer = 0 To 9
    c.records(i).field1 =
    "1"
    c.records(i).field2 = "1234"
    Next
    fnTestDLL(c)
    End Sub

    End Module

    This seems to work as expected - Let me know if this still isn't what you're looking for.



  • Francy

    Hi,

    Given I've already had a look at this area (hence my comments on VBFixedString etc) a little more precise guidance would be appreciated e.g. a few URLs.......

    Regards

    Michael


  • Karthick Sukumaran

    The following may help show the change from VB6 to VB.Net with regard to calling API's

    This is a simple example sending a file to the recycle bin but it defines a structure used in the API.

    http://www.developerfusion.co.uk/show/4334/

    fixed length strings and API functions

    http://groups.google.com/group/microsoft.public.dotnet.languages.vb/browse_thread/thread/282a4b3969498eb5/f7e6db7474437cb2%23f7e6db7474437cb2 sa=X&oi=groupsr&start=0&num=3


  • Jvalente

    Hi,

    I still can't get this to work.

    The .NET structures are as follows. The only way I can get this to work is if I convert the array of sub-structures to dummy fields in the main structure. Then the data is correctly passed to the API. If I pass as is I get a 'Parameter Incorrect' error message.

    Structure repeatingRecord

    <VBFixedString(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> _

    Public field1 As String

    <VBFixedString(5), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=5)> _

    Public field2 As String

    End Structure

    Structure maintype

    <VBFixedString(7), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=7)> _

    Public field1 As String

    <VBFixedArray(10)> Dim records() As repeatingRecord

    'UPGRADE_TODO: "Initialize" must be called to initialize instances of this structure. Click for more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm keyword="vbup1026"'

    Public Sub Initialize()

    ReDim records(10)

    End Sub

    End Structure


  • Grozen

    Hi,

    sorry - but neither of these links address the core issue here which is how to pass to correctly arrays of subordinate structures.

    Regards

    Michael Green


  • Varsha

    I am having a similar problem. Could you please reply and paste in a snippet of code that you used to convert the structure to a char array

  • milTash

    Micheal...

    Take a look at interop services and Marshalling. There are way to describe those string that you won't find anywhere else.



  • Margriet

    The Help files is what I was referring to......

    I refer to them often and the fora have settle into the phrase "have a look at" to mean either help or the object browser. In this case, help will be better.



  • Passing a structure with arrays of fixed length strings to a DLL