[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 529
  • Last Modified:

Passing an array from Visual Basic to a Delphi DLL

I am banking all of my points on asking this question... I really need to solve this problem!

I have written a DLL in Delphi 4.0. It compile successfully and I am able to call it and acces the procedure that I need in it from within VB.

Here is the code for the declaration of the procedure in Delphi:

TYPE
   myarray = array of double;

PROCEDURE myprocedure (rob : myarray;
                       width, height : integer;
                       ndimen, isign : integer); stdcall;

I pass it an array from within VB, but the as soon as I exit out of the DLL the changes are not saved to the array. (I have tried putting "VAR" in front of rob... but it did not solve the problem)

This is my DLL Declare in VB:

Declare Sub myprocedure lib "delphidll.dll" (ByRef junk as double,
                                             ByVal wid as integer,
                                             ByVal hgt as integer,
                                             ByVal ndim as integer,
                                             ByVal isign as integer)

I call the DLL as follows from VB:

    ReDim sindata(1 To 256 * CLng(256)) As Double
    i = 1
    While (i < 256 * CLng(256))
        sindata(i + 1) = Sin(i)
        sindata(i) = 0
        i = i + 2
    Wend

myprocedure sindata(1, 1), 128, 256, 2, 1

I can debug the DLL from within Delphi once the VB app is compiled into an EXE. I set breaks in the DLL, and I see that the DLL is populated correctly, and while the dll is running, the values in the array are changed, but the thing is this... once the dll is finished, then all of the changes are not retained... meaning once back in VB code, the array has the ORIGINAL values in it.

Can someone help me with this problem that I've got? If you would like more details about the problem email me: rwlodarc@ic.sunysb.edu and I'll be glad to send you the code for both the Delphi DLL and the VB App.

Thanks in advance!
0
RWlodarczyk
Asked:
RWlodarczyk
  • 9
  • 5
  • 3
  • +1
1 Solution
 
tomookCommented:
What is the definition of the array "Complex"? If it is not declared as an array of "Long", you are getting a temporary copy, much like in C++ if you pass an object with a type conversion operator, it creates a temporary object.
0
 
RWlodarczykAuthor Commented:
Edited text of question
0
 
RWlodarczykAuthor Commented:
Adjusted points to 185
0
Nothing ever in the clear!

This technical paper will help you implement VMware’s VM encryption as well as implement Veeam encryption which together will achieve the nothing ever in the clear goal. If a bad guy steals VMs, backups or traffic they get nothing.

 
RWlodarczykAuthor Commented:
Adjusted points to 195
0
 
tomookCommented:
Sometimes you can fool VB by changing the function declaration to As Any.
Declare Sub myprocedure lib "delphidll.dll" (ByRef junk as Any,
                                             ByVal wid as integer,
                                             ByVal hgt as integer,
                                             ByVal ndim as integer,
                                             ByVal isign as integer)

If this does not work, please try using a Double variable instead of an array element. I am curious if it would work.
0
 
anthonycCommented:
it also looks like in your call to the DLL, you are passing a value of the array instead of the array instead:

ReDim sindata(1 To 256 * CLng(256)) As Double
    i = 1
    While (i < 256 * CLng(256))
        sindata(i + 1) = Sin(i)
        sindata(i) = 0
        i = i + 2
    Wend


'myprocedure sindata(1, 1), 128, 256, 2, 1
myprocedure sindata(), 128, 256, 2, 1

0
 
RWlodarczykAuthor Commented:
Adjusted points to 200
0
 
RWlodarczykAuthor Commented:
The reason why anthonyc's answer is wrong is BAD PROGRAMMING! This array... sindata() may be in excess of 5 MB! You don't want to pass the entire array! You only want to pass the first element of the array, then, knowing the bounds of the array, you can locate any element in the array!
0
 
anthonycCommented:
so you are relying on VB to place all array elements next to one another?  now that's bad programming.

VB when using redim preserve... you are screwed.
0
 
RWlodarczykAuthor Commented:
I'm not using redim preserve...


0
 
anthonycCommented:
but if you are writing a general purpose dll.......nevermind
0
 
tomookCommented:
Did you try "As Any"?
0
 
cd74013Commented:
I will wade in with a possibility.

In your code you define the delphi type as
TYPE
   myarray = array of double;

an un bounded array definition, then .....
The procedure definition.....
PROCEDURE myprocedure (rob : myarray;
                       width, height : integer;
                       ndimen, isign : integer); stdcall;

If you compare it with the VB definition
Declare Sub myprocedure lib "delphidll.dll" (
          ByRef junk as double,
          ByVal wid as integer,
          ByVal hgt as integer,
          ByVal ndim as integer,
          ByVal isign as integer)

You are giving a reference to a double variable, rather than a double array.  You might try changing the first parameter to
ByRef junk() as double, also unfortunately languages have a tendancy to have different views on the definition of a type.  Hopefully the delphi type DOUBLE and the VB type DOUBLE are the same, especially in storage terms ( VB double is 8 bytes,  what is delphi?).  

Again verify the size of the delphi integer ( 2 or 4 bytes ) as the VB integer is only 2 (+/- 32768 ish ).  

From a long ago memory, pascal type languages ten to set up the stack in a weird way for un bounded arrays, often by putting the bounds of the array at the beginning of the array definition.  You might fiddle the whole thing by keeping the VB definition as a reference to a variable (rather than the array), then in the VB code that calls the delphi routine pass the FIRST element of the array ( as by ref it will pass the pointer to the array).

Well thats my 2cents worth.
0
 
RWlodarczykAuthor Commented:
double in VB is double in Delphi... that's been check before...

integer in VB is integer in Delphi.

Also, I pass only the first element of the array, because Delphi actually accepts it as a pointer to the array, and then it works with that...
0
 
tomookCommented:
Can you get a single double ;) value back, rather than an array? I would also be curious if using Dim rather than ReDim makes any difference.

