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

Calling a dll made with Fortran by C

patuco
Beginner
7,020 Views
Hi,
i am getting crazy tying to find out where or why is teh problem in the program I'm doing. If someone could help me, it would be great.
Ill explain you my problem:
i am doing some test to try out how the jni of javaworks. i implemented a dumy program which only purpose is to call a Frotran dll which has to show on the screen the typical Hello world. I did the C++ wrapper using the visual studio .net. Ive already accomplished the communication between the wrapper and Java. in a second stage I try to do the same but with the wrapper calling the fortran dll, and here is where the problems occur: the function called by the wrapper located in the fortran dll is not "found":
ReadValue error LNK2019: smbolo externo _PRINTER@0 sin resolver al que se hace referencia en la funcin "long __stdcall Java_ReadValue_getValue(struct JNIEnv_ *,class _jobject *)" (?Java_ReadValue_getValue@@YGJPAUJNIEnv_@@PAV_jobject@@@Z)
The Fortran code is as follows:
INTEGER FUNCTION PRINTER()
!decs attributes c :: PRINTER
!MS$ATTRIBUTES DLLEXPORT,STDCALL,ALIAS:'PRINTER'::PRINTER
WRITE(6,'("-- FORTRAN funcion printer --")')
PRINTER=2
END
as you can observed is quite obvious.
So as the wrapper:

#include "stdafx.h"

#include "stdio.h"

#include "ReadValue.h"

#include "jni.h"

extern "C" __stdcall int PRINTER();

// i even try with : extern "C" __cdecl int PRINTER();

JNIEXPORT jint JNICALL Java_ReadValue_getValue(JNIEnv * env, jobject jobj)

{

printf("-- A ver si funciona la referencia -- ");

int result = PRINTER();

printf(" -- valor de retorno ke leyo del archivo -- ",result);

return result;

}

Anyone can help me?? Thanks.

0 Kudos
78 Replies
patuco
Beginner
1,802 Views

just a dummy question about your implementation:

i suppose it is neccesary to define the parameter iLen as integer isnt it?

SUBROUTINE GETNAME(VAL, ARRAKY, iLen)
!MS$ATTRIBUTES DLLEXPORT,C,ALIAS:'_Getname'::GETNAME
!MS$ATTRIBUTES REFERENCE:: Arraky
INTEGER val, iLen
CHARACTER(iLen) ARRAKY

i comment it cuz im trying the suggestion and teh compiler is asking me for the iLen (I am using the Microsoft Developer Studio, as you said a couple years old).

After adding teh decalration of the iLen:

SUBROUTINE GETNAME(VAL, ARRAKY,LEN)
!MS$ATTRIBUTES DLLEXPORT,C,ALIAS:'_Getname'::GETNAME
!MS$ATTRIBUTES REFERENCE :: ARRAKY
INTEGER VAL,LEN
CHARACTER (LEN) ARRAKY
ARRAKY= "ayudaaaaaaa"
ARRAKY= TRIM(MOLECULE(VAL))//CHAR(0)
WRITE(*,*) LEN(ARRAKY)
WRITE(*,*) "The ARRAKI is ", ARRAKY
END SUBROUTINE GETNAME

and compiling the result is:

Compiling Fortran...
E:Proyectofortranmlvginterface_get.for
Assertion failed: ch_len != NULL, file err_genex.c, line 3741

abnormal program termination
Error executing fl32.exe.
mlvg.dll - 1 error(s), 0 warning(s)

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,802 Views
Len argument is not necessary, but you have to give the string length one way or another. It looks like a compiler bug works fine on my CVF 6.6C.

Which compiler is it, by the way "Microsoft Developer Studio" is not the compiler but the IDE? You should see the CVF version on Help/About legitimate versions can be 5.0, 5.0D, 6.0, 6.1 etc.
0 Kudos
patuco
Beginner
1,802 Views

First of all, gracias, it is working but ill show you something strange right now. Thanks you guys for your help.

ok the code which is working on my comp. is as follows:

SUBROUTINE GETNAME(VAL, ARRAKY, i_Len)
!MS$ATTRIBUTES DLLEXPORT,C,ALIAS:'_Getname'::GETNAME
!MS$ATTRIBUTES REFERENCE :: ARRAKY
INTEGER VAL, i_Len
cCHARACTER(i_Len) ARRAKY not working!!!
CHARACTER(48) ARRAKY
ARRAKY="working?"
ARRAKY= TRIM(ARRAKY)//CHAR(0)
WRITE(*,*) LEN(ARRAKY)
WRITE(*,*) "The ARRAKI is ", ARRAKY
END SUBROUTINE GETNAME

