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,032 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
Steven_L_Intel1
Employee
1,191 Views
I prefer to use message boxes for displaying status in GUI apps, rather than fiddling with consoles. I'll admit that this isn't an ideal solution for everyone.
0 Kudos
anthonyrichards
New Contributor III
1,191 Views

If it just status you want, then I agree with Steve about message boxes. Here is a trimmed-down example of your formatted message as it would appear and here is the code

  character(256) message
  character*24 chain, crlf*2
  real*8 mua,mub,muc,colden

   chain='abcdefghijklmnopqrstuvwx'
   mua=1.0d+00
   mub=2*mua
   muc=3*mua
   colden=1.0d-10
   crlf=char(10)//char(13)
  write(message,2001)crlf,chain,crlf,mua,crlf,mub,crlf,muc,crlf,colden,crlf

  2001    FORMAT(1X,24('*'),a2, &
      '  chain   = ',A24,a2, &
      '  Mua                 = ',1PG10.4,' D',a2, &
      '  Mub                 = ',1PG10.4,' D',a2, &
      '  Muc                 = ',1PG10.4,' D',a2, &
      '  COLUMN DENSITY      = ',1PG10.4,' CM-2',a2, &
       1X,24('*'))

  	ret=MESSAGEBOX(ghWndMain, message//''c,&
                    'Test of Output'C, &
					  MB_ICONEXCLAMATION .OR. MB_OK)
  


0 Kudos
Steven_L_Intel1
Employee
1,191 Views
You need a:

use ifwin

in there to make the MessageBox and MB_xxx symbols available.
0 Kudos
patuco
Beginner
1,191 Views
the idea of the message box is really good, but it moves away from the specs. It has to be an interface with an area where what the library does will be shown. So all the operations the library does use the command write. My first idea was the simple but the hardest, to redirect the outpu of the console in the java, but i did not pay attention that only the java messages would be shown and not the fortran ones, which are the ones i am interested in. I have been reading about AllocConsole comments and i am afraid of getting the same results, just the printf of C would be redirected (this is a supposal, i havent yet check it)
So the final option i think is better is to use a pipe, but i cant avoid feeling or thinking is not the best solution.
0 Kudos
patuco
Beginner
1,191 Views
Whoww i have read a little bit of the Pipes.f90 and it si really hard.
Question how can i change themodule dfwin? because in the Fortran PowerStatio 4.0 is not found, Either the ifwin.
Jugoslav could u explainit a littel bit , i mean, which are the basic steps to create a Pipe just where the fortran write, it has not to read.
Thanks
0 Kudos
patuco
Beginner
1,191 Views

by the way an easy question

how can i write the messages into a file?, i mean ive never had worked with files so i hav no clue how to create, open,write and close them

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,191 Views
Look up OPEN statement for write to file -- that's the simplest way to go. There is plenty of such code on this forum and elsewhere.

My Lord, you're still using Microsoft Fortran PowerStation 4.0 ?! It's not a problem if it suits you well, but note that it's 10 years old (and one of buggiest compilers I've seen).

The pipes sample might work if you USE MSFWIN instead, but I can't offer any guarantees on FPS4.0. It had a rather incomplete set of API translation, and I can't tell whether the call prototypes are compatible with IVF ones. Basically, you only need to redirect stdin to "read" end of the pipe (read from C/Java) and stdout to "write" end (fortran WRITE). However, it's still questionable whether it will work. If you can't get simple WRITE to write to the console, it's unlikely to work for a pipe –' the issue is when Fortran run-time library "associates" the STD_OUTPUT_HANDLE with WRITE(*) stream, and whether it looks up to it later. If the association happens at dll load time, you can't prevent it (except perhaps by redirecting first from C and then calling LoadLibrary/GetProcAddress).
0 Kudos
patuco
Beginner
1,191 Views

hi

i am trying to use some of the code you did in the pipe to test how it works, but i am getting some troubles:

!code form Jugoslav

INTEGERiStdoutWr, iStdoutRd,iret
TYPE(T_PROCESS_INFORMATION):: PI1
TYPE(T_STARTUPINFO):: SI1
TYPE(T_SECURITY_ATTRIBUTES):: SA1

SA1.nLength = sizeof(SA)
SA1.bInheritHandle = TRUE
SA1.lpSecurityDescriptor = NULL
iret = CreatePipe(LOC(iStdoutRd), LOC(iStdoutWr), SA, 0)
iret = SetHandleInformation( iStdoutRd, HANDLE_FLAG_INHERIT, 0)

SI1.cb = sizeof(SI1);
SI1.hStdError = iStdoutWr
SI1.hStdOutput = iStdoutWr
SI1.dwFlags = STARTF_USESTDHANDLES

PI1 = T_PROCESS_INFORMATION(0, 0, 0, 0)

iret = SetStdHandle(STD_OUTPUT_HANDLE, iStdInWr)

WRITE(*,*) 'Prueba'
iret = CloseHandle(iStdoutWr)
iret = CloseHandle(iStdoutRd)

iret = CloseHandle(PI1.hProcess)
iret = CloseHandle(PI1.hThread)