VB should be using a SAFEARRAY internally. By referencing the first element, you should be getting the address of the data portion of the SAFEARRAY, as long as you are in-process. I don't see how your DLL could be out of process.

On the same note, if you want to pass the SAFEARRAY, you could use:
Dim lPtr As Long
lPtr = VarPtr(sindata)

and pass the pointer in as a long. Do you need the C definition of a SAFEARRAY?
0
 
RWlodarczykAuthor Commented:
The C definition would be good!

tomook --> I think your suggestion will work... It makes alot of sense... I'll try it and see.
0
 
tomookCommented:
typedef struct FARSTRUCT tagSAFEARRAY {
    unsigned short cDims;         // Count of dimensions in this array.
    unsigned short fFeatures;    // Flags used by the SafeArray
                                // routines documented below.
    unsigned long cbElements;    // Size of an element of the array.
                                // Does not include size of
                                // pointed-to data.
    unsigned long cLocks;        // Number of times the array has been
                                // locked without corresponding unlock.
    void HUGEP* pvData;                 // Pointer to the data.
    SAFEARRAYBOUND rgsabound[1];        // One bound for each dimension.
} SAFEARRAY;

Note that the last argument (rgsabound) will have one array element for each dimension of the array, so it will actually be rgsabound[2] in your case. The left-most dimension is rgsabound[0]. SAFEARRAYBOUND is defined as:
typedef struct tagSAFEARRAYBOUND {
    unsigned long cElements;
    long lLbound;
} SAFEARRAYBOUND;

Unless you want to manipulate the SAFEARRAY structure itself, you do not need to worry too much about rgsabound. I just want to reiterate that you may be able to pass it by declaring the argument "As Any", and using "sindata()" in the call. If not, VarPtr is an option, and you pass that as a long. Let me know how it turns out.
0
 
cd74013Commented:
One thing I noticed is that the definition of you call in delphi is a pass by value ( from my limited delphi knowledge ) in order for VB to populate back the values this should surely need the VAR keyword to allow the array to be passed by reference and hence the values placed into the memory by vb being available after return to delphi.

TYPE
   myarray = array of double;


PROCEDURE myprocedure (rob : myarray;
                       width, height : integer;
                       ndimen, isign : integer); stdcall;
or
PROCEDURE myprocedure ( VAR rob : myarray; etc


0
 
RWlodarczykAuthor Commented:
ok... but that does some funky stuff to the the array... I'll try it again though!

Thanks,

Rob.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 5
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now