the wrapper:

const int i = 48;

int parameter = param;

char buf;

printf("--C-- buffer: %s ",buf);

Getname(param,buf, i);

printf(" -- C --Returnbuf: %s ", buf);

jstring jstrBuf = env->NewStringUTF(buf);

return jstrBuf;

output:

--C --buf: //only rubbish
48
The ARRAKI is working?
-- C --Returnbuf: working?
JAVA value:
working?

so as you can observed it works because of the same value of teh length of the array. I think it is necessary but how to pass it, i do not know yet, but i will make a couple of tests, and i let you know what happend. If you have any dea how can be used the last parameter, let me know, I am really far from what you know.

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,802 Views
buf = " ";
doesn't do the "obvious" thing in C. You need strcpy(buf, "Whatever"); instead.

As for the length problem, try passing Len by reference (int* + DEC$ATTRIBUTES reference) maybe that will "cheer up" the compiler ;-).
0 Kudos
patuco
Beginner
1,802 Views

Hi,

i was thinking about the implementation of the code im using and im considering the idea of changing the calls, i mean instead of using the format:

extern

"C" __declspec(dllexport) void Initapp();

use the stdcall, but i do not know how to do and how it will affect the fortran calls, specially the function described before, the one which returns the char *.

Any suggestion?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,802 Views
There is no compelling reason for a change, other than (as far as I know) stdcall is callable from Visual Basic while cdecl is not.

The change will (erm, should) not affect how arguments are passed; !DEC$ATTRIBUTES STDCALL and C have very similar semantics. All you have to do is to change ALIASes to include appropriate @n suffixes and use __stdcall on C++ side.

