Calling Visual Basic code from Fortran - Anyone?

Calling Visual Basic code from Fortran - Anyone?

Hi,

I'veended up with a set of formulas originally coded in Visual Basic, that I now need to call from Fortran.

Anyone tried that?

Thanks in advance for any help...

Best regards,

8-) Egil

Egil Giertsen
Senior Research Scientist
Phone : +47 7359 2081
Telefax: +47 7359 2660
Mobile : +47 9305 8672
_____________________________
MARINTEK SINTEF GROUP
Department of Structural Engineering
Otto Nielsens vei 10
P O Box 4125, Valentinlyst
N-7450 Trondheim
NORWAY
_____________________________
http://www.marintek.sintef.no

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

That direction is a lot of work. What version of VB are you using? (And what version of Fortran?) I think the way you have to do it is create a .NET assembly in VB and use the Intel Fortran Module Wizard to create interfaces for it, but this is not sonething I have tried.

It might be a lot simpler to translate the function code to Fortran.

Steve

Steve, thanks for getting back to me on this.

Currently, I use quite old versions of Fortran (CVF v6.6) and VB (v6.0).

Hhmm, was a bit afraid about getting the "a lot of work" answer. I have thought about calling the VB code wrapped in a VB DLL from C/C++, and then call the C/C++ vrapper code from Fortran. I'm not sure, but I believe that might work. Any immediate thoughts?

I have also thought about recoding all formulas from VB to Fortran. Does anyone know about a VB to Fortran code translator? Not many of those I guess...

Egil

If you're using VB6, it may be less work. You should be able to call a VB6 DLL from CVF as long as you get the calling sequence right.

Steve

Steve,

I had a go at it, with the following test code:

VB (ActiveX DLL):
-------
Public Sub VBROUTINE(iop As Long)
iop = 5
End Sub
-------

Fortran (Console Application):
-------
program test
INTERFACE
SUBROUTINE vbroutine (iop)
!DEC$ ATTRIBUTES DLLIMPORT :: vbroutine
!DEC$ ATTRIBUTES ALIAS: '_VBROUTINE@4' :: vbroutine
INTEGER iop
END SUBROUTINE vbroutine
END INTERFACE
integer icode
icode = 0
CALL vbroutine (icode)
print*,'icode = ',icode
END
-------

I've added the VB generated DLL as a file to the project.

The CVF linker fails with the following message:
--------------------Configuration: CallingVBfromFortran - Win32 Debug--------------------
Linking...
CallingVBfromFortran.obj : error LNK2001: unresolved external symbol _VBROUTINE@4
Debug/CallingVBfromFortran.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
CallingVBfromFortran.exe - 2 error(s), 0 warning(s)

Hence, it is note able to get hold of the VB routine from the DLL.

Any idea?

Thanks in advance...

Egil

VB does not "decorate" its names. You'll have to analyze the DLL to see what name it has chosen. Dependency Walker is good for this.

Steve

Wait a minute, wait a minute. Unless I'm sadly and massively mistaken, you can't call VB DLL code like that. VB6 can only generate activex DLLs, not 'regular' DLLs like c/c++ or fortran. And an activeX DLL has to be instantiated as an object. If you were doing the calling in VB, it would be something like

dim something as object

set something=createobject("x.y")

where x and y were defined by the internals of the ActiveX. (Please ignore my bad memory of the syntax of creating ActiveX objects from vb, but the principle is correct.)Now you can't just do that in fortran with the syntax of using a normal DLL (i.e. an interface and a call). You've got to go the whole COM route, which is nasty stuff even in c++. You've got to initialize COM, something like ::CoInitialize(NULL); and on and on.

My current level of knowledge tells me there's no simple way: it's a long hard slog.

Yes, I've found out that you are basically right - but fortunately there is a workaround. After some searching I came across the following - quite great - article:
http://www.windowsdevcenter.com/pub/a/windows/2005/04/26/create_dll.html

