Welcome To The Home Of The Visual FoxPro Experts  
home. signup. forum. archives. search. google. articles. downloads. faq. members. weblogs. file info. rss.
 From: Ken Blum
  Where is Ken Blum?
 Chicago
 Illinois - United States
 Ken Blum
 To: Boudewijn Lutgerink
  Where is Boudewijn Lutgerink?
 Hoonaardstraat, Driel
 Netherlands
 Boudewijn Lutgerink
 Tags
Subject: RE: XML Web Services
Thread ID: 50473 Message ID: 51005 # Views: 2 # Ratings: 0
Version: Visual FoxPro 7 Category: XML
Date: Tuesday, September 07, 2004 9:50:49 PM         
   


> > > > > Where can I find the "XML Web Services" under "Tools" menu? Is it only existing from VFP8 and onwards?
> > > > >
> > > > > Belle
> > > >
> > > > In VFP7, it is at the same place as in VFP8: Tools | Wizards | Web Services. Note that VFP8's support for XML is a lot better.
> > > > --
> > > Also note that vfp9's webservices are webservices with turbo and on steroids... Bllllllazing fast....
> > >
> > > Boudewijn LutgeĀ®ink
> > > There are 10 types of people: Those that do understand binary calculations and those that do not.
> >
> > Why & How?
> >
> > KTB
>
> Dunno why and how, just noticed it.
> Do you mind BTW to tell a bit on how you do the upgrades of software through xm-webservices? I noticed it somewhere that you told this was possible. Looks awesome.
> Boudewijn LutgeĀ®ink
> There are 10 types of people: Those that do understand binary calculations and those that do not.

As my 3 year old would say "showur" (sure)! This is one of the best things I've done to improve service to my customers, and cut down on a lot of my time for support.

The clientapp.exe program allows for a user to set up scheduled updates. I add a timer object class (in a container object) to the _Screen when clientapp.exe starts. This timer looks for when an update is due every 60 seconds. When it's time to check for an update it calls a prg that calls the Web Service function to get the update version number. The Web Service will then return "No Update Available" or the latest version number available. If the update version number does not match the client version number, it will then download the Self-Extracting Zip update table via the web service. Here's the Update_Program function that handles that portion (modified a bit to protect the innocent!)...

LPARAMETERS lNoPrompt	&& .T. = update called manually by user - not through timer

LOCAL loWS,lcIPAddr,lcConnectString,lCloseClient,cCurVer,lcResult
IF VARTYPE(UPDATE_IN_PROGRESS) != 'U'
	RETURN
ENDIF

IF !USED("Client")
	USE CLIENT IN 0
	lCloseClient = .T.
ENDIF
&& Web Service
lcIPAddr = ALLTRIM(Client.Server_IP)
IF lCloseClient
	USE IN CLIENT
ENDIF

IF !lNoPrompt
	DO FORM Genio WITH "Retrieve System Update","Enter System Web Site. Blank=cancel",lcIPAddr,"KT" TO lcIPAddr
	lcIPAddr = TRANSFORM(lcIPAddr)
ENDIF
IF IS_Blank(lcIPAddr)
	RETURN
ENDIF

SET MESSAGE TO "Checking System Web Site for available updates..."

lcIPAddr = ALLTRIM(lcIPAddr)
IF RIGHT(lcIPAddr,1) != "/"
	lcIPAddr = lcIPAddr + "/"
ENDIF
lcConnectString = ALLTRIM(lcIPAddr)+"SoapServices/mywebservice.WSDL"

LOCAL loWS AS "XML Web Service"
LOCAL loException, lcErrorMsg, loWSHandler

TRY
	loWSHandler = NEWOBJECT("WSHandler","_ws3client.vcx")
	loWS = loWSHandler.SetupClient(lcConnectString, "myws", "mywsSoapPort")
CATCH TO loException
	lcErrorMsg="Error: "+TRANSFORM(loException.Errorno)+" - "+loException.Message
	DO CASE
	CASE VARTYPE(loWS)#"O"
		* Handle SOAP error connecting to web service
	CASE !EMPTY(loWS.FaultCode)
		* Handle SOAP error calling method
		lcErrorMsg=lcErrorMsg+CHR(13)+loWS.Detail
	OTHERWISE
		* Handle other error
	ENDCASE
	* Use for debugging purposes
	IF !lNoPrompt
		MESSAGEBOX(lcErrorMsg)
	ENDIF