Please read the CVF help page on !DEC$ATTRIBUTES carefully. I find the semantics and order of application of attributes confusing (as you saw, string-passed-by-value got myself confused as well; For what it's worth, I filled in a "feature request" for a change of the behavior), but most of it is heritage from PowerStation from 1994. or so.
0 Kudos
patuco
Beginner
1,802 Views

Hi again,

there is an error i have no idea what is mean and why it is produced after checking the libraries with the dependancy walker. It happens both stdcall or c libraries declarations

Anyone any idea?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,802 Views
Simply, it can't find msjava.dll. On my computer, it is located in C:WindowsSystem32, but I think it doesn't come by default with the system anymore.

http://www.microsoft.com/mscorp/java/faq.asp

They don't seem to support Microsoft VM for Java anymore as a part of the deal with Sun. You can still find the package lurking around on the internet, but apparently not on MS website:

http://www.google.co.uk/search?q=msjavx86.exe&start=0&ie=utf-8&oe=utf-8
0 Kudos
patuco
Beginner
1,802 Views

Hi again,

i hava a question really strange for me.

I have a fortran code as dllwhich is using this, i think to show the line:

2001 FORMAT(1X,76('*'),/,
1 ' chain = ',A24,/,
1 ' Mua = ',1PG10.4,' D',/,
1 ' Mub = ',1PG10.4,' D',/,
1 ' Muc = ',1PG10.4,' D',/,
1 ' COLUMN DENSITY = ',1PG10.4,' CM-2'/,
2 ' KINETIC TEMPERATURE = ',1PG10.4,' K',/,
2 ' ETL TEMPERATURE = ',1PG10.4,' K',/,
3 ' H2 VOLUME DENSITY = ',1PG10.4,' CM-3',/,
4 ' LINEWIDTH = ',1PG10.4,' KM/S',/,
5 ' HELIUM ABUNDANCE = ',1PG10.4,/,
6 ' STAR RADIUS AND TEM.= ',1PG10.4,' CM ;',4X,1PG10.4,' K',/,
8 ' SHELL RADIUS = ',1PG10.4,' CM ;',
8 ' DILUTION FACTOR = ',1PG10.4,/,
8 ' EPSILON-1 = ',0PF10.5,/,
9 ' ROTATIONAL LEVELS = ',I6,'; VIBRATIONAL LEVELS = ',
1 I2,' == ',I5,' RAD. TRANSIT.',/,
1 1X,76('*'))


I am calling it with the wrapper.dll and i was expecting to become some message in the command window but nothing becomes, i do not know and understand why.

Could help me?

0 Kudos
patuco
Beginner
1,802 Views

Hi again,

i hava a question really strange for me.

I have a fortran code as dllwhich is using this, i think to show the line:

2001 FORMAT(1X,76('*'),/,
1 ' chain = ',A24,/,
1 ' Mua = ',1PG10.4,' D',/,
1 ' Mub = ',1PG10.4,' D',/,
1 ' Muc = ',1PG10.4,' D',/,
1 ' COLUMN DENSITY = ',1PG10.4,' CM-2'/,
2 ' KINETIC TEMPERATURE = ',1PG10.4,' K',/,
2 ' ETL TEMPERATURE = ',1PG10.4,' K',/,
3 ' H2 VOLUME DENSITY = ',1PG10.4,' CM-3',/,
4 ' LINEWIDTH = ',1PG10.4,' KM/S',/,
5 ' HELIUM ABUNDANCE = ',1PG10.4,/,
6 ' STAR RADIUS AND TEM.= ',1PG10.4,' CM ;',4X,1PG10.4,' K',/,
8 ' SHELL RADIUS = ',1PG10.4,' CM ;',
8 ' DILUTION FACTOR = ',1PG10.4,/,
8 ' EPSILON-1 = ',0PF10.5,/,
9 ' ROTATIONAL LEVELS = ',I6,'; VIBRATIONAL LEVELS = ',
1 I2,' == ',I5,' RAD. TRANSIT.',/,
1 1X,76('*'))


I am calling it with the wrapper.dll and i was expecting to become some message in the command window but nothing becomes, i do not know and understand why.

Could help me?

0 Kudos
patuco
Beginner
1,802 Views

Hi again,

i hava a question really strange for me.

I have a fortran code as dllwhich is using this, i think to show the line:

2001 FORMAT(1X,76('*'),/,
1 ' chain = ',A24,/,
1 ' Mua = ',1PG10.4,' D',/,
1 ' Mub = ',1PG10.4,' D',/,
1 ' Muc = ',1PG10.4,' D',/,
1 ' COLUMN DENSITY = ',1PG10.4,' CM-2'/,
2 ' KINETIC TEMPERATURE = ',1PG10.4,' K',/,
2 ' ETL TEMPERATURE = ',1PG10.4,' K',/,
3 ' H2 VOLUME DENSITY = ',1PG10.4,' CM-3',/,
4 ' LINEWIDTH = ',1PG10.4,' KM/S',/,
5 ' HELIUM ABUNDANCE = ',1PG10.4,/,
6 ' STAR RADIUS AND TEM.= ',1PG10.4,' CM ;',4X,1PG10.4,' K',/,
8 ' SHELL RADIUS = ',1PG10.4,' CM ;',
8 ' DILUTION FACTOR = ',1PG10.4,/,
8 ' EPSILON-1 = ',0PF10.5,/,
9 ' ROTATIONAL LEVELS = ',I6,'; VIBRATIONAL LEVELS = ',
1 I2,' == ',I5,' RAD. TRANSIT.',/,
1 1X,76('*'))


I am calling it with the wrapper.dll and i was expecting to become some message in the command window but nothing becomes, i do not know and understand why.

Could help me?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,802 Views
That's a format statement. I can't conclude anything from it. Is there a related WRITE statement?

If the C application is not a console-based one, you won't get a command window at all. In that case, you can create one using AllocConsole() function (USE DFWIN).
0 Kudos
patuco
Beginner
1,802 Views
yes you areright,my bad, i forgot to include the wirte statement:
WRITE(IUNIT,2001)MOLEC,
1MUA,MUB,MUC,
1CODE_CAPA,TK,TETL,NH2,VEXP,...
I have already thyed changing the IUNIT for *
2001 FORMAT(1X,76('*'),/,
1 ' chain = ',A24,/,
1 ' Mua = ',1PG10.4,' D',/,
1 ' Mub = ',1PG10.4,' D',/,
1 ' Muc = ',1PG10.4,' D',/,
1 ' COLUMN DENSITY = ',1PG10.4,' CM-2'/,
2 ' KINETIC TEMPERATURE = ',1PG10.4,' K',/,
2 ' ETL TEMPERATURE = ',1PG10.4,' K',/,
3 ' H2 VOLUME DENSITY = ',1PG10.4,' CM-3',/,
4 ' LINEWIDTH = ',1PG10.4,' KM/S',/,
5 ' HELIUM ABUNDANCE = ',1PG10.4,/,
6 ' STAR RADIUS AND TEM.= ',1PG10.4,' CM ;',4X,1PG10.4,' K',/,
8 ' SHELL RADIUS = ',1PG10.4,' CM ;',
8 ' DILUTION FACTOR = ',1PG10.4,/,
8 ' EPSILON-1 = ',0PF10.5,/,
9 ' ROTATIONAL LEVELS = ',I6,'; VIBRATIONAL LEVELS = ',
1 I2,' == ',I5,' RAD. TRANSIT.',/,
1 1X,76('*'))
The problem is that for teh moment i am using the console but i dont even get any of this results on the screen and i do not understand why.
I am having the same problem whith this: .
WRITE(*,*)' **** LIST OF IMPLEMENTED COMMANDS ****'
WRITE(*,*)
DO L=1,NUMERO_COMANDOS,10
L1=L
L2=L1+9
IF(L2.GT.NUMERO_COMANDOS)L2=NUMERO_COMANDOS
c WRITE(*,'(10(3X,A4))')(COMANDOS(K),K=L1,L2)
WRITE(*,*)(COMANDOS(K),K=L1,L2)
ENDDO
WRITE(*,*)
WRITE(*,*)' **** HELP COMMAND NAME ****'
0 Kudos
patuco
Beginner
1,802 Views
Could you explain me the suggestion? ive never heard about that.
0 Kudos
patuco
Beginner
1,802 Views

about the last subject, the messages are shown on the screen using the console but without the format, i do not understand why???

Apart from that, could you explain me the idea of AllocateConsole() in the wrapper??

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,802 Views
AllocConsole creates a console if there isn't one (e.g. in a GUI application). Normally, it's not desired in a GUI application, but may be useful while debugging. (Do you use the debugger, btw)?

I don't know why it doesn't use the format statement. As a suggestion, I'd propose that you break it into several WRITEs and several FORMATs (or, better still, embed the format in WRITE statement instead of keeping it on separate line). As it is now, it's a nightmare to parse and maintain. Maybe you'd find the answer on the way.
0 Kudos
patuco
Beginner
1,802 Views
the purpose is not use the console as a degugger or something like that, but it is a requirement for the project, something strange is true, but the main goal is to be able to show in a panel (useas console or jst simulating it) of an interface the write commands in fortran.That is the reason I am trying to create it.
Now im checking the doc about AllocConsole, but i am worried about the fact that the formated text is not showed.
0 Kudos
patuco
Beginner
1,802 Views
First of all, i do not know if it is the rigth place to describe this problem, but if it is not, moderator please tell, and i quit this message.
Ok the problem with the project right know is to show in a GUI the messages that the Fortran library is sending. Those are shown when the Java code is execute in the console, but not using a GUI i.ve implemented besides the new definition of the system.out:
System.setOut(new PrintStream(new OutputStream() {
public void write(int b) throws
IOException {
// write to the text area
textArea.append(String.valueOf((char)b));
// write to the default System.out
sysOut.write(b);
}
}));
now what a was thinking about is if there isany function in fortran to specify where to write, beacuse for the moment im using write(*,*), but iam not sure how it will affect the output :?
Thanks
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,801 Views
Well, write(*) writes into the "standard output". Standard output is by default a console, but it can be redirected to a file or pipe by the calling process or code (SetStdHandle API). However, as far as I know, Fortran run-time-library grabs the standard output handle first time it encounters an I/O statement (or, perhaps, specifically, a write(*) statement) and subsequent SetStdHandle's will not affect where write(*) writes (Note: that was my casual observation, take it with a grain of salt).

So, if there is no console, standard output is by default "nowhere" (aka dev/null in unixspeak). Now, an early call to AllocConsole might solve the problem, as AllocConsole is supposed to also redirect standard output to itself. A call to GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) should tell you where the standard output is going to.

