Solved

Passing an array from Visual Basic to a Delphi DLL

Posted on 1998-07-26
19
501 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
  • 9
  • 5
  • 3
  • +1
19 Comments
 
LVL 4

Expert Comment

by:tomook
Comment Utility
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
Comment Utility
Edited text of question
0
 

Author Comment

by:RWlodarczyk
Comment Utility
Adjusted points to 185
0
 

Author Comment

by:RWlodarczyk
Comment Utility
Adjusted points to 195
0
 
LVL 4

Expert Comment

by:tomook
Comment Utility
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
Comment Utility
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
Comment Utility
Adjusted points to 200
0
 

Author Comment

by:RWlodarczyk
Comment Utility
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
Comment Utility
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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:RWlodarczyk
Comment Utility
I'm not using redim preserve...


0
 
LVL 6

Expert Comment

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

Expert Comment

by:tomook
Comment Utility
Did you try "As Any"?
0
 
LVL 1

Expert Comment

by:cd74013
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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 200 total points
Comment Utility
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
Comment Utility
ok... but that does some funky stuff to the the array... I'll try it again though!

Thanks,

Rob.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

771 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now