CVF callback to VB.NET

CVF callback to VB.NET

I have managed to get a callback froma cvf dll to a "Delegate Sub" in a VB.net driver program. HoweverI have only managed to get single variables working. When I try a simple integer array, everything goes well untilthe callback subroutine in the cvf dll calls the "Sub" in the vb code. Only the first element of the array makes it to the vb sub (In fact in the VB Sub, the array is of length one).

No crash happens and the code executes normally.

Has anybody managed to do what I am attempting successfully?

Regards,
Denis

14 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

The approach you're suggesting won't work. VB5/6 and VB/C#.NET DLLs don't expose their exports. A 3rd party product SpyWorks.COM/NET has a utility that implements an interface in VB.COM/NET or C#.NET and generates an unmanaged conduit DLL that accesses whatever functionality you want to export from VB or C#. Now CVF or IVF can call your VB or C# exports. SpyWorks costs ~U$750.

HTH,
Gerry T.

Gerry, I don't think Denis is doing what you describe -- I read that he has a plain vanilla Fortran dll called by VB, and passes a VB routine as a callback using AddressOf or like (whereby it acts as an EXTERNAL dummy argument from Fortran's viewpoint). IMO that's doable provided the callback has the right interface (and is unmanaged) and is called in the right way. However, he should provide more info and code fragments so that we could see what could be wrong.

Jugoslav

Jugoslav
www.xeffort.com

Thanks gentlemen for your replys.

Firstly, this callback process does work, but only for single variables. I cannot get arrays to pass back to the delegate function form the dvf DLL.
The fortran dll is:-

Subroutine CallBack( a, n, m, f )
! Expose subroutine CallBack to users of this DLL
!DEC$ ATTRIBUTES DLLEXPORT :: CallBack
!DEC$ ATTRIBUTES ALIAS:'CallBack' :: CallBack
Integer, Intent(IN) :: n
Integer, Intent(IN) :: a(n)
Integer, Intent(OUT) :: m
Integer :: f

m = f( n, a )

Return
End Subroutine CallBack
get arrays to pass back to the delegate function form the dvf DLL.
TheVB.NET code is:-

Module Module1

Public Delegate Function FPtr(ByRef n As Integer, _
ByVal a() As Integer) As Integer
Public Class LibWrap
Declare Sub CallBack Lib _
"e:CalrelTestFortranDLLDebugTestFortranDLL.dll" _
(ByVal a() As Integer, _
ByRef n As Integer, _
ByRef m As Integer, _
ByVal f As FPtr)
End Class

Private Function DoSomething(ByRef n As Integer, _
ByVal a() As Integer) As Integer
Dim i, j As Integer
For i = 0 To a.GetUpperBound(0)
j = j + a(i)
Next
Return j
End Function

Sub Main()
Dim a(), n, b As Integer
n = 10
ReDim a(n - 1)
Dim f As FPtr
f = AddressOf Module1.DoSomething
Dim i As Integer
For i = 0 To a.GetUpperBound(0)
a(i) = a.GetUpperBound(0) - i + 1
Next
LibWrap.CallBack(a, n, b, f)
MessageBox.Show(b.ToString)
End Sub

End Module

These codes actually work - no crashes or errors! I have debugged both the VB.NET and Fortran. The problem is the call f(n,a) to the delegated VB function DoSomething. Only the first element of the array gets through.

I suspect that I may need to use DVF pointers (not F90 pointers!).

Hopefully you can help me.

Denis

I don't know about VB.NET much to tell you what exactly you should do. Also, I usually don't reply when I don't have much to contribute, but I made an exception this time, because I can spot what's wrong:

For i = 0 To a.GetUpperBound(0)

There's no way that a.GetUpperBound() information can be preserved. I suspect that VB uses the same mechanism like Fortran assumed-size arrays, i.e. passes only address of first element of an array. If DoSomething were written in Fortran, e.g.

Code:

subroutine DoSomething(n, a)
integer, intent(in):: n
integer, intent(in):: a(*)

do i = 1, UBOUND(a)

You would get a compile-time error saying that you can't get UBOUND of an assumed-size array. (Error: Upper Bound of array is not computable). I assume the VB works the same way -- thus, you either need to declare Dim A(n) or just run the For loop from i=0 to n-1. (I don't knowwhich is allowed byVB syntax, but my point is that you have to pass the size information separately, as you did -- you just didn't use it).

Jugoslav

Jugoslav
www.xeffort.com

I agree with Jugoslav's comments including his clarification for me re your use of AddressOf.

What happens if you replace

LibWrap.CallBack(a, n, b, f)