i am becoming some errors:

1. i have changed the names adding 1 because it sayd multiple type declarations for symbol PI
2. with this lines i am getting this two errors:

error FOR2290: implicit type for ISTDINWR
error FOR2290: implicit type for SIZEOF

3. where is it written? i mean in order to tell java where to read??

Thanks for your help

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,191 Views
In principle, it's sufficient to do that somewhere on Java or C wrapper code. For instance:
//C wrapper
#include "windows.h"
...
HANDLE hReadEnd, hWriteEnd;
CreatePipe(&hReadEnd, &hWriteEnd, NULL, 0);
SetStdHandle(hWriteEnd, STD_OUTPUT_HANDLE);
SetStdHandle(hReadEnd, STD_INPUT_HANDLE);

However, forget about the idea if you're using single-threaded exe, even if you succeed in redirecting I/O to the pipe, you cannot simultaneously WRITE on Fortran side and ReadPipe on C side. Pipes example uses two processes which run concurrently, so one can wait for the other to complete I/O operation and display the output as soon as it's done. In your case, you could only display the pipe contents after Fortran has finished.
0 Kudos
patuco
Beginner
1,191 Views

man i owe you a couple drinks, thanks for the help,

but please tell me that there is a way in java using this editor, to write a file besides open an unit and write on it, because it makes me change a lot of lines that are done as write(*,*) and i really hate this kind of work

Thanks

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,191 Views
Well, you can always open all .for files in a decent text editor and just replace all occurences of "WRITE(*" with "WRITE(42". Even if the editor doesn't have "replace across files" capability, I guess it's not that much of a job unless you have 100 source files or so?
0 Kudos
patuco
Beginner
1,191 Views

Hi,

i was performing some tests to learn how to use AllocConsole, but the repplies werent so good as I expected. The wrapper is creating a console in order to show the printf and write messages (from the Fortran and of course the own library). I am creating it as follows:

JNIEXPORT

void JNICALL Java_Main_console(JNIEnv *env, jobject jobj)

{

static const WORD MAX_CONSOLE_LINES = 500;

int hConHandle;

long lStdHandle;

CONSOLE_SCREEN_BUFFER_INFO coninfo;

FILE *fp;

// allocate a console for this app

AllocConsole();

// set the screen buffer

GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);

coninfo.dwSize.Y = MAX_CONSOLE_LINES;

SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);

// redirect unbuffered STDOUT to the console

lStdHandle = (

long)GetStdHandle(STD_OUTPUT_HANDLE);

hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

fp = _fdopen( hConHandle, "w" );

*stdout = *fp;

setvbuf( stdout, NULL, _IONBF, 0 );

// redirect unbuffered STDIN to the console

lStdHandle = (

long)GetStdHandle(STD_INPUT_HANDLE);

hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

fp = _fdopen( hConHandle, "r" );

*stdin = *fp;

setvbuf( stdin, NULL, _IONBF, 0 );

// redirect unbuffered STDERR to the console

lStdHandle = (

long)GetStdHandle(STD_ERROR_HANDLE);

hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);

fp = _fdopen( hConHandle, "w" );

*stderr = *fp;

setvbuf( stderr, NULL, _IONBF, 0 );

// point to console as well

ios::sync_with_stdio();

printf("I did it! ");

cout << "Hello"

}

Please any idea why is not any message shows?

thanks

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,191 Views
Which message? Your code works for me, as well as the Compaq Visual Fortran dll called from C GUI app. I can't predict what PowerStation will do though. Here's the attachment, with binaries in Release folder.
0 Kudos
patuco
Beginner
1,191 Views
The messages are the printf. When i am calling the dll with the java, it opens a console whichshows nothig, and i mean, the printf just below the creation of it.
I hope anddo not thinkthat Compaq Visual Fortran and the compiler i have to use will send the messages in differents places.
ive tryed your example and i observed that instead of using the native, you usean api. Wiht the gui i should call this function :?

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

//create the console

startConsoleWin();

}

JNIEXPORT void JNICALL Java_Main_console(JNIEnv *env, jobject jobj)

{

//call the api????

printf("1 ");

}

Message Edited by patuco on 02-22-2006 03:10 AM

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,191 Views
I don't have Java, know Java, nor know how its p-code works and interacts with the system APIs. I was merely trying to demonstrate that it works in a native GUI app I don't have an idea how Java environment affects the behavior.

Sorry for having to make such disclaimers, but I really can't offer much help regarding Java setup, and tell why the concrete code doesn't work. There are too many low-level issues involved. You can also try some Java-related group comp.os.ms-windows.programmer.win32 on groups.google.com.
0 Kudos
patuco
Beginner
1,191 Views

do not worried about the disclaimers, it is normal and happens a lot.

Just a question to know your opinion after reading again what you said about pipes in some posts before.

Will be possible to use pipes to write the outputs of the librariy to a file? (I am asking it because i know how to use pipes in java, and this option wont make me change the fortran files, which as i supposed you suspect are not implemented for me, besides the fact i should review and correct them).

Thanks

0 Kudos
Reply