Check it out - I've tested it from VB - works like a charm...

I will now try it out from Fortran.

Egil

Hi again!

As I mentioned in my previous post, I've managed to make a VB DLL, and to test it from a VB application. However, how do I make the proper reference to the DLL routines during linking, to avoid getting unresolved externals?

--------------------Configuration: CallingVBfromFortran - Win32 Debug--------------------
Linking...
CallingVBfromFortran.obj : error LNK2001: unresolved external symbol _SQUAREUC@4
Debug/CallingVBfromFortran.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
CallingVBfromFortran.exe - 2 error(s), 0 warning(s)

Thanks for any help...

Egil

See my previous post.

Steve

I wouldn't go that far. This secondary rehash is a vulgarization of John Chamberlain's article (+ VB addin) titled 'Compile Controller' that appeared in VBPJ in Nov 1999.

Check it out. I've been calling VB from Fortran since DVF days.

Gerry

I salute those who have created regular DLLs from VB... an impressive piece of work. I stand corrected, mind blown. I have googled for Chamberlain's article, finding only references, no actual text. Can anyone produce a valid link, or upload it?

Hi again,

Sorry about this, but I'm still struggling with getting the naming of the routines in my Fortran INTERFACE block to match the exported routine in my Visual Basic (VB) generated DLL.

When using DependencyWalker on the VB generated DLL, the exported names seems to be straightforward and as expected. I've then added the .lib file generated together with the DLL to my Fortran project, but when linking the Fortran test program the routines which shouldbe inthe VB DLL are reported asundefined.

Using the same approach with a Fortran generated DLL works fine.

Am I missing something obvious? Any help is deeply appreciated...

What is the best way of inspecting the .lib file generated with a DLL?

Thanks,
Egil

For more help, you must list here a)the EXACT names of the routines EXPORTed by your DLL, and b) list yourFortran DLLIMPORT and other compiler directives in your Fortran INTERFACE blocks for the routines you wish to import.

Use DUMPBIN to get a list of EXPORTS

(please delete, multiple post )

Hi,

DUMPBIN /EXPORTS on my VB DLL gives the following output:

============
Microsoft COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

Dump of file MathDLL.dll

File Type: DLL

Section contains the following exports for MathDLL.dll

0 characteristics
468CAAB3 time date stamp Thu Jul 05 10:24:19 2007
0.00 version
1 ordinal base
9 number of functions
9 number of names

ordinal hint RVA name

1 0 00001AF0 Decrement
6 1 00001966 DllCanUnloadNow
7 2 0000193A DllGetClassObject
2 3 00001990 DllMain
8 4 00001950 DllRegisterServer
9 5 00001924 DllUnregisterServer
3 6 000019B0 Increment
5 7 00001C30 Square
4 8 00001D90 Square2

Summary

1000 .data
1000 .reloc
1000 .rsrc
2000 .text
============

My Fortran test program source code is as follows:

============
program test

INTERFACE
SUBROUTINE Square2 (ivar1)
!DEC$ ATTRIBUTES DLLIMPORT :: Square2
!DEC$ ATTRIBUTES ALIAS : '_SQUARE2@4' :: Square2
integer ivar1
END SUBROUTINE Square2
END INTERFACE

INTERFACE
SUBROUTINE FortranDLL (ivar2, rvar2)
!DEC$ ATTRIBUTES DLLIMPORT :: FortranDLL
!DEC$ ATTRIBUTES ALIAS : 'FortranDLL' :: FortranDLL
integer ivar2
double precision rvar2
END
END INTERFACE

integer nmb

integer i1
double precision r1

nmb = 4

print*,'Before Square: nmb = ',nmb
call Square2 (nmb)
print*,'After Square: nmb = ',nmb

i1 = 4
r1 = 3.14159e2

print*,'Before FortranDLL'
call FortranDLL (i1, r1)
print*,'After FortranDLL'