by

LibWrap.CallBack(a(0/1), n, b, f)?

In VB a is 0-based whereas in Fortran it's 1-based.

Good Luck,

Gerry T.

Thanks for all your efforts and i have tried them all (some of them I had tried before I posted this). I'm afraid that I still am not successful.

The problem is not with the with the call to "CallBack" in the dll (a gets through fine). It's the line
m = f( n, a )
When It gets to the delegated DoSomething in VB, only the first element of "a" gets through. Even ReDimensioning a does not work: the 9 other elements are still missing. Andonce "CallBack" is finished in the VB program, the "a" is perfect subsequently.

I have also succeeded in using the dvf pointer but got exactly the same results.

What really annoys me is that it works for single variables. There is an example with dvf that passes strings: thats where I got the pointer idea. However that example uses ConvertStringToBSTR andthis is stuff I know little about.

So thanks again for all your efforts. If I have an inspired idea, I'll post the solution up!
Regards,
Denis

But what happens if you simply use

For i = 0 Ton
j = j + a(i)
Next

?

Jugoslav

Jugoslav
www.xeffort.com

Denis, I don't know much about this callback mechanism but I use to use ByVal only for string variables. Have you tried ByRef for a in your DoSomething declaration?

Sabalan.

Jugoslav, I have tried that. in fact it was the first thing I tried. After many years of writing code, when things don't work, I reduce the number of unknowns and when I get the simple working, I then add the complexity!

Sabalan, ByRef does not work with arrays. I have never quite undestood the reason, but I have written alot of VB.NETfront-endsfor Fortrancode (no callbacks, just calling Fortran functions) and single variables are ByRef and arrays ByVal. It throws a runtime error if you use the wrong option.

I thought this was going to be easy: that there was somebody out there who had already done this!
Every day is a school day!

Denis,

May be I don't get the question but I doubt that you need ByVal for arrays in VB declaratin. I think that the problem is a missing STDCALL in your DLLEXPOT.

The following works for me in VB 6.0 and it should work in Vb.Net too:

Make a form with a command button and a text box in VB, add a module with this declaration:

Declare Sub DLLInOut Lib "MyDLL.dll" (ByVal FileName As String, MyArray As Long)

Paste the following code in the code window of the form:

Dim FileName As String * 512, MyArray(1 To 100) As Long
Private Sub Command1_Click()
On Error Resume Next
FileName = UCase("C:TempHello.txt")
Call DLLInOut(FileName, MyArray(1))
Text1.Text = MyArray(50)
End Sub

Make a Fortran DLL called MyDLL with the following code:

SUBROUTINE DLLInOut(FileName, MyArray)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: DLLInOut
!DEC$ ATTRIBUTES ALIAS : 'DLLInOut' :: DLLInOut
!DEC$ ATTRIBUTES REFERENCE:: FileName
Implicit None
Integer I, MyArray(100)
Character*512 FileName
Do I = 1, 100
MyArray(I) = I
End Do
Open (1, File=Trim(FileName))
Write (1,'(A)') ' *** Hello world! ***'
Close(1)
End

Compile and run. You are going to see 50 in the text box.

Sabalan.

Iwanted to try your code, but alas 1) my Visual Basic 6 (never used) crashes at startup 2)I don't have VB in myVS.NET and 3) VS.NET installation CDs are in another office.

I checked ByVal for arrays in MSDN, and you're right -- it'shas a differentsemantics than "scalar"ByVal. Namely, ByVal for arrays roughly corresponds to Fortran DIMENSION(*), while ByRef corresponds to POINTER, DIMENSION(:).

If you put in the tests for AddressOf(a) / LOC(a) throughout the code, do they produce the same result in all three routines involved?

Jugoslav

Jugoslav
www.xeffort.com

One more thing, Denis: for INTEGER at Fortran side, you have to have LONG on the VB side.

Sabalan.

In the early days when MS introduced AddressOf into VB5 they gave the following caution:

"...additional care must be taken with regards to what code can be executed within the callback function. Any use of the following within the callback function may cause undesirable results:

File I/O.
Error handling.
Fixed size arrays.
Set statements.
COM method calls that return HRESULTs (such as any Visual Basic ActiveX object).
Declare calls.
Global objects such as the Application object.
Most of the Visual Basic run-time files."

ASAIK, MS haven't recinded these remarks even for VB.NET.
Personally I use AddressOf within VB for hooking, subclassing, and the like, but for exVB usage, I export the functionality. However, YMMV.

Ciao,
Gerry T.

Leave a Comment

Please sign in to add a comment. Not a member? Join today