Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Passing an array from Visual Basic to a Delphi DLL

Posted on 1998-07-26
19
Medium Priority
?
524 Views
Last Modified: 2013-11-25
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
Comment
Question by:RWlodarczyk
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 5
  • 3
  • +1
19 Comments
 
LVL 4

Expert Comment

by:tomook
ID: 1466731
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
 

Author Comment

by:RWlodarczyk
ID: 1466732
Edited text of question
0
 

Author Comment

by:RWlodarczyk
ID: 1466733
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.

 

Author Comment

by:RWlodarczyk
ID: 1466734
Adjusted points to 195
0
 
LVL 4

Expert Comment

by:tomook
ID: 1466735
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
 
LVL 6

Expert Comment

by:anthonyc
ID: 1466736
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
 

Author Comment

by:RWlodarczyk
ID: 1466737
Adjusted points to 200
0
 

Author Comment

by:RWlodarczyk
ID: 1466738
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
 
LVL 6

Expert Comment

by:anthonyc
ID: 1466739
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
 

Author Comment

by:RWlodarczyk
ID: 1466740
I'm not using redim preserve...


0
 
LVL 6

Expert Comment

by:anthonyc
ID: 1466741
but if you are writing a general purpose dll.......nevermind
0
 
LVL 4

Expert Comment

by:tomook
ID: 1466742
Did you try "As Any"?
0
 
LVL 1

Expert Comment

by:cd74013
ID: 1466743
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
 

Author Comment

by:RWlodarczyk
ID: 1466744
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
 
LVL 4

Expert Comment

by:tomook
ID: 1466745
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
 

Author Comment

by:RWlodarczyk
ID: 1466746
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
 
LVL 4

Expert Comment

by:tomook
ID: 1466747
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
 
LVL 1

Accepted Solution

by:
cd74013 earned 800 total points
ID: 1466748
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
 

Author Comment

by:RWlodarczyk
ID: 1466749
ok... but that does some funky stuff to the the array... I'll try it again though!

Thanks,

Rob.
0

Featured Post

Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses

650 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question