Announcement

Collapse
No announcement yet.

Visual Basic Arrays and PB/DLL

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Visual Basic Arrays and PB/DLL

    I am currently trying to understand an extension of mine to a post under "Frequently Asked Questions" by Dave Navarro entitled "Visual Basic Arrays and PB/DLL". When I tried to extend his excellent suggestion for Long Arrays, to Integer and Byte arrays, I received a compile error "BYREF Argument type mismatch" The modified VB6 code for the Integer case, which triggered the compile error, looked like the following:

    Private Sub Form_Load()
    Dim N As Integer
    Call Transfer(A(0), 5)
    For N = 0 To 4
    Text1.Text = Text1.Text & CStr(A(N)) & vbCrLf
    Next N
    End Sub


    Option Explicit
    Declare Sub Transfer Lib "D:\ArrayDLL_INT\Test.dll" (FirstElem As Long, ByVal Total As Integer)
    Global A(0 To 4) As Integer

    The associated PowerBasic code was:
    GLOBAL A()AS INTEGER
    SUB Transfer ALIAS "Transfer" (BYVAL FirstElem AS LONG, BYVAL Total AS INTEGER) EXPORT

    REDIM A(0 TO Total-1) AS INTEGER AT FirstElem
    DIM N AS INTEGER
    FOR N = 0 TO Total-1
    A(N) = 12345
    NEXT N
    END SUB


    To correct the compile error, I modified the VB6 code to the following:

    Private Sub Form_Load()

    Dim N As Integer
    Dim Address As Long
    Address = VarPtrArray(A())
    Call Transfer(Address, 5)
    For N = 0 To 4
    Text1.Text = Text1.Text & CStr(A(N)) & vbCrLf
    Next N
    End Sub

    Declare Sub Transfer Lib "D:\ArrayDLL_INT\Test.dll" _
    (ByVal FirstElem As Long, ByVal Total As Integer)

    Declare Function VarPtrArray Lib "msvbvm60.dll" _
    Alias "VarPtr" (Var() As Any) As Long

    Global A(0 To 4) As Integer

    I got the VarPtrArray function from the Microsoft Knowledge Base but this was the first time I have tried it. The VarPTRArray approach got rid of the compile error but the VB6 Array A() contained all zeros in lieu of the expected "12345". Further-more, when I used this approach for the original A() dimensioned as a Long array, I also erroneously got all zeros in lieu of "12345" It seems that the VarPtrArray fucntion doesn't work as I have applied it. Can you suggest an approach to remove the compile error which would work for both Integer and Byte arrays? What was wrong with the VarPtrArray approach that I used above?

  • #2
    I can't exactly follow what you are trying to do Norm, but in this case below...
    Code:
    Option Explicit
    Declare Sub Transfer Lib "D:\ArrayDLL_INT\Test.dll" (FirstElem As Long, ByVal Total As Integer)
    Global A(0 To 4) As Integer
    ...which I'm assumming is VB code, FirstElem is being passed By Reference, which means its address is being passed. In this 2nd case, whatever number is contained at FirstElem is being passed -- not an address.

    Code:
    The associated PowerBasic code was:
    GLOBAL A()AS INTEGER
    SUB Transfer ALIAS "Transfer" (BYVAL FirstElem AS LONG, BYVAL Total AS INTEGER) EXPORT
    Fred
    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

    Comment


    • #3
      Read Appendix B in the PBWin help file--re: VB safe arrays. Power Basic also supplied some VB samples in the samples directory. I am betting the farm that it is a safe array issue.
      The most exasperating part of the "rat race" is how often the rats are in the lead!

      Comment


      • #4
        Funny this should come up... I am looking at a project requiring this myself.

        The info in the help file is good and I'll be trying that soon, but I had a question:

        The help file suggests for scalar (non-UDT, non-string) arrays, one pass the address of the first element and an element count, but use the "safearray" functions for UDT and string arrays.

        Is there some reason to not use the 'safearray' functions for all arrays?

        My application (an API for the ANSI ASC X12N X096A1 and X098A1 837 Health Care Claim or Encounter documents) has functions which pass and redimension both scalar and non-scalar arrays, and I'd kind of like to leave the call syntax (and therefore the documentation and the header files) pretty much the same for a "Visual Basic compatible" version.

        Thanks,
        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Yes, you have the idea.

          In the first case, I was passing A(0) BYREF and its address was being implicitly passed. This only works if A() is dimensioned as a LONG array. When A() is dimensioned as an INTEGER array, the VB compile error occurs.

          In the second case, I tried to explicitly obtain the address of the first element in the INTEGER array A() using the MS VarPtrArray function. Because it was an address, I passed the result BYREF. No compile error occurred, but the address obtained via VarPtrArray was apparently not correct.

          Thanks for the input, but the solution is still not apparent. Some others have suggested this is related to SafeArrays but the VarPtrArray function is supposed to return the address of the SafeArray. It is a mystery to me.

          Comment


          • #6
            Originally posted by Michael Mattias View Post
            Is there some reason to not use the 'safearray' functions for all arrays?
            Michael,

            See Mike Stefenik's post in this thread :
            http://www.powerbasic.com/support/pb...ight=safearray



            Scott
            The most exasperating part of the "rat race" is how often the rats are in the lead!

            Comment


            • #7
              Because it was an address, I passed the result BYREF. No compile error occurred, but the address obtained via VarPtrArray was apparently not correct.
              Addresses are almost never passed by reference. Try passing by value.

              MCM
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                Thank you.

                I guess using the safearray functions will then always be, well, safe.

                MCM
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  Originally posted by Michael Mattias View Post
                  Addresses are almost never passed by reference. Try passing by value.

                  MCM
                  My response was in error, Mike. Because it was an address obtained from the VarPtrArray function, I did pass it ByVal and it did not work.

                  Comment


                  • #10
                    At this point you are reduced to showing your code. Show your PB DLL code in it's entirety (all it should be is your LibMain function, one 'non-working' function, plus any #INCLUDE lines or GLOBAL variables used), plus all relevant call lines and DECLAREs from your VB code.

                    Please don't forget the code tags.

                    OR MAYBE NOT...

                    If this code is still what you are using, here is your problem....
                    in PB code, SUB Transfer:
                    Code:
                    REDIM A(0 TO Total-1) AS INTEGER [b]AT FirstElem[/b]
                    ...
                    In calling code:
                    Code:
                    [b]Address[/b] = VarPtrArray(A())
                    Call Transfer(Address, 5)

                    When you REDIM "AT" the value should be the address of the first element. Your code is passing the address of the array descriptor itself.

                    You should be passing the address of the first array element - A(0) - however you get that in VB (I don't do VB).

                    [again, later}

                    I think this might work in VB...
                    Code:
                    Declare Sub Transfer Lib "D:\ArrayDLL_INT\Test.dll" (FirstElem [b]As ANY[/b], ByVal Total As Integer)
                    .....
                    Call Transfer(A(0), 5)
                    ....
                    Can any VB-refugees out there confirm that DECLARING "AS ANY" will pass the address of whatever variable is used in that parameter position (just like PB works)????


                    MCM
                    Last edited by Michael Mattias; 28 Dec 2007, 10:26 AM.
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      Hi Mike
                      Actually, I did post my code on the initial query but you nailed the problem! Here is my DLL code for a Byte Array as the approach works for Long, Integer and Byte arrays;

                      #COMPILE DLL
                      GLOBAL A()AS BYTE
                      SUB Transfer ALIAS "Transfer" (BYVAL FirstElem AS LONG, BYVAL Total AS INTEGER) EXPORT
                      REDIM A(0 TO Total-1) AT FirstElem
                      DIM N AS INTEGER
                      FOR N = 0 TO Total-1
                      A(N) = 128
                      NEXT N
                      END SUB

                      Here are my VB Declarations:

                      Global A(0 To 4) As Byte
                      Declare Sub Transfer Lib "D:\ArrayDLL_LONG\Test.dll" _
                      (FirstElem As Any, ByVal Total As Integer)

                      and here is the VB form_Load code which initiates the process and prints the expected value from the DLL of 128:

                      Private Sub Form_Load()
                      Dim N As Integer
                      Call Transfer(A(0), 5)
                      For N = 0 To 4
                      Text1.Text = Text1.Text & CStr(A(N)) & vbCrLf
                      Next N
                      End Sub

                      Your suggestion to use FirstElem as Any in the VB declaration solved the issue. Thank you so much.

                      As far as the SafeArray approach with the VB function VarPtrArray, according to MS, this function points to the address of the first element in the array and not the location of the header. This part remains a mystery but one I don't need to solve.

                      One last issue relative to LibMain. I thought that was an optional part of a DLL so could you comment on why it should be included?

                      Many thanks again, Norm

                      Comment


                      • #12
                        You really need to learn how to use the code tags. I think this is the linK:



                        And while you are surfing this board, why don't you check in with your "profile" and add your geographic location so we can all see where you are coming from?

                        MCM
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          One last issue relative to LibMain. I thought that was an optional part of a DLL so could you comment on why it should be included?
                          It probably says this somewhere in the help file, but if you don't include a LIBMAIN function when you #COMPILE DLL, the compiler inserts a default LIBMAIN function for you.

                          If you want to do anthing other than the default action (which is to do nothing and return 'success' for any of the notification codes), you'll have to code a Libmain function. Typically you might save the module instance handle in a GLOBAL variable on the DLL_PROCESS_ATTACH notification (reason) code. (Hell, that's what I do).

                          MCM
                          Michael Mattias
                          Tal Systems (retired)
                          Port Washington WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            For the interested, here's the link to the Knowledge Base article mentioned in post #1
                            Michael Mattias
                            Tal Systems (retired)
                            Port Washington WI USA
                            [email protected]
                            http://www.talsystems.com

                            Comment

                            Working...
                            X