pause

END
============

During linking I get the following error message:
CallingVBfromFortran.obj : error LNK2001: unresolved external symbol _SQUARE2@4

As you can see I've tried to add alias definition to the INTERFACE, without success.

Thanks,

Egil

Not surprising - as shown in the output you posted, the name of the routine in the DLL is "Square2", not _SQUARE2@4". VB does not apply the usual STDCALL decoration rules.

Steve

You now have a VB DLL with unmangled exports, except for FortranDLL. You don't need to use !DEC$ metacommands in writing the interfaces. See the IVF Samples on how to access a classic DLL, as is your VB DLL,from C/Fortran/VB. You'll need to use the Win API to load the, resolve its exports, and free the DLL when you're done.

Gerry

Steve,

This Wizard sounds exciting.

Please try to create a simple sample of Fortran using VB.NET or C#, for I have the follwoing issue in Visual Studio 2005.

The issue seems to be simple to define:

1. Visual Studio VB and C# projects can use other VB and C# projects.

2. Visual Studio VB and C# projects can use other FORTRAN projects.

3. Visual Studio FORTRAN projects can use other FORTRAN projects.

4. Visual Studio FORTRAN projects cannot use other VB and C# projects.

Was this an oversight? Will th Wizard fix it?

Thanks,

Norm

The Module Wizard handles your item #4. It is not an oversight. I'll try to work up an example, though I'm not experienced at VB or C#.

Steve

Assuming your VB dlls is not exposing the code you want to call inside objects, I would personally try and do a LoadLibrary call on it to load it. You can then call GetProcAddress to get the function address, and there is a way to do that using the function ordinal (shown in dumpbin) rather than the name, btw.

We dynamically load DLLs (havent tried VB) and call into them this way and it works fine.

Just make sure you declare your Fortran prototype to be compatible but judging on the mangled name I doubt you have complex arguments. Also, you may have to try a few different calling conventions to get the right one.

Alternatively (and maybe cleaner) create a simple little COM wrapper around the DLL (you can quickly create a COM wrapper using the activescript wizard etc.). Then create an instance of the COM object and call into that. If you have trouble doing that from Fortran code, you can link in a little C code to do and easily call the C code from Fortran.

Sadly, none of this will work with a VB DLL which is a COM thingy or ActiveX DLL as opposed to a classic DLL with exports that can be gotten at via GetProcAddress. So you have to use COM protocol with the assistance of the Module Wizard or figure out how to change an ActiveX DLL into a classic DLL as discussed earlier in this thread.

Gerry

Quoting - Steve Lionel (Intel)
The Module Wizard handles your item #4. It is not an oversight. I'll try to work up an example, though I'm not experienced at VB or C#.

steve, if you decide to do this example, I now have working code that calls (hardcoded) VB2008 scripts from both C++ and Fortran (both using the COM interface, which for C++ comes naturally but for Fortran has to be extracted using the Wizard).

It took me a while, but its pretty neat! I am quite sure the C# version could be worked out realtively easily by analogy.

I will try to document it better and post it (maybe as some kind of short knowledge-base article? this forum has been very helpful for me and so would be nice to contribute something back if its deemed useful).

The whole experience with writing the VB/C++/Fortran connections was rather instructive! I do wish there was some way of learning this more or less systematically rather than by trial and error. Are these matters subjects of any courses, or books? or is the subject too fast-developing for the written word? I certainly found the VB conventions changed sugnificantly over the last few years so some of the "help files" were more like "confusion files" ..

We would be delighted to have you write an article for our Knowledge Base with examples. Let me know how I can help.

Steve

Quoting - Steve Lionel (Intel)
We would be delighted to have you write an article for our Knowledge Base with examples. Let me know how I can help.

Hi Steve,