FINALLY
ENDTRY

IF TYPE('loWS') != 'O'
	SET MESSAGE TO "Failed to connect to Web Service."
	RETURN
ENDIF

cCurVer = loWS.Get_TRC(1)	&& Get update version
IF VARTYPE(cCurVer) != 'C'
	SET MESSAGE TO "System Update Failure 1"
	RETURN
ENDIF
IF cCurVer = "No"	&& No update available
	SET MESSAGE TO cCurVer
	RETURN
ENDIF

PUBLIC UPDATE_IN_PROGRESS
UPDATE_IN_PROGRESS = .T.


IF cCurVer = PROGRAM_VERSION	&& Versions match
	IF lNoPrompt
		SET MESSAGE TO "Your System is up to date"
		RELEASE UPDATE_IN_PROGRESS
	ELSE
		IF MSB("Do you want to force an System Update?",4,"Your System is up to date") != 6
			RELEASE UPDATE_IN_PROGRESS
		ENDIF	
	ENDIF
ENDIF

IF VARTYPE(UPDATE_IN_PROGRESS) != 'U'
	SET MESSAGE TO "Downloading ClientApp Version "+ALLTRIM(cCurVer)+" - Please wait..."
	lcResult = loWS.Get_TRC(2)	&& Retrieve Self-Extracting DBF record

	IF VARTYPE(lcResult) != 'C' OR lcResult != [<?xml]
		SET MESSAGE TO "TRC Update Failure 2"
		RELEASE UPDATE_IN_PROGRESS
	ELSE
		SELECT 0
		XMLTOCURSOR(lcResult,"UpdateFile")			
		IF !USED("UpdateFile") OR TYPE("UpdateFile.UpdFile") = 'U'
			SET MESSAGE TO "System Update Failure 3"
			USE IN SELECT("UpdateFile")
			RELEASE UPDATE_IN_PROGRESS
		ELSE	
			SET SAFETY OFF
			IF STRTOFILE(UpdateFile.updfile,"SystemUpdate.EXE",0) < 200000
				SET MESSAGE TO "SystemUpdate Failure 4"
				USE IN SELECT("UpdateFile")
				RELEASE UPDATE_IN_PROGRESS
			ENDIF
			USE IN UpdateFile
		ENDIF
	ENDIF
ENDIF

IF !USED("Client")
	USE CLIENT 
ENDIF

SET MESSAGE TO "Incrementing Next Update Date"

IF !Is_Blank(Client.Update_Next) AND Client.Update_Next <= DATETIME()
	dNextTime = Client.Update_Next
	DO WHILE dNextTime <= DATETIME()
		DO CASE
			CASE Client.Update_Freq = 'H'
				dNextTime = dNextTime + (60*60)
			CASE Client.Update_Freq = 'D'
				dNextTime = dNextTime + ((60*60) * 24)
			CASE Client.Update_Freq = 'W'
				dNextTime = dNextTime + (((60*60) * 24) * 7)
			CASE Client.Update_Freq = 'M'
				dNextMonth = DTOT(GOMONTH(dNextTime,1))
				dNextTime = dNextMonth + (dNextTime - DTOT(TTOD(dNextTime)))
		ENDCASE
	ENDDO
	REPLACE Client.Update_Next WITH dNextTime
ENDIF

USE IN CLIENT

SET MESSAGE TO

IF VARTYPE(UPDATE_IN_PROGRESS) != 'U'
	RUN /N1 "PRGUPD.EXE" 
	QUIT
ENDIF


After the download has completed, it will increment the next update date and then run an update program PRGUPD.EXE and exit the ClientApp.Exe program. Here's the PRGUPD.EXE main.prg, which is all the project contains...

LOCAL fh,ctr,exearg
_SCREEN.Caption = "Performing ClientApp Update - Please wait..."
_SCREEN.Height = 300
_Screen.Width = 500
SET SYSMENU TO


