MPSystemsServices / CodeBase-for-DBF

CodeBase is a C-based library to read, write and manage DBF type tables and indexes.
GNU Lesser General Public License v3.0
52 stars 33 forks source link

f4str and f4strMemo not working inVB.NET (VS 2019) #8

Closed colindjmi closed 4 years ago

colindjmi commented 4 years ago

What is the correct way to declare f4str and f4strMemo? I am trying to write the ShowData example in Visual Basic .NET. It is working (although I had to Remove integer overflow checks in Advanced Compile Options) up to the point when it tries to retrieve the value of the field. It then spends a few seconds in the function and then terminates with no error message. See entire form below:

Option Explicit On
Imports System.Runtime.InteropServices

Public Class Form1
    Declare Function code4init Lib "C4DLL.dll" Alias "code4initVB" () As Integer
    Declare Function code4initUndo Lib "C4DLL.dll" (ByVal cb As Integer) As Integer
    Declare Function d4open Lib "C4DLL.dll" (ByVal cb As Integer, ByVal fileName As String) As Integer
    Declare Function d4close Lib "C4DLL.dll" (ByVal db As Integer) As Long
    Declare Function code4errorCode Lib "C4DLL.dll" (ByVal cb As Integer, ByVal errCode As Integer) As Integer
    Declare Function d4top Lib "C4DLL.dll" (ByVal db As Integer) As Integer
    Declare Function d4recCount Lib "C4DLL.dll" Alias "d4recCountDo" (ByVal db As Integer) As Integer
    Declare Function d4numFields Lib "C4DLL.dll" (ByVal db As Integer) As Short
    Declare Function d4fieldJ Lib "C4DLL.dll" (ByVal db As Integer, ByVal j As Short) As Integer
    Declare Unicode Function f4memoStr Lib "C4DLL.dll" (ByVal fldPtr As Integer) As String
    Declare Function f4str Lib "C4DLL.dll" (ByVal fldPtr As Integer) As String
    Declare Function d4skip Lib "C4DLL.dll" (ByVal db As Integer, ByVal recsToSkip As Integer) As Integer
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'ShowData sample code

        Dim cb As Integer
        Dim db As Integer
        Dim fldPtr As Integer
        Dim rc As Integer
        Dim fPath As String

        cb = code4init()                     'Initialize CodeBase
        If cb = 0 Then
            MsgBox("code4init( ) failed")
            Exit Sub
        End If
        'Code4initUndo(cb)
        'Exit Sub

        fPath = "c:\users\colindjmi\downloads\CodeBase\"

        db = d4open(cb, fPath + "SHOWDATA")        'Open File

        If db = 0 Then
            MsgBox("Open Failed")
            rc = code4errorCode(cb, 0)                    'Reset error code
            Exit Sub
        End If

        Dim numRecs As Integer
        Dim numFields As Integer
        Dim i As Short, j As Short
        Dim strField As String

        rc = d4top(db)
        numRecs = d4recCount(db)
        numFields = d4numFields(db)
        For i = 1 To numRecs                  'Loop through records
            For j = 1 To numFields                    'Loop through each field
                fldPtr = d4fieldJ(db, j)                     'Get Field Pointer
                strField = f4str(fldPtr)               'Print field contents
            Next j
            'Print("")
            rc = d4skip(db, 1)                              'Blank lines between recs.
        Next i                                       'Go to next record

        rc = d4close(db)
        rc = code4initUndo(cb)              'Close everything and free resources

    End Sub
End Class

By the way, there does not seem to be a CODEBASE.BAS file in the project. Is one available?

trevster344 commented 4 years ago

I have added two files to my fork of this repo.

https://github.com/trevster344/CodeBase-for-DBF

See VB.NET/Source/codebase.vb for VB.NET See VB6/Source/codebase.bas for VB6

If you have any other issues let me know. Please make sure you have c4dll.dll in the system or local to your application.

colindjmi commented 4 years ago

Thanks for your prompt response. It is working now. So the return value is a char and the Interop mechanism does not convert it for you. I did not think of trying memcpy, although I did* try <MarshalAs(Unmanaged.LPstr)> on the return value without success.

I am using VB.Net and type suffix & = Long = 64-bit integer so I had to edit your declarations. Is there something that I should be doing to make VB.NET interpret Long as 32-bit instead of 64-bit?

trevster344 commented 4 years ago

You should be okay, the data returned may be long but its not too big to fit in an integer. Are you seeing a scenario where this is a problem? I've never had any issues personally.

colindjmi commented 4 years ago

Until I started using Integer instead of Long in the parameter declarations, calls would crash saying that the stack was unbalanced, which usually means that the VB declaration did not match the C declaration.

trevster344 commented 4 years ago

Which dll are you using for your application? Have you tried again with the codebase.vb from my repo without and modifications? I haven't had any issues outside of memory errors when using this module and c4dll.dll in my VB.NET applications. Are you explicitly compiling to x86 or just letting the compiler automate it?

colindjmi commented 4 years ago

I am using the C4DLL.dll from the root folder of your project. I copied the definitions out of the email that you sent, but I had to replace the type suffixes and explicitly start Integer or Short. I am running the program within the IDE (Debug x86). I have not tried to run it outside of the IDE yet. I am using VB.NET in Visual Studio 2019.

colindjmi commented 4 years ago

And I am not seeing a codebase.vb at the project site.

trevster344 commented 4 years ago

Try this link.

https://github.com/trevster344/CodeBase-for-DBF/blob/master/VB.NET/Source/codebase.vb

For any VB.NET project I start that uses CodeBase I add the vb module, add a reference to Microsoft.Visualbasic.compatibility and off I go. Most my apps are running in x86 because my c4dll.dll is compiled x86 and my applications make many references to COM dlls written in VB6.

colindjmi commented 4 years ago

Thanks. This will work fine because your declarations are like this: Declare Function d4open Lib "c465net.dll" (ByVal c4 As Integer, ByVal DbfName As String) As Integer instead of Declare Function d4open& Lib "c465net.dll"(ByVal c4&, ByVal DbfName$)

Of course, I can easily search and replace the DLL name. I assume that you compiled c465net.dll yourself. Is that something that should be in the repository also? My simple ShowData sample is working with C4DLL.dll.

trevster344 commented 4 years ago

There are declarations for both c465net.dll and c4dll.dll in there. It will run whichever one is present. You shouldn't have to copy or modify anything in that module.

colindjmi commented 4 years ago

Good. Thanks again.