I sent you a 'message' a couple of days ago - just wondering if it got thru as I had some difficulties making it work... I also tried to attach a very rough draft with a working example. Let me know if its of worth continuing..

thanks,
d

I don't get email when private messages arrive, so I didn't see it. Unfortunately, attachments don't work in private messages. Please attach the ZIP to a reply here and I'll be glad to look at it.

Steve

Quoting - Steve Lionel (Intel)
I don't get email when private messages arrive, so I didn't see it. Unfortunately, attachments don't work in private messages. Please attach the ZIP to a reply here and I'll be glad to look at it.

Hi Steve,
see attached. Its rather rough but the example works - I thought I'd let you see it before trying to do much more.
cheers,dmitri

Attachments: 

Quoting - forall

Hi Steve,
see attached. Its rather rough but the example works - I thought I'd let you see it before trying to do much more.
cheers,dmitri

cant seem the get the attachment working here either ...

Attachments: 

Got it - thanks.

Steve

Hi Steve,

just wondering if you had a chance to have a look at the files and have any feedback?

cheers,

d

While Steve will give you an expert's feedback, this has been quite helpful to me. I encapsulated it in a module and can call any COM object I created using VB.

Currently I am struggling with passing arrays "from" Fortran "to" VB and on keeping the VB form "alive" even after the Fortran program quits. I need to figure out my way through the safe-array business for the former while the latter has stumped me quite a bit.

Abhi

Sorry, have not had cycles for this. I have not forgotten you.

Steve

Sorry to drag up an old topic, but I am having the same issue and I didn't see the resolution in this forum. I have a DLL, created in VB6 with the functions I want exported, that I need to link into my Fortran code. I can see the functions I want in the dumpbin output and I have created a DEF file, and used that to create a LIB file that I put into my project, but I still get a linker error of unresolved external symbols. Any ideas?

Thanks!

Attachments: 

AttachmentSize
Download VB_DLL_Test.zip31.42 KB

You cannot link to a VB DLL - or any DLL. The linker requires an "export library" (.LIB) which VB does not create.

If you want to call a routine in a DLL without an export library, you need to use LoadLibrary and GetProcAddress as demonstrated in the sample DLL\DynamicLoad

Steve

Created a new console project with the .F90 and the LIB added to the project.
DUMPBIN on the .LIB shows symbols with leading underscores.
Correcting the ALIAS to show this allows me to compile and link.
Registered the DLL and added it to C:\WIndows\system32\ so that it could be found.
Program runs but crashes with access error on the call to PrintTiltlesName
Can you show your Visual Basic function prototype declarations?

Thank you, I guess I should have seen that but couldn't.

I think the crash is related to passing a string into the DLL. Do I need to do this as a safearray? Or a BSTR pointer?

Private Declare Function ApplyNNet Lib
"NNetApply.dll" (MyNNetType As String, MyAddress As String, MyInput()
As Double) As Variant

Private Declare Sub PrintTitlesName Lib
"NNetApply.dll" (MyAddress As String)

Passing strings from VB to a Fortran DLL I can do. Getting a string back from a Fortran DLL I can do also.
Going the other way is a real pain. Strings are horrible compard to integers, reals etc.

You want to 'send' a string from Fortran to VB. This means that the memory location (buffer) for the string is allocated on the Fortran side so you need to send the address of the start of that buffer to VB. If VB needs/assumes/stores strings a BITSTRINGS, then you would be wise to cast your character string on the Fortran side as a BITSTRING. There are functions available that do this which will give you a pointer (address) to the BITSTRING. Then all you need to do is pass this pointer to VB.

I find that dealing with adresses makes it easier to see what's happening in memory.
I would try making MyAdress ByRef for a start (and make the argument the pointer with a VALUE attribute on the Fortran side), then post a new DLL. Can you supply a Debug version for test purposes?

P.S. What does PrintTitlesName do?
Can you arrange for the function to display a message box showing what turns up as the argument?

Login to leave a comment.