Passing Structure to Function

trims30

Member
Joined
Aug 7, 2007
Messages
17
Programming Experience
10+
I have some code I'm converting from VB6 and am experiencing problem passing a structure to a function call parameter.

Function dataBuffer (DB) parameter in VB6 is passed "AS ANY"
VB.NET:
   Declare Function BtrCall Lib "wbtrv32.dll" Alias "BTRCALL" _
   (ByVal OP%, _
    ByVal PB$, _
  [B]  db As Any[/B], _
    DL As Long, _
    kb As Any, _
    ByVal kl%, _
    ByVal kn%) As Integer

In VB.NET db As Any is not allowed so I'm using ByRef DataBuffer as String Parameter

VB.NET:
    Declare Function BtrCall Lib "w3btrv7.dll" Alias "BTRCALL" _
        (ByVal OpCode As Short, _
         ByVal Cursor As String, _
        [B] ByVal DataBuffer As String, _[/B]
         ByRef DataBufferLength As Short, _
         ByVal KeyBuffer As String, _
         ByVal KeyLength As Short, _
         ByVal KeyNum As Short) As Short

Am able to pass structure as string by converting it using StructToString function shown below.

VB.NET:
 Public Function StructToString(obj As Object) As String
        Return String.Join(" ", obj.GetType().GetFields().Select(Function(field) field.GetValue(obj)))
    End Function

This appears to work OK and since I'm using ByRef I can get modified structure back as a string but I need to parse the string to place values back in original structure.

Now, herein lies my problem. If I have a structure "BTSTATUS" containing an array (SEG) I don't believe it's passing the array.
In this case SEG() is another Structure


VB.NET:
    [B] Structure BTSegment[/B]
        Public iPosition As Short
        Public iSize As Short
        Public iFlags As Short
        <VBFixedString(4)> Public slCount As String
        <VBFixedString(1)> Public sType As String
        <VBFixedString(1)> Public sNullValue As String
        <VBFixedString(4)> Public sReserved As String
    End Structure

       [B] Structure BtStatus[/B]
        Public iRecSize As Short
        Public iPageSize As Short
        Public iIndexCount As Short
        <VBFixedString(4)> Public slRecordCount As String
        Public iFileFlags As Short
        <VBFixedString(2)> Public sReserved As String
        Public iPreAlloc As Short
        [B]Public Seg() As BTSegment[/B]
    End Structure

How do I convert all this to a string that the function I'm calling can interpret?

How do I convert the returned DataBuffer "ByRef" back to a Structure?
 

humanon10

New member
Joined
Sep 24, 2013
Messages
3
Programming Experience
5-10
Hello! I need to contact you to ask something about what you were trying to do with passing the structure directly to BTRCALL. Still pending the forum?
 

trims30

Member
Joined
Aug 7, 2007
Messages
17
Programming Experience
10+
I believe I was investigating working with FairCom database when I posted question.
It's a dead issue at this time.

I'll be happy to answer any btrieve questions you may have.

Lee
 

humanon10

New member
Joined
Sep 24, 2013
Messages
3
Programming Experience
5-10
Thanks you!! This is my situation...

Hello, thank you very much for answering!
If you could give me a time to read my question, I would greatly appreciate it. Maybe from that moment you have an example that you could share. If not, very grateful in any case for reading about my problem.


The way I was always working the BTRCALL was with a pointer. For example look at the following by sending the pointer instead of the structure:


Dim PayConfQptrDataBuffer As IntPtr


OpCode = BGETFIRST


LocalVBFixedLength.KeyBuf = " "
keydata = StrToByteArray(LocalVBFixedLength.KeyBuf)


Do
X = BTRCALL(OpCode, PosBlk(PayConfQFNum).PosBlkHnd, PayConfQptrDataBuffer, PayConfQDataBufLen, keydata, 16, 1)


OpCode = BGETNEXT


Select Case X
Case 0
StrPayConfQ.FillStructure(PayConfQptrDataBuffer, PayConfQ)
MsgBox(PayConfQ.AgOdNum)
Case 4, 9
Exit Do
End Select
Loop


The second parameter in the call to StrPayConfQ.FillStructure() is the structure that fills with what the pointer returns.


My BTRCALL statement is the following ...

Declare Function BTRCALL Lib "w3btrv7.dll" (ByVal Opcode As Short, _
ByVal Cursor() As Byte, _
ByVal DataBuffer As IntPtr, _
ByRef DataBufferLength As Short, _
ByVal KeyBuffer() As Byte, _
ByVal KeyLength As Short, _
ByVal KeyNum As Short) As Short


Although it has always worked, now we do not want to use it like that anymore. The boss wants to send the structure directly. What I found that started to work was the following:


Declare Function BTRCALL Lib "w3btrv7.dll" (ByVal Opcode As Short, _
ByVal Cursor() As Byte, _
<MarshalAs(UnmanagedType.Struct, SizeConst:=255)> ByRef databuffer As PayConfQType,
ByRef DataBufferLength As Short, _
<MarshalAs(UnmanagedType.LPArray, SizeConst:=255)> KeyBuffer() As Byte,
ByVal KeyLength As Short, _
ByVal KeyNum As Short) As Short


This works well. Only that overloading must be used to use as many "BTRCALL()" as there are structures.
Also in more advanced tests in tables of variable fields I began to have problems.
Will you have an example saved from when you were working on this two years ago?
Thanks and Regards!
 

trims30

Member
Joined
Aug 7, 2007
Messages
17
Programming Experience
10+
Call we use is same a yours:

Declare Function BTRCALL Lib "w3btrv7.dll" (ByVal Opcode As Short, _
ByVal Cursor() As Byte, _
ByVal DataBuffer As IntPtr, _
ByRef DataBufferLength As Short, _
ByVal KeyBuffer() As Byte, _
ByVal KeyLength As Short, _
ByVal KeyNum As Short) As Short

We have created our own Field Definition Table as well as index Definition Table and have written functions for most all btrieve function codes - eliminated use of structures for the most part. Method may be redundant but we converted from DataFlex database some years ago and tried to emulate as many Dataflex codes as possible.

For example, to find Equip_ID "A100" in the Equipment File we use the following code:

DB_Clear Equipment 'Clear Buffer
finderr=true 'Set Error flag to prevent Error Message from Find (useful in terminating loop)
PF EQUIPMENT_EQUIP_ID,"A100" 'Put search value in buffer -
er%=DB_find EQ, EQUIPMNT,INDEX_1,Finderr 'Do Find EQ on Index 1 returns findErr
If finderr then
msgbox "Error"
else
debug.print gf(Equipmnt_EQUIP_ID),GF(Equipment_Description) 'print 2 fields from buffer.
end if
 

trims30

Member
Joined
Aug 7, 2007
Messages
17
Programming Experience
10+
Forgot to mention that the PF function uses File/Field parameter defining File Number and Field number.
No need to use structures for data layout on each file. We have 70 files managed this way.

Our File Table defines file Name, Field Type, Offset and Field length.
So PF EQUIPMENT_EQUIP_ID,"A100" calls the PF Sub which breaks down EQUIPMENT_EQUIP_ID to the pointer for Equipment File and pointer to EQUIP_ID Field. It then puts "A100" into the buffer. The GF Function returns value of specified FILE_FIELD from buffer.
 

humanon10

New member
Joined
Sep 24, 2013
Messages
3
Programming Experience
5-10
Thank you very much for your fast response! I'm going to talk to my boss about the contacts I've had with you. If I take more help then I will write to you in case you have the time to help me more. Thank you very much!
 
Top Bottom