|
I tried to look at the error code but it is a little smiley in my command window. I have to find out how to format Fortran to write in hex, oh dear.
-------------
Bibo ergo sum
|
|
|
|
|
Hi,
I would try "filename1\rfilename2\r" as a single string; I suspect \r is the right separator
for Fortran, NULL is needed on the sender side, and an extra NULL in between the filenames
ends up in FLBASE[1].
If the final NULL is confusing something else later on, there are ways to send a string without
a terminating NULL too.
A final thought:
I understand you can no longer compile the full Fortran app.
If your tests fail to show the way, you could write just a small Fortran program that tests
the communication and shows all the characters that actually get read into FILEN and FLBASE.
|
|
|
|
|
No, putting them in one string didn't work, it really wants two, with \n. It doesn't seem to care about C++'s \0. Does it read them out of the pipe in the same order as I put them in? I tried both ways but it didn't work either.
That is a good idea with the little test program. I have just written my first Fortran code in 20 years. Ugh, they call that a debugger? I shall now try and run that from C++. Progress report to follow...
-------------
Bibo ergo sum
|
|
|
|
|
What happened? When I call my little ftest.exe from the debugger or from the command window it works, I have to enter the two strings by hand. I can see that it has filled the input strings up to 80 chars, but still manages to open the file.
When I call it from C++ it fills the strings up to 80 chars, but can't open the file. I tried terminating with \n, with \r\n, and with \r\n\0, it all made no difference.
There must be something else. This is very strange.
READ(5,'(A)',IOSTAT=IOS) FILEN
It must be the '(A)'
-------------
Bibo ergo sum
modified on Tuesday, December 9, 2008 8:22 AM
|
|
|
|
|
Hi,
AFAIK '(A)' just means "take any text"
I suggest you:
- make sure your debugging stuff visualizes all special chars including space, NULL, CR, LF
- display the status of both openfile operations, I mean the actual value so you can google it
(a >0 test is not sufficient)
- try the Fortran test app manually with different paths
- show us all the relevant Fortran code
|
|
|
|
|
This is the entire code:
PROGRAM FTEST
IMPLICIT NONE
C
INTEGER IOS
CHARACTER*80 FILEN, FLBASE
C
C
CONTINUE
READ(5,'(A)',IOSTAT=IOS) FILEN
IF ( IOS .NE. 0 ) STOP 'MUST PROVIDE A FILE NAME'
WRITE (6) 'FILEN = *', FILEN, '*'
READ(5,'(A)',IOSTAT=IOS) FLBASE
IF ( IOS .NE. 0 ) STOP 'MUST PROVIDE A ROOT FILE NAME'
WRITE (6) 'FLBASE = *', FLBASE, '*'
OPEN(17,FILE=FILEN,FORM='FORMATTED',STATUS='OLD',
$ READONLY,IOSTAT=IOS)
IF ( IOS .NE. 0 ) THEN
WRITE (6, FMT=*) 'ERROR NO INPUT FILE ', IOS
ELSE
WRITE (6) 'OPENED INPUT FILE OK'
ENDIF
C
CONTINUE
END
-------------
Bibo ergo sum
modified on Tuesday, December 9, 2008 8:46 AM
|
|
|
|
|
OK, now
1. what is the result opening the first file? is it ERROR ... or OK on first file?
2. where is the opening of the second file? and what is its result?
|
|
|
|
|
It gives me an IOS=2 on the first file. I will worry about the second string another day, it gets used to build some complicated output filenames.
-------------
Bibo ergo sum
|
|
|
|
|
Hi,
Not sure but maybe IOS=2 means "the file you want to read exists but is empty". Please check.
I expect IOS=6 for "no such file", IOS=0 for anything else (until you start working on the file that is) unless the filename is invalid (not sure which code gets emited then).
You could try creating and writing the file, rather than opening and reading; that way, Explorer (or DOS DIR) would show the effective filename.
|
|
|
|
|
Hi,
I installed Silverfrost F95 and was able to run this:
PROGRAM FTEST
IMPLICIT INTEGER(I-N)
INTEGER IOS
CHARACTER*80 FILEN, FLBASE
CHARACTER C
PRINT *,'enter filename1'
READ(5,'(A)',IOSTAT=IOS) FILEN
IF ( IOS .NE. 0 ) STOP 'MUST PROVIDE A FILE NAME'
PRINT *, 'FILEN = *', FILEN, '*'
DO 10 I = 1,80
C=FILEN(I:I)
IF (ICHAR(C).NE.32) PRINT *, 'FILEN[',I,']=',C,'=',ICHAR(C)
10 CONTINUE
PRINT *,'enter filename2'
READ(5,'(A)',IOSTAT=IOS) FLBASE
IF ( IOS .NE. 0 ) STOP 'MUST PROVIDE A ROOT FILE NAME'
PRINT *, 'FLBASE = *', FLBASE, '*'
DO 20 I = 1,80
C=FLBASE(I:I)
IF (ICHAR(C).NE.32) PRINT *, 'FLBASE[',I,']=',C,'=',ICHAR(C)
20 CONTINUE
OPEN(17,FILE=FILEN,FORM='FORMATTED',STATUS='OLD',IOSTAT=IOS)
IF ( IOS .NE. 0 ) THEN
PRINT *, 'ERROR NO INPUT FILE 1 ', IOS
ELSE
PRINT *, 'OPENED INPUT FILE 1 OK'
ENDIF
OPEN(18,FILE=FLBASE,FORM='FORMATTED',STATUS='OLD',IOSTAT=IOS)
IF ( IOS .NE. 0 ) THEN
PRINT *, 'ERROR NO INPUT FILE 2 ', IOS
ELSE
PRINT *, 'OPENED INPUT FILE 2 OK'
ENDIF
END
it gives OK for existing files, and error 128 for non-existing files.
The documentation says error codes could be different on different compilers.
So it is my guess something is wrong in the way you pass the filenames from C++;
anyway the above should be able to tell you what gets read.
|
|
|
|
|
Luc Pattyn wrote: I installed Silverfrost F95
nice one Luc - thats dedication !!!
'g'
|
|
|
|
|
My very first large apps were coded in Fortran IV, some 30 years ago, but I hadn't done any Fortran work since I switched to C, also long ago. This was an opportunity to read some of the docs, and experiment a bit.
|
|
|
|
|
Thankyou. You have helped me immensely. It almost works now; I can run my test exe from C++, now "just" need to get the real thing running.
If I discover anything new I will report it. Meanwhile I am very grateful.
-------------
Bibo ergo sum
|
|
|
|
|
Another possible difference to running it from the command line is the location of the working directory (I note that you seem to be using filenames and not full paths). Maybe you are now successfully transferring the filenames but the working directory is different, perhaps somewhere where the program doesn't have permission, or a file that should exist in it doesn't.
The statement:
OPEN(17,FILE=FILEN,FORM='FORMATTED',STATUS='OLD',
$ READONLY,IOSTAT=IOS)
will give you some sort of error if the file doesn't exist as STATUS='OLD' tells the program that it should be there.
Peter
"Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
|
|
|
|
Yes yes yes!
I put the whole path in (without doubling the \) and the test program works. It doesn't work for the original Fortran yet but at least I know where to start. If Fortran is only going to give it 80 chars every time I can see some problems coming up on the target machine, because the paths can get a lot longer. I did try a relative path but it wasn't having it, must try and get Fortran to tell me where it is. In C++ I use _getcwd, can someone tell me how to get it in Fortran?
It was giving me IOS=2, which is not in the list of Intel error messages.
-------------
Bibo ergo sum
|
|
|
|
|
To find out where you are, GNU Fortran has a GETCWD call
link[^] I don't know how standard it is.
It doesn't seem to have a corresponding SETCWD call.
If you are starting the program using CreateProcess() then you can set the working directory, and I think it will default to the working directory of the calling process if you don't.
Peter
"Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
|
|
|
|
Unfortunately the Absoft compiler is a bit basic and does not have such luxuries. But I must check what I put in CreateProcess. I have to put it all in the command line, maybe I missed the path and it was just luck that it ran where it is.
-------------
Bibo ergo sum
|
|
|
|
|
Check out the lpCurrentDirectory parameter to the CreateProcess call
Peter
"Until the invention of the computer, the machine gun was the device that enabled humans to make the most mistakes in the smallest amount of time."
|
|
|
|
|
Hi,
if pathname length is a concern, you can always "map a network drive" (it works on the local machine too, despite the name), i.e. assign a drive letter to a (deep) subdirectory, allowing you to shorten the pathname considerably.
|
|
|
|
|
Fixed it!
I finally ported the old Fortran to Windows and recompiled it. I put some prints in to see what it gets up to.
It works. The problem was the Fortran having been compiled under Cygwin, some kind of Linux for Windows. It ran under Windows, but not quite. So when I compiled it myself, it could use the strings to open the file.
Just because it runs from the command line does not mean you can embed it and it still runs.
|
|
|
|
|
Hello
I have a MFC program with 2 threads. First is User Interface (Main) thread, and second one is worker thread that is created in the beginning and used till the end of application life. In the second thread in the begining I create CInternetSession and CHTTPConnection. I make some HTTP requests from second thread and everything is fine. But this is until I create and show InternetExplorer control in UserInterfece thread. Then something goes wrong and i lost my cookies in second thread and after a few requests my application crash (I will find where in code exactly this happened) When I show Internet Explorer control my second thread didn't make are requests. But I think that the problem is related with multithread using of WinInet libraries.
I found this problem soon because it didn't happened on computers that have all windows updates (Windows XP)
What you will recommend me to do?
P.S. I forget to mention that in second thread I make mostly a HTTPS requests
P.S. IE Control that I use is this one
http://www.codeproject.com/KB/miscctrl/simplebrowserformfc.aspx[^]
Julian Popov
абвгдежзийклмнопрстуфхцчшщъьюя
modified on Tuesday, December 9, 2008 6:04 AM
|
|
|
|
|
For one of my projects I've created a class wrapper around some functions contained in a DLL. To use these DLL functions, I instantiate an object of the type class wrapper, and then call the member function LoadDLL(). LoadDLL() calls ::LoadLibrary() for the DLL, and then calls GetProcAddress() for each DLL function I wish to wrap. If any of the functions couldn't be found, I wish to FreeLibrary(), and return false.
At the moment I do something along the lines of:
typedef void (*p2DLLFunc1) (void);
typedef char* (*p2DLLFunc2) (void);
bool CDLLWrapper::LoadDLL()
{
bool bResult = false;
m_hmoduleDll = ::LoadLibrary(_T("DLLName"));
if (NULL != m_hmoduleDll)
{
m_funcDLLFunc1 = reinterpret_cast<p2DLLFunc1>(GetProcAddress(m_hmoduleDll, _T("DLLFunc1")));
m_funcDLLFunc2 = reinterpret_cast<p2DLLFunc2>(GetProcAddress(m_hmoduleDll, _T("DLLFunc2")));
m_funcDLLFunc3 = reinterpret_cast<p2DLLFunc1>(GetProcAddress(m_hmoduleDll, _T("DLLFunc3")));
if ( NULL != m_funcDLLFunc1 &&
NULL != m_funcDLLFunc2 &&
NULL != m_funcDLLFunc3)
{
bResult = true;
}
else
{
::FreeLibrary(m_hmoduleDll);
}
}
return bResult;
}
However, when lots of functions are being wrapped the above method is a bit tedious and can be error prone. Instead, I would like to do it with a lookup table, like so
bool CDLLWrapper::LoadDLL()
{
struct MyLUT {
TCHAR* tcFuncName;
funcDLLFunc;
int iFunctionSignatureType;
};
static MyLUT arrWrappedFuncs[] = { _T("DLLFunc1"), m_funcDLLFunc1, 0
_T("DLLFunc2"), m_funcDLLFunc2, 1
_T("DLLFunc3"), m_funcDLLFunc3, 0
};
const int iNUM_WRAPPED_FUNCTIONS = sizeof(arrWrappedFuncs) / sizeof(MyLUT);
bool bResult = false;
m_hmoduleDll = ::LoadLibrary(_T("DLLName"));
if (NULL != m_hmoduleDll)
{
bResult = true;
for (int i = 0; i < iNUM_WRAPPED_FUNCTIONS; ++i)
{
switch(arrWrappedFuncs[i].iFunctionSignatureType)
{
case 0:
{
arrWrappedFuncs[i].funcDLLFunc = reinterpret_cast<p2DLLFunc1>(GetProcAddress(m_hmoduleDll, arrWrappedFuncs[i].tcFuncName));
}
break;
case 1:
{
arrWrappedFuncs[i].funcDLLFunc = reinterpret_cast<p2DLLFunc2>(GetProcAddress(m_hmoduleDll, arrWrappedFuncs[i].tcFuncName));
}
break;
default:
{
}
}
if (NULL == arrWrappedFuncs[i].funcDLLFunc)
{
bResult = false;
break;
}
}
if (!bResult)
{
::FreeLibrary(m_hmoduleDll);
}
}
return bResult;
}
The two problems I've got are:
1) How can I store a type in an array, so that I can use it in the reinterpret_cast<> ?
2) What type to define funcDLLFunc in struct MyLUT ?
Not sure about (1), but was thinking of using a union for (2), containing all the different function signatures. Every time a newly wrapped function had a different signature, I would just add a new member to the union and create a new Type.
If it's not possible to store a type in an array, then I guess the only solution is to have a switch statement on iFunctionSignatureType, and then just have the GetProcAddress() line for each type with a different reinterpret_cast<>. However, this is tedious as well, hence my hope for being able to store a type in an array.
Any ideas ?
|
|
|
|
|
Whz do you need reinterpret_cast at the first place? Shouldn't that work without any casting?
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|
Unfortunately not, as you get a compiler error:
error C2440: '=' : cannot convert from 'FARPROC' to 'p2DLLFunc1'
|
|
|
|
|
Try something like:
struct MyLUT {
TCHAR* tcFuncName;
FARPROC *funcDLLFunc;
};
static MyLUT arrWrappedFuncs[] = { {_T("DLLFunc1"), (FARPROC *)&m_funcDLLFunc1},
{_T("DLLFunc2"), (FARPROC *)&m_funcDLLFunc2},
{_T("DLLFunc3"), (FARPROC *)&m_funcDLLFunc3},
};
...
(*arrWrappedFuncs[i].funcDLLFunc) = GetProcAddress(m_hmoduleDll, arrWrappedFuncs[i].tcFuncName));
...
I just modified your code, so it might not compile, and probably needs adjustment here and there but maybe you get the main idea.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
|
|
|
|
|