Releasing extenal prg's

Topics: Developer Forum
Coordinator
Jun 18, 2010 at 8:33 PM
Edited Jun 18, 2010 at 9:24 PM
Any idea how to realease additional extenal programs for compiling purposes? In my scenario, under the main.prg function VFPInit, I added the an external prg by the following lines. zclientconfig = ADDBS(oProp.AppStartPath) + 'prg\zclientconfig.prg' SET PROCEDURE TO (zclientconfig) ADDITIVE If I use the project website and need to additional validation in the zclientconfig.prg, I can save the zclientconfig.prg but could not compile it unless 1. Close the browse that using the website; 2. Stop the WWW service. Most of the time it's number 2. Now here's the thing, if my function resides in the MAIN.PRG and I modify the it, I can compile it no problem by just closing the browser. Any idea how to release this additional external programs?
Coordinator
Jun 18, 2010 at 8:55 PM

Hmm, well the easy way and the way I did it with main.prg :

lcScript=FILETOSTR(oProp.AppStartPath+'\prg\main.prg')
lcHTMLout= EXECSCRIPT(lcScript) &&main()  && run the application

You're just recompiling main.prg and zclientconfig.prg, right?  No need to recompile the project unless the above doesn't work.  In which case you would include zclientconfig.prg and mark it external.  At that point you wouldn't need to recompile the project again.

When you say 'close the browse', do you mean close the browser or close a browse??   I don't think you should need to do anything besides compile those programs and just replace the original ones - should be no locking whatsoever..

 

 

Coordinator
Jun 18, 2010 at 9:22 PM
Edited Jun 18, 2010 at 9:23 PM
Sorry it's the browser that needs to be closed, not browse. The zclientconfig.prg is already marked as external. The thing that I don't understand is if my function that I'm editing is in the MAIN.PRG, I can quickly save and recompile it no problem. If my function is in zclientconfig.prg, then I have to close the browser, then I have to wait for a couple of minutes to recompile it. If I try to recompile it I'm having a locking issue. So it's either close the browser, wait a few minutes, recompile and test again or close the browser, stop www services and recompile. Btw, when I say recompile, I only recompile the external prg (zclientconfig.prg) not the whole project.
Coordinator
Jun 18, 2010 at 9:45 PM

Unless you recompile the whole project at least once, it doesn't know that it's external..

If it's not as simple as that, then EXECSCRIPT(yourPRG) will do it.  Foxtrails uses instances or something to avoid locking but I couldn't figure out how he did it.  So I took the easy route with ExecScript for Main.prg (is easier better??)...

 

 

Coordinator
Jun 18, 2010 at 9:57 PM
claudefox wrote:

Unless you recompile the whole project at least once, it doesn't know that it's external..

If it's not as simple as that, then EXECSCRIPT(yourPRG) will do it.  Foxtrails uses instances or something to avoid locking but I couldn't figure out how he did it.  So I took the easy route with ExecScript for Main.prg (is easier better??)...

 

 

