Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Calling C(++) DLLs from Fortran

kenwhit
Beginner
922 Views
Some of your contributions are close to my problem, but do not cover it entirely. I want to run a Pico Technologies ADC 212 (an analogue to digital converter) from Fortran/Winteracter. Pico supply drivers for VC and VB, but not the source code of course. I tried the CVF sample LoadExp1 which works of course. I substituted the variables from the example with variables from the Pico dll. The loadlibrary function worked, but I have been unable to make the getprocaddress function to work. I therfore resorted to trying to insert the addresses via the library routine supplied by Pico (for C(++)). After apparent success with a trial function, I coded for most of the functions of initialisation etc. After some experimentation, I am in the position of being able to measure a voltage temporarily. After this stage the stack has clearly lost the return address and the programme hangs. If I do checks at various stages inserting RETURNs, it has clearly lost the return address after about 4 function calls. I think my problem lies in the possible confusion between addresses and values, despite careful attention to the Interfaces. If I insert diagnostic Write(*,*) lines the results are bizarre and unpredicatable, but usually terminated by an Error 157. I am aware of the problems of passing parameters by value or by reference and I have tried to make the interface do the same as the VB example. I feel that there may be some simple compiling or linking parameter which is eluding me. If there is interest in the problem, I could expand on some of the details and perhaps send some source code.
0 Kudos
5 Replies
Jugoslav_Dujic
Valued Contributor II
922 Views
If GetProcAddress fails, the most likely reason is that you misspelled the routine name. You should open the dll in "Dependency walker" and see what are the exact exported names (case matters!). Only when you get the GetProcAddress working, then we can talk about correct argument passing and calling convention.

Jugoslav
0 Kudos
kenwhit
Beginner
922 Views
Thank you for making such a prompt reply. It is very helpful to have someone to explain to rather than just a screen. I have appended some source code to help explain what I am doing. ADC212 is the programme which fails to pick up the process address. The ATTRIBUTES line is to force Fortran to send the process name as is rather than converting to upper case. The name is all lower case and this is how it appears when one inspects the binary code of the .dll. The same name does succeed in ADC212A which is linked with the library file supplied by Pico. I had hoped to use the run-time dynamic linking approach as this has one fewer file to raise doubts about compatibility and in any case this is how the Visual Basic programme works. The MSDN note on this procedure appears to anticipate that it might fail. Eventually I hope to go back to this. The actual API call is of course the compiled Fortran version and it might be necessary to investigate its compatibility. ADC212A is a simple programme which is linked with the adc200ms.lib and uses an interface for this particular procedure. The actual procedure used is a simple one which checks the driver version number which resides in the adc200.sys file installed in Windows. I am now writing a simplified Fortran console programme to investigate the other function calls. This has no subroutines to complicate the situation and will be easier to use with Debug. It is already showing bizarre results, depending on where or if one inserts a Write statement.
0 Kudos
kenwhit
Beginner
922 Views
Addendum
0 Kudos
Jugoslav_Dujic
Valued Contributor II
922 Views
For the start, you don't need the ALIAS in the interface statement. INTERFACEd routines with cray-pointers (routine pointees) are just "placeholders" for something that will be assigned later, in run-time (by GetProcAddress and assignment to q). Thus, you can name it just "Foo" in the interface statement (and CALL Foo once you bind it).

Instead, you need the full decorated name here:
q = getprocaddress(p, "_adc_200_get_driver_version@0"C)

I didn't look at the rest of the code; hope this helps.

Jugoslav
0 Kudos
kenwhit
Beginner
922 Views
Thank you. I will look at that. As far as the more important problem of bizarre results when printing or referencing results, I seem to have resolved this by changing the Attributes from C to STDCALL. The different responsibilities for handling the stack seem to have resolved the problem.
0 Kudos
Reply