ctr = 1
DO WHILE ctr <= 12
	fh = FOPEN("ClientApp.EXE",1)
	IF fh != -1
		FCLOSE(fh)
		exearg = FULLPATH("")
		? "Executing Update..."
		RUN /N7 "SystemUpdate.EXE" /AUTO &exearg
		SleepWait(10)
		PUBLIC SDT_TB
		OPEN DATABASE ENOVISION
		? "Updating Database..."
		SDT_TB = NewObject("SDTTOOLS","SDTCL","",4) && Rebuilds All Files, No DBC close
		RELEASE SDT_TB
		CLOSE DATABASES ALL
		? "Update Complete."
		EXIT
	ENDIF
	WAIT WINDOW "Waiting for ClientApp to shut down..." TIMEOUT 5
	ctr = ctr + 1
ENDDO
? "Starting System..."
RUN /N7 "ClientApp.EXE"
QUIT


It basically waits until the ClientApp.Exe instance is terminated by trying to open the executable exclusively. Then it just runs the SystemUpdate.exe program that was delivered by the Web Service as a table, and converted back into an exe via STRTOFILE(). Since the main app is shut down, the SystemUpdate program can extract the new clientapp.exe file and any other related files (like StoneField Meta Data files). I then run a process to update any table structures (thanks to Doug Henning and Stonefield Database Toolkit), and finally recall the ClientApp.Exe which may also perform additional update duties on startup, one of which is to change the current database version number to the new program version number.

The Web Service side has a table with a single record that contains 2 fields: Version char(10) and UpdFile Memo Binary. This table is updated by a little function on the ServerApp.exe program called "Publish Update", which just prompts for the new version number, and does a FILETOSTR() into the table of the self-extracting zip file.

The Web Service function just returns the UpdateTable.Version when called, and then the entire cursor as XML when requested for a download update. I use a table to store the self-extracting zip file because I had protocol problems when attempting to transfer the actual self-extracting file via XML. Here's the Web Service function...

	FUNCTION Get_TRC(nMode as Integer)
		IF !FILE("C:\SoapServ\SYSTEMUPDATE.DBF")
			RETURN "No Update Available"
		ENDIF

		USE "C:\SoapServ\SYSTEMUPDATE" ALIAS SQLCursor
		IF !USED("SqlCursor") OR RECCOUNT("SqlCursor") = 0 OR ISNULL(SqlCursor.Version)
			RETURN "No Update Available"
		ENDIF
		IF nMode = 1
			THIS.sXML_Data = ALLTRIM(SQLCursor.Version)
		ELSE
			THIS.To_XML()
		ENDIF
		USE IN SQLCursor			
				
		RETURN THIS.sXML_Data
	ENDFUNC

	FUNCTION To_XML()
		LOCAL loXML,TempXML_Data
		
	
		loXML = CREATEOBJECT("XMLAdapter")
		loXML.AddTableSchema("SQLCursor")
		loXML.ToXML("TempXML_Data")
		loXML.ReleaseXML
		THIS.sXML_Data = TempXML_Data
		RELEASE TempXML_Data
		RELEASE loXML
	ENDFUNC


That's it! Automatic Updates! All I have to do after I create a new update is copy the self-extracting zip file to my server and run the Publish Update function. My clients think it's pretty hot to have automatic update features just like big old Microsoft! Haahahahahha...

KTB

ENTIRE THREAD

XML Web Services Posted by Belle Fong @ 9/2/2004 10:17:57 AM
RE: XML Web Services Posted by Eric den Doop @ 9/2/2004 10:41:04 AM
RE: XML Web Services Posted by Boudewijn Lutgerink @ 9/3/2004 12:23:18 PM
RE: XML Web Services Posted by Ken Blum @ 9/3/2004 3:51:30 PM
RE: XML Web Services Posted by Boudewijn Lutgerink @ 9/6/2004 6:41:49 AM
RE: XML Web Services Posted by Ken Blum @ 9/7/2004 9:50:49 PM
RE: XML Web Services Posted by Boudewijn Lutgerink @ 9/8/2004 8:44:48 AM
RE: XML Web Services Posted by Ken Blum @ 9/8/2004 6:07:00 PM
RE: XML Web Services Posted by Mandeep Ravesh @ 8/16/2005 6:26:12 AM
RE: XML Web Services Posted by Belle Fong @ 9/6/2004 4:58:07 AM