convert program to a network version
convert program to a network version
Can anyone recommend some material available on how to convert my present app (not networkable) to a network version.
Using clipper 5.2e Harbour and FWH
Thanks
Using clipper 5.2e Harbour and FWH
Thanks
Thank you
Harvey
Harvey
-
- Posts: 824
- Joined: Thu Oct 13, 2005 7:39 am
- Location: Germany
Re: convert program to a network version
Harvey,
just some hints:
databases must be opened in shared mode (SET EXLUSIVE OFF, USE...SHARED)
before any write access you must lock either the dbf or the record and unlock it when the write access is finished.
if you need to rebuild the index files you have to close the dbf and open it in exlusive mode
In clipper there is the file lock.prg where you can find usefull functions for opening and locking dbf´s in a network environment
just some hints:
databases must be opened in shared mode (SET EXLUSIVE OFF, USE...SHARED)
before any write access you must lock either the dbf or the record and unlock it when the write access is finished.
if you need to rebuild the index files you have to close the dbf and open it in exlusive mode
In clipper there is the file lock.prg where you can find usefull functions for opening and locking dbf´s in a network environment
kind regards
Stefan
Stefan
- Rick Lipkin
- Posts: 2668
- Joined: Fri Oct 07, 2005 1:50 pm
- Location: Columbia, South Carolina USA
Re: convert program to a network version
Harvey
You are looking at a major update if you are going to move from an 'exclusive' .dbf environment to a network share .. I use the associated function(s) whether I use it on a network or on a local machine that is a single user.
Here is a set of functions you can use :
NetUse()
Addrec()
RecLock()
// netuse
select 1
if netuse( "test.dbf", .f.,5 ) // database, .t. for excluse lock, .f. for shared, 5 for time-out
else
return(.f.)
endif
// addrec()
select database
if addrec(5) // time-out
else
return(.f.)
endif
database->field := cValue
unlock
// reclock()
select database
if reclock( 5 ) // time-out
else
return(.f.)
endif
database->field1 := cValue
unlock
Hope this helps..
Rick Lipkin
You are looking at a major update if you are going to move from an 'exclusive' .dbf environment to a network share .. I use the associated function(s) whether I use it on a network or on a local machine that is a single user.
Here is a set of functions you can use :
NetUse()
Addrec()
RecLock()
// netuse
select 1
if netuse( "test.dbf", .f.,5 ) // database, .t. for excluse lock, .f. for shared, 5 for time-out
else
return(.f.)
endif
// addrec()
select database
if addrec(5) // time-out
else
return(.f.)
endif
database->field := cValue
unlock
// reclock()
select database
if reclock( 5 ) // time-out
else
return(.f.)
endif
database->field1 := cValue
unlock
Hope this helps..
Rick Lipkin
Code: Select all | Expand
/* LOGICAL NETUSE( CDATABASE, LOPENMODE, NSECONDS )
CHARACTER CDATABASE - NAME OF DATABASE
LOGICAL LOPENMODE - OPEN MODE .T. exclusive .F. shared
NUMERIC NSECONDS - NUMBER OF SECONDS TO WAIT 0 forever
RETURN .T. if successful, .F. if not
SAMPLE CALL IF NETUSE( "CALLS", .F., 5 )
*/
Func NETUSE( CDATABASE, LOPENMODE, NSECONDS )
LOCAL FOREVER, RESTART, WAIT_TIME, YESNO
RESTART := .T.
FOREVER := ( NSECONDS = 0 )
YESNO := {"Yes" , "No"}
DO WHILE RESTART
WAIT_TIME := NSECONDS
DO WHILE ( FOREVER .OR. WAIT_TIME > 0 )
IF LOPENMODE
USE ( CDATABASE ) via "DBFCDX" EXCLUSIVE
ELSE
USE ( CDATABASE ) via "DBFCDX" SHARED
ENDIF
IF .NOT. NETERR()
RETURN(.T.)
ENDIF
INKEY(1)
WAIT_TIME--
ENDDO
* lock failed, ask to continue
IF MsgYesNo( "Cannot lock " + CDATABASE + ", retry ?" )
ELSE
EXIT
ENDIF
ENDDO
RETURN(.F.)
//--------------------------
/*
LOGICAL ADDREC( NWAITSECONDS )
NUMERIC NWAITSECONDS
APPEND BLANK function with user interaction if failed
RETURN .T. if successful, .F. if not
SAMPLE CALL IF ADDREC( 5 )
SAMPLE TO UNSELECTED DATABASE IF ADDRESS->(ADDREC(5))
*/
Func ADDREC( NWAITSECONDS )
LOCAL LFOREVER, WAIT_TIME, RESTART, YESNO
APPEND BLANK
IF .NOT. NETERR()
RETURN(.T.)
ENDIF
RESTART := .T.
LFOREVER := ( NWAITSECONDS = 0 )
YESNO := {"Yes", "No"}
DO WHILE RESTART
WAIT_TIME := NWAITSECONDS
DO WHILE ( LFOREVER .OR. WAIT_TIME > 0 )
APPEND BLANK
IF .NOT. NETERR()
RETURN .T.
ENDIF
INKEY(.5) // wait 1/2 second to try again
WAIT_TIME := WAIT_TIME - .5
ENDDO
* if failed ask user to continue
IF MsgYesNo( "Cannot add Record, retry ?" )
ELSE
EXIT
ENDIF
ENDDO
RETURN(.F.)
//-----------------
/*
LOGICAL RECLOCK( WAIT )
NUMERIC WAIT
RETURN .T. if successful, .F. if not
RECORD LOCK ROUTINE WITH USER INTERACTION IF LOCK FAILES
SAMPLE CALL IF RECLOCK( 5 )
*/
Func RECLOCK( NSECONDS )
LOCAL LFOREVER, RESTART, WAIT_TIME, YESNO
IF RLOCK()
RETURN (.T.) // LOCKED
ENDIF
RESTART := .T.
LFOREVER := ( NSECONDS = 0 )
YESNO := {"Yes" , "No"}
DO WHILE RESTART
WAIT_TIME := NSECONDS
DO WHILE ( LFOREVER .OR. WAIT_TIME > 0 )
IF RLOCK()
RETURN(.T.)
ENDIF
INKEY(.5)
WAIT_TIME := WAIT_TIME - .5
ENDDO
* lock failed
IF MsgYesNo( "Cannot lock Record, retry ?" )
ELSE
EXIT
ENDIF
ENDDO
RETURN( .F.)
Re: convert program to a network version
Rick:
You wrote "Hope this helps.."
I'm such a novice anything will help.
Where do I put the functions you described.
I open 20 + data files at beginning of the program and others elsewhere.
Are the functions a one time call for each file or a many time call where are initialized?
You wrote "Hope this helps.."
I'm such a novice anything will help.
Where do I put the functions you described.
I open 20 + data files at beginning of the program and others elsewhere.
Are the functions a one time call for each file or a many time call where are initialized?
Thank you
Harvey
Harvey
Re: convert program to a network version
Dear Mr.Harvey,
You should open all your dbf files in shared mode. You can use the functions provided by Mr.Rick to open the DBF files in shared mode
For Eg:
Assuming that you have 2 DBF files namely Customer.Dbf and Invoice.Dbf
Instead of executing the regular xBase command to open the Dbf
For eg:
Select 1
Use Customer
Select 2
Use Invoice
You should open the Dbf in shared mode using the Function NetUse() (the second parameter should be .F.)
Once you have opened a DBF in shared mode, it remains shared till you close the DBF.
Once you have opened a DBF in shared mode, you should also make use of the Functions Addrec() and RecLock()
ie Whenever you try to add a new record to the DBF opened in shared mode, instead of Append Blank you should use Addrec()
Whenever you try to edit a record, before you start editing, you should lock the record using the Function RecLock()
Regards
Anser
Where do I put the functions you described.
I open 20 + data files at beginning of the program and others elsewhere.
You should open all your dbf files in shared mode. You can use the functions provided by Mr.Rick to open the DBF files in shared mode
For Eg:
Assuming that you have 2 DBF files namely Customer.Dbf and Invoice.Dbf
Instead of executing the regular xBase command to open the Dbf
For eg:
Select 1
Use Customer
Select 2
Use Invoice
You should open the Dbf in shared mode using the Function NetUse() (the second parameter should be .F.)
Code: Select all | Expand
select 1
if netuse( "Customer.dbf", .f.,5 ) // database, .t. for exclusive lock, .f. for shared, 5 for time-out
else
return(.f.)
endif
Select 2
if netuse( "Invoice.dbf", .f.,5 ) // database, .t. for exclusive lock, .f. for shared, 5 for time-out
else
return(.f.)
endif
Are the functions a one time call for each file or a many time call where are initialized?
Once you have opened a DBF in shared mode, it remains shared till you close the DBF.
Once you have opened a DBF in shared mode, you should also make use of the Functions Addrec() and RecLock()
ie Whenever you try to add a new record to the DBF opened in shared mode, instead of Append Blank you should use Addrec()
Whenever you try to edit a record, before you start editing, you should lock the record using the Function RecLock()
Regards
Anser
Re: convert program to a network version
Thanks for the useful info.
How do I use an alias with netuse() ?
I open file
Use name.dbf alias name new
How do I use an alias with netuse() ?
I open file
Use name.dbf alias name new
Thank you
Harvey
Harvey
- Otto
- Posts: 6403
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 22 times
- Been thanked: 2 times
- Contact:
Re: convert program to a network version
To all,
This is what I do, too. But nowadays I feel it would be better to open the files as short as possible.
What is your experience?
Best regards,
Otto
>I open 20 + data files at beginning of the program and others elsewhere.
This is what I do, too. But nowadays I feel it would be better to open the files as short as possible.
What is your experience?
Best regards,
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
- Otto
- Posts: 6403
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 22 times
- Been thanked: 2 times
- Contact:
Re: convert program to a network version
Hello Anser, hello Rick,
ad Select 1)
What is the advantage of selecting a workarea before opening?
Ad exclusive)
I personally change always in a prgInit procedure the exclusive mode to off.
So all databases are automatically opened shared.
Best regards,
Otto
ad Select 1)
What is the advantage of selecting a workarea before opening?
Ad exclusive)
I personally change always in a prgInit procedure the exclusive mode to off.
So all databases are automatically opened shared.
Code: Select all | Expand
INIT PROCEDURE PrgInit
SET CENTURY ON
SET EPOCH TO YEAR(DATE())-98
SET DELETED ON
SET EXCLUSIVE OFF
REQUEST HB_Lang_DE
REQUEST HB_CODEPAGE_DEWIN
HB_LangSelect("DE")
HB_SetCodePage("DEWIN")
SET DATE TO GERMAN
SetHandleCount(205)
rddsetdefault( "DBFCDX" )
RETURN
Best regards,
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
Re: convert program to a network version
Dear Mr.Otto,
Normally I don't use Select while opening a DBF, instead I use the clause NEW in the Function NetUse() which is very much similar to what Mr.Rick has already posted above in this post. Using NEW clause will avoid errors of Selecting a workarea which is already used by another DBF
I have this flexibility in my NetUse(). A parameter to decide whether the DBF to be opened in Exclusive or shared mode.
Regards
Anser
Normally I don't use Select while opening a DBF, instead I use the clause NEW in the Function NetUse() which is very much similar to what Mr.Rick has already posted above in this post. Using NEW clause will avoid errors of Selecting a workarea which is already used by another DBF
Code: Select all | Expand
use &dbfname ALIAS &mAlias SHARED NEW
Ad exclusive)
I personally change always in a prgInit procedure the exclusive mode to off.
So all databases are automatically opened shared.
I have this flexibility in my NetUse(). A parameter to decide whether the DBF to be opened in Exclusive or shared mode.
Regards
Anser
Last edited by anserkk on Tue Jul 21, 2009 7:06 am, edited 1 time in total.
Re: convert program to a network version
Dear MR.Harvey,
You will have to modify the Function NetUse() to accept one more parameter cAlias. After that you may modify the following code in the NetUse()
Regards
Anser
How do I use an alias with netuse() ?
You will have to modify the Function NetUse() to accept one more parameter cAlias. After that you may modify the following code in the NetUse()
Code: Select all | Expand
IF LOPENMODE
if empty(cAlias)
USE ( CDATABASE ) via "DBFCDX" EXCLUSIVE
else
USE ( CDATABASE ) ALIAS &cAlias via "DBFCDX" EXCLUSIVE
Endif
ELSE
if empty(cAlias)
USE ( CDATABASE ) via "DBFCDX" SHARED
else
USE ( CDATABASE ) ALIAS &cAlias via "DBFCDX" SHARED
ENDIF
Regards
Anser
- Enrico Maria Giordano
- Posts: 8753
- Joined: Thu Oct 06, 2005 8:17 pm
- Location: Roma - Italia
- Has thanked: 1 time
- Been thanked: 4 times
- Contact:
Re: convert program to a network version
hag wrote:Can anyone recommend some material available on how to convert my present app (not networkable) to a network version.
Using clipper 5.2e Harbour and FWH
Thanks
In 1985 I found Clipper 5 original manual very useful. But keep in mind that you can't simply take a single user app, replace some functions and magically get a multi users app. Multi user apps require a programming strategy because each section of the program can now be executed by more than one user simultaneously. Think about unique code generation or what can happen during the editing of record fields or report/export, etc. And some multi user effects are very hidden and nasty. In conclusion, you'd better not underestimate the difficult of porting your app to multiuser environment.
EMG
Re: convert program to a network version
Thank you all for the help. Converting my app will not be easy and i'll spend sometime before I make my final decision to complete the task.
My preference would be to move the app to internet based. Any suggestions?![Smile :)](./images/smilies/icon_smile.gif)
My preference would be to move the app to internet based. Any suggestions?
![Smile :)](./images/smilies/icon_smile.gif)
Thank you
Harvey
Harvey
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: convert program to a network version
Harvey,
I should point out that using database objects make programming easier, including mult-user. The class automatically handles aliasing so instead of having to do (cAlias)->(dbskip()), you just do oCustomer:skip(). You can also open multiple copies of the same database using exactly the same syntax.
oCustomer1:= TCust():new()
oCustomer2:= TCust():new()
The database class can also handle all the multi-user issues.
For more information see my website http://www.goIntellitech.com/program.htm. There are a number of articles there.
Regards,
James
I should point out that using database objects make programming easier, including mult-user. The class automatically handles aliasing so instead of having to do (cAlias)->(dbskip()), you just do oCustomer:skip(). You can also open multiple copies of the same database using exactly the same syntax.
oCustomer1:= TCust():new()
oCustomer2:= TCust():new()
The database class can also handle all the multi-user issues.
For more information see my website http://www.goIntellitech.com/program.htm. There are a number of articles there.
Regards,
James
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: convert program to a network version
Harvey,
I know it is all scary since it is so different, but once you get over the intial learning curve, programming is so much easier, less error prone, and requires much less code. While converting some older programs I have reduced the code by as much as 50-90 percent.
When you are doing a conversion there are tricks. For instance, you can move entire functions into methods of a new class, then convert those functions into OOP as time permits. Think of it as wrapping legacy code into a class.
You can also use classes in some part of your application, and legacy code in others so you can convert a little at a time.
Read and re-read my articles, and then try some of the test programs. I think you will be amazed at how simple it is.
Regards,
James
I know it is all scary since it is so different, but once you get over the intial learning curve, programming is so much easier, less error prone, and requires much less code. While converting some older programs I have reduced the code by as much as 50-90 percent.
When you are doing a conversion there are tricks. For instance, you can move entire functions into methods of a new class, then convert those functions into OOP as time permits. Think of it as wrapping legacy code into a class.
You can also use classes in some part of your application, and legacy code in others so you can convert a little at a time.
Read and re-read my articles, and then try some of the test programs. I think you will be amazed at how simple it is.
Regards,
James