That's make sense now, to recompile once so it would know the external prg's. I'll try your approach then by using the EXECSCRIPT function. Thank you.
Coordinator
Jun 30, 2010 at 4:30 PM
Edited Jul 2, 2010 at 5:37 AM
Does the ExecScript approach work well for you? It would be nice if we could just pop in a random prg that dynamically compiles and runs. I would like this whole environment to be as easy as something like PHP/WordPress and maybe similar to the way they develop. I guess we could have standard prgs like main.prg for some other prg names. Those could be pre-compiled as 'External'. In WordPress they have standard PHP files for the parts of an HTML like header.php, footer.php, but also things like functions.php. (But that's all for themes and plugins,etc.).
Anyway, for random on the fly addition/modification of prgs that won't have the lock problem, here's an example format (not complete since avfpinit would have to be modified to accept and return parameters):
cTest=Execscript(filetostr(oProp.AppStartPath+'\prg\'+'AVFPinit.prg')) && set data and HTML paths
nRows = ALINES(laData, cTest, .F., ",")
oProp.DataPath=laData[1]
oProp.HtmlPath=laData[2]
Otherwise, the traditional way will work but may be locked (did you try the release/clear commands and all of that stuff?)
  SET PROCEDURE TO avfpinit ADDITIVE
  AVFPinit()  && variables stay in scope
  CLEAR PROGRAM AVFPinit
 
Coordinator
Jun 30, 2010 at 8:26 PM

Claude, I tried the Execscript but still locking the my external prgs (without having to recompile the DLL).  In my code I also don't release this function/procedures since it contains the business rules that is being used through out the web application.  I can probably release it once the client press something like a log-out button, but what if they didn't and just close the browser itself?  I know there are techniques there can probably call a "clean-up code" once the browser has been closed or so but I just don't enough time to implement it yet on the production model that currently is running at the moment.

 

PS.

Love the idea of having multiple extenal prg's pre-compiled in the DLL that you have mention.

Coordinator
Jun 30, 2010 at 8:37 PM
I'm going to test this sometime, but, the thing with a stateless environment is that everything goes away after every transaction (every click) anyway. The whole environment is loaded/unloaded with every click - nothing stays in memory. Not like a regular vfp app at all. So if you clear all in the end, it doesn't matter since it's all going to get loaded again with the very next click..
Coordinator
Jul 1, 2010 at 8:26 PM

I think when you tested this you had the prg locked from a previous test because it works works for me without locking:

Execscript(filetostr(oProp.AppStartPath+'\prg\'+'AVFPinit.prg'))  &&works without locking like Main.prg

However, this definitely is not ideal since you have to pass and receive parameters instead of the simple SET PROC TO.  I'll do some more research and see if this can be improved to not do any locking.  Also would be better than Execscript to minimize I/O for performance reasons..

Coordinator
Jul 1, 2010 at 10:16 PM
claudefox wrote:
I'm going to test this sometime, but, the thing with a stateless environment is that everything goes away after every transaction (every click) anyway. The whole environment is loaded/unloaded with every click - nothing stays in memory. Not like a regular vfp app at all. So if you clear all in the end, it doesn't matter since it's all going to get loaded again with the very next click..

Does this means AVFPInit is always called for every load of page thru the entire website?  For example I have a custom property oprop.myid = sys(2015) which is defined in the AVFPInit, then if its true, it will have a different value for every load of each page? Did I understand this correctly?

Coordinator
Jul 1, 2010 at 10:19 PM
Yes, and you should be able to test that pretty easily. If you're generating a unique id for each user, you could either pass it on the URL for each hit or store it in the Session (preferred).
Coordinator
Jul 1, 2010 at 10:26 PM

Thank you for confirming it, I tested it and its generating different values as I load pages.

Coordinator
Jul 2, 2010 at 1:58 AM
Edited Jul 2, 2010 at 1:58 AM
Ok, this looks like it works for releasing an external program so that it's easily replaced:
SET proc TO oProp.AppStartPath+'\prg\'+'AVFPinit.prg' add
avfpinit()
SET proc TO
CLEAR PROGRAM avfpinit

Please try it and let me know..
Coordinator
Jul 4, 2010 at 12:53 AM
Edited Jul 4, 2010 at 12:54 AM

EXECSCRIPT(FILETOSTR(oProp.AppStartPath+'\prg\AVFPinit.prg'))

works and probably is the preferred way.  Scope DOES remain intact which is what I was worried about.  No locking whatsoever, Even when errors occur.  Compiles on the fly, so you can distribute only PRG scripts and no FXPs (starting to look more and more like a PHP app)

The following works but will lock if an ERROR occurs:
SET proc TO oProp.AppStartPath+'\prg\'+'AVFPinit.prg' add
avfpinit()
SET proc TO
CLEAR PROGRAM avfpinit
Coordinator
Jul 5, 2010 at 3:50 PM
Edited Jul 5, 2010 at 6:56 PM

My External function looks like this. (myexternalfunc.prg)

Function Hello_world1

return "Hello World 1"

ENDFUNC

 


 

So in the main.prg, under AVFPInit do I execute like this?

EXECSCRIPT(FILETOSTR(oProp.AppStartPath+'\prg\myexternalfunc.prg')) and

for every action I just call each function like:

CASE oprop.Action = 'say_hello_world'

return say_hello_world()

 


 

or do I execute it when I need the function as needed like this...

CASE oprop.Action = 'say_hello_world'

local lcRetVal

lcRetVal = EXECSCRIPT(FILETOSTR(oProp.AppStartPath+'\prg\myexternalfunc.prg'))

return lcRetVal

 

Coordinator
Jul 5, 2010 at 4:30 PM
Edited Jul 9, 2010 at 1:54 PM

The latter.  Every time you need to call an external program, use execscript.  (avfpinit.prg was just an example - it doesn't do anything special).

So this is correct everytime you need to use it:

lcRetVal = EXECSCRIPT(FILETOSTR(oProp.AppStartPath+'\prg\myexternalfunc.prg'))

 

This way you only need to have the prgs on the server and no fxps and everything is compiled dynamically.  This also means the AVFP developer is free from having to have a copy of Visual Foxpro development to create web apps.