I am running PB/win 8.04. If I OPEN a file in the main program for input or output, and later perform LINE INPUT# or PRINT# to that file in a subroutine located in the same source file, then the scope of the OPEN statement extends into the subroutine (I can read and write to the file opened in the main program). However, if I compile the subroutine as a separate dll, then the scope of the OPEN statement does not extend into the subroutine (I can not read or write to the file opened in the main program). To turn my subroutine into a dll, I am embedding my subroutine into the dll templet provided as a sample with PB/win 8.04. I am also declaring the subroutine at the top of the main program.
Announcement
Collapse
No announcement yet.
Scope of OPEN statement to DLL Subroutines
Collapse
X
-
Correct, the PB file handle is only valid within the code module in which it is obtained.
I just (last couple of days) posted an example of how to pass that open handle using OPEN HANDLE, let me see if I can find that thread...
Yup, here is is... http://www.powerbasic.com/support/pb...t=35218&page=3
Post # 38 on page 3
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
-
-
Will the OPEN with a file HANDLE in the subroutine cause my program to lose its position in the sequential file, when calling and returning and calling the routine again? Normally, each input or output command should advance to the next line of the sequential file. UPDATE -- Experimentation shows that each call to the subroutine causes the INPUT # or PRINT # to restart at the beginning of the file, when the INPUT and PRINT are embedded between the open-with-handle and close statements in the subroutine. It appears the file-handle will point to the file but not the position in the file.Last edited by John Harvill; 26 Oct 2007, 06:20 PM.
Comment
-
-
Great! That works. Therefore, PB/win 8.04 requires managing two variables when opening in the main (or calling routine) and using INPUT# and PRINT# in the called routine in another source file, especially in a dll. We must manage both the system-file-handle and the position in the file. Therefore, in a simplified format, the templet for sequential files is as follows (OUTPUT is similar):
In the main or calling routine:
1. OPEN "filename" FOR INPUT AS filenum
2. sysFileHandle = FILEATTR( filenum, 2 )
3. FilePosition = SEEK( filenum )
4. CALL routine ( ..., sysFileHandle, FilePosition )
5. CLOSE filenum
In the called routine:
1. OPEN HANDLE sysFileHandle FOR INPUT AS filenum
2. SEEK filenum, FilePosition ..................'Sets the position in the file
3. INPUT#
4. FilePosition = seek( filenum ) .............'Gets the new position for later use
5. CLOSE filenum
Thank you. I appreciate your guidance in this matter.
Comment
-
-
You really shouldn't need to set the filepointer.
Or maybe you do.
The doc on using the HANDLE option is a tad thin..e.g., must be opened in consistent access and sharing modes at a minimum. You'd think the help file would say 'something' about the filepointer if it were important.
I would think when the compiler does an 'open HANDLE' it would pick up the filepointer if it needs to track it itself in the RTL.
Darned, now I have to test it. Oh well, it's the kind of thing I enjoy doing on Saturdays anyway.
Whoa, wait a minute....I've done the example I posted, and it works just fine. Then again, that's about the only way I've done it (OPEN for sequential output). So I guess I do have to test some other modes.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
-
Ok, I found TWO errors in my originally-posted test suite, one logic and one signficant typing error.
It appears you DO have to set the filepointer, except when opening for APPEND.
Which is - all and all - quite understandable.
I'll send a note in to the PB Documentation department to ask them to upgrade the "OPEN HANDLE" portion of the help file.
DLL SOURCE CODE
Code:' FILE: FPHLIB.BAS ' Test the SEEK value returned by PB when a file is opened in a DLL using OPEN HANDLE. ' 10.26.07 ' Compiler both DLL and EXE ==> PB/Win 8.03 #COMPILE DLL #REGISTER NONE #DEBUG ERROR ON #TOOLS OFF %NOGDI = 1 ' no GDI (Graphics Device Interface) functions %NOMMIDS = 1 ' no Multimedia ID definitions #INCLUDE "Win32API.INC" FUNCTION LIBMAIN (BYVAL hInstance AS LONG, BYVAL Reason AS LONG, BYVAL Reserved AS LONG) EXPORT AS LONG SELECT CASE Reason CASE %DLL_PROCESS_ATTACH ' Indicates that the DLL is being loaded by another process (a DLL OR EXE is loading the DLL). ' DLLs can use this opportunity to initialize any instance or GLOBAL data, such as arrays. ' Must NOT call any functions not in KERNEL32.DLL under this notification CASE %DLL_PROCESS_DETACH ' Indicates that the DLL is being unloaded OR detached FROM the calling application. ' DLLs can take this opportunity to clean up all resources for all threads attached and known to the DLL. ' This is functionally equivalent to the WEP function in 16-BIT DLLs. CASE %DLL_THREAD_ATTACH ' Indicates that the DLL is being loaded by a new thread in the calling application. ' DLLs can use this opportunity to initialize any thread local storage (TLS). CASE %DLL_THREAD_DETACH ' Indicates that the thread is exiting cleanly. ' IF the DLL has allocated any thread local storage (TLS), it should be released. ' Reserved specifies further aspects of the DLL initialization and cleanup. ' If Reason is %DLL_PROCESS_ATTACH, Reserved is NULL (zero) for dynamic loads and non-NULL for static loads. ' If Reason is %DLL_PROCESS_DETACH, Reserved is NULL IF LibMain has been called by using the ' FreeLibrary API call and non-NULL If LibMain has been called during process termination. END SELECT FUNCTION = 1 ' return 1 if succesfully initialized. ' return zero if failure. END FUNCTION FUNCTION FpfReturnSeek ALIAS "FphReturnSeekPos"_ (BYVAL hSys AS LONG, openmode AS STRING, OPTIONAL SeekPos AS LONG) EXPORT AS LONG LOCAL h AS LONG h = FREEFILE SELECT CASE LCASE$(openmode) CASE "input" OPEN HANDLE hSys FOR INPUT AS h CASE "binary" OPEN HANDLE hSys FOR BINARY AS h CASE "output" OPEN HANDLE hSys FOR OUTPUT AS h CASE "append" OPEN HANDLE hSys FOR APPEND AS h CASE ELSE MSGBOX USING$ ("Unsupported open mode '&'", openmode) FUNCTION = -1& EXIT FUNCTION END SELECT ' ------------------------------------------ ' if a seek position was specified, do that ' ------------------------------------------ IF VARPTR(SeekPos) THEN SEEK h, Seekpos END IF IF ISFALSE ERR THEN FUNCTION = SEEK(h) CLOSE h ELSE MSGBOX USING$ ("Error on open or seek # &", ERR, ERROR$(ERR)) FUNCTION = -1& END IF END FUNCTION ' /// END OF FILE ////
Code:' fphcall.bas ' Check Seek Position here vs what is reported in library function which ' opens the file using OPEN HANDLE ' for various open modes. ' MCM 10/26/07 (public domain, not that it's worth anything anyway). ' Compiler both DLL and EXE ==> PB/Win 8.03 #COMPILE EXE #DIM ALL #REGISTER NONE #DEBUG ERROR ON #TOOLS OFF $TESTFILE_NAME = "~fph.dat" DECLARE FUNCTION FphReturnSeekPos LIB "fphlib.dll" ALIAS "FphReturnSeekPos" _ (BYVAL hSys AS LONG, openmode AS STRING, OPTIONAL SeekPos AS LONG) AS LONG FUNCTION PBMAIN () AS LONG LOCAL openMode () AS STRING, msg AS STRING LOCAL h AS LONG, Z AS LONG REDIM OpenMode (3) Openmode (0) = "INPUT" Openmode (1) = "BINARY" Openmode (2) = "APPEND" Openmode (3) = "OUTPUT" ' Create a test file we can do stuff with ' filesize = 100*(78+2) = 800 CALL CreateTestFile () ' now do the test using $TESTFILE_NAME Msg = "" ' initialize CALL DoTheTest (openMode(), msg) MSGBOX MSG,, "results" END FUNCTION FUNCTION DoTheTest (OpenMode() AS STRING, msg AS STRING) AS LONG LOCAL h AS LONG, hSys AS LONG, mBUff AS STRING LOCAL exepos AS LONG, dllPos AS LONG LOCAL i AS LONG, sData AS STRING, bOpen AS LONG LOCAL iTestNo AS LONG ' 0 = no directed seek in call, 1 = directed seek in call, 2 = no SEEK in ExE at all ' --------------------------------------------- MSG = "" FOR iTestNo = 0 TO 2 MSG = MSG & CHOOSE$( ItestNO+1,_ "Seek in main, no directed seek in call", _ "Seek in main, directed seek in call", _ "No Seek in main (get default by openmode)") _ & $CRLF FOR i = LBOUND (openmode,1) TO UBOUND (openMode,1) ' recreate the test file so results are always clean CALL CreateTestFile h = FREEFILE ERRCLEAR SELECT CASE LCASE$(Openmode (I)) CASE "input" OPEN $TESTFILE_NAME FOR INPUT AS h CASE "output" OPEN $TESTFILE_NAME FOR OUTPUT AS h CASE "binary" OPEN $TESTFILE_NAME FOR BINARY AS h CASE "append" OPEN $TESTFILE_NAME FOR APPEND AS h END SELECT IF ISFALSE ERR THEN bOpen = 1 SELECT CASE iTestNo CASE 0,1 SEEK h, 401 ' seek to start of 51st record END SELECT IF ISFALSE ERR THEN exePos = SEEK (h) hSys = FILEATTR (h, 2) ' get system handle ' either do or don't pass directed SEEK to library. SELECT CASE ITestNO CASE 0,2 ' no directed seek dllPos = FphReturnSeekPos (hSys, OpenMode(I)) CASE 1 ' directed seek dllPos = FphReturnSeekPos (hSys, OpenMode(I), exepos) END SELECT mBUff = USING$ ( "mode & ExePos ### DllPos ###", openMode(i),exePos, dllPos) ELSE ' SEEK failed mBuff = USING$ ("Mode & returns Error # on SEEK", openMode(i), ERR) END IF ELSE 'open failed bOpen = 0 mBUff = USING$ ("Mode & returns Error # on OPEN", openmode (I), ERR) END IF Msg = MSG & mbuff & $CRLF IF bOpen THEN CLOSE h END IF NEXT i ' test next openmode in this test NEXT iTestNO ' do the other tests MSG = MSG & "End of Test" END FUNCTION ' do the test FUNCTION CreateTestFile () AS LONG LOCAL h AS LONG, Z AS LONG, msg AS STRING h = FREEFILE OPEN $TESTFILE_NAME FOR OUTPUT AS h msg = STRING$(78, "x") FOR Z = 1 TO 100 MSG = RSET$ (FORMAT$(Z),6) & STRING$(72,"x") PRINT #h, msg ' appends CRLF for total record size of 6 + 72 + 2 ==> 80 NEXT CLOSE h END FUNCTION ' /// END OF FILE
Last edited by Michael Mattias; 27 Oct 2007, 10:56 AM. Reason: Had several errors, resulting in bad conclusions. I think it's OK now.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
-
I agree. More details in the help file to clarify the responsiblities of the programmer when working with sequential files would be useful for those new to PowerBASIC, especially for someonw like me from the FORTRAN world who hasn't been thinking about Handles and File Pointers. Thanks for your effort with this issue.Last edited by John Harvill; 27 Oct 2007, 06:25 PM.
Comment
-
-
Creating that test program was kind of fun for me.
The last couple of months I have not had too many opportunities to just sit down and create applications in BASIC - which is something I truly enjoy doing.
The whole 'OPEN HANDLE' thing I had not done for a number of years and at least three versions of the compiler, so my recall perforce was 'fuzzy' at best as to how it works.
The fringe benefit is, it shows it's really not that difficult to "TRY IT! - a technique which all too often seems in short supply around here. That whole thing took me maybe an hour, hour and a half - and that is a very long time for a dinky little test program like this.
Even if I only use OPEN HANDLE once in the next year, what I learned by actually DOING it rates to repay my time investment on that very first use.
On the subject of applications, I was pretty happy to be able to create a new demo this past week. I have a commercial application - the EDI PAl(tm) ANSI ASC X12 Viewer-Editor-Printer - where the primary user action is to "open" a file to "do something" with it.
I am also a (heavy) user of this application. While I have standard "file/open", "recent files (MRU),"send to" (from file Explorer) and "drag and drop" ways to open a file, I found myself constanly 'browsing' to the same files because I open enough different files that the MRU list overflows and rolls over .. and the browse is often to a file which is 'deeply nested' in the directory tree.. eg C:\Program Files\Trading Partner\Edata\COmmerce\K-Mart\ANSI\004010\850.. quite time-consuming using the standard "OpenFileName" common dialog.
One of my users was watching me do this and said,"You know, you should have a "Favorites" menu to select those commonly-opened files."
Duh! Another new feature suggestion out of left field - one I can't help but think *I* should have conceived a long time ago.
So, since I didn't want to develop this by hackin' and whackin' inside a 50 Kloc program, I set out to get the code wokring correctly in a 'standalone' environment. And since it was 'standalone' I thought it might be a nice demo for people here - pretty easy to 'cut and paste and tweak' into any application where a primary user activity is "file/open" or "file/select."
The result is this demo: Add a 'Favorite Files' menu to your application 10-25-07
(I have since tried it with PB/WIN 8.03 and the Windows' header files supplied with that release and it works just fine).
(While I did't try it, I think it will work with PB/CC.. except you'll have to change the MSGBOX calls to something else but that takes what, 12-13 seconds for a global "search and replace?").
<'I'd better quit now because I am starting to ramble on' icon here>
MCM
PS: The suggestion I sent to PB for a doc upgrade was this:
I think I would suggest under OPEN, where the discussion of the HANDLE
clause reads....
"HANDLE The HANDLE option allows you to access files that have already been
opened by another process, DLL, or API function. The filehandle specified
here must be a valid Win32 operating system file handle.
[INSERT POINT]
When PowerBASIC closes ... [rest not relevant to this discussion]...."
.. I would add at the [INSERT POINT] something like this...
"The use of the HANDLE option causes the file pointer to be reset to the
default position for the open mode specified in the OPEN HANDLE statement.
That is, files opened FOR INPUT, RANDOM or BINARY reset the pointer to the
value specified in the BASE= clause (or the default of "1" if BASE= not
used), and files opened FOR APPEND have the filepointer set to the end of
the current file.
It is totally silly to OPEN HANDLE "FOR OUTPUT" since that erases any file
and you did not need to worry about passing a handle in the first place. [I
think your doc writers can clean this up a bit]"
The file pointer which is reset is that associated with the PB handle used in the OPEN HANDLE statement. I do not know if the file pointer is reset on the PB handle from which the system handle was originally obtained.
That of course could be tested by performing an additional test: reading, writing or SEEKing in the function in the DLL and then testing the SEEK position of 'h' in the EXE on return.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
Comment