LB Booster
General >> General Board >> Passing info between programs
http://lbb.conforums.com/index.cgi?board=general&action=display&num=1423798879

Passing info between programs
Post by Alincon on Feb 13th, 2015, 02:41am

I have been using the hidden text editor method to pass data between running programs, but it seems so crude.
Is there a better, cleaner method in LBB?
(or in LB4, for that matter)

r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 13th, 2015, 08:16am

on Feb 13th, 2015, 02:41am, Alincon wrote:
I have been using the hidden text editor method to pass data between running programs, but it seems so crude. Is there a better, cleaner method in LBB?

Several methods of inter-process communication (IPC) are available in Windows:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa365574.aspx

Most of those can be used from LBB, with more or less difficulty. To give more detailed advice I would need to know the kind of data you want to pass, how quickly, whether it's in only one direction or bidirectional etc.

Richard.
Re: Passing info between programs
Post by SarmedNafi on Feb 13th, 2015, 10:17am



Wonderful Richard,
For me:
Quick in one direction.


Regards,
Sarmed

Re: Passing info between programs
Post by Richard Russell on Feb 13th, 2015, 11:48am

on Feb 13th, 2015, 10:17am, SarmedNafi wrote:
Quick in one direction.

The simplest method of unidirectional communication in LBB is to use a shared random-access file. The sending end opens the file for OUTPUT and the receiving end opens the file for INPUT. You should ideally store the file in the temp folder (use the 'GetTempPath' API to find this).

This is straightforward if you simply need to communicate a state: to update the state the sending end does a PUT, and the receiving end periodically tests it by doing a GET, probably in a timer subroutine. Here is a trivial example:

Compile this to filerecv.exe:
Code:
    ' receiving end

    tempfile$ = space$(260)
    calldll #kernel32, "GetTempPathA", 260 as long, tempfile$ as ptr, ret as long
    tempfile$ = left$(tempfile$, ret) + "LBBpipe.tmp"
    open tempfile$ for input as #shared len = 20
    field #shared, 20 as state$
    timer 100, [test]
    wait

[test]
    get #shared, 1
    print state$
    wait 

And then run this in the same folder:
Code:
    ' sending end

    tempfile$ = space$(260)
    calldll #kernel32, "GetTempPathA", 260 as long, tempfile$ as ptr, ret as long
    tempfile$ = left$(tempfile$, ret) + "LBBpipe.tmp"
    open tempfile$ for output as #shared len = 20
    field #shared, 20 as state$ 
    run "filerecv.exe"
    timer 100, [send]
    wait

[send]
    state$ = date$("dd/mm/yyyy") + " " + time$()
    put #shared,1
    wait 

If you are sending a data stream rather than a state then this simple approach won't suffice and you need to think about issues of synchronisation and what happens if the 'sending' program outputs data more quickly than the 'receiving' program can accept it. This is a fundamental issue with unidirectional communication because the receiving end cannot say 'slow down'!

Richard.

Re: Passing info between programs
Post by Alincon on Feb 13th, 2015, 4:09pm

I was thinking more of calling a program that does a common task and sends back the result. I have one that is called from programs that need standard state abbreviations. It presents a list box of State names and returns the corresponding abbreviation for the chosen state.
I have another called program that verifies login and password.
The calling program sends a name, the called program requests log in and password, and returns pass/fail.
In the second case using the clipboard might compromise security.
Using a common file might require timing to ensure the called program has finished before the calling program tries to use the requested data.

r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 13th, 2015, 5:27pm

on Feb 13th, 2015, 4:09pm, Alincon wrote:
I was thinking more of calling a program that does a common task and sends back the result.

I would have thought the 'standard' way of doing that (in general, unrelated to LB/LBB) is to use files. The vast majority of data processing and conversion programs I use take their input from one file and send their output to another file.

Apart from being such a commonplace method, using files for input and output may make it easier to debug because you can examine the files afterwards. I can't see any benefit in 'reinventing the wheel'.

Richard.

Re: Passing info between programs
Post by Phineas Freak on Feb 14th, 2015, 08:26am

Take a look at the Memory Mapped Files demo from LBPE. You can probably transfer any kind of data between two or more program instances and without writting to the hard drive.

Note: I compliled it under linux. It runs but you cannot run a second instance and when you try to change the data on the first instance it complains about a "type mismatch". Commenting this line:

Code:
g.caption$ = "Local string = " + str$(Shared.strVar.struct) 