I don't know Java to be able to tell what the code fragment you posted is supposed to do.

Perhaps the best solution would be to pass a Fortran-callable routine in C or Java to the dll, and the Fortran code should call it with an appropriate text argument. However, it looks difficult because of 3 languages involved.
0 Kudos
patuco
Beginner
1,801 Views
I agree that it will be hard, moreover because of i do not know how the write or system.out operates with the OS. Due to the lack of time of the project and the fact the beneficts of this implementation wont be so big, i gonna try to put this write messages into a file(eg write(*,*)"New chain:") or pipe and make java read them. So i have not idea how can i do that a statement will be stored in a file, and if it is possible to save it into a file and at the same time show it on the console.
Could u give me a hand? Thanks
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,801 Views
I recently posted a sample with pipe-talking between two processes (I think nothing prevents you to do this within the same process, providing that you don't redirect "primary" stdin/stdout as in the sample), where "child process" stdin/stdout are redirected to a pipe (so that it uses only READ(*) and WRITE(*)) (Communication between exe files thread).

But no, you can't have double output simultaneously with one WRITE statement; at least, you have to duplicate WRITE statements.

What does GetStdHandle(STD_OUTPUT_HANDLE) return when called from Fortran code in GUI app? What does GetFileType() return for it? Have you tried AllocConsole()?

Message Edited by JugoslavDujic on 02-20-2006 04:40 PM

0 Kudos
Reply