allows the first instance to change the data but i had no luck running a second instance to fully test it :-[ .
Re: Passing info between programs
Post by Richard Russell on Feb 14th, 2015, 10:14am

on Feb 14th, 2015, 08:26am, PreciseTiming wrote:
Take a look at the Memory Mapped Files demo from LBPE.

Memory-mapped files (more accurately called 'shared memory' in this context) have the issue that I mentioned before: they are ideal for transferring a state but problematical for transferring a data stream. At least the communication is bi-directional so it would be possible to devise some kind of handshaking protocol.

Incidentally I think the code at LBPE is over-complicated. Whenever I've used shared memory (in BBC BASIC, I've never tried it in Liberty BASIC) I've not found it necessary to use the map-copy-unmap sequence for each transaction as recommended there. Leaving the structure mapped for the entire duration of the program has always worked for me:

http://bb4w.wikispaces.com/Sharing+a+structure+between+processes

Richard.
Re: Passing info between programs
Post by Alincon on Feb 21st, 2015, 11:45pm

I have succeeded in passing information between programs by using a small file. My small file is sequential, not random, but it works.

I had concerns about this quote from the LB4 help file:

"Execution of an external program does not cause the calling Liberty BASIC program to cease executing."

But, at least in my case, it appears that the calling program does wait for the called .tkn program to finish.

r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 22nd, 2015, 07:04am

on Feb 21st, 2015, 11:45pm, Alincon wrote:
But, at least in my case, it appears that the calling program does wait for the called .tkn program to finish.

Sounds very risky to me. The RUN statement definitely doesn't wait; on a single-core CPU it may be a few milliseconds before it returns but you can't rely on it.

You say '.TKN'; was this using LB4 or LBB? In LBB you would need to use the WAIT qualifier to the RUN command.

Richard.
Re: Passing info between programs
Post by Alincon on Feb 22nd, 2015, 12:31pm

Here's my code:

Code:
    run "c:\libbas\_mylibbas\personnel\lookupNames.tkn ";"*.sal"
    open "C:\libbas\_mylibbas\personnel\fileNamePass.txt" for input as #pnt
        input #pnt, fileName$
    close #pnt
 


The calling program passes a file type (via command line), and, presto! the file name is immediately available in the common file.

The called program fills an array for a list box and when the user makes a selection, passes back a file name.

Why would this be risky?

BTW: Is there any advantage in using a random file?

r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 22nd, 2015, 1:08pm

on Feb 22nd, 2015, 12:31pm, Alincon wrote:
Why would this be risky?

It's risky because if the file fileNamePass.txt is being created by the program lookupNames.tkn there's no reason at all to expect the file to have already been created when the RUN command returns.

The RUN command simply 'launches' the external program; then both that program and yours run concurrently. The degree of concurrency is of course dependent on your PC's architecture: if you have two or more CPU cores the programs may well be running literally simultaneously. If you have only one core they will be time-shared by Windows, but that is out of your control. Either way, the file may be created some time after the RUN command has returned.

But anyway this is evidently not LBB code ('RUN lookupNames.tkn' cannot work in LBB, unless you've associated the TKN extension with run404.exe), so you may want to raise the issue on one of the Liberty BASIC support forums.

Incidentally the ' ";" ' in your command string achieves nothing; you might as well (and more simply) use:

Code:
    run "c:\libbas\_mylibbas\personnel\lookupNames.tkn *.sal" 

Richard.

Re: Passing info between programs
Post by Alincon on Feb 23rd, 2015, 5:55pm

Chris Iverson (on the LB msg board) says my code works for .tkn, but it won't work for .exe. That makes sense to me.

r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 23rd, 2015, 6:43pm

on Feb 23rd, 2015, 5:55pm, Alincon wrote:
Chris Iverson (on the LB msg board) says my code works for .tkn, but it won't work for .exe.

He seems to think that a TKN is run not as an 'external' program at all, but using the same runtime engine as the calling program. That may be true but AFAIK it's a completely undocumented feature. I wouldn't want to rely on it.

Certainly, LBB doesn't have a comparable capability (it could do in principle, but as it's so easy to compile a sub-program to a compact EXE you might just as well run it as a 'proper' external program). I could easily add a wait option to LBB's RUN command if that would be helpful*.

One thing I don't understand is why you're calling a sub-program at all. If it's also written in Liberty BASIC, why isn't it just implemented as a subroutine (in LBB it could be an 'included' library subroutine)?

*Edit: I've decided that I will add a wait option to the RUN statement in the next release of LBB. This will be mutually exclusive with the other modes (so you won't be able to wait and hide).

Richard.
Re: Passing info between programs
Post by Alincon on Feb 24th, 2015, 12:01am

As to 'including', instead of 'calling', I guess I'm still thinking in LB4 terms; I chose calling because more than one program calls the routine

Thanks for offering to add a wait option to the run command, but if I'm the only one requesting it...

r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 24th, 2015, 08:15am

on Feb 24th, 2015, 12:01am, Alincon wrote:
Thanks for offering to add a wait option to the run command, but if I'm the only one requesting it...

I'm not adding it for you, I'm adding it because I think it's a good idea (it's only doing internally what the 'cheat' code I listed does anyway, so it's just syntactic sugar).

Richard.

Re: Passing info between programs
Post by tsh73 on Feb 24th, 2015, 4:23pm

Richard, thank you for adding good stuff just because it's a good idea.
Re: Passing info between programs
Post by Alincon on Feb 25th, 2015, 11:24pm

I want to try the LBB approach of 'including' sub-programs instead of calling them. What I get is a "type mismatch" error message.

the called sub-program:
Code:
function lookUpName$(typ$)
     files deptPath$, info$(
     fc = val(info$(0, 1))    ' folder count
     for cf = 1 to fc
        foldName$ = info$(cf, 0)
        files foldName$, info2$(
        fc2 = val(info2$(0,1))
        for cf2 = 1 to fc2
            fold2Name$ = info2$(cf2,0)
            files fold2Name$, typ$, info3$(
            fc3 = val(info3$(0,0))  'file count
              for cf3 = 1 to fc3
                x$ = info3$(cf3,0)
                if (right$(x$,3) = "sal" or right$(x$,3) = "hly") then
                    y$ = getFldr$(foldName$)
                    z$ = getFldr$(fold2Name$)
                    n = n + 1
                    emps$(n) = tb$(x$,28) + y$ +"\"+ z$ + "\"
                end if
              next cf3
        next cf2
    next cf

    WindowWidth = 220:    WindowHeight = 400
    BackgroundColor$ = "cyan"
    ListboxColor$ = "cyan"
    statictext #elist.st1, "Employees", 60,5,55,20
    listbox #elist.lb1, emps$(,[getEmp],2,24,217,375
    Stylebits #elist.lb1, 0, _LBS_DISABLENOSCROLL, 0, 0
    button #elist.btn1, "X", [noSelect],UL, 195,2,20,20
    open "Employee List" for window_popup as #elist
    #elist, "trapclose [empsClose]"
    #elist, "font consolas 9"
    #elist.lb1, "singleclickselect"
    sort emps$(,1,n
    #elist.lb1, "reload"
    wait

 [getEmp]
    #elist.lb1, "selection? emp$"
    fileName$ = deptPath$ +"\"+ mid$(emp$,29) + left$(emp$,28)   ' 28 is forced length of emp name
    goto [empsClose]

 [noSelect]
    fileName$ = "none"

 [empsClose]
    lookUpName$ = fileName$
    close #elist
    end function
 


the calling program (including old run statement, etc)
Code:
' run "c:\libbas\_mylibbas\personnel\tokens\lookupNames.tkn ";"*.sal"
   ' open "C:\libbas\_mylibbas\personnel\fileNamePass.txt" for input as #pnt
   '     input #pnt, fileName$
   ' close #pnt
	fileName$ = lookUpName$("*.*")  ' the error line
    if fileName$ = "none" then wait
    goto [getCommon]
 


and the 'include statement (starting in col 1)

Code:
'include lookupNamesIncl.bas
 


r.m.
Re: Passing info between programs
Post by Richard Russell on Feb 26th, 2015, 08:56am

on Feb 25th, 2015, 11:24pm, Alincon wrote:
I want to try the LBB approach of 'including' sub-programs instead of calling them. What I get is a "type mismatch" error message.

It works for me. A 'Type mismatch' error is what you would get if the included file was not found since, in the absence of the FUNCTION definition, lookUpName$( looks like an array!

So, check that the included file has the correct name and that it is stored in the same directory as the calling program.

I deliberately arranged that 'include doesn't throw an error if the file isn't found, in case a program happened to have a 'regular' comment line starting with the word include. However that does mean that you can get an 'unexpected' error (such as your 'Type mismatch') rather than a more straightforward 'Include file not found'.

Richard.

Re: Passing info between programs
Post by Alincon on Feb 26th, 2015, 7:26pm

I figured that 'type mismatch' was not the real problem.
The included code now executes w/o an error message, but the listbox that the code is supposed to fill is empty. Maybe there is another scope problem, since it is a function.
Some times scope can be more of a problem than the code itself.

r.m.