West Wind Web Connection Class and Tool Reference Class and Tool Reference Rick Strahl, West Wind Technologies, 1997 Support: http://www.west-wind.com/wwThreads Overview of the main classes The image above describes the main framework classes that are implemented in Visual FoxPro code by Web Connection. The four important classes are: wwServer This class and the wwOLEServer subclass are responsible for communicating with the Web server handling request routing and passing the input data and output HTTP results between the Web Connection DLL and the Visual FoxPro framework. Also handles logging and all aspects of the visual server window. - Page 1 - West Wind Web Connection Class and Tool Reference wwProcess This is the 'application' class that will be subclassed by you to handle all your application logic. Each Web request translates into a matching method in this class. While you can write all of your code inside of this class, you can also delegate logic from your entry method to other objects or user defined functions. wwCGI/wwPostRequest You use the wwCGI object as your program input. The wwCGI Object abstracts all the incoming data from the Web server. This includes server variables, browser information, HTTP information, HTML form variables and Web Connection status info. wwHTML You use the wwHTML object as your program output. The wwHTML class is used to return all output back to the Web server. Output is string based and this class abstracts the interface with a large collection of both high and low level methods for creating HTML and HTTP compliant output. There are additional classes that are subclasses of these four basic classes as well: wwOLEServer This subclass is specific to Automation servers. It essentially overrides wwServer's ProcessHit, Init, Error methods to allow to be able to respond to Automation commands sent by the Web Connection DLL. wwHTMLString This subclass of the HTML class keeps output in a result string, rather than sending output to file immediately as the wwHTML class does. wwHTMLString optimizes string output by dumping large strings to disk – disk based output is much faster for multiple concats on strings than memory operations. The interface is identical to wwHTML. wwNetscapeCGI This subclass of the CGI class is specific to Netscape servers and works around Netscape's non-standard implementation of the Windows CGI standard. A number of support classes that are called by these classes and are available for use in your code. Some of the support classes available are: wwAPI A class that contains a number of API functions that are used in Web Connection. Includes INI, Registry access, path related functions, Process priority function and more. wwEval This class allows safe execution of EVALUATEs as well as providing the ability to run entire programs and routines without requiring the development version of Visual FoxPro. Courtesy of Randy Pearson's CodeBlck class. wwIPStuff Provides a number of Internet related functions in a compact DLL with a Visual FoxPro class wrapper. Included are Async and blocking SMTP, FTP Get and Send, HTTP Get for getting Web pages into a string and DNS and reverse DNS lookup. wwHTTPHeader This class allows building custom HTTP headers with ease. The class allows for adding individual header strings as well as providing one line access to advanced features such as redirection and Authentication. wwShowCursor This powerful class can be used to display table based data in HTML table output with a single method call. It also includes single record display in both ASCII and HTML table output formats. wwSession This class allows you to track users through a site by attaching dynamic variables stored in a table to a user. With this mechanism you can implement a state table that can remember settings or filters set on previous requests. Works in conjunction with HTTP Cookies. wwDBFPopup This class allows building complex HTML popup boxes that are data driven. wwHTMLForm This class allows on the fly display of most Visual FoxPro forms as HTML based forms under Internet Explorer 4.0 (Enterprise Edition only). - Page 2 - West Wind Web Connection Table of Contents Table of Contents Class and Tool Reference ......................................................................................................................1 Overview of the main classes .................................................................................................................................................... 1 Table of Contents....................................................................................................................................3 Class wwServer & Class wwOLEServer ..............................................................................................9 Parent Class: wwServerForm Source: wwServer.prg ............................................................................................................ 9 How it works ............................................................................................................................................................................. 9 How to use it.............................................................................................................................................................................. 9 Server Setup ........................................................................................................................................................................ 10 Implementing your own wwServer class............................................................................................................................. 10 Pathing issues and dealing with multiple setups ................................................................................................................. 12 Exposed Properties: ................................................................................................................................................................. 12 Exposed Methods: ................................................................................................................................................................... 13 wwServer::Init .................................................................................................................................................................... 13 wwServer::SetServerEnvironment (virtual) ........................................................................................................................ 13 wwServer::SetServerProperties .......................................................................................................................................... 14 wwServer::ReadSettingsFromIni ........................................................................................................................................ 14 wwServer::SetCGIClass...................................................................................................................................................... 15 wwServer::Show ................................................................................................................................................................. 15 wwServer :: SetCGIFilePath ............................................................................................................................................... 16 wwServer :: SetForegroundTasking .................................................................................................................................... 16 wwServer :: SetTimerInterval ............................................................................................................................................. 17 wwServer :: SetLogToFile .................................................................................................................................................. 17 wwServer :: GetLogToFile ................................................................................................................................................. 18 wwServer :: LogEntry ......................................................................................................................................................... 18 wwServer :: SetStatusWindow ............................................................................................................................................ 19 wwServer :: SetCGITemplateFile ....................................................................................................................................... 19 wwServer :: CleanTempFiles .............................................................................................................................................. 20 wwServer::SendMail........................................................................................................................................................... 20 wwServer :: CreateSessionEntry ......................................................................................................................................... 21 wwServer :: KillSessionEntry ............................................................................................................................................. 22 wwServer :: GetSessionCount............................................................................................................................................. 22 wwServer :: GetAppBasePath() .......................................................................................................................................... 22 Class wwProcess..................................................................................................................................23 Parent Class: Relation Source: wwProcess.prg .................................................................................................................... 23 How it works ........................................................................................................................................................................... 23 Exposed Properties: ................................................................................................................................................................. 25 Exposed Methods .................................................................................................................................................................... 26 wwProcess::Init ................................................................................................................................................................... 26 wwProcess::Process (Virtual) ........................................................................................................................................... 26 wwProcess::InitSession....................................................................................................................................................... 27 wwProcess::GetAppIniVar ................................................................................................................................................. 27 wwProcess::DisplayFile ...................................................................................................................................................... 28 wwProcess::Error ................................................................................................................................................................ 28 wwProcess::StandardPage .................................................................................................................................................. 28 wwProcess::ErrorMsg ......................................................................................................................................................... 29 Class wwCGI .........................................................................................................................................30 Parent Class: Relation Source: wwCGI.PRG ....................................................................................................................... 30 How it works ........................................................................................................................................................................... 30 How to use it............................................................................................................................................................................ 30 wwCGI::Init ........................................................................................................................................................................ 31 wwCGI::LoadCGIFileNames ............................................................................................................................................. 31 - Page 3 - West Wind Web Connection Table of Contents wwCGI::ServerVariables .................................................................................................................................................... 31 wwCGI::GetCGIVar ........................................................................................................................................................... 32 wwCGI::Form ..................................................................................................................................................................... 33 wwCGI::SetKey .................................................................................................................................................................. 33 wwCGI::GetFormCheckBox............................................................................................................................................... 33 wwCGI::GetFormMultiple.................................................................................................................................................. 34 wwCGI::aFormVars ............................................................................................................................................................ 34 wwCGI::GetOutFile ............................................................................................................................................................ 35 wwCGI::GetContentFile ..................................................................................................................................................... 35 wwCGI::QueryString .......................................................................................................................................................... 35 wwCGI::aCGIParms ........................................................................................................................................................... 36 wwCGI::GetCommandLine ................................................................................................................................................ 36 wwCGI::GetPreviousUrl..................................................................................................................................................... 36 wwCGI::GetCurrentUrl ...................................................................................................................................................... 37 wwCGI::GetServerAdmin................................................................................................................................................... 37 wwCGI::GetServerName .................................................................................................................................................... 37 wwCGI::GetRemoteAddress............................................................................................................................................... 37 wwCGI::GetBrowser .......................................................................................................................................................... 38 wwCGI::IsHTML30 ........................................................................................................................................................... 38 wwCGI::IsSecure ................................................................................................................................................................ 38 wwCGI::IsLinkSecure ........................................................................................................................................................ 38 wwCGI::GetClientCertificate ............................................................................................................................................. 39 wwCGI::GetCookie ............................................................................................................................................................ 39 wwCGI::GetRequestMethod ............................................................................................................................................... 39 wwCGI::GetRequestProtocol.............................................................................................................................................. 39 wwCGI::GetAuthenticatedUser .......................................................................................................................................... 40 wwCGI::GetPhysicalPath ................................................................................................................................................... 40 wwCGI::GetLogicalPath ..................................................................................................................................................... 40 wwCGI::ForcePath ............................................................................................................................................................. 40 Class wwPostRequest ..........................................................................................................................41 Parent Class: wwCGI Source: wwPostRequest.prg ............................................................................................................. 41 wCGI::GetMultiPartFile ..................................................................................................................................................... 41 wwCGI::GetMultiPartFormVar .......................................................................................................................................... 42 Class wwHTML .....................................................................................................................................43 Parent Class: Relation Source: wwHTML.prg..................................................................................................................... 43 How it works ........................................................................................................................................................................... 43 wwHTML Class: Exposed Methods ........................................................................................................................................ 43 wwHTML::Init.................................................................................................................................................................... 43 wwHTML::Destroy............................................................................................................................................................. 43 wwHTML::Write ................................................................................................................................................................ 44 wwHTML::Send ................................................................................................................................................................. 44 wwHTML::SendLn ............................................................................................................................................................. 44 wwHTML::FastSend........................................................................................................................................................... 45 wwHTML::SendPar ............................................................................................................................................................ 45 wwHTML::SendMemoLn................................................................................................................................................... 45 wwHTML::BreakMemo ..................................................................................................................................................... 46 wwHTML::ShowCursor ..................................................................................................................................................... 46 wwHTML::ExpandTemplate .............................................................................................................................................. 47 wwHTML::ExpandScript ................................................................................................................................................... 48 wwHTML::EnclosedText ................................................................................................................................................... 49 wwHTML::HeaderText ...................................................................................................................................................... 50 wwHTML::HRef................................................................................................................................................................. 50 wwHTML::HTMLColor ..................................................................................................................................................... 50 wwHTML::List ................................................................................................................................................................... 51 wwHTML::DBFPopup ....................................................................................................................................................... 51 wwHTML::ContentTypeHeader ......................................................................................................................................... 52 wwHTML::HTMLHeader .................................................................................................................................................. 53 - Page 4 - West Wind Web Connection Table of Contents wwHTML::HTMLFooter ................................................................................................................................................... 55 wwHTML::HTMLAuthenticate .......................................................................................................................................... 55 wwHTML::HTMLRedirect ................................................................................................................................................ 56 wwHTML::HTMLError ..................................................................................................................................................... 56 wwHTML::FormTextBox................................................................................................................................................... 57 wwHTML::FormTextArea.................................................................................................................................................. 57 wwHTML::FormButton ...................................................................................................................................................... 58 wwHTML::FormRadio ....................................................................................................................................................... 58 wwHTML::FormCheckbox................................................................................................................................................. 58 wwHTML::NoOutput ......................................................................................................................................................... 59 wwHTML::SetHTTPHeaderClass ...................................................................................................................................... 59 wwHTML::AutoRefresh ..................................................................................................................................................... 59 wwHTML::IEChart............................................................................................................................................................. 60 Class wwHTMLString ...........................................................................................................................62 Parent Class: wwHTML .......................................................................................................................................................... 62 wwHTML::Init.................................................................................................................................................................... 62 wwHTMLString::Send........................................................................................................................................................ 62 wwHTML::GetOutput ........................................................................................................................................................ 63 wwHTML::SetBufferSize ................................................................................................................................................... 63 Class wwShowCursor ..........................................................................................................................64 Parent Class: Relation Source: ShowCursor.prg .................................................................................................................. 64 How it works ........................................................................................................................................................................... 64 Paged ShowCursor Display ..................................................................................................................................................... 65 Exposed Properties .................................................................................................................................................................. 67 Exposed Methods .................................................................................................................................................................... 67 wwShowCursor::Init ........................................................................................................................................................... 67 wwShowCursor::GetOutput ................................................................................................................................................ 68 wwShowCursor::ShowCursor ............................................................................................................................................. 68 wwShowCursor::ShowRecord ............................................................................................................................................ 68 wwShowCursor::ShowASCIIRecord .................................................................................................................................. 69 wwShowCursor::BuildFieldListHeader .............................................................................................................................. 69 wwShowCursor::SetCursor ................................................................................................................................................. 69 Class wwDBFPopup .............................................................................................................................71 Parent Class: Relation Source: DBFPopup .......................................................................................................................... 71 How it works ........................................................................................................................................................................... 71 Exposed Properties .................................................................................................................................................................. 71 Exposed Methods .................................................................................................................................................................... 72 wwDBFPopup::Init ............................................................................................................................................................. 72 wwDBFPopup::GetOutput .................................................................................................................................................. 72 wwDBFPopup::BuildList ................................................................................................................................................... 72 wwDBFPopup::Reset.......................................................................................................................................................... 73 Class wwHTTPHeader ..........................................................................................................................74 Parent Class: Relation Source: wwHTML.prg..................................................................................................................... 74 How it works ........................................................................................................................................................................... 74 wwHTTPHeader::GetOutput .............................................................................................................................................. 75 wwHTTPHeader::CompleteHeader .................................................................................................................................... 75 wwHTTPHeader::ClearHeader ........................................................................................................................................... 75 wwHTTPHeader::DefaultHeader ....................................................................................................................................... 76 wwHTTPHeader::SetProtocol ............................................................................................................................................ 76 wwHTTPHeader::SetContentType ..................................................................................................................................... 76 wwHTTPHeader::AddCookie............................................................................................................................................. 77 wwHTTPHeader::AddForceReload .................................................................................................................................... 77 wwHTTPHeader::More Methods ....................................................................................................................................... 78 Class wwHTMLForm .............................................................................................................................79 Parent Class: wwHTMLControl Source: wwForm.prg ........................................................................................................ 79 How to use it:........................................................................................................................................................................... 79 - Page 5 - West Wind Web Connection Table of Contents Using the wwForm Wrapper ............................................................................................................................................... 79 Using the Class ................................................................................................................................................................... 79 How it works: .......................................................................................................................................................................... 80 Field and Value mapping .................................................................................................................................................... 80 HTML and Script hooks ..................................................................................................................................................... 80 Form Submission and Assigning values back to the form................................................................................................... 80 Rules of Operation .............................................................................................................................................................. 81 Overriding Object Types with your own Renderers............................................................................................................ 81 What doesn’t work .............................................................................................................................................................. 82 How to use it: ...................................................................................................................................................................... 82 Grids ................................................................................................................................................................................... 83 Exposed Properties: ................................................................................................................................................................. 85 Exposed Methods: ................................................................................................................................................................... 85 wwHTMLForm::Init ........................................................................................................................................................... 85 wwHTMLForm::GetOutput ................................................................................................................................................ 86 wwHTMLForm::ShowContainer ........................................................................................................................................ 86 wwHTMLForm::SetValues................................................................................................................................................. 87 wwHTMLForm::OverrideInsertObjectHTML.................................................................................................................... 87 wwHTMLForm::OverrideSetValue .................................................................................................................................... 88 Class wwVFPScript ..............................................................................................................................89 Parent Class: Relation Source: wwVFPScript.prg ............................................................................................................... 89 Related Classes: Request, Response, Session, Server.............................................................................................................. 89 How it works....................................................................................................................................................................... 89 A sample script page ........................................................................................................................................................... 91 Accessing Objects – ASP Objects and Web Connection Objects ....................................................................................... 92 The need to compile............................................................................................................................................................ 92 Class wwSession ..................................................................................................................................94 Parent Class: Relation Source: wwSession.prg .................................................................................................................... 94 How it works ........................................................................................................................................................................... 94 wwSession::Init ................................................................................................................................................................... 96 wwSession::Reindex ........................................................................................................................................................... 97 wwSession::NewSession ..................................................................................................................................................... 97 wwSession::IsValidSession................................................................................................................................................. 97 wwSession::SetSessionVar ................................................................................................................................................. 98 wwSession::GetSessionVar................................................................................................................................................. 98 wwSession::GetUserId ........................................................................................................................................................ 98 wwSession::GetField .......................................................................................................................................................... 99 Class wwIPStuff .................................................................................................................................. 100 Parent Class: Custom Source: wwIPStuff.vcx .............................................................................................. 100 How it works ......................................................................................................................................................................... 100 How to use it.......................................................................................................................................................................... 101 Sending SMTP Mail ......................................................................................................................................................... 101 Sending and receiving files via FTP ................................................................................................................................. 101 Retrieving HTTP requests to strings (HTTP GET) .......................................................................................................... 102 Sending and Retrieving HTTP requests to strings (HTTP POST) .................................................................................... 102 Sending and Receiving files over HTTP: ......................................................................................................................... 102 Domain Name Lookup ...................................................................................................................................................... 103 Exposed Properties: ............................................................................................................................................................... 103 SMTP properties:.............................................................................................................................................................. 103 FTP Properties: ................................................................................................................................................................. 104 HTTP Properties: .............................................................................................................................................................. 104 Exposed Methods: ................................................................................................................................................................. 105 wwIPStuff::Init ................................................................................................................................................................. 105 wwIPStuff::GetDomainFromIp ......................................................................................................................................... 105 wwIPStuff::GetIPFromDomain ........................................................................................................................................ 106 wwIPStuff::SendMail wwIPStuff::SendMailAsync ......................................................................................................... 106 - Page 6 - West Wind Web Connection Table of Contents wwIPStuff::FTPGetFile .................................................................................................................................................... 107 wwIPStuff::FTPSendFile .................................................................................................................................................. 108 wwIPStuff::FTPDeleteFile................................................................................................................................................ 108 wwIPStuff::aFTPDir ......................................................................................................................................................... 109 wwIPStuff::HTTPGet ....................................................................................................................................................... 109 wwIPStuff::HTTPConnect ................................................................................................................................................ 110 wwIPStuff::HTTPGetEx ................................................................................................................................................... 110 wwIPStuff::OnHTTPBufferUpdate .................................................................................................................................. 111 wwIPStuff::HTTPGetExAsync ......................................................................................................................................... 112 wwIPStuff::AddPostKey ................................................................................................................................................... 113 wwIPStuff::HTTPClose .................................................................................................................................................... 114 wwIPStuff::EncodeDBF ................................................................................................................................................... 114 wwIPStuff::DecodeDBF ................................................................................................................................................... 114 Low Level HTTP Methods ............................................................................................................................................... 115 wwIPStuff::RasDial .......................................................................................................................................................... 115 wwIPStuff::RasHangup..................................................................................................................................................... 116 wwIPStuff::GetSystemErrorMsg ...................................................................................................................................... 116 Class wwHTTPAsync .......................................................................................................................... 117 Parent Class: Timer Source: wwIPStuff.vcx ............................................................................................................ 118 How it works ......................................................................................................................................................................... 118 Properties and Methods ......................................................................................................................................................... 119 Class wwHTTPData & wwHTTPFile ................................................................................................... 120 Parent Class: aHTTPData Source: wwIPStuff.vcx ................................................................................................... 120 How it works ......................................................................................................................................................................... 120 The Client Side ................................................................................................................................................................. 120 The Server Side ................................................................................................................................................................ 121 Security.................................................................................................................................................................................. 122 Basic Authentication ......................................................................................................................................................... 122 Secure Sockets Layer (SSL) ............................................................................................................................................. 122 Uploading Files via HTTP with wwHTTPFile ................................................................................................................. 122 wwHTTPData::Execute .................................................................................................................................................... 123 wwHTTPData::S_Execute ................................................................................................................................................ 124 wwHTTPFile::SendFile .................................................................................................................................................... 124 wwHTTPFile::S_SendFile ................................................................................................................................................ 125 Class wwPDF – Adobe Acrobat File Creation ................................................................................... 126 Source: wwPDF.prg............................................................................................................................................................... 126 How to use it:......................................................................................................................................................................... 126 Adobe PDFWriter Configuration .......................................................................................................................................... 127 Support Classes ................................................................................................................................. 129 Class wwAPI ......................................................................................................................................................................... 129 Class wwEval ........................................................................................................................................................................ 131 Procedure Library wwUtils................................................................................................................. 135 Function File2Var .................................................................................................................................................................. 135 Function Extract .................................................................................................................................................................... 135 Function MergeText .............................................................................................................................................................. 135 Function AparseString ........................................................................................................................................................... 136 Function Path ......................................................................................................................................................................... 136 Function OpenExclusive ........................................................................................................................................................ 136 Functions URLEncode and URLDecode ............................................................................................................................... 137 IsComObject .......................................................................................................................................................................... 137 RegisterOleServer.................................................................................................................................................................. 137 DCOMCnfgServer ................................................................................................................................................................. 138 Function GetAppStartPath ..................................................................................................................................................... 138 Function DomainName .......................................................................................................................................................... 138 Function GoURL ................................................................................................................................................................... 138 Function ShowHTML............................................................................................................................................................ 139 - Page 7 - West Wind Web Connection Table of Contents Function StripHTML ............................................................................................................................................................. 139 Function HTMLColor ........................................................................................................................................................... 139 Function DateToC ................................................................................................................................................................. 139 Functions JustFname, JustStem, JustExt, JustPath, ForcePath and AddBs ............................................................................ 140 Function IsDir ........................................................................................................................................................................ 141 Function FileSize ................................................................................................................................................................... 141 Function ProgLevel ............................................................................................................................................................... 141 Function PropertyDump ........................................................................................................................................................ 141 Function InputForm ............................................................................................................................................................... 141 Function PEMStatus .............................................................................................................................................................. 142 Other Tools.......................................................................................................................................... 143 West Wind Web Monitor ...................................................................................................................................................... 143 Web Server Configuration Component ................................................................................................................................. 143 Dependicies: ..................................................................................................................................................................... 143 Text Wrapper......................................................................................................................................................................... 144 ScriptMap .............................................................................................................................................................................. 144 LogCount ............................................................................................................................................................................... 144 - Page 8 - West Wind Web Connection Class wwServer & Class wwOLEServer Class wwServer & Class wwOLEServer Parent Class: wwServerForm Source: wwServer.prg The wwServer Class is responsible for retrieving incoming Web requests and passing them on to a user defined program or procedure for processing, passing a wwCGI object as a parameter. The user procedure is responsible for creating an output HTML document or command. When the Process() method returns wwServer returns the output to the Web Server for display on the client's browser. How it works The Web Connection Server responsible for communicating with the Web server is implemented using the following class hierarchy: wwServerForm - Visual Form Aspects wwServer - Main Server Logic and File Based Messaging Implementation wwOleServer - Overrides the relevant wwServer methods for operation as an Automation Server wwServerForm is a visual class contained in WebConnection.vcx and contains only the visual aspect of the Server component. wwServer is the heart of the Server classes which contains the core logic of handling incoming Web requests. Web Connection is set up to handle two communication methods with the Web server using file based messaging using a standalone VFP application or OLE Automation based messaging using a compile Automation server. wwServer implements the file based messaging mechanism with wwOLEServer overriding the relevant routines that are different for operation under OLE Automation. The bottom line is that the external interface of the classes are identical and require no specific knowledge of whether the code is running under Automation or File based messaging. File based messaging is implemented using a timer on the main form. The timer polls for request files that are generated by the Web Connection connector DLL (or EXE in the case of WinCGI). The request files go into a specified directory with a given file name template that the Web Connection server is waiting for in the polling loop. When a message file is found an internal method called ProcessHit() is invoked by wwServer. This method retrieves the file along with the path information that is contained within it pointing at an INI file that contains all the server and HTML form data. The INI file is abstracted into a wwCGI object by the wwServer object and then passed on to the Process() method which can now handle the Web request by routing it to a custom program or class. OLE Automation messaging works similiarily, but takes the polling out of the process. Instead of polling for a file, the ProcessHit() method of the wwOLEServer class is called directly when a request is incoming. The Web Connection connector ISAPI DLL loads the Automation server(s) and calls the OLEPUBLIC server ProcessHit() method in the Automation server. A parameter is passed containing the path of the INI file with the Server and HTML Form data. From here on in the process is identical to file based messaging: The INI is abstracted into an wwCGI object and the Process() method is invoked. The wwServer object contains a large number of methods and properties that can be set to configure the server for optimal performance in your environment. How to use it Using the wwServer or wwOleServer classes is a snap. There are two steps for setup: Create a custom class that customizes the server for your application, then instantiate the server. With file based messaging a mainline program has to load the server, with Automation the Web Connection DLL simply creates the server. What follows might look like a lot of code, but if you look closely you'll see that most of it is comments and that you can simply cut and paste the code and change 4 lines of code or so. - Page 9 - West Wind Web Connection Class wwServer & Class wwOLEServer Server Setup With File based messaging the steps come down to initializing the server and then simply showing the server form, which handles the entire server process. Here’s the code to get the server started and waiting for incoming Web requests using file based messaging: #INCLUDE WCONNECT.H DO WCONNECT && Load all the framework classes oServer=CREATE("wwMyServer") oServer.show() RETURN This code loads the server and displays the server form. Check out the code in wcMain.prg for a more complete setup that sets the basic environment and provides some basic loadtime error handling. Implementing your own wwServer class Before you can instantiate your own server though you have to subclass the Web Connection server. This requires creating a class and overriding at minimum 2 methods: SetServerEnvironment() which is used to configure the server internally and Process() which is the entry point routine when a Web hit arrives. The following code shows a minimal implementation of the server class. Note that there are two class defines, one for the OLE server and one for the standalone server. This is necessary since both server types share the same method interface, but a different messing interface – hence the #DEFINE OLESERVER logic to create the appropriate type of server. #IF OLESERVER ************************************************************* DEFINE CLASS wcDemoServer AS wwOLEServer OLEPUBLIC ************************************************************* #ELSE ************************************************************* DEFINE CLASS wcDemoServer AS wwServer ************************************************************* #ENDIF ************************************************************* ************************************************************************ * wwCGIServer :: SetServerEnvironment ************************************* *** This method sets up the environment *** These settings are required! For a more detailed example *** on how to handle multiple setups see wcMain.prg ************************************************************************ FUNCTION SetServerEnvironment *** Must establish root dir SET DEFAULT TO C:\wwApps\wc2 *** Point at the startup INI file THIS.cSetupIniFile="C:\WWAPPS\WC2\wcmain.ini" *** Set up any paths required DO PATH WITH "WWDEMO" ENDFUNC ************************************************************************ * wcDemoServer :: SetServerProperties ************************************* *** Function: This Method should be used to set any server properties *** This occurs just prior to showing the server window. *** Optional – if you do call it it's recommended you - Page 10 - West Wind Web Connection Class wwServer & Class wwOLEServer *** ReadSettingsFromIni(). ************************************************************************ FUNCTION SetServerProperties THIS.ReadSettingsFromIni() && Reads from THIS.cSetupIniFile *** Any settings you want to make to the server THIS.Caption = " Demo - Web Connection " + WWVERSION *** You can override anything here, but I suggest you use *** the INI file for most settings * THIS.SetTimerInterval(150) * THIS.SetCGITemplate("XX_") ENDFUNC * SetServerProperties ************************************************************************ * wcDemoServer :: Process ************************* *** Function: This procedure's main purpose is to route incoming *** requests to individual project PRGs/APPs. ************************************************************************ FUNCTION Process THIS.oCGI.aCGIParms() && Create Array of parameters lcParameter=UPPER(THIS.oCGI.GetCGIParameter(1)) && Get first Parameter (Project) *** Set up project *** Think of these DO CASE CASE lcParameter DO wwDemo with types and call external processing programs: as 'projects' that contain many Web request handlers each == "WWDEMO" THIS.oCGI,THIS CASE lcParameter == "WWTHREADS" DO WWTHREADS WITH THIS.oCGI, THIS *** SYSTEM TASKS CASE lcParameter == "WWMAINT" DO wwMaint with THIS.oCGI, THIS OTHERWISE *** No matching method loHTML=CREATE("wwHTMLString") loHTML.HTMLError("Unhandled CGI Request",; "The server is not setup to handle this request: "+lcParameter) #IF OLESERVER *** Simply assign to output property THIS.cOutput=loHTML.GetOutput() #ELSE *** File based: We need to create and output to file loHTML2=CREATE("wwHTML",THIS.oCGI.GetOutFile()) IF TYPE("loHTML2")="O" loHTML2.Send(loHTML.GetOutput()) ENDIF #ENDIF ENDCASE RETURN ENDDEFINE - Page 11 - West Wind Web Connection Class wwServer & Class wwOLEServer Once you've set up the server and you're running you can forget about this code – it's unlikely to require any changes, other than perhaps an addition for a new 'project' routine or setup for a new site. Pathing issues and dealing with multiple setups This brings up the issue of pathing. You might wonder why there are hardcoded path inside of the class. Unfortunately, this is necessary in order to allow the server to figure out where it's running from – servers might be started from within a system context which is unlikely to put the default path into a known directory. Hence the server needs to have a baseline to find supporting data files and the startup config file. In order to support multiple sites I've taken to using a global #DEFINE LOCALSITE in WCONNECT.H – a numeric value that determines the site that I'm currently running under. In the wwServer::SetServerEnvironment I can then do the following: *** This value in WCONNECT.H #DEFINE LOCALSITE 1 && 1 – Office 2 – Online 3 – Notebook etc. *** This code in wwYourServer::SetServerEnvironment() #IF LOCALSITE=1 SET DEFAULT TO "C:\WWAPPS\WC2\" THIS.cSetupIniFile="C:\WWAPPS\WC2\wcmain.ini" #ENDIF #IF LOCALSITE=2 SET DEFAULT TO C:\WCONNECT THIS.cSetupIniFile="c:\WCONNECT\wcmain.ini" #ENDIF Exposed Properties: Property What it does cTempCGIFile The wwCGI object that is created whenever a Web request comes in. This object is created once and then recycled for each hit. An API object that is used internally by the server, but can also be used externally to minimize object creation. The temporary file path where Web Connection stores and retrieves the messaging files used for communications with the server. Full file path to the INI file that contains the server information. cCGIFileTemplate The three letter template that is used in File based messaging cDLLIniFile The name of the Web Connection DLL startup INI file. This file contains the system level parameters. This value is set only after the first hit from the DLL occurs onto the server. The startup path of the application. This value is read with GetAppBasePath() and set in the Init() of this class. The Init does a SET DEFAULT TO (THIS.cAppBasePath). To override this value set it in SetServerProperties directly or override GetAppBasePath() The name of the Setup INI file that contains the server's startup parameters. Typically this is the same name as the mainline program. For example: wcMain.ini. This property is handy for reading application specific info such as paths from the INI. The file is located using the cAppBasePath property path. Contains an error message if the server's ProcessHit() method failed. oCGI oAPI cTempFilePath cAppBasePath cSetupIniFile cErrorString nScriptMode Property that determines how the default scriptmaps are for WCS pages are executed. The following values are available: 2 - Precompiled FXP files 3 - Runtime Interpretation using CodeBlock (default) For maximum flexibility at design and runtime use the Codeblock method. For maximum speed but lack of dynamic changes to pages uses 2 precompiled FXP files. Because FXP files are compiled - Page 12 - West Wind Web Connection Class wwServer & Class wwOLEServer changes made to the script will not reflect until the FXP is recompiled. Exposed Methods: wwServer::Init The class constructor for the wwServer class sets up the basic options for the server class by specifying the program to execute when a CGI request is received. Syntax Return Arguments oServer=CREATE(“wwServer”, cTimerClass) Nothing CtimerClass This parameter lets you specify the name of the timer class that is used to poll for incoming requests. This option allows you to override the default timer and use your own version, which should be subclassed from wwCGITimer. Example oServer=CREATE(“wwServer”,”ProcessCGI”,"MyCGITimer") Remarks See Also wwCGI::SetForegroundTaskingPriority; wwServer::Show; wwServer::SetCGIClass wwServer::SetServerEnvironment (virtual) This method is responsible for setting up the server's environment in terms of path information and finding the setup files to put the server into a predictable state. Typically you'll set the the DEFAULT directory here and point the cSetupIniFile property at the server settings INI file. Syntax oServer.SetServerEnvironment() Return Nothing Arguments None. Example *** Example implementation of SetServerEnvironment FUNCTION SetServerEnvironment *** Location of the startup INI file THIS.cSetupIniFile= ADDBS(THIS.cAppBasePath) + "wcmain.ini" *** This URL is executed when clicking on the Automation Server *** form Exit button. It forces operation through a browser! THIS.cOleReleaseUrl=; "http://localhost/wconnect/wc.dll/maintain?release" #IF !DEBUGMODE ON ERROR DO ErrorHandler WITH ; ERROR(),MESSAGE(),MESSAGE(1),SYS(16),LINENO() IN WCMAIN.PRG #ENDIF ENDFUNC * SetServerEnvironment - Page 13 - West Wind Web Connection Class wwServer & Class wwOLEServer Remarks See Also This method is virtual and must be overridden by your code. wwServer::SetServerProperties wwServer::SetServerProperties This method is responsible for configuring the server object properties. This method is called just before the server is made visible on the desktop with the Show() method, but after all objects have been created on the form. Syntax oServer.SetServerProperties() Return Nothing Arguments None Example *** Sample Implementation FUNCTION SetServerProperties THIS.ReadSettingsFromIni() && Reads from THIS.cSetupIniFile *** Any settings you want to make to the server THIS.Caption = " Demo – Web Connection " + WWVERSION *** Any path settings should go here – SET DEFAULT already done DO PATH WITH "WWDEMO" DO PATH WITH "WWTHREADS" ENDFUNC Remarks See Also wwServer::SetServerEnvironment wwServer::ReadSettingsFromIni This method reads the standard INI file properties at startup. This method is automatically called in SetServerProperties. If you override SetServerProperties you have to either call this method explicitly or load the following properties according to your set up: INI file keys read by ReadSettingFromIni Path=c:\temp\ Template=WC_ Priority=0 TimerInterval=250 LogToFile=On ShowStatus=On SaveRequestFiles=Off Properties set by ReadSettingsFromIni: cTempFilePath="" cCGIFileTemplate="WC_" nTaskingPriority=0 tmrRequest.Interval=250 lLogStatus=.T. lShowStatus=.T. lSaveRequestFiles=.F. - Page 14 - West Wind Web Connection Class wwServer & Class wwOLEServer Syntax oServer.ReadSettingsFromIni() Return nothing Arguments none Example PROTECTED FUNCTION SetServerProperties *** Reads the settings from the WCMAIN.INI file *** using the THIS.cSetupIniFile member THIS.ReadSettingsFromINI() … your additional code here ENDFUNC * SetServerProperties Remarks See Also This method is called automatically in SetServerProperties. You should call this method anytime you override SetServerProperties. wwServer::SetServerProperties wwServer::SetCGIClass This method allows you to specify the CGI class that is instantiated and passed to your user defined function by the Web Connection CGI Server. This allows you to subclass the CGI class for your own customizations or special Web Server specific implementations. Syntax Return Arguments oServer.SetCGIClass( cClassName ) Nothing cClassName The name of the class that is instantiated by the CGI Server and passed to the user defined function. Example Remarks See Also oServer=CREATE(“wwServer”,”Process”) oServer.SetCGIClass("MyCGIClass") oServer.Show Required only if you are overriding the default wwCGI class provided with Web Connection. wwServer::Init wwServer::Show The Show method is the do all function that creates the process form, timer and initiates the event loop used to process incoming CGI requests. By default the form created is modally, but you can pass a parameter of .T. to allow non-modal server operation. The Show method is automatically called for Automation servers at the end of the Form's Init. Syntax Return Arguments oServer.Show( nModal ) nothing nNotModal This parameter is not used internally, but required for baseclass compatibility Example oServer=CREATE(“wwServer”) - Page 15 - West Wind Web Connection Class wwServer & Class wwOLEServer oServer.Show() In this example the server is started and will sit on the Show() method until the form’s Exit button or close button is clicked. PUBLIC oServer oServer=CREATE(“wwServer”) oServer.Show(0) In this example the server will continue to run once you return to the FoxPro command window. Note, that due to the way the VFP timer is used to periodically check for CGI request files, the server will not check for requests whileVFP processes non-interactive commands. This means it’ll only work non-modally from the command window, or while sitting on a READ EVENTS while waiting for input. Remarks See Also wwServer::Init wwServer :: SetCGIFilePath Allows you to set the path where the CGI server looks for CGI request files. By default this is the local machine’s TEMP directory as received through Windows, but you can specify another path, most notable a network drive to move the VFP CGI Server process onto a machine other than the one running the web server. To run remotely VFP and the entire VFP Web Connection code resides on a separate network machine, while the web server and wwcgi.dll execute on a dedicated Web Server machine. In this situation you usually assign the path to something like H:\TEMP where H: is the network drive that contains the web server. This setting must match the path that is used by the web server and wwcgi.dll to place temporary files, which with WebSite is in the local machine’s TEMP directory. Syntax Return Arguments oServer.SetCGIFilePath(cPath) Nothing cPath The path where to look for CGI request files generated by the wwcgi.dll CGI program. This method is optional and used internally by ReadSettingsFromIni() Example Remarks See Also oServer=CREATE(“wwServer”) oServer.SetCGIFilePath(“F:\TEMP\”) oServer.Show() Use this method to effectively separate the web server and VFP CGI server process by pointing at the Web Server’s TEMP over a network link. wwServer::Init wwServer :: SetForegroundTasking Allows you to set the operating system tasking priority of the VFP server process. By default VFP operates as a background task on the Windows desktop. By bumping up the priority level VFP can drastically speed up processing of requests. Keep in mind that setting priority levels on VFP will affect other sessions. You need to experiment to find a balance that will allow you to run multiple VFP sessions with equal response times. Syntax Return Arguments oServer.SetForegroundTasking(nPriority) Nothing nPriority This is the priority level to set the CGIServer task to. VFP’s normal status is 0 and when set to a background task results in abysmal performance. The default value set is 1, and is - Page 16 - West Wind Web Connection Class wwServer & Class wwOLEServer also set by the Init method (higher priority). Valid values are: 0 - Normal (background operation – recommended for multi-session under NT) 1 - Above Normal (recommended for Win95 or single server) Web Connection Default 2 – Highest 15 - Critical (not recommended) 31 - Real Time (not recommended) Levels above 2 are not recommended as they will shut down even system tasks and mouse operation. Example oServer=CREATE(“wwServer”) oServer.SetForegroundTasking(2) Remarks This option can also be set with the Init method’s nTaskingPriority parameter. Setting this option may require some tweaking depending on your configuration and on how you use the VFP Web sessions. As a generic starting point priority 1 works very well. In addition I find these priority settings adequate: Single session: NT: 1 95: 2 Multi-Session: NT: 0 and set Control Panel Tasking to equal back and foreground 95: 1 See Also wwServer::Init wwServer :: SetTimerInterval Allows you to specify the timer resolution of the polling loop used to check for incoming requests when using file based messaging. Shorter intervals provide quicker response, but more CPU overhead. This method allows you to control the proper balance on your own. Syntax Return Arguments oServer.SetTimerInterval(nInterval) Nothing NInterval The timer interval value in milliseconds. The default (if not called or called without a parameter) is 250 milliseconds, which works well on Pentium class machines. Slower machines should use larger numbers to minimize CPU load while polling. Example Remarks See Also oServer=CREATE(“wwServer”) oServer.SetTimerInterval(500) Applies only to file based messaging. Do not set this value too small or you might incur too high of a CPU load looking for files. 100 is a good low value for busy servers that are running P166 or faster machines. wwServer::SetForegroundTasking wwServer :: SetLogToFile Turns file logging of requests to a table on or off. By default no logging of requests takes place, but when passed .T. this function sends all request statistics to the CGILOG.DBF table. Syntax Return oServer.SetLogToFile (lLoggingOn) Nothing - Page 17 - West Wind Web Connection Class wwServer & Class wwOLEServer Arguments lLoggingOn Turn logging on if .T. off if .F. .F. is the default at form creation time. Example Remarks See Also oServer=CREATE(“wwServer”) oServer.SetLogToFile(.T.) Use only if you need to keep a log of CGI requests since it affects performance slightly. If you receive lots of requests the log file can big quickly and cause overhead. CGILOG table logs: Date/Time, CGI parameter string, remote address (if available) and the processing duration of the query/process. wwServer::SetStatusWindow; wwServer::LogEntry wwServer :: GetLogToFile Tells whether file logging is turned on or off. Syntax Return Example oServer.GetLogToFile () .T. or .F. llLoggingON=oServer.GetLogToFile() Remarks See Also wwServer::SetLogToFile; wwServer::LogEntry wwServer :: LogEntry Places an entry into the log file, but only if request logging is turned on with SetLogToFile(.T.). When logging is enabled this method is called automatically following each request. Entries are logged into CGILOG.DBF. Syntax Return Arguments oServer.LogEntry(cDescription, cRemoteAddress, nSeconds) Nothing cDescription When automatic logging is enabled the CGI parameter is passed as the first description. If you manually call this method use any string that describes the entry. This can be very handy for writing error messages to the log file in case the program bombs. There are two template values that you can pass: START STOP - Server Startup Entry Server Shutdown Entry cRemoteAddress When automatic logging is enabled the remote address if available is placed into this parameter. Note that some browser do not pass this information along for privacy reasons. Use Local for system messages. nSeconds When automatic logging is enabled this parameter receives the time that it took to process a CGI request by the user defined process. This is the same value that is displayed in the server status window. Use 0 for system log entries or errors. Example PUBLIC oServer, glExitCGIServer ON ERROR DO ERROR WITH ERROR(), MESSAGE(), MESSAGE(1) - Page 18 - West Wind Web Connection Class wwServer & Class wwOLEServer oServer.SetLogToFile(.T.) oServer.LogEntry("START") oServer.Show oServer.LogEntry("STOP") && Turn Logging on && Send Start Message to log PROCEDURE ERROR LPARAMETER nErrorNo,cErrorMsg1,cErrorMsg2 lcError="Error #"+STR(nErrorNo)+CR+; cErrorMsg1+CR+cErrorMsg2+CR+CR+; "CGI Parameter String: "+ oServer.oCGI.GetCGIParameter() oServer.LogEntry(lcError,"Local",0) CLOSE DATA RETURN TO MASTER Remarks See Also wwServer::SetLogToFile wwServer :: SetStatusWindow Determines whether the status window shows the server status by displaying the processing light and showing the recent request in the client area. Turning off the status window can speed operation slightly, since VFP's I/O operations are notoriously slow. Use this only if you want to eek out every last bit of speed from a processing request or if you are already logging the info to file. Syntax Return Arguments oServer.SetStatusWindow(lUpdateWindow) Nothing lUpdateWindow Set to .F. if you don't want the status window to display the last request information. Example oServer=CREATE(“wwServer”) oServer.SetStatusWindow(.F.) Remarks Only minor performance enhancements can be achieved by using this option. See Also wwServer::SetLogToFile wwServer :: SetCGITemplateFile Sets the template for the message file that the CGI server is looking for. The template consists of the first few letters plus a unique hex string plus a TMP file extension. For example a template of “ww_” would yield: ww_xxxxxx.tmp where the xxxxx would be a unique hex number. You have to use this method in conjunction with the Template entry in the wwcgi.ini (or renamed) file setting to create files with this template. Syntax Return Arguments oServer.SetCGITemplate(cTemplateChars) Nothing cTemplateChars First letters of the temporary message files that the CGI server is looking for. Default is “wc_”, which is also the wwcgi.dll default. Example oServer=CREATE(“wwServer”) oServer.SetCGITemplate (“wwWeb_”) - Page 19 - West Wind Web Connection Class wwServer & Class wwOLEServer Remarks See Also This method is useful only if you decide to rename the wwcgi.dll file to something else and edit the corresponding .ini file to create message files with the new template. Using this approach allows you to essentially separate VFP CGI Servers to process only requests specific to a particular application for example. wwcgi.ini Template setting wwServer :: CleanTempFiles This routine can be used to clean up any remaining temporary files generated by Web Connection and/or WinCGI Web servers. Just call the method without parameters and it will clean up the temp files. Syntax Return oServer.CleanTempFiles() Nothing Arguments Example Remarks oServer.CleanTempFiles() Use this method to cleanup leftover temp files. These files can be left over when requests time out on the FoxPro end and cause the Web Connection connector to terminate the link before output could be sent back from the FoxPro session. Call this routine in an infrequently accessed method of your process class to execute occasionally. wwServer::SendMail The SendMail method allows your Web Connection server to send SMTP email messages via an accessible SMTP email server. SMTP mail is implemented in the wwIPStuff class using its SendMailAsync() method. The wwIPStuff.dll file must be installed either in your Windows SYSTEM directory or within the FoxPro PATH in order to load the DLL properly. WinSock 2.0 is required. Syntax Return Arguments oCGI.SendMail(cMailServer, cSenderDisplayName,; cSenderEmailAddress, cRepientList, cCCList,; cSubject, cMessage,; cAttachment,cBCCList,cContentType) .T. or .F. If .F. check wwIPStuff::cErrorMsg for an error message CmailServer The Domain name or IP Address of the mail server that will handle sending the message. The mail server must be accessible via a TCP/IP connection at the designated IP address and you must have a valid account on this mail server to successfully send email. IP Addresses are in the format “205.111.111.2”. CsenderDisplayName The return address name that is displayed on the email message when received. This is the display name only, not the email address. Note that most mail servers override this with the name set up on the sending email account. CsenderEmailAddress The actual return address email address that is displayed on the email message. This should be the address that you want replies to be sent to. CrecipientList The list of recipients represented as a comma delimited string. All recipients should be - Page 20 - West Wind Web Connection Class wwServer & Class wwOLEServer entered as fully qualified email addresses. You may also use the following syntax to enter display names and email addresses: ["Rick Strahl" <rstrahl@west-wind.com>,Bill Dozer <bdozer@mail.com>] CCCList List of CCs represented as a comma delimited string. All recipients should be entered as fully qualified email addresses. Csubject The subject for the email message. Cmessage The actual message text. This string can be of any length and can contain line breaks as necessary. Cattachment You can attach one file attachment to the message. The file is UUEncoded and must exist while the message is being sent. Since SendMail works asynchronously you can't delete the file as part of your request CcontentType Allows you to set the Content Type of a message. The default is text/plain, but you can also set it to text/html to send HTML formatted messages. Example Remarks oServer.SendMail(; "205.000.000.000",; "Rick Strahl",; "rstrahl@west-wind.com",; "budney@bbatech.com, dan@gorge.net",; "glenn@gorge.net, webmaster@surplus.com",; "Test Message",; "This is a test message."+CR+"End of Message") All parameters to this method are optional! If not specified the class properties are used instead and this is the recommended way to use this function. The parameter names directly correspond to the property names that can be used instead. Sendmail returns .T. or .F. If it returns .F. you can check the wwIPStuff::cErrorMsg property for a potential error message wwServer :: CreateSessionEntry This and the following functions deal with managing multiple simultaneous Web Connection/Visual FoxPro sessions. These methods are called by the SESSIONS procedure in the main program file (wcMain). This method simply writes a session into the current session file. Sessions are created when Web Connection is started and deleted when it's shut down. The Session table is called WWSESSIONS and is located in the Temp file directory. The file is accessed only for maintainence tasks. This method is likely only going to be called internally, but is provided here for completeness since the opposite method KillSessionEntry is exposed in order to allow for early exits via QUIT. Syntax Remarks See Also oServer.CreateSessionEntry () Creates a session entry in wwSessions.dbf which is located in your CGITemp directory. If no serious crashing errors occur wwSessions should contain an accurate count of sessions running wwServer::KillSessionEntry; wwServer::GetSessionCount - Page 21 - West Wind Web Connection Class wwServer & Class wwOLEServer wwServer :: KillSessionEntry KillSessionEntry deletes the current server from the SessionLog file. This method is automatically called in the Destroy event of this class. However, it's necessary to call this method manually when causing an early exit as required by the Session functions to exit and recycle Visual FoxPro. When using these call KillSessionEntry to make sure the list of servers is updated appropirately. Syntax Remarks See Also oServer.KillSessionEntry () Deletes the current server's entry in wwSessions.dbf which is located in your CGITemp directory. If no serious crashing errors occur wwSessions should contain an accurate count of sessions running wwServer::CreateSessionEntry; wwServer::GetSessionCount wwServer :: GetSessionCount This method returns the number of sessions that are currently running. The count is based on the number of valid entries in wwSessions in the CGITempFilePath. . Syntax Remarks See Also oServer.GetSessionCount () Returns the numeric value for the number of sessions. If no sessions are running or an error occurs accessing the session file the method returns 0. wwServer::KillSessionEntry; wwServer::GetSessionCount wwServer :: GetAppBasePath() This method returns the application startup path. The application startup path comes out of the registry by default – the value is set from the Status window's Startup Path field (when you click Update Settings). This value is read at application startup. If the value doesn't exist the startup directory of the EXE/APP/PRG is written to the registry as the new startup path. This method sets the cAppBasePath property. You can override this method for special handling of application startup paths and setting the cAppBasePath property. Syntax Remarks See Also oServer.GetAppBasePath() Returns the application startup path from the registry. wwServer::cAppBasePath - Page 22 - West Wind Web Connection Class wwProcess Class wwProcess Parent Class: Relation Source: wwProcess.prg The wwProcess class is meant to be used as the Web application class or at least as the entry point rotuine for any Web request. Each Web request has a corresponding method in this class that is called for each request. The class provides automatic initialization of CGI and HTML objects which become members of the class and are thus accessible for all process methods. In addition the class provides built in error handling with an Error Method that automatically displays and logs an error page in case of any error (unless DEBUGMODE is set to .T. in WCONNECT.H in which case the error bombs for debugging purposes). The wwProcess class is not a required component in Web Connection. The way Web Connection you can use the main function that is called of the wwServer::Process() method directly to handle requests without creating an instance of the wwProcess object. However, use of this class will make life easier for you as it encapsulates access to various other objects in the framework. How it works The wwProcess class is mostly a container class for other objects in order to simplify access to the other objects throughout the framework. As such only a few custom methods and properties are defined in this class. Typically a Web Connection request is started off by the wwServer::Process() method calling a UDF or PRG of your choice. This PRG takes two parameters: a wwCGI and wwServer object. These parameters are used to create a new Process object which builds references to them and uses them internally making them available for your own routines. The setup code for the UDF and class creation looks like this: * PROCEDURE wwDemo LPARAMETER loCGI, loCGIServer #INCLUDE WCONNECT.H #IF OLESERVER loProcess=CREATE("webConnectDemo",loCGI,loCGIServer,"~","+","wwhtmlstring") #ELSE loProcess=CREATE("webConnectDemo",loCGI,loCGIServer,"~","+","wwhtml") #ENDIF *** Call the Process Method that handles the request loProcess.Process() #IF OLESERVER *** Must return output to the server in cOutput property loCGIServer.cOutput=loProcess.oHTML.GetOutput() #ENDIF RETURN The code above basically the two objects as parameters then creates a Process object and calls its Process() method which is its entry point for Web request processing. The actual wwProcess class implementation needs to be subclassed by you in order to attach custom processing methods to the code. The minimal wwProcess subclass looks like this: ************************************************************* - Page 23 - West Wind Web Connection Class wwProcess DEFINE CLASS webConnectDemo AS wwProcess ************************************************************* ************************************************************************ * webConnectDemo :: HelloWorld * URL to arrive here: wc.dll?MyPrg~HelloWorld ************************************************************************ FUNCTION HelloWorld THIS.StandardPage ("Hello World","Hello from Visual FoxPro. "+; "The current time is: <b>"+Time()+"</b>") RETURN *EOF TestPage FUNCTION OtherRequest … ENDFUNC ENDDEFINE Each additional request you create with a link from an HTML page (link or Form button that calls wc.dll) needs to have a corresponding method in this class. Your subclass of wwProcess can contain as many methods as you see fit, although it's best to logically break up the size of classes into logical classes stored in separate program files or classes. In order to do so you'd pass a different first 'parameter' on the URL (in the example above MyPrg – MySecondPrg for example) to route to another PRG file that can handle another set of requests using another subclass of the wwProcess object. The wwProcess class actually manages calling your code via its entry point method – the Process() method. If you need to do some logic tasks that need to occur on each hit you should override the Process method with your own code. A typical custom Process method looks like this: ************************************************************************ * webConnectDemo :: Process *************************** *** Function: This is the callback program file that handles *** processing a CGI request *** Return: .T. to erase Temp File .F. to keep it ************************************************************************ FUNCTION Process LOCAL lcParameter, lcOutFile, lcIniFile, lcOldError *** And retrieve the HTMLPagePath and cDataPath vars THIS.cHTMLPAGEPATH = THIS.GetAppIniVar("HTMLPAGEPATH",THIS.Class) THIS.cDATAPATH = THIS.GetAppIniVar("DATAPATH",THIS.Class) *** Retrieve the second parameter PrgFile~Method lcParameter=UPPER(THIS.oCGI.GetCGIParameter(2)) DO CASE CASE lcParameter = "DISPLAYFILE" OR lcParameter="SHOWPAGE" =THIS.DisplayFile(THIS.oCGI.GetCGIParameter(3),THIS.cHTMLPagePath) *** GENERIC ROUTING BY PARAMETER NAME CASE !EMPTY(lcParameter) AND PEMSTATUS(THIS,lcParameter,5) =EVALUATE("THIS."+lcParameter+"()") OTHERWISE *** Unhandled method - display error page THIS.ErrorMsg("The server was unable to respond "+; "to the CGI request",; "Parameter Passed: <b>"+PROPER(lcParameter)+"</b><CR>"+; "Error: <b>Unhandled Method</b>") ENDCASE RETURN - Page 24 - West Wind Web Connection Class wwProcess Some things you might want to do in your custom Process method is do password validation, checking for Authentication, checking for cookies or other UserIds or anything that basically happens on every or most hits that you don't want to handle on a specific request each time. For example, to check authorization you might use the following code snippet inside of the Process() method: *** Check if user was previously Authenticated lcUserName=loCGI.GetAuthenticatedUser() IF EMPTY(lcUserName) *** User hasn't logged in yet *** create HTTP header to force dialog THIS.oHTML.HTMLAuthenticate(loCGI.GetServername()) RETURN .T. ENDIF DO CASE … ENDCASE RETURN The wwProcess object subclass you've created has a built-in error method. The Error method captures all errors that are generated while processing CGIProcess code. Since all of your processing code will be implemented using new methods in this subclass the Error method will catch the majority of coding errors. The error method simply returns an error message to the Web Server thus completing the CGI request even though the actual CGI process failed. The ErrorMsg method is a quick way to spit out an HTML error page, or any other quick message in response to unexpected events, either under program control or as a response to an error event. To turn off built-in Error handling you can toggle the #DEFINE DEBUGMODE switch in WCONNECT.H. When set .T. the Error method is not compiled into the code and errors stop in the VFP debugger for you to trace or fix the error. When .F. the Error method gets compiled and saves handles the error. Exposed Properties: Property oCGI oHTML oCGIServer oSession cHTMLPagePath cDataPath What it does An instance of a wwCGI object that is pre-initialized when the Process object is created. The object is passed in as part of the class Constructor (init()). See wwProcess::Init for details. An instance of an HTML that is pre-initialized for the appropriate output method when the Process object is created. Note: The class that is used for this object can be passed as the last parameter of the class Constructor (Init()). See wwProcess::Init for details. An instance of a wwServer object that is responsible for calling this request. This back reference allows access to properties and methods of the server object that might be used for maintenance and error operations. An instance of a wwSession Object that must be explicitly created using the InitSession() method. This object automatically manages an HTTP Cookie, setting and retrieving the value as needed. Once created you can call Get and SetSessionVar() methods to store user specific data. Note: This object is not created automatically! The default is .NULL.! A text variable that is empty by default, but should contain the base physical HTML path where your code goes looking for template HTML pages. Use wwProcess::GetAppFromIniFile() to potentially retrieve this value from the startup INI file. Note: This property is not filled by default. A text variable that holds the path to your data. This should be a base path that is specific for the machine that this request is running on. You can use wwProcess::GetAppFromIniFile() to retrieve the value from the Setup INI for - Page 25 - West Wind Web Connection Class wwProcess example. Note: This property is not filled by default. Exposed Methods wwProcess::Init The wwProcess constructor is responsible for setting up CGI and HTML member objects. Syntax oProcess.Init(oCGI, oServer, cParmDelimiter, cParmSpaceChar, cHTMLClass) Return Nothing Arguments oCGI A wwCGI object passed from the Server process. oServer A wwServer object passed from the process. cParmDelimiter This optional parameter determines the character that is used to separate CGI parameters passed as part of the CGI command line following the ? for the purpose of automatically parsing the parameters into an array. For example: wc.dll?Parameter~Optional+Arguments. The ~ here is a parameter separator. The default is the ‘~’ character. The above example will create a parameter array containing 2 elements: ‘Parameter’ and ‘Optional Parameters’. For more details see the wwCGI::aCGIParms method. CparmSpaceChar Since spaces are not allowed as part of the CGI command line, a replacement character is needed. This parameter specifies the character that is used. By default this character is a ‘+’. Optional. CHTMLClass The name of the HTML class that is automatically created. (wwHTML) Example See Also oProcess=CREATE(“wwMyCGIProc”,loCGI,loServer,”&”,”+”, "wwHTML") wwCGI::aCGIParms wwProcess::Process (Virtual) This method needs to always be overridden by the subclassed version. This method should be a routing routine that figures out what task is to be performed based on the parameter(s) that were passed as part of the CGI commandline. Syntax Return Arguments Example oProcess.Process(oCGI) Nothing OCGI An wwCGI object as passed by the CGIServer process. oProcess.Process(loCGI) - Page 26 - West Wind Web Connection Class wwProcess wwProcess::InitSession This method is responsible for initializing the oSession object property. The object allows attaching a Session to a particular user and attachment of any character variables to that user and session using the THIS.oSession.GetSessionVar() and THIS.oSession.GetSessionVar() methods. This method automatically retrieves a Cookie specified by the single parameter. The method also sets a cookie on the response request if a new cookie is created as long as an wwHTTPHeader Object, or wwHTML::ContentTypeHeader, HTMLHeader, ShowHTMLPage, ShowMemoPage are used. Syntax Return Arguments Example oProcess.InitSession(cSessionCookieName) Session ID string (Char 9) cSessionCookieName Optional – Name of the Cookie that is automatically set and read. Default: wwSessionId loProcess=CREATE("webConnectDemo",loCGI,loServer,,,; [WWC_wwHTMLstring]) *** Enable Automatic Session Object on every request loProcess.InitSession() loProcess.oSession.nSessionTimeout = 3600 && 1 hour *** Call the Process Method that handles the request loProcess.Process *** Usage in wwProcess Request Method PROCEDURE SomeMethod lcWhere = THIS.oSession.GetSessionVar("SQLFilter") IF EMPTY(lcWhere) lcWhere = "" ENDIF SELECT * FROM SomeFile WHERE &lcFilter *** To retrieve the SessionId for use as a Key use this lcSessionId = THIS.oSession.cSessionId INSERT INTO Shoppers (UserId,Visits) VALUES (lcSessionId,1) ENDPROC Remarks See Also This method must be explicitly called in order to create the oSession object. If not called the object will be .NULL. You can choose between using the object as in the example above on every request, or selectively in just the methods that require it. The latter is usually more efficient unless every request requires the object. WwSession Class wwProcess::GetAppIniVar This method retrieves values from the startup INI file. Typically the name of this file will have the same name as the mainline program such as wcmain.ini for wcmain.exe/prg. Values are retrieved from a specific section of the file – by default this section carries the same name as the name of your subclass of this wwProcess implementation. You can use this method to store and retrieve app specific settings from the startup INI file. Good values to pull include an HTML base path and the path to your data files. Syntax Return Arguments oProcess.GetAppIniVar (cValue, cSection) String value of the key or "" if not found. cValue - Page 27 - West Wind Web Connection Class wwProcess The value to retrieve cSection INI file section. If not passed the name of the current class is used. Example * wwMyProcess :: Process PROCEDURE Process THIS.cHTMLPagePath=THIS.GetAppIniVar("HTMLPagePath",; "wwMyProcess") THIS.cDataPath=THIS.GetAppIniVar("DataPath") ENDPROC See Also wwProcess::DisplayFile This is a highlevel method that allows generic display of Web Connection HTML files containing embedded FoxPro expressions or code blocks. To call this method from a URL you would simply do: <a HREF="http://www.west-wind.com/displayfile~Nocode.wc">No code required</a> In order for this to work you need to set up a special handler in the Process method to allow routing any call using DisplayFile to this routine: CASE lcParameter="DISPLAYFILE" =THIS.DisplayFile(loCGI.GetCGIParameter(2),HTMLPAGEPATH) Once this is set up, though, no more code is required to diplay any page that contains embedded FoxPro code! Syntax Return Arguments oProcess.DisplayFile(cPageFile, cBaseHTMLPath) nothing cPageFile Filename of the the HTML template file to display. cBaseHTMLPath Path where the page is to be displayed in. Note that this path should be the base path - any subpaths that are server relative can be specified directly in the URL. Example oProcess.DisplayFile("Nocode.wc",HTMLPAGEPATH) wwProcess::Error This method captures all errors that occur while processing occurs in the wwProccess class. It calls the ErrorMsg method to display an error page and log the error to the error log. wwProcess::StandardPage This method can be used to quickly display a simple HTML page by passing a title and a message. The page is generated with a simple header and the message text. This page is fully self contained including a standard HTTP header. Syntax Return Arguments oProcess.StandardPage(cTitle, cMessage) Nothing cTitle - Page 28 - West Wind Web Connection Class wwProcess The page header. The header is displayed in <h2> text followed by an <HR> line. The window title of the browser is also set. cMessage The main message text for the page. Note – this text can include HTML formatted text. Example oProcess.ErrorMsg("Query Results",; lcResultHTML) wwProcess::ErrorMsg Same as StandardPage – included only for backwards compatibility as well as for readability to distinguish error messages from simple status message pages. Syntax Return Arguments oProcess.ErrorMsg(cTitle, cMessage) Nothing cTitle The page header. The header is displayed in <h2> text followed by an <HR> line. The window title of the browser is also set. cMessage The main message text for the page. Note – this text can include HTML formatted text. Example oProcess.ErrorMsg("Invalid Input",; "Make sure you enter a name..") - Page 29 - West Wind Web Connection Class wwCGI Class wwCGI Parent Class: Relation Source: wwCGI.PRG The wwCGI class’ purpose is to allow your programs to receive information from the web server and the HTML page that generated a CGI request. With it you can retrieve values from variables placed on HTML forms and information about the web server, the client and its browser. An instance of this class is passed to your VFP program that is responsible for creating an HTML form in response to a CGI request generated by the server. How it works A CGIServer object waits for incoming CGI requests. When the Web Server generates a CGI request it is picked up by the VFP CGI request server which in turn passes the wwCGI object to your user defined procedure or program. The wwCGI class’ methods provide easy access to all of the CGI options provided by the server. Website uses an INI file that contains all of the CGI parameters and envrionment variables which are easily accessed with the wwCGI classes methods. The various Get Methods of this class provide specialized and formatted access to all of the CGI variables made available by the web server with specialized methods available for the most commonly used variables. How to use it Your use of the wwCGI class consists mainly of retrieving variables and server stats from the CGI request. Here’s the startup code for the Process procedure that is called when there is an incoming CGI request: PROCEDURE Process LPARAMETERS loCGI LOCAL lcParameter, lcOutFile, lcIniFile lcParameter=loCGI.GetCGIParameter() lcOutFile=loCGI.GetOutfile() lcLastName=loCGI.GetVar(“LastName”) && Optional CGI parameters following EXE name && The output HTML file && Retrieve the last name entered into form The procedure receives a CGI object as a parameter and then immediately pulls some vital information from the CGI request: The optional parameter passed on the CGI command line (ie. /cgi-win/wwcgi?Test_Page) which is used to determine the type of request we’re dealing with, the output file name which is the name of the output HTML file we need to create. For illustration purposes the example also pulls a form variable from the CGI request, but normally this is better left to the specific request handler code that processes a given CGI request. - Page 30 - West Wind Web Connection Class wwCGI wwCGI::Init This constructor of the wwCGI class takes a CGI commandline and assigns a basic set of CGI variables that allow retrieval of all CGI variables from the CGI content file created by the Web Server. In addition, you can specify a path where wwCGI looks for its temporary file. The latter parameter is used to map file names to network drives if the web server is running on a nonlocal machine. Syntax Return Arguments oCGI=CREATE(“wwCGI”,cCommandLine,cTempFilePath) Nothing cCommandLine The constructor of the wwCGI class must be passed a CGI command line that was passed by the web server. The webserver calls the wwcgi.dll file, which in turn captures the commandline. This commandline contains the filenames of the content INI file, the output file, as well as any of the optional CGI parameters that where passed as part of the CGI command issued by the HTML form following a ‘?’ or other CGI path directive. CtempFilePath This optional parameter is important only when the web server is not running on the local machine and is accessed over a network connection. By passing the path that contains the temporary files the web server generates its temporary files to the GetOutFile() and GetContentFile() are automatically translated and mapped to the remote drive. By default this value is assigned by the wwServer class when it passes the CGI request to you - the path is determined by the server’s SetCGIFilePath method. Example Remarks See Also oCGI=CREATE(“wwCGI”,”ProcessCGI”,lcCommandline) You shouldn’t have to worry about this constructor, since the CGI object is created for you in the wwServer class code and both parameters are passed to you pre-set. wwCGI::LoadCGIFileNames; wwCGI::ForcePath wwCGI::LoadCGIFileNames This method assigns the filenames passed on the Webserver command line. Each time a request is incoming the filenames are updated to reflect the latest input and output files specified by the CGI request. Syntax Return Arguments oCGI.LoadCGIFileNames(cCommandLine) Nothing cCommandLine The Web Servers command line passed to the wwcgi.dll program file. Example Remarks See Also oCGI.LoadCGIFileNames(lcCommandLine) You shouldn’t have to worry about this method, since this assignment is made automatically for you when the wwServer class receives a request. wwCGI::Init wwCGI::ServerVariables This is the low level method that allows accessing all CGI variables contained in the Website request information.This method allows access to all variables. To see a complete list of avaiable keys use the Status form's Save Request Files option to capture - Page 31 - West Wind Web Connection Class wwCGI and view the request file. Most keys are abstracted with full methods listed below, but those few keys that don't have dedicated methods can be accessed directly Syntax Return Arguments oCGI.ServerVariables (cVariable,cSection,lForceNull) CGI Variable string or .NULL. cEntry The entry/key from the INI file to return. cSection Optional. This applies only when using the INI file Post Method where keys are separated into sections. Default: CGI Example Remarks See Also oCGI.ServerVariables (“Server Name”) This function allows you access to those values that aren’t as commonly accessed and thus have no specific methods associated with them below. Use the specialized methods when available. Specific variable retrieval methods wwCGI::GetCGIVar This is the low level method that allows accessing all CGI variables contained in the Website content file. The content file contains information about form variables, the web server and the calling web browser. More specialized methods that retrieve and format specific values from the CGI file are provided below. For all available CGI variables check your WebSite documentation. Syntax Return Arguments oCGI.GetCGIVar(cEntry,cSection,lForceNull) CGI Variable string or .NULL. cEntry The entry/key from the INI file to return. Csection The INI file section from the INI file to return. This parameter is optional and defaults to the ‘CGI’ section which contains standard CGI variables. LForceNull Pass as .T. if you want .NULL. to be returned for missing entries. Otherwise a null string is returned, which also applies to empty entries. This optional parameter allows you to specify how non-existant entries are returned. The wwAPI::GetProfilestring method returns a .NULL. value by default, but for the CGI purposes it is more useful to return a null string (“”) instead so no additional checking for .NULL. has to take place. Example Remarks See Also oCGI.GetCGIVar(“Query String”,”CGI”) This function allows you access to those values that aren’t as commonly accessed and thus have no specific methods associated with them below. Use the specialized methods when available. Specific variable retrieval methods - Page 32 - West Wind Web Connection Class wwCGI wwCGI::Form This method retrieves HTML form variables from the CGI content file. It works both with plain variables and for long text vars or variables with embedded control characters. Syntax Return Arguments Example Remarks See Also oCGI.Form(cVarname) Value entered on the form or “” cVarname The name of the form variable to retrieve a value for as defined on the HTML form’s NAME property. oCGI.Form(“LastName”) The format used follows CGI conventions for the various variable types like SELECT MULTIPLE, radio buttons and lists. Variables are formatted (ie. Spaces and control characters are properly translated). wwCGI::GetFormMultiple; wwCGI::ScatterFormVars wwCGI::SetKey This method allows setting a value in the existing CGI object INI file. Useful when using Auto update functions such as the wwHTMLForm :: SetValues() method when trying to not update certain fields on a form automatically. Syntax Return Arguments oCGI.SetKey(cKey,cValue,cSection) Nothing cKey The entry/key from the INI file. cValue The value to set the key to. cSection Section where the key lives. Default: Form Literal Example *** First let's make sure these values are *NOT* updated by *** setting them to 'Null' loCGI.SetKey("lstGuests",WWC_NULLSTRING) loCGI.SetKey("txtCustId",WWC_NULLSTRING) loCGI.SetKey("txtEntered",WWC_NULLSTRING) *** Now update the rest of the form from the request oHTMLForm.SetValues(loCGI) Remarks This method makes it possible to dynamically set values in the existing request. Use to manipulate the key values prior to being used by 'generic' processing routines. You can delete a key by passing CHR(0) as the value. You can use WWC_NULLSTRING as a value to let WC methods know that the value is invalid or should be left alone. See Also wwCGI::GetFormCheckBox This method retrieves HTML form variables that is a checkbox and returns a logical value rather than ON or OFF. - Page 33 - West Wind Web Connection Class wwCGI Syntax Return Arguments oCGI.GetFormCheckBox(cVarname) .T. or .F. cVarname The name of the form checkbox variable to retrieve a value for as defined on the HTML form’s NAME property. Example Remarks See Also oCGI.GetFormVar(“chkDownloadData”) The format used follows CGI conventions for the various variable types like SELECT MULTIPLE, radio buttons and lists. Variables are formatted (ie. Spaces and control characters are properly translated). wwCGI::GetFormVar; wwCGI::ScatterFormVars wwCGI::GetFormMultiple This method retrieves multiselect HTML form variables from the CGI content file into an array. Multiselect variables can be returned when using scrolling HTML lists with the SELECT MULTIPE option. Syntax Return Arguments oCGI.GetFormMultiple(@aVars,cVarName) Count of variables returned. aVars This is the array that will return the selected values. Must be passed by reference! cVarname The variable name used on the HTML form to define the SELECT MULTIPLE tag. Example Remarks See Also DIMENSION laVars[1] lnVars=oCGI.GetFormMultiple(@laVars,“LastName”) The format used follows CGI conventions for the various variable types. Variables are returned formatted and decoded (ie. Spaces and control characters are properly translated). wwCGI::GetFormVar wwCGI::aFormVars Returns all the form vars captured by a request into an array. The array contains 2 dimensions – the name of the form variable and its text value. Use this function to generically retrieve all the information of a form for library routines or repetitive input captures that can be automated. Syntax Return Arguments nVarCount=oCGI.aFormVars (@laFormVars) The number of variables that were created @laFormVars An array that will receive the 2 dimensional array result. Must be passed by reference using the @ operator. Example DIMENSION laFormVars[1] lnVars = THIS.oCGI.aFormVars(@laFormVars) *** Output all form vars FOR x = 1 to lnVars loHTML.SendLn(laFormvars[x,1] + ": " + laFormVars[x,2]) - Page 34 - West Wind Web Connection Class wwCGI ENDFOR Remarks See Also MuliSelect values are not directly supported. These values are returned as they appear in the ISAPI request: MultiVar, MultiVar_1, Multivar_2 etc. and are returned as individual variables. Also note that CheckBoxes that are not checked are not returned as a (empty) key as the ISAPI/CGI request does not make them available. wwCGI::GetFormVar; wwCGI::GetFormMultiple wwCGI::GetOutFile This method returns the name of the output file that the web server expects to receive as a result of the CGI request. The output file must be a MIME/HTML compliant document (see your WebSite or general CGI documention for details). Syntax Return oCGI.GetOutFile() The output file name. Applies only to file based messaging. wwCGI::GetContentFile This method returns the name of the CGI content file. This method is probably most useful for debugging purposes so you can capture the output file and save it for closer examination. Under normal circumstances you shouldn’t need to know what the Content file name is as the class encapsulates it for you and automatically accesses it for all CGI variable requests. Syntax Return oCGI.GetContentFile() The Content file name wwCGI::QueryString This method returns the Query String and individual pieces of it. The method supports both numeric,positional parameters and named parameters. Positional parameters are great for grabbing request information: wc.dll?ClientForm~West+Wind+Technologies~ID0001 URLEncoded parameters are better for optional parameters and look like this: wc.dll?UserName=Rick+Strahl&UserId=0111&Address=400+Morton%0A%0Dhood+River,+OR Essentially spaces are converted to + signs, keys are separated by & and any control characters are converted to hex representations preceeded by a % sign. You can mix positional and URLEncoded parameters by adding a separating ~ between the posititional parms and the named ones: wc.dll?wwdemo~URLTest~&Username=Rick+Strahl&Company=West+Wind which allows you to use both GetCGIParameter(2), which returns URLTest or QueryString("Company") which returns West Wind. - Page 35 - West Wind Web Connection Class wwCGI Syntax Return Arguments oCGI.QueryString(vParameterName) Returns the value of the parameter key specified as the parameter. If the parameter key specified does not exist a null string ("") is returned. cParameterName The parameter key name to retrieve. The parameter can either be numeric for a positional parameter or character to return a URLEncoded parameter. If no parameter is specified the entire querystring is returned. Remarks The key name specified is case sensitive! In the example above, "UserName" works "USERNAME" does not. Parameter styles may be mixed. You can use Web Connection style parameters as long as the URLEncoded parameters follow the WC parameters. To make things more efficient when mixing styles preceed the first URLEncoded parameter with a &. Example See Also lcName=loCGI.QueryString ("UserName") lcRequest = loCGI.QueryString(2) wwCGI::GetCGIParameter wwCGI::aCGIParms This method parses all numeric parameters separated by ~ into an internal array property, translating the decoding parameters. This array of arguments is then accessible by using GetCGIParameter(nParameterIndex). Syntax Return Arguments oCGI.aCGIParms(cSeperator, cSpaceChar) count of parameters cSeparator This optional character that is used to separate individual parameters on the CGI commandline following the ?. By default this is a Tilde ('~') cSpaceChar Optional character used to replace spaces on the CGI parameter commandline. By default this is a plus sign ('+'). Example loCGI.aCGIParms("~","+") lcName=loCGI.GetParameter(2) Remarks Only works with Positional parameters See Also wwCGI::GetCGIParameter wwCGI::GetCommandLine This method returns the full commandline that was used to call the wwCGI.dll/exe file. Again, this is more of a debugging or information tool, more than a truly useful method. Syntax Return oCGI.GetCommandLine() The command line the Web Server used to call the CGI exe file. wwCGI::GetPreviousUrl This method returns the URL of the previous page that was used to call this CGI script. - Page 36 - West Wind Web Connection Class wwCGI Syntax Return Remarks oCGI.GetPreviousURL() The URL of the previously accessed page.. If you nest CGI requests this value returns invalid URL addresses - it’s not possible to dynamically return to a previously generated CGI page other than using the browser’s ‘Back’ button. In these cases use a hardcoded URL instead wwCGI::GetCurrentUrl Returns the current link that's running. Syntax Arguments oCGI.GetCurrentURL(lSecureLink) lSecureLink If specified returns HTTPS instead of HTTP for the protocol portion. Return The currently executing URL wwCGI::GetServerAdmin This method returns the name of the server Administrator as specified in the web server’s setup. Usually this is an e-mail address. Syntax Return oCGI.GetServerAdmin() The server administrator’s email address. wwCGI::GetServerName This method returns the domain name of the server or the IP address if a domain name isn’t available. Syntax Return oCGI.GetServerName() The server name. wwCGI::GetRemoteAddress Returns the IP Address for the remote machine. This information is also logged in the CGILog file. You can use the wwIPStuff::GetDomainFromIP method to resolve the IP address to a domain name. Syntax Return See Also oCGI.GetRemoteAddress() The IP Address of the client connecting to the server. Only available if the browser makes it available. wwCGI::GetServerName - Page 37 - West Wind Web Connection Class wwCGI wwCGI::GetBrowser This method returns the name of the Web Browser used to access the server. Syntax Return See Also oCGI.GetBrowser() The name of the Web Browser (ie. Mozilla, Mosaic etc.) wwCGI::IsHTML30 wwCGI::IsHTML30 This method returns .T. if the Browser in use supports HTML 3.0 tables. Use this method to check for table support. Note: This method replaces the wwHTML::IsNetscape method which still works identically. Syntax Return See Also oCGI.IsHTML30() .T. if the browser supports Netscape extensions and tables. wwCGI::GetBrowser() wwCGI::IsSecure This method returns .T. if the Browser supports secure transactions. This method needs to be updated based on browser types that support SSL or other secure format HTML forms. Syntax Remarks Return See Also oCGI.IsSecure() The functionality needs to be customized as new browser start supporting secure form processing. .T. if the browser supports secure transactions. wwCGI::GetBrowser() wwCGI::IsLinkSecure This method returns .T. if the request was passed over an encrypted link port. By default this method checks the server port for 443, but you can specify an optional port as a parameter. Syntax Arguments Remarks Return See Also oCGI.IsLinkSecure(cPort) cPort Optional parameter that sets the port that is considered the secure port. Default: 443 The functionality needs to be customized as new browser start supporting secure form processing. .T. if the browser supports secure transactions. wwCGI::GetBrowser() - Page 38 - West Wind Web Connection Class wwCGI wwCGI::GetClientCertificate Returns the contents of a client Certificate's Subject key. This information contains the info about the client. The following information is provided: ClientCert Flags=1 ClientCert Cookie=b0c24e793b9f11367c8ec916101b931e ClientCert Subject= L=Internet, O="VeriSign, Inc.", OU=VeriSign Class 1 CA - Individual Subscriber, OU="www.verisign.com/repository/CPS Incorp. by Ref.,LIAB.LTD(c)96", OU=Digital ID Class 1 - Microsoft Full Service, CN=Rick Strahl, E=rstrahl@west-wind.com You can retrieve the Flags and Cookie with the GetCGIVar() method. This method only retrieves information in the Subject key. Syntax Arguments Example Remarks oCGI.GetClientCertificate(cSubKey) cSubKey Retrieves the key from the subject line. A couple of special keys have been provided: EMIAL, EMAIL retrieve those values. All other keys including the CN and E keys can be retrieved by specifying the keyname. oCGI.GetClientCertificate("CN") && Retrieve Common Name This method only works when the PostMethod = URLEncoded in wc.ini and POSTDATA=.T. in wconnect.h wwCGI::GetCookie Returns an HTTP Cookie that was previously set. HTTP cookies allow keeping state by keeping a persistent variable on the user's browser. Cookies are sent along in each HTTP request and appear as a CGI variable in the Extra Headers section output. Syntax Arguments Example Remarks oCGI.GetCookie(cCookieName) cCookieNameCookies only work with Netscape, Internet Explorer and some of the newer browser implementations. Older browsers in general do not support Cookies. The value of the cookie or "" if not found wwCGI::SetCookieString() wwCGI::GetRequestMethod This method returns the CGI method used to generate this request. “GET”, “POST” or “TRANSPARENT” are common settings. Syntax Return oCGI.GetRequestMethod() The request method used to initiate CGI request. wwCGI::GetRequestProtocol This method returns the name of the protocol used by the Web Browser that initiated the CGI request. - Page 39 - West Wind Web Connection Class wwCGI Syntax Return oCGI.GetRequestProtocol() Request Protocol (“HTTP/1.0” for example) wwCGI::GetAuthenticatedUser Returns the name of a user if he has been authenticated by the Web server. This variable gets set and stays set once a user has entered a valid username into the browser dialog box when prompted. The username is valid for a given Web server path and down and once set cannot be unset until the browser is shut down. Syntax Return See Also oCGI.GetAuthenticatedUser () The request method used to initiate CGI request. wwHTTPHeader::Authenticate; wwHTML::HTMLAuthenticate wwCGI::GetPhysicalPath Returns the full path of the currently loaded page. Typically this will be the physical path to the wc.dll file. If you use IIS script mapping to the physical path of the mapped page will be returned. For example: /wconnect/nocode.wc would return C:\HTTP\WCONNECT\NOCODE.WC. Note: the path is not translated for network purposes – a local drive is always returned. Your code needs to handle that if you're running sessions across the network. You can use the ForcePath method to do this chore. Syntax Return See Also oCGI.GetPhysicalPath() The physical path of the page requested. Typically the path will be to the wc.dll. The path is not network corrected, but local to the Web server wwCGI::GetLogicalPath wwCGI::GetLogicalPath Returns the Web server relative path of the currently loaded page. The path is returned relative to the Web server root with forward slashes. Syntax Return See Also oCGI.GetLogicalPath() The logical path of the current request, most likely the name of the wc.dll. wwCGI::GetPhysicalPath wwCGI::ForcePath This utility method should be used on all CGI pathnames that are not retrieved with the specialized CGI methods. Forcepath will strip a file’s current path and replace it with the path where the temporary CGI work files reside. Syntax Return oCGI.ForcePath(cFilename) Adjusted Filename that contains the translated path. - Page 40 - West Wind Web Connection Class wwPostRequest Class wwPostRequest Parent Class: wwCGI Source: wwPostRequest.prg The wwPostRequest class is a specialized subclass of wwCGI to handle communication with URLEncoded string parameters passed to the Web Connection server instead of the original INI file. This class is actually the default class in version 2.70 and later. This class is invoked instead of wwCGI whenever the #DEFINE POSTDATA .T. is set in wconnect.h The exposed interface of this class is identical to wwCGI. wCGI::GetMultiPartFile This methods allows retrieval of an uploaded file from an HTML page using multi-part forms. Multi-part forms and file uploads are fairly efficient as they bypass the traditional URLEncoding that occurs with Form posts. The page link to start a file upload looks like this: <form ACTION="wc.dll?wwDemo~FileUpload" METHOD="POST" enctype="multipart/form-data"> <input TYPE="FILE" NAME="File"><br> <input TYPE="submit" value="Upload File" name="btnSubmit"> </p> </form> To retrieve the file on the server you can use the following code: lcFileName = "" lcFileBuffer = Request.GetMultiPartFile("File",@lcFileName) lcNotes = Request.GetMultipartFormVar("txtFileNotes") lcFileName = SYS(2023)+"\"+lcFileName *** Now dump the file to disk File2Var(lcFileName,lcFileBuffer) Note that lcFilename is passed by reference and filled by the call to GetMultiPartFile(). Note: If you're uploading a file and also receive other form variables those form variables cannot be retrieved with the Form() method as the format of the request is now a multipart form. In order to retrieve other form variables you have to use GetMultipartFormVar(). Also note, that if you try to view the last request data from the server status window the data will look funky as it is not URLEncoded as other text. To check out the request data with multi-part forms you can view the raw request data. Syntax Return Arguments Request.GetMultiPartFile(cFormVar, @cFileName) Value entered on the form or “” cFormVar Name of the Form variable for the File input field on the calling HTML form. @cFileName - Page 41 - West Wind Web Connection Class wwPostRequest Passed by reference! This var receives the name of the file that was uploaded. The var contains only the filename without a path. Example Remarks See above Multipart forms are fairly efficient as they bypass the traditional URLEncoding and Decoding required by POST requests. Files are sent as is in binary form. Please be aware that you may want to check for file sizes and disk space before accepting files and saving them to disk. There's potential to do damage with this feature as people can send you huge files that clog up memory or your disk. Use with caution! See Also wwCGI::GetMultiPartFormVar wwCGI::GetMultiPartFormVar When retrieving multi-part forms because a file upload is included with the form submission you have to use GetMultiPartFormVar() in order to retrieve any additional form variables. Syntax Return Arguments Request.GetMultiPartFormVar (cFormVar) Value entered on the form or “” cFormVar Name of the Form variable to retrieve See Also wwCGI::GetMultiPartFile - Page 42 - West Wind Web Connection Class wwHTML Class wwHTML Parent Class: Relation Source: wwHTML.prg The wwHTML class provides the tools to easily create HTML pages in program code. While this class is purely optional, the example code for Web Connection uses it exclusively to generate HTML output. Other methods of creating output are available, like using the report generator or merging text from tables, but hand coded HTML pages usually provide the fastest way to generate web output in real time. You can also combine use of these other methods with the text output options of this class. How it works The HTML class encapsulates the file output routines required, so that you don’t have to worry about accessing low level file functions for outputting your HTML text. All output can be sent either to a specified file or optionally be returned to you as a result string without actually sending the output to file by setting the tlNoOutput parameter to .T. on each of the methods used. The latter approach comes in handy to nest multiple HTML strings and formats into a single output command, or to use the HTML class only as a partial solution when generating web documents. wwHTML Class: Exposed Methods wwHTML::Init The wwHTML constructor is responsible for setting up the HTML class by setting up the filename that is used to send output to. Syntax Return Arguments oHTML.Init(cOutFile) Nothing Coutfile The filename that all output is sent to. The file is created and must be accessible. You can also pass “NOFILE” which results in output not being sent to a file. This is useful if you want to use the HTML class only partially to handle special HTML features, but handle I/O with another method (say the report writer for example). Example oHTML=CREATE(“wwHTML”,loCGI.GetOutFile) Remarks See Also wwHTML::Destroy, wwHTML::ContentTypeHeader wwHTML::Destroy The wwHTML destructor is responsible for closing the HTML output file of output is sent to a file. - Page 43 - West Wind Web Connection Class wwHTML Syntax Return oHTML.Destroy() Nothing Arguments Example Remarks See Also RELEASE oHTML You will be unable to access the HTML file while the oHTML object is in scope, since the output file will open. wwHTML::Init wwHTML::Write Same as wwHTML::Send wwHTML::Send The Send method is used for all output that is sent to the HTML document in order to keep all file access localized to this one method. Output is sent as is without a trailing carriage return. The optional lNoOutput parameter is used to avoid sending output to the file, returning a string as a result of the method instead. This tlNoOutput option is available for most other wwHTML class methods and passed through to the Send and SendLn methods. Syntax Return Arguments oHTML.Send(cText,lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cText The text to be output. This text can be plain, or HTML formatted - this method doesn’t care. It’s the low level output routine. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks See Also oHTML.Send(“<h1>Hello World Wide Web</h1>”) Output is send as is, without trailing carriage return. wwHTML::SendLn; wwHTML::SendMemoLn wwHTML::SendLn The SendLn method sends a carriage return terminated string to the HTML file. The syntax is identical to the Send method, but operationally this method simply calls the Send method to carry out it’s output. Syntax Return Arguments oHTML.SendLn(cText,lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cText The text to be output. This text can be plain, or HTML formatted - this method doesn’t care. It’s the low level output routine. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. - Page 44 - West Wind Web Connection Class wwHTML Example Remarks See Also oHTML.SendLn(“<h1>Hello World Wide Web</h1>”) Output gets an carriage return at the end. wwHTML::Send; wwHTML::SendMemoLn wwHTML::FastSend The FastSend method is identical in operation to the Send method, but only outputs to the final datasource, missing the lNoOutput option. This method provides the fastest possible output and should be used when dumping output in tight loops. Syntax Return Arguments Example Remarks See Also oHTML.Send(cText) "" cText The text to be output. This text can be plain, or HTML formatted - this method doesn’t care. It’s the low level output routine. oHTML.FastSend(“<h1>Hello World Wide Web</h1>”) Sends output directly to the output source. There is no error checking and the lNoOutput option is not supported wwHTML::SendLn; wwHTML::SendMemoLn wwHTML::SendPar This very simple method sends a hard paragraph break after the text specified if any. Same as SendLn(lcText+“<p>”) but easier to type. Syntax Return Arguments oHTML.SendPar(cText, lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cText Optional text to output before sending <p> lNoOutput When set to .T. output is not sent to file, instead returning the result as a string. See Also wwHTML::SendLn wwHTML::SendMemoLn The SendMemoLn method formats mulit-line text output to look more like standard memo output you’d expect on a report. HTML tends to crowd lines together and skip over carriage returns, which makes unformatted memo/multi-line text look unprofessional. This method allows you to format the memo output by breaking up lines and indenting the text. Syntax oHTML.SendMemoLn(cText,lBreakLines,nColumns,; nIndent,lNoOutput) Return “” if sending to file and the output text if lNoOuput is .T. Arguments cText The text to be output. This text can be plain, or HTML formatted. lBreakLines When set to .T. lines are broken at carriage returns in the memo or when the width specified with nColumns is exceeded. - Page 45 - West Wind Web Connection Class wwHTML nColumns Column to break lines at. nIndent Number of columns to indent text with. Note this will only work if you are using a fixed font (using the <PRE></PRE> tag). lNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks See Also oHTML.SendMemoLn(“<h1>Hello World Wide Web</h1>”) Output gets an carriage return at the end. The indenting option only works appropriately when using the <PRE> pre-formmatted text tag. wwHTML::Send; wwHTML::SendLn wwHTML::BreakMemo A simpler and faster routine to break long text that needs to be displayed as standard font HTML output. All double breaks are converted to <p> tags, all single breaks are converted to <BR> breaks. Lines are not broken as with the SendMemoLn method only natural breaks are converted. Syntax Return Arguments oHTML.BreakMemo(cText, lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cText The text to be output. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks See Also oHTML.BreakMemo(lcLongTextField) This routine is much faster than SendMemoLn. wwHTML::Send; wwHTML::SendLn; wwHTML.SendMemoLn wwHTML::ShowCursor This method allows easy display of an entire table, simply by having a table or cursor selected and calling this method. You can optionally pass an array of headers as well as a title and the option to automatically sum all numeric fields. Syntax oHTML.ShowCursor(@aHeaders, cTitle, lSumNumbers, lNoOutput,; cTableTags) Return “” Arguments aHeaders An array that should contain as many text headers as they are columns in the table/cursor to display. If this parameter is not passed the field names are used as column headers. The header names may be followed by a colon followed by a number indicating the width of the header to override the field width which is used by default. Ctitle Title text to display above the headers. lSumNumbers Flag that allows automatic summing of all numeric fields in the table to display. The total is displayed at the bottom of the display below the appropriate numeric fields. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. cTableTags Allows adding additional table tags to the table display to control the appearance of the HTML table. For example, you could pass "WIDTH=100% BORDER=5" to force the - Page 46 - West Wind Web Connection Class wwHTML table to be full size. The default value is "WIDTH=90%". Example SELECT company, lname ; FROM TT_Cust ; INTO CURSOR Tquery DIMENSION laHeader[2] laHeader[1]=”Company” laHeader[2]=”Last Name” oHTML.ShowCursor(@laHeaders,”Client List”) Remarks See Also By default an HTML table is used for output unless output size exceeds MAX_TABLE_CELLS (Wconnect.h) . To allow HTML tables you have to first call SetAllowHTMLTables with .T. wwHTML::SetAllowHTMLTables wwHTML::ExpandTemplate The ExpandTemplate method method is used to expand template pages that contain FoxPro expressions using Active Server like syntax. The syntax allowed is simple and looks as follows: <%= <%= <%= <%= <%= Version() %> Table.FieldName %> MyUDF() %> PrivateVar %> Class.Property %> or <% Code Block (any valid procedural FoxPro code) %> Expressions are expanded prior to sending the document back to the client, so expressions are valid anywhere inside of the HTML document including in HTML field values and HREF links etc. Note: Since embedded functions are dynamically evaluated through macro expansion you'll want to keep the use of functions to a minimum for speed reasons. If you use excessive functions in your pages I would highly recommend you build a custom Processing routine instead of building the code into an HTML page. Custom code is much easier to debug and maintain and also runs a lot faster since no on the fly evaluation takes place. As a compromise use UDF()s instead of inline functions. Syntax oHTML.ExpandTemplate(cPageName, vContentType, lTemplateString,; lNoOutput) Return “” if sending to file and the output text if lNoOuput is .T. Arguments cPagename The id of the page as entered into the pagename field of the wwHTML table. vContentType By default this parameter creates an HTML formatted document header. You can specify any content type header, or “” to skip the content type header altogether. You may also pass a previously set wwHTTPHeader object. See ContentTypeHeader() method for more details for valid options. lTemplateString If this value is .T. the cPagename parameter contains the actual HTML template rather than a filename. lNoOutput When set to .T. output is not sent to file, instead returning the result as a string. - Page 47 - West Wind Web Connection Class wwHTML Example *** Output page in WWHTML.DBF oHTML.ExpandTemplate(Request.GetPhysicalPath()) Remarks All but the first parameter are optional. Embedded expressions must evaluate to character using EVALUATE(). An internal error handler catches invalid expressions and embeds and shows expressions un interpreted if an error occurs. See Also wwHTML::ContentTypeHeader; wwHTML::CreateHTMLdbf wwHTML::ExpandScript The ExpandScript method method is used to expand script pages that contain FoxPro expressions using Active Server like syntax. The syntax allowed is simple and looks as follows: <%= <%= <%= <%= <%= Version() %> Table.FieldName %> MyUDF() %> PrivateVar %> Class.Property %> or <% Code Block (any valid procedural FoxPro code) %> Script pages differ from template in that they are complete Visual FoxPro programs that support structured statements inside the HTML document. You can do things like the following: <% *** Demonstrate using WC objects lcCompany = Request.QueryString("Company") && ASP Syntax SELECT company,careof ; FROM TT_CUST ; WHERE UPPER(Company) = UPPER(lcCompany) ; INTO Cursor TQuery %> <% SCAN %> <HR> Company: <%= Tquery.Company %> Name: <%= Tquery.CareOf %> <% ENDSCAN %> Note the SCAN loop implemented at the script level. Web Connection implements scripts using TEXTMERGE and 'running' the script as an actual program that contains TEXT/ENDTEXT and embedded textmerge expressions. Expressions are expanded prior to sending the document back to the client, so expressions are valid anywhere inside of the HTML document including in HTML field values and HREF links etc. Note: Because scripts are essentially programs they can rather fast. Three scripting modes are 321- Interpreted (using CodeBlock) Compiled (running as a precompiled FXP file) Inside of the VFP (recompiled on each hit in the IDE) - Page 48 - West Wind Web Connection Class wwHTML Option 2 and 1 are rather fast as they run as native code. Option 1 is much slower as each line of code is interpreted by Randy Pearson's CodeBlock. However, because CodeBlock is fully interpreted it works dynamically in either the development environment or runtime to allow making page changes without recompilation. Syntax Return Arguments oHTML.ExpandScript(cPageName, nScriptMode,vContentType) "" string always – output is sent directly to the Response stream CPagename The Page that is to be interpreted as script. NScriptMode The mode that the script runs in 3Interpreted (using CodeBlock) 2Compiled (running as a precompiled FXP file) 1Inside of the VFP (recompiled on each hit in the IDE) Default: 1 (It's recommended you pass THIS.oCGIServer.nScriptMode which can be configured in the startup INI file) vContentType By default this parameter creates an HTML formatted document header. You can specify any content type header, or “” to skip the content type header altogether. You may also pass a previously set wwHTTPHeader object. See ContentTypeHeader() method for more details for valid options. LTemplateString If this value is .T. the cPagename parameter contains the actual HTML template rather than a filename. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example *** Output page in WWHTML.DBF oHTML.ExpandScript(Request.GetPhysicalPath()) Remarks All but the first parameter are optional. Embedded expressions must evaluate to character using EVALUATE(). Any error in the script will cause an error message to be displayed attempting to show the context of the error in several surrounding lines of code. See Also wwHTML::ContentTypeHeader wwHTML::EnclosedText This method encloses the specified text in a pair of HTML tags. For example, SendPar(“b”,”Hello World”) will generate “<b>Hello World</b>”. Syntax Return Arguments oHTML.EnclosedText(cTag, cText, lNoOutput) “” if sending to file and the output text if lNoOuput is .T. CTag HTML Tag name without the enclosing <>’s CText The text to enclose LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks oHTML.EnclosedText(“b”,”This is a bold Statement”) No carriage return send at end of line. See wwHTML::HeaderText for sending headers that are followed by CRs. You’ll commonly use this with the lNoOutput option to embed - Page 49 - West Wind Web Connection Class wwHTML enclosed text into another string. See Also wwHTML::HeaderText wwHTML::HeaderText This method encloses the specified text in a pair of HTML tags. For example, HeaderText(“H2”,”Hello World”) will generate “<h2>Hello World</h2>”. The text is followed by a carriage return. Syntax Return Arguments oHTML.EnclosedText(cTag, cText, lNoOutput) “” if sending to file and the output text if lNoOuput is .T. CTag HTML Tag name without the enclosing <>’s CText The text to enclose LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks See Also oHTML.HeaderText(“h2”,”Hello World”) A carriage return is send at end of line. See wwHTML::EnclosedText for sending in line tags that aren’t followed by a carriage return. wwHTML::EnclosedText wwHTML::HRef This method creates a hypertext link to another document, section or CGI command using the HTML HREF tag. Syntax Return Arguments oHTML.HRef(cLink, cText, lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cLink The hypertext link or address. Ctext The text to enclose lNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.Href(“mailto:rstrahl@west-wind.com”,”Email Rick”) or oHTML.Href(“http://microsoft.com/index.htm”,”MS Home Page”) or oHTML.Href(“/cgi-win/wwcgi?ClientList”,”Show Clients”) Remarks See Also No carriage return send at end of line. See wwHTML::HeaderText for sending headers that are followed by CRs. wwHTML::HeaderText wwHTML::HTMLColor This method outputs an HTML color string value from a Visual FoxPro RGB() color triplet. Syntax oHTML.HTMLColor(nColorValue, lNoOutput) - Page 50 - West Wind Web Connection Class wwHTML Return Arguments “” if sending to file and the color value output text if lNoOuput is .T. Color value is preceeded by a #. For example, RGB(255,255,255) returns "#FFFFFF" nColorValue A Visual FoxPro color value. This value can come from a Visual Control color property or an RGB() triplet. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example lcColor=oHTML.HTMLColor(RGB(192,192,192),.t.) wwHTML::List This method creates a HTML list of manually entered items. The list can be of any of the supported HTML list types. Currently there is no support for not sending the output directly to a file. Fix it/Wish List: Add support for arrays, allow lNoOutput option Syntax Return Arguments oHTML.List(cType, cItem1, cItem2…cItem9) “” cType Any legal HTML list type: UL - unordered list OL - ordered list DL - definition list. cItem1..cItem9 Text to be displayed for each list item. In the future the first item may be an array. Example oHTML.List(“UL”,”Option 1”,”Option 2”,; oHTML.Href(“index.htm”,”Back to home page”,.T.)) Remarks output cannot be returned as a string See Also wwHTML::DBFPopup This method creates a HTML <SELECT></SELECT> form popup box populated by the currently open table. Form popups are embedded inside of HTML forms and this routine generates only the popup list variable definition with the list populated from an expression defined from the open table. Not final: This implementation may change. (03/21/96) Syntax oHTML.DBFPopup(cFormVarName, cCharExpression, nSelected,; nHeight, cFirstItem, lNoOutputList) Return Full <SELECT> </SELECT> string or nothing Arguments cFormVarName The name of the popup field on the HTML form. The value chosen can be retrieved with wwCGI::GetFormVar() cCharExpression The expression that is returned for each record in the open table/cursor. For example if you have a customer list and you wanted to display the company field you would pass "Tquery.Company" as the expression. The expression can be any valid FoxPro expression that evaluates to a string. - Page 51 - West Wind Web Connection Class wwHTML cDefaultText Text of an option that is highlighted when the form is first loaded . nHeight HTML lists can either be popups or lists. The height determines which is used. nHeight determines the number of items that are visible in the list. Default is 1 or a Popup. cFirstItem Allows you to insert a list item at the top of the list. Useful for a blank entry or instructions before a selection is made. To not force a first item pass a non-character value or leave the parameter off. lNoOutput Determines whether output goes to file or is returned as a string. Example oHTML.DBFPopup("Company","Tquery.Company","",; 1,"Select Customer") Remarks Table referenced by cCharExpression must be open and selected. Performs a SCAN to populate the list. wwHTML::ContentTypeHeader The ContentTypeHeader method sends an HTTP content type header which has to preceed any CGI processed request. A typical Content Type header looks like this: HTTP/1.0 200 OK Content-type: text/html <HTML> ... </HTML> In the above example the Content Type line plus a blank line is the actual text that makes up the Content type header. Directly displayed text or HTML documents do not need a content type header, but any document that is sent via CGI to the HTTP server must include a content type header. This method is provided mainly for internal use by various full page methods. You programs should use HTMLHeader instead which also calls this method to output the content type header. Syntax Return Arguments oHTML.ContentTypeHeader([oHTTPHeader | cContentType], lNoOutput) “” if sending to file and the output text if lNoOuput is .T. oHTTPHeader or cContentType You can pass either a text based header type or an HTTP header object that is preconfigured. oHTTPHeader You can pass an HTTP header object that was previously created in your request routine. The object is expected to hold a valid HTTP header as created by oHTTP.DefaultHeader() or any of the additional methods. loHeader=CREATE("wwHTTPHeader") loHeader.DefaultHeader() && Create Default loHeader.AddForceReload() && Force to not Cache page *** Check if a Cookie exists for wwID lcId=loCGI.GetCookie("wwId") IF EMPTY(lcId) lcId=Sys(3) loHeader.AddCookie("wwId",lcId) ENDIF - Page 52 - West Wind Web Connection Class wwHTML *** Now display the header on the page loHTML.ContentTypeHeader(loHeader) Note that if you simply create loHeader without calling any of the following methods no HTTP header is created at all which works well for static HTML pages that aren't returned to a Web Server. cContentType For backward compatibility you can also call this method with a text parameter CGI requests require a Content Type header which usually looks like this in the generated document: Content Type: text/html Common types are: “text/html” - Default “Force Reload” - Force browser to always reload page “text/plain” - Displays plain text (non-HTML) “none” - No header is sent - your code has to set it up This parameter basically creates a Content type line, so any Content Type that is legal can be passed. The default is “text/html”. Another commonly used type is “text/plain” which sends text without HTML formatting. Use “none” to skip creating the Content Type header for example when creating static, non-CGI HTML pages for later display. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks oHTML.ContentTypeHeader () Non-CGI pages should always set the cContentType parameter to “none”. You can send a full HTTP1/0 header response using the Send/SendLn commands without this method. The Force Reload option should be used on any pages that need to be reloaded each time the page is hit. For example an order form page should be always be recalculated even when the user moves back to the page with the Browser’s Back button. Force Reload immediately forces the cache to expire and causes any further access to reload the page from the CGI script. By default pages do not expire, so that the user can get back to a CGI page via the Back button or on some browsers (like MS IE) via a previously cached HREF link. This works well for lookup lists and provides better speed on the browser’s end… Force Reload send a full HTTP header with a content type of text/html. See Also oHTML::HTMLHeader wwHTML::HTMLHeader The HTMLHeader method creates the beginning of a typical HTML document. By default this document includes a the content type header required for CGI generated documents, a title (displayed in the browser’s title bar) and header text or a header tag which can include images. Syntax oHTML.HTMLHeader(cHeaderText, cDocTitle,cBackground | cBGColor,; oHTTPHeader | cContentType, lNoOutput) Return “” if sending to file and the output text if lNoOuput is .T. Arguments cHeaderText - Page 53 - West Wind Web Connection Class wwHTML This is typical header text displayed in the <h1> tag, followed by a <HR> line. If you pass a preformatted string that contains tags (like an IMG SRC for example) the header text is placed unformatted. CDocTitle This text is the document title that is displayed in the Browsers title bar. If not passed this value is the same as the headertext. CContentType This optional parameter allows you to specify the MIME content type header for CGI documents. By default this parameter is set to “text/html”, but it can also be set to “text/plain” or “none”. “none” specifies that you don’t want a content type header, which is appropriate for creating standalone, permanent HTML documents. cBackground | cBGColor Allows you to specify a background image to use as a backdrop on HTML pages. The image is tiled across the page. Optionally you may specify a background color rather than an image. To do so, specify the color using Hex RGB notation: #FFFF00 for example. oHTTPHeader | cContentType This optional parameter allows you to customize the HTTP header for a document. CGI requests require an HTTP Content Type header which usually looks like this in the generated document: HTTP 1.0/200 Ok Content Type: text/html You can pass either a HTTPHeader object or use a text based command that will fill a common default header. oHTTPHeader You can pass an HTTP header object that was previously created in your request routine. The object is expected to hold a valid HTTP header as created by oHTTP.DefaultHeader() or any of the additional methods. loHeader=CREATE("wwHTTPHeader") loHeader.DefaultHeader() && Create Default loHeader.AddForceReload() && Force to not Cache page *** Check if a Cookie exists for wwID lcId=loCGI.GetCookie("wwId") IF EMPTY(lcId) lcId=Sys(3) loHeader.AddCookie("wwId",lcId) ENDIF *** Now display the header on the page loHTML.ContentTypeHeader(loHeader) cContentType For backwards compatibility or simplified requests you can pass a text parameter: “text/html” - Default “text/plain” “Force Reload” - Force browser to always reload page from link. “none” This parameter basically creates a Content type line, so any Content Type that is legal can be passed. The default is “text/html”. Another commonly used type is “text/plain” which sends text without HTML formatting. Use “none” to skip creating the Content Type header for example when creating static, non-CGI HTML pages for later display. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. - Page 54 - West Wind Web Connection Class wwHTML Example Remarks See Also oHTML.HTMLHeader(“Welcome to West Wind Technologies”,; “West Wind Technologies”,; “/images/background.gif”) Non-CGI pages should always set the cContentType parameter to “none”. oHTML::HTMLFooter wwHTML::HTMLFooter The HTMLFooter method finishes up an HTML document by adding the </BODY></HTML> document tags to the document. It also allows you to pass a text string that is inserted just prior to these tags. This function does nothing special other than conveying balance for code when using HTMLHeader(). Syntax Return Arguments oHTML.HTMLFooter(cFooterText,lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cFooterText Allows you to specify text to be used on the page footer LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.HTMLFooter() Remarks See Also oHTML::Href wwHTML::HTMLAuthenticate This method sends an Authorization request to the Web server to figure out whether the user is allowed access. The implementation of this mechanism depends on the Web server and operating system, but in most cases a request for authentication will display a login box into which the user types a username and password. The username and password are returned as "Authenticated User" and "Authenticated Password" in the CGI portion of the CGI profile. You can access this info with loCGI.GetCGIVar("Authenticated User") and loCGI.GetCGIVar("Authenticated Password"). Note for MS Internet Information Server: Some Web servers, namely MS IIS, will not send the password! In order for IIS to send even the user name you need to set the Basic Authentication flag on the Web server property sheet. IIS also verifies all users through the NT security settings so each entry into the Auth box must first be validated through NT, before the value is passed back to you in the CGI object. Once authenticated only the user name is sent. Syntax Return Arguments oHTML.HTMLAuthenticate (cDomain, lNoOutput) “” if sending to file and an HTTP - 401 header. cDomain The 'realm' that this authentication is to be checked for. This can be an entire domain or a domain subdirectory or other server resource. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example FUNCTION AuthTest *** Easier reference loCGI=THIS.oCGI *** Try to retrieve the cookie... lcUserName=loCGI.GetCGIVar("Authenticated Username") lcUserId=loCGI.GetCGIVar("Authenticated Password") - Page 55 - West Wind Web Connection Class wwHTML IF EMPTY(lcUserName) *** Send Password Dialog THIS.oHTML.HTMLAuthenticate(loCGI.GetServername()) RETURN ENDIF THIS.ErrorMsg("You've been validated for this request...") RETURN Remarks Implementation varies from Web server to Web server. IIS does not return the password ever. See Also wwHTML::HTMLHeader; wwHTML.ContentTypeHeader; wwHTTPHeader::Authenticate wwHTML::HTMLRedirect The HTMLRedirect method redirects output to another hyperlink rather than generating and displaying a page. This method simply points at another URL or directive and executes that link. Syntax Return Arguments oHTML.HTMLRedirect(cLink, lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cLink The hotlink or URL to goto or execute. LNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example Remarks See Also oHTML.HTMLRedirect(“index.htm”) This method is useful when you need a program to decide which page should be displayed. This provides another option for quickly accessing a page under program control. oHTML::HTMLHeader wwHTML::HTMLError The HTMLError method allows you to quickly generate a customized HTML error document. This method should be called anytime your VFP code fails (possibly as part of an error handler) or when unhandled conditions occur. When the HTMLError method is called all existing HTML output is overwritten with a standard error message that includes a pair of messages that can be supplied as parameter. In addition you can specify the name of the system administrator and the referring document. Syntax oHTML.HTMLError(cErrorHeader, cErrorMessage, cAdministrator, cReferDoc) Return Nothing Arguments cErrorHeader This is the main header message displayed of the error document. Should be a general explanation in a few short words - uses <h1> tag, ie. big and bold. CErrorMessage This should be a more detailed description of the error that occurred. This text appears in bold using the <h3> tag after a general error message. Optional. Cadministrator This should contain an email address that is used as a hotlink in the document to be sent messages regarding the problem from users of the page. Usually this will be loCGI.GetServerAdmin(). Optional. Creferdoc The referring document that called the current CGI request. Again this should be passed from the CGI object with loCGI.GetPreviousUrl. Optional. - Page 56 - West Wind Web Connection Class wwHTML Example oHTML.HTMLError(“Hold on to your hats!”,; “The requested CGI request could not be ”+; “completed, because the program is not “+; “set up to handle this operation yet.”,; loCGI.GetServerAdmin(),; loCGI.GetPreviousUrl()) Remarks See Also wwHTML::FormTextBox Creates a textbox on a form. Syntax oHTML.FormTextBox(cFieldName, cValue, nWidth, nMaxWidth, ; cCustomTags, lNoOutput) Return “” if sending to file or the output text if lNoOuput is .T. Arguments cFieldName The NAME= tag for the text field. For example, "txtEntry" cValue The default value to display in the text field. nWidth Width of the text field. nMaxWidth Maxium characters to allow. cCustomTags Any custom tags for the INPUT tag. LnoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.FormTextBox ("txtCompany",lcCompany,20) wwHTML::FormTextArea Syntax oHTML.FormTextArea(cFieldName, cValue, nHeight, nWidth,; cCustomTags, lNoOutput) Return “” if sending to file or the output text if lNoOuput is .T. Arguments cFieldName The NAME= tag for the text field. For example, "txtEntry" cValue The default value to display in the text field. nHeight Number of rows for this text area. nWidth Display width of the text area. cCustomTags Any custom tags for the INPUT tag. LnoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.FormTextArea("txtNotes",lcNotes,10,80) - Page 57 - West Wind Web Connection Class wwHTML wwHTML::FormButton Syntax oHTML.FormButton(cFieldName, cCaption, ; cCustomTags, lNoOutput) Return “” if sending to file or the output text if lNoOuput is .T. Arguments cFieldName The NAME= tag for the button. cCaption The display text of the button. cCustomTags Any custom tags for the INPUT tag. LnoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.FormButton ("btnSubmit","Send us your Order") wwHTML::FormRadio Creates an individual radio button. Syntax oHTML.FormRadio(cFieldName, cValue, cText, lSelected,; cCustomTags, lNoOutput) Return “” if sending to file or the output text if lNoOuput is .T. Arguments cFieldName The NAME= tag for the text field. For example, "txtEntry" cValue The default value to display in the text field. cText The text to display on the right of the button. lSelected Determines whether the button is CHECKED. Note: Only one button can be checked. cCustomTags Any custom tags for the INPUT tag. LnoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.FormRadio("optColors","Red","Red Color",.T.) wwHTML::FormCheckbox Creates an individual radio button. Syntax oHTML.FormBox(cFieldName, lValue, cText,; cCustomTags, lNoOutput) Return “” if sending to file or the output text if lNoOuput is .T. Arguments cFieldName The NAME= tag for the text field. For example, "txtEntry" lValue .T. or false to determine whether the form is checked. cText The text to display on the right of the button. cCustomTags Any custom tags for the INPUT tag. lNoOutput When set to .T. output is not sent to file, instead returning the result as a string. Example oHTML.FormCheckBox ("optColors",.T.,"Download Orders",,.T.) - Page 58 - West Wind Web Connection Class wwHTML wwHTML::NoOutput This method is used to keep output from going to file no matter how you call any of the above CGI routines. Useful after errors to turn off file further file output that might be created by incomplete HTML processing code. Only affects output through wwHTML of course. Syntax Return Arguments Example Remarks See Also oHTML.NoOutput(lNoOutput) "" if sending to file and the output text if lNoOuput is .T. lNoOutput If .T. output will not be sent to file. oHTML.NoOutput(.T.) Note that this is different than using the lNoOutput option on the various HTML functions, since it does not affect how text is returned to you from the HTML functions. If you want text returned as text instead of having it sent to file you still need to specify the lNoOutput parameter on the individual HTML method calls. lNoOutput parameter wwHTML::SetHTTPHeaderClass Sets the class that is used internally for setting up HTTP headers. Use this method only if you plan to subclass the wwHTTPHeader class. Syntax Return Arguments oHTML.SetHTTPHeaderClass(cClassname) Nothing cClass Name of the class to create for headers. wwHTML::AutoRefresh This method creates allows refreshing a page at certain intervals either with the same page or another page. However, this method only works if you build the HTML header of the page manually as demonstrated in the example below. Syntax Return Arguments oHTML.AutoRefreshPage(cURL,nInterval,lNoOutput) "" or the generated text string if lNoOutput is set to .T. cURL The URL to refresh the page with. If this value is a null string ("") the current page is refreshed. nInterval The interval at which the page is refreshed in seconds. LnoOutput Remarks If .T. output will not be sent to file. This method only works if you manually build the header of a form. The <META> tag resides in the top of the HTML document so you can't use HTMLHeader. You can however embed a call to this method into template pages! Example *** Login Page loHTML.ContentTypeHeader() loHTML.Sendln("<HTML><HEAD><TITLE>Authenticated</TITLE>") loHTML.AutoRefreshPage(loCGI.GetPreviousURL(),.01) loHTML.SendLn("</HEAD>") - Page 59 - West Wind Web Connection Class wwHTML loHTML.SendLn([<BODY BGCOLOR="#FFFFFF">]) loHTML.SendLn("<h2>You're now logged in for " + lcAdmin_type + " access</h2><HR>") loHTML.SendLn([<CENTER><b>]) loHTML.HREF(loCGI.GetPreviousURL(),"Click here to return continue") loHTML.SendLn([</b></CENTER>]) loHTML.HTMLFOOTER(PAGEFOOT) See Also wwHTML::IEChart This method allows embedding of the IE Chart ActiveX Control into your pages driven by data from the currently active cursor when the method is called. The data in the cursor to graph must contain at least two fields in the following format: Field Type Function Field1 Character Field 2-n Numeric The label that is to be displayed with the data item. In a bar chart this means the column labels on a Pie chart it means the labels on the pie attached to each piece. The data item to graph. Syntax Return Arguments oHTML.IEChart(cChartType,vWidth,cHeight,lNoOutput) "" or the generated text string if lNoOutput is set to .T. cChartType Determines the type of chart that is displayed. Available chart types are: BAR LINE AREA PIE The default graph type if not passed is BAR. You may also pass a numeric string that corresponds to the IEChart object graph type explicitly. You can get the available types from the IEChart object documentation from MS’s ActiveX Gallery site. nColumns Determines the number of columns that are graphed. By default only one column is graphed, but you make specify more than one for various graphs that support multiple datasets such as the stacked bar chart. VWidth Determines the width of the chart. You may pass a numeric value that contains a fixed pixel width or character string that specifies a percentage. The default is "100%". Nheight Determines the display height of the chart object in the HTML document in pixels. Default is 250. Clabels You can specify space separated list of labels for the legend. If not specified no legend is displayed on the graph. If specified the number of space separated labels should match the number of colums specified in the nColums parameter. LnoOutput If .T. output will not be sent to file. Example SELECT hour(time) as HOUR, COUNT(time) AS Hits, DAY(TIME) AS DAY; FROM cgilog ; WHERE time > datetime() - 82800 ; - Page 60 - West Wind Web Connection Class wwHTML GROUP BY 1 ; INTO Cursor Tquery loHTML=CREATE("wwHTML","Chart.htm") loHTML.HTMLHeader("IE Chart Test") loHTML.IEGraph("AREA",1,"100%",250) Remarks Output generates an <OBJECT> tag which works only with ActiveX enabled browsers like MS Internet Explorer 3.0. See Also - Page 61 - West Wind Web Connection Class wwHTMLString Class wwHTMLString Parent Class: wwHTML This subclass of the HTML class builds an output string rather than outputting the result HTML document to a file. The string is concatenated and internally stored in the class. All methods from the wwHTML class apply. Web Connection provides automatic and transparent overflow buffering to disk. You can use the SetBufferSize method to specify a buffer size above which Web Connection starts dumping to file. By default this value is set to a large number to essentially disable disk buffering, but a good number is typically 10-15k at which point disk buffering becomes more efficient than concatenating memory variables in physical memory. Note: Crazy as it may sound, file based output is as much as 5-25 times faster than using strings to build your HTML output. The larger the output string and the more string concats occur per request the more significant the performance difference. The reason for this is VFP's string handling mechanism which forces strings to be concatenated only by copying the content of the previous string then appending the new value (ie lcString=lcString+lcNewText). Since the entire string is copied each time this process can get very slow especially if strings get over 20k in size. File processing on the other hand simply dumps output to disk. Since disk access is typically buffered in memory this is vastly more efficient than string concats for anything over 20k strings. wwHTMLString automatically implements dumping to disk via the #DEFINE MAX_STRINGSIZE which is defined as 5000 by default. Any string used with HTMLString over this byte code goes to disk and is retrieved when GetOutput() is called. wwHTML::Init The wwHTML constructor is responsible for setting up the HTML class by setting up the filename that is used to send output to. Syntax Return oHTML.Init() Nothing Arguments Example Remarks See Also oHTML=CREATE(“wwHTML”) Unlike the wwHTML file based class, the Init method does not accept a parameter. wwHTML::Destroy, wwHTML::ContentTypeHeader wwHTMLString::Send The Send method is overridden for the HTML string concatenate all output to a string instead of sending output to file. If SetBufferSize was called to specify a string buffer size, output goes to a temporary file once the buffer exceeds the specified buffer size. - Page 62 - West Wind Web Connection Class wwHTMLString Syntax Return Arguments oHTML.Send(cText,lNoOutput) “” if sending to file and the output text if lNoOuput is .T. cText The text to be output. This text can be plain, or HTML formatted - this method doesn’t care. It’s the low level output routine. LNoOutput When set to .T. output is not sent to the output string, instead returning the result as a string return value. Example Remarks oHTML.Send(“<h1>Hello World Wide Web</h1>”) Output is send as is, without trailing carriage return. Note that Send is used for all output operations by the HTMLString class. See Also wwHTML::GetOutput Returns the current HTML output that has been built with the HTML class. Syntax oHTML.GetOutput() Return HTML output Arguments None Example oHTML=CREATE(“wwHTMLString”,loCGI.GetOutFile) oHTML.ShowMemoPage(HTMLPAGEPATH+"NoCode.wc",.T.) oHTML.HTMLFoot(PAGEFOOT) lcText=oHTML.GetOutput wwHTML::SetBufferSize Setting this value determines when the HTML class decides to dump output to file instead of using a string. When output gets larger than this value a new HTML file object is created and any existing output gets dumped to it. Any subsequent output also goes to file. wwHTMLString transparently handles output between string based and file based output. Syntax Return Arguments oHTML.SetBufferSize(nBufferSize) nothing nBufferSize Specify the size of the string buffer in bytes. By default this value is set to 2 megs, so typically disk buffering won't kick in. To enable you should experiment with values between 10-20k bytes. Example loHTML.SetBufferSize(15000) - Page 63 - West Wind Web Connection Class wwShowCursor Class wwShowCursor Parent Class: Relation Source: ShowCursor.prg The wwShowCursor class allows for easy display of table based data in HTML form. Its main functionality is to show a FoxPro table as HTML table output for a list display using a single method call. There are also methods for displaying a single record either as ASCII output (handy for email messages) or as an HTML table for display on an HTML page. How it works The wwShowCursor class builds output on the fly from the currently selected Visual FoxPro workarea. The class takes an HTML object as an input parameter to the Constructor (init()) so you can send output to the selected HTML output source in an optimized fashion. If no wwHTML object is passed an wwHTMLString object is created internally and the output is returned via this self-created object. wwShowCursor can display an entire table as row based list either using an HTML table or <PRE> tag list using the ShowCursor() method. loHTML=THIS.oHTML loHTML.HTMLHeader("ShowCursor Test") loShowCursor=CREATE("wwShowCursor",loHTML) SELECT Company, CareOf as Full_Name ; FROM TT_CUST ; INTO CURSOR Tquery loShowCursor.ShowCursor() loHTML.HTMLFooter() In addition there's support for building paged displays showing n of x pages per page by setting the appropriate nPage_ properties of the class. wwShowCursor can also display a single record either as an HTML table using the ShowRecord() method or as plain ASCII using using ShowASCIIRecord. To use the record functions you might do: loShowCursor=CREATE("wwShowCursor") SELE TT_CUST LOCATE FOR CustNo = lcCustId loShowCursor.ShowRecord() lcOutput=loShowCursor.GetOutput() Note that here no HTML object is passed. In this case an HTML object is created internally and the output can be returned with the GetOutput() method. You can SET FIELDS TO to limit fields to display or use a SELECT statement to select a single record with the appropriate fields. Field headers are displayed from the plain field names, except for ShowRecord/ShowASCIIRecord which use the DBC captions if available. In most cases tables used here are result sets from queries, so naming your fields with descriptive names using the AS clause is a good idea. When fields are displayed any underscores ("_") are converted to spaces in the field display. - Page 64 - West Wind Web Connection Class wwShowCursor Paged ShowCursor Display The ShowCursor() method supports paged display via the cPage_ properties. By default these properties are disabled and paged display is off. Paged display allows viewing the results of a query in small pages rather than a whole result set. This is useful for large result sets that would take a long time to generate all at once. It's important to understand that this process is not fully automatic – some programming logic on the calling program code is required to implement paging. The idea is that you tell wwShowCursor how many items to display and which page to show. wwShowCursor will then take your result set and filter it accordingly and display only that data. In addition, it then tells you what the next and previous page numbers are so you can use them on the same request. Optionally, you can set up a base URL that will allow ShowCursor to display the Next and Previous buttons automatically the link of which point at the base URL plus an added page parameter (~10 for example for page 10). Paged display requires keeping track of the user who created the query and potentially the query conditions that created the cursor. You can use your own mechanism or use the wwSession object to assign the user some state information (see wwSession for more details on creating sessions). The following example uses a wwSession object: ************************************************************************ * wwDemo :: PagedCustomerList ********************************* *** Function: Demonstrates use of the wwSession object, Cookies the *** wwShowCursor's Paging mode to display a query in paged *** format. The code below stores the Filter of the query *** in a Session variable which is retrieved on each page *** hit to re-run the query and jump to the appropriate *** page. ************************************************************************ FUNCTION PagedCustomerList LOCAL lcCookie, loSession, loHeader, loHTML, loCGI loCGI=THIS.oCGI loHTML=THIS.oHTML *** Ideally this object should be: *** THIS.oCGIServer.AddObject("oSession","wwSession") *** in wwServer :: SetServerProperties loSession=CREATE("wwSession") loSession.nSessionTimeout=1800 && Seconds - 1/2 hour *** Retrieve the Cookie lcCookie=loCGI.GetCookie("WWDEMOID") *** We'll need to create a custom HTTP header so we can potentially *** add the Cookie to it loHeader=CREATE("wwHTTPHeader") loHeader.DefaultHeader() *** Check if we have a valid Session IF !loSession.IsValidSession(lcCookie) *** Nope create it lcCookie=loSession.NewSession() *** And add a Cookie to the Request Header loHeader.AddCookie("WWDEMOID",lcCookie) ENDIF *** Now try retrieving the Query Parameters *** Values on relevant if we're running from the form on the 'first hit' lcCompany=loCGI.GetFormVar("txtCompany") lcName=loCGI.GetFormVar("txtName") - Page 65 - West Wind Web Connection Class wwShowCursor *** Retrieve the page number - wc.dll?wwDemo~PagedCustomerList~PageNo lnCurrentPage=VAL(loCGI.GetCGIParameter(3)) IF lnCurrentPage=0 lnCurrentPage=1 ENDIF *** Check if we clicked the button of the form IF !EMPTY(loCGI.GetFormVar("btnSubmit")) *** Build a filter lcFilter="" IF !EMPTY(lcCompany) lcFilter="UPPER(Company) = '" + UPPER(lcCompany) + "' AND " ENDIF IF !EMPTY(lcName) lcFilter=lcFilter + "UPPER(Careof) = '" + UPPER(lcName) + "' ENDIF AND " IF !EMPTY(lcFilter) lcFilter = lcFilter + "!DELETED()" ENDIF *** Store the filter in the Session Object loSession.SetSessionVar("CustomerQueryFilter",lcFilter) ELSE *** No - paging through file *** Retrieve the filter from the Session Variable lcFilter=loSession.GetSessionVar("CustomerQueryFilter") ENDIF IF !EMPTY(lcFilter) lcFilter= "WHERE " + lcFilter ENDIF SELECT Company, CareOf, Phone ; FROM TT_CUST ; &lcFilter ; ORDER BY Company ; INTO CURSOR TQuery *** Create the HTML header for the page *** Note the custom HTTP header object containing the Cookie (loHeader) loHTML.HTMLHeader("Paged Customer List",,BACKIMG,loHeader) *** Create a ShowCursor Object and pass our HTML object loSC=CREATE("wwShowCursor",loHTML) *** Set the Paging parameters - 5 per page loSC.nPage_ItemsPerPage=5 loSC.nPage_ShowPage=lnCurrentPage && Which page? *** The URL to use for the Next/Prev buttons - This page loSC.cPage_PageURL="wc.dll?wwDemo~PagedCustomerList" *** Now dump the HTML loSC.ShowCursor() loHTML.HTMLFooter(PAGEFOOT) ENDFUNC * PagedCustomerList A single Web Connection request handler handles this display by running a query, then re-calling this request for each of the Next/Previous links from the resulting HTML display. Note the use of the wwSession object to save the filter condition (lcFilter) between requests. The Session is established at the top and saved with the use of an HTTP Cookie (loHTTP.AddCookie()) that is passed to the client. On repeat hits, the cookie is found and the filter is retrieved based on that - Page 66 - West Wind Web Connection Class wwShowCursor cookie from the wwSession object. The query is re-run and passed to loSC.ShowCursor() which in turn filters the result based on the pages set on wwShowCursor object. Exposed Properties Property Function Display Attributes: cTableBGColor cHeaderBGColor cTableWidth cExtraTableTags cTableBorder cCellPadding cCellSpacing lCenterTable lSumNumerics lShowAsTable nForceToPREList oHTML Background Color for the table. "#EEEEEE" Background Color for the table header and Summary Total Footer. "#FFFFCC" The width of the HTML table. Can be specified in percentages or pixel values. If using percent add % to the end of the string. "95%" Extra tags that are added to the <TABLE> tag of the HTML table. Note that the width and border attributes are always preset. Numeric value specified as a string to specify the width of the border. "2" The amount of padding applied to each cell. "3" The spacing between cells in addition to the border. "2" Whether the table is centered. If .T. all numeric fields will be totalled and displayed in the table footer. Determines whether the result is displayed as an HTML table or as <PRE> list. .T. Number of cells after which to default to <PRE> tagged list The HTML object that is used to send output to. You can directly access this object if necessary. Paging Attributes: nPage_ItemsPerPage nPage_ShowPage nPage_NextPage nPage_PrevPage cPage_PageURL cPage_LinkHTML Determines the number of items per page to display. Only applies if this value is non-zero. 0 The page that is actually displayed. 0 The next page or 0 if the current page is the last. 0 The previous page or 0 if the current page is 1. 0 The base URL used for the Next and Previous Links. For example: wc.dll?wwDemo~PagedList. The full HTML for the Previous/Next links as a string. Exposed Methods wwShowCursor::Init The Constructor of this class handles basic setup for the display operation. It takes a single parameter of a wwHTML object which can be passed to allow sending output directly to that object's output mechanism for optimized speed. Syntax Return Arguments oShowCursor=CREATE("wwShowCursor",oHTML) nothing oHTML A reference to an existing wwHTML object. This parameter is optional – if no HTML - Page 67 - West Wind Web Connection Class wwShowCursor Example oShowCursor=CREATE("wwShowCursor",oHTML) Remarks See Also wwHTML::ShowCursor wwShowCursor::GetOutput If you want to return the output from the ShowCursor method use this method to return the text. Note: This method applies only if you did not pass an HTML object in the Constructor. Syntax oShowCursor.GetOutput() Return HTML output Arguments None Example SELECT * FROM TT_CUST INTO CURSOR Tquery oShowCursor=CREATE("wwShowCursor") oShowCursor.ShowCursor() lcText=oShowCursor.GetOutput() Remarks This method applies only if you did not pass in an existing HTML object. If you passed in a wwHTML object GetOutput() will always return a "" string. If a wwHTMLString object was passed in, its entire contents including any prior content will be returned. Thus only use this method to return the output if no object was passed in. wwShowCursor::ShowCursor This method actually goes out and displays the currently selected workarea as an HTML table. It uses the property settings that have been set previously or uses the defaults defined there. Syntax Return Example oShowCursor.ShowCursor() nothing oShowCursor=CREATE("wwShowCursor",oHTML) oShowCursor.cTableBGColor="#FFFFFF" oShowCursor.ShowCursor() Remarks See Also wwHTML::ShowCursor wwShowCursor::ShowRecord This method displays a record as an as a simple two column text view displaying the field name or caption on the left and the field value on the right. Syntax Return Example oShowCursor.ShowRecord nothing oShowCursor=CREATE("wwShowCursor",oHTML) SELE Tquery LOCATE FOR CustId=lcCustId - Page 68 - West Wind Web Connection Class wwShowCursor IF FOUND() oShowCursor.ShowRecord () ENDIF lcEmailText=oShowCursor.GetOutput() wwShowCursor::ShowASCIIRecord This method displays a record as an ASCII list as a simple two column text view. This can be handy for emailing results of some data entry to a user with a single method call. This method uses the field names from the data dictionary if a DBC is open for the current table. Syntax Return Example oShowCursor.ShowASCIIRecord nothing oShowCursor=CREATE("wwShowCursor",oHTML) SELE Tquery LOCATE FOR CustId=lcCustId IF FOUND() oShowCursor.ShowASCIIRecord () ENDIF lcEmailText=oShowCursor.GetOutput() wwShowCursor::BuildFieldListHeader This method allows customizing the header for the ShowCursor() method. You can create custom field header strings in an array and pass this array to this method. Syntax Return Arguments Example oShowCursor.BuildFieldListHeader(aHeader) nothing aHeader You can pass an array of headers to this method. The headers are then used instead of the field names. The array must be passed by Reference! If you don't call this method explicitly wwShowCursor calls it internally and uses the field names for headers. DIMENSION laHeaders[3] laHeaders[1]="Field 1" laHeaders[1]="Field 2" laHeaders[1]="Field 3" oShowCursor.BuildFieldListHeader(@laHeaders) Remarks See Also This method is also called internally by ShowCursor. Once the header is filled it won't fill again. To clear the header wwHTML::ShowCursor wwShowCursor::SetCursor This method allows setting the table that is used with the action methods of this class. Syntax oShowCursor.SetCursor(cTable) - Page 69 - West Wind Web Connection Class wwShowCursor Return Arguments Example Remarks See Also nothing cTable Table/View or Alias name that is to be operated on by ShowCursor() or the other action methods. field names for headers. oShowCursor.SetCursor(DATAPATH + "TT_Cust") oShowCursor.ShowCursor() This method is only required if you want to use a cursor other than the one currently open in the current work area. Typically, you'll run a SELECT and then use the result set in which case this method is not required. wwHTML::ShowCursor - Page 70 - West Wind Web Connection Class wwDBFPopup Class wwDBFPopup Parent Class: Relation Source: DBFPopup The wwDBFPopup class allows for easy creation of data driven HTML popup form elements from a FoxPro table. How it works The wwDBFCursor class essentially takes an HTML object and then builds output on the fly from the currently selected Visual FoxPro workarea. The class takes an HTML object as an input parameter to the Constructor (init()) so you can send output to the selected output source in an optimized fashion. If no wwHTML object is passed an wwHTMLString object is created internally and the output is returned via this self-created object. Here's an example on how you can use this object to display a state popup from a table: loHTML=THIS.oHTML && called in standard wwProcess Method *** Create a popup object and send output to the current HTML object loPopup=CREATE("wwDBFPOPUP",loHTML) SELECT cData AS StateName, cData1 AS StateCode ; FROM sub_lookups ; WHERE TYPE="STATE" ; INTO CURSOR TList loPopup.cKeyValueExpression="TList.StateCode" loPopup.cDisplayExpression="TList.StateName" loPopup.cFormVarName="co_state_ID" loPopup.cAddFirstItem="&ltSelect for US or Canada&gt" loPopup.cSelectedValue=Subscribers.Co_state_Id *** Build the Popup – output goes to HTML object loPopup.BuildList() *** If you don't pass HTML object a wwHTMLString object is created *** behind the scenes. To retrieve the value you'd use: * lcStatePopup=loPopup.GetOutput() Exposed Properties The following properties can be set after an instance of the wwDBFPopup object has been created. STRING_NULL is defined as "*#*" to differentiate between empty strings and unselected items. oHTML=.NULL. cFormVarName="" cDisplayExpression="" cKeyValueExpression="" cAddFirstItem="" cSelectedValue=STRING_NULL cSelectedDisplayValue=STRING_NULL lMultiSelect=.F. - Page 71 - West Wind Web Connection Class wwDBFPopup nHeight=1 Exposed Methods wwDBFPopup::Init The Constructor of this class handles basic setup for the display operation. It takes a single parameter of a wwHTML object which can be passed to allow sending output directly to that object's output mechanism for optimized speed. Syntax Return Arguments Example Remarks See Also oPopup=CREATE("wwDBFPopup",oHTML) nothing oHTML A reference to an existing wwHTML object. This parameter is optional – if no HTML object is provided a wwHTMLString object is created behind the scenes. Use the wwDBFPopup::GetOutput() method to retrieve the generated text in that case. oDBFPopup=CREATE("wwDBFPopup",oHTML) The wwHTML::DBFPopup method uses this object wwHTML::DBFPopup; wwDBFPopup::GetOutput() wwDBFPopup::GetOutput If you want to return the output from the DBFPopup method use this method to return the text. Note: This method applies only if you did not pass an HTML object in the Constructor. Syntax oDBFPopup.GetOutput() Return HTML output Arguments None Example SELECT * FROM TT_CUST INTO CURSOR Tquery oDBFPopup=CREATE("wwDBFPopup") oDBFPopup.BuildList() lcText=oDBFPopup.GetOutput() Remarks This method applies only if you did not pass in an existing HTML object. If you passed in a wwHTML object GetOutput() will always return a "" string. If a wwHTMLString object was passed in, its entire contents including any prior content will be returned. Thus only use this method to return the output if no object was passed in. wwDBFPopup::BuildList This method actually goes out and displays the currently selected workarea as an HTML table. It uses the property settings that have been set previously or uses the defaults defined there. Syntax Return oDBFPopup.BuildList() nothing - Page 72 - West Wind Web Connection Class wwDBFPopup Example SELECT * FROM TT_CUST INTO CURSOR Tquery oDBFPopup=CREATE("wwDBFPopup") oDBFPopup.BuildList() lcText=oDBFPopup.GetOutput() wwDBFPopup::Reset This method resets all of the properties of the object to its default values. Syntax oDBFPopup.Reset(). - Page 73 - West Wind Web Connection Class wwHTTPHeader Class wwHTTPHeader Parent Class: Relation Source: wwHTML.prg The wwHTTPHeader class provides an easy interface for building HTTP headers that can be output using both high and lowlevel HTML class methods. HTTP headers are used to tell the Web Server certain characteristics about the Web page that is being returned for display. HTTP Header options available include providing the content type, Cache and Page Expiration options, HTTP Cookies for persistent state keeping between hits and sessions, Redirection and Authentication among other things. Note: The wwHTTPHeader class is new in Verson 1.70. It provides enhanced functionality that supercedes the functionality provided in wwHTML::ContentTypeHeader(). Functions that previously used text strings to specify the Content Type header can now specify this HTTP Header object instead. For backwards compatibility the old text based strings still work. An oHTTPHeader object can be passed to the following wwHTML class methods: ContentTypeHeader HTMLHeader ExpandTemplate ExpandScript These methods will incorporate the object and properly extract the header output and insert them into the output stream. You can also force the HTTPHeader object to 'print' itself with the Getoutput method without using those methods: loHTML.Send( loHeader.GetOutput() ) How it works The HTTPHeader class essentially consists of a string property that's holds the entire HTTP header info. The string starts as a blank and is filled with by any of the class method calls. You can return no header by simply creating the header and not calling any of the methods provided. The GetOutput() method allows you to retrieve the HTTP header as a string. Here's a typical example of how it works. LoHTML=THIS.oHTML && CGI Process object HTML object loHeader=CREATE("wwHTTPHeader") loHeader.DefaultHeader() && Create Default Content Type="text/html" loHeader.AddForceReload() && Force to not Cache page *** Check if a Cookie exists for wwID lcId=loCGI.GetCookie("wwId") IF EMPTY(lcId) lcId=Sys(3) loHeader.AddCookie("wwId",lcId) ENDIF *** Display a page from disk and add the HTTP header loHTML.ShowMemoPage(HTMLPAGEPATH+"NoCode.wc",.t.,loHeader) RETURN - Page 74 - West Wind Web Connection Class wwHTTPHeader wwHTTPHeader::GetOutput Returns any of the previously set HTTP header text. Simply returns a string that contains the current settings of the HTTP Header. Syntax oHeader.GetOutput() Arguments None Return HTTP Header as a string Example oHeader=CREATE(“wwHTTPHeader") oHeader.DefaultHeader() loHTML.Send(oHeader.GetOutput()) See Also wwHTTPHeader::CompleteHeader wwHTTPHeader::CompleteHeader This method should be used only if you're not calling GetOutput() on the wwHTTPHeader object to retrieve the header generated. It should be used when output is sent directly to an HTML object passed in the Init() and stored in the oHTML property of this object. The method simply appends the finally carriage return required at the end of the HTTPHeader block. This method is called automatically from GetOuput(). Syntax oHeader.CompleteHeader() Arguments None Return nothing Example See Also loHTML = CREATE("wwHTML","c:\test\temp.htm") oHeader=CREATE(“wwHTTPHeader",loHTML) oHeader.DefaultHeader() oHeader.CompleteHeader() wwHTTPHeader::GetOutput wwHTTPHeader::ClearHeader Releases any previous header settings and sets the HTTP header to "". If an HTML object was passed to this object in the Init the entire HTML output is cleared. Syntax oHeader.ClearHeader() Arguments None Return Nothing Example oHeader=CREATE(“wwHTTPHeader") oHeader.DefaultHeader() oHeader.ClearHeader() *** Start over - Page 75 - West Wind Web Connection Class wwHTTPHeader See Also oHeader.SetProtocol() oHeader.SetContentType() wwHTTPHeader::GetOutput wwHTTPHeader::DefaultHeader Creates a standard HTTP header that should be used for most Web HTML pages returned from a Web Connection request. This Header creates: HTTP/1.0 200 OK Content-type: text/html Syntax oHeader.DefaultHeader() Arguments None Return Nothing Example See Also oHeader=CREATE(“wwHTTPHeader") oHeader.DefaultHeader() wwHTTPHeader::SetProtocol, wwHTTPHeader::SetContentType wwHTTPHeader::SetProtocol This lower level function sets the protocol used when returning an HTML document. Use this method only if you are NOT using DefaultHeader(). Creates: HTTP/1.0 200 OK Syntax Arguments oHeader.SetProtocol(cProtocol) cProtocol Specifies the protocol to be used by the Web server. In most cases this will be HTTP/1.0 200 OK Return Example See Also which is the default if not specified. Nothing oHeader=CREATE(“wwHTTPHeader") oHeader.SetProtocol("HTTP/1.1") wwHTTPHeader::DefaultHeader wwHTTPHeader::SetContentType This lower level function sets the Content type used when returning an HTML document. Use this method only if you are NOT using DefaultHeader(). Creates: Content-type: text/html Syntax Arguments Return oHeader.SetContentType (cContentType) cContentType Content Type of the document. The default is "text/html". Nothing - Page 76 - West Wind Web Connection Class wwHTTPHeader Example See Also oHeader=CREATE(“wwHTTPHeader") oHeader.SetContentType() wwHTTPHeader::DefaultHeader wwHTTPHeader::AddCookie This method adds an HTTP cookie to the header. HTTP cookies are stored on the client machine in special file that the Web browser makes available. Cookies are stored and organized by site and path and when the site and path are accessed the Cookie is sent to the Web server along with all other CGI information. You can retrieve cookies with wwCGI::GetCookie() method. HTTP cookies are great for keeping track of users during a session by assigning the user a Cookie Id that can be retrieved on each request. The Cookie can be mapped to an ID in a user table for example to always know which user has initiated the current request. This method creates a cookie by adding it to the HTTP header. Creates a string like the following: Set-Cookie: CookieId=CookieValue; path=/; expires=Fri, 09-01-94 00:00:00 GMT Syntax Arguments oHeader.AddCookie(cCookieName, cCookieValue, cPath, cExpire) cCookieName Specifies the cookie name or the identifier that is used to retrieve a cookie. See wwCGI::GetCookie for more information on retrieving a cookie from a CGI request. cCookieValue The value to assign to the cookie. cPath Specifies the path that of the current server that the Cookie applies to. If omitted the path is the root ("/") which means the Cookie is available on the entire site. cExpire Specifies when the Cookie is to expire. You can also specify "NEVER". Expiration times should be specified in the following format: "Fri, 31-Dec-99 01:01:01 GMT" Return Nothing Example oHeader=CREATE(“wwHTTPHeader") oHeader.DefaultHeader() *** Check if a Cookie exists for wwID lcId=loCGI.GetCookie("wwId") IF EMPTY(lcId) *** Nope, create it lcId=Sys(3) loHeader.AddCookie("wwId",lcId) ENDIF *** Display page from disk and add HTTP Header loHTML.ShowMemoPage(HTMLPAGEPATH+"NoCode.wc",.T.,loHeader) See Also wwHTTPHeader::DefaultHeader, wwCGI::GetCookie wwHTTPHeader::AddForceReload This method forces the page to not cache, so subsequent hits to the current CGI link will always reload the page from the scipt. Adds: Expires: Sunday 15-May-94 16:00:01 GMT - Page 77 - West Wind Web Connection Class wwHTTPHeader Syntax oHeader.AddForceReload() Arguments None. Return Nothing Example See Also oHeader=CREATE(“wwHTTPHeader") oHeader.DefaultHeader() oHeader.AddForceReload() wwHTTPHeader::DefaultHeader wwHTTPHeader::More Methods ************************************************************************ * wwHTTPHeader :: AddCustom *************************** *** Function: Allows adding any custom header information to the *** HTTP header. Note that a single CR is appended *** automatically. *** Pass: tcCustomString - Full HTTP Header line or lines *** Return: nothing ************************************************************************ ************************************************************************ * wwHTTPHeader :: Redirect ************************** *** Function: Redirects Server output to the specified URL or Locator. *** Note this operation creates a full document and erases *** any existing text that was sent. *** Pass: lcUrl ************************************************************************ ********************************************************************** * wwHTTPHeader :: Authenticate ****************************** *** Function: Sends the authorization content type header *** Use to pop up Security Dialog and force authentication. *** You can use Authentication Username (CGI) *** to retrieve the entered user name if valid... *** Pass: tcRealm - Domain to log in to. *** tlNoOutput - When .T. text is returned as string *** Return: nothing or string if tlNoOutput=.T. ********************************************************************** ************************************************************************ * wwHTTPHeader :: GetOutput *************************** *** Function: Returns the HTTP header as a string. Adds *** terminating CR at the end. *** Return: HTTP Header ************************************************************************ ************************************************************************ * wwHTTPHeader :: ClearHeader ***************************** *** Function: Clears the HTTP header string from any previous settings. *** Return: nothing ************************************************************************ - Page 78 - West Wind Web Connection Class wwHTMLForm Class wwHTMLForm Parent Class: wwHTMLControl Source: wwForm.prg Support Classes: wwHTMLControl and its subclasses for each control supported. wwHTMLControl, wwHTMLLabel, wwHTMLTextBox, wwHTMLEditBox, wwHTMLCheckbox, wwHTMLRadio, wwHTMLListBox, wwHTMLButton, wwHTMLShape, wwHTMLImage, wwHTMLPageFrame, wwHTMLGrid. The controls are contained in wwCtls.prg. Disclaimer: This class will generate output only for use with Internet Explorer 4.0 and the Dynamic HTML specification! How to use it: Using the form rendering class is very easy. There are two modes of operation, one using a program file wrapper and one using the class itself. Let's start with the program file. Using the wwForm Wrapper DO FORM Guest NAME oGuest LINKED DO wwForm with oGuest This will run the guest sample form and then render it as DHTML and automatically display in your browser (if IE4 is your default browser – otherwise you may see some garbage <s>). The full syntax to wwForm is as follows: LPARAMETER loContainer, lnValueType, lcOutputFile, llNoShow loContainer is the form or container object that you want to render. Remember any contained objects and containers inside of the container are also rendered. For a form this means the form and any page frames or containers get rendered. lnValueType allows you to determine how field values are displayed: 1 – Actual display value in the form (live), 2 – Blank values (great if you need to modify the form) or 3 – using script tags that are compatible with Web Connection and Active Server Pages (<%= Guest.Name %> where the expression is the control source). lcOutputFile lets you dump the result to a file and llNoShow will supress the display in the Browser if set to .T. Using the Class Using the class is a little more complex, but gives you access to the full range of functionality of the class. The class properties and method hooks are described in detail below, but here is a simple example that shows how to use the class against the sample form: DO FORM Guest2.scx NAME oGuest LINKED && NOSHOW *** Set up the Form rendering class and point it at the oGuest form oHTMLForm=CREATEOBJECT("wwHTMLForm",oGuest) *** Some of the properties you can set oHTMLForm.lShowAsFullHTML=.T. && Add HTML Startup <HTML><BODY> and title *oHTMLForm.lShowFormCaption=.T. *oHTMLForm.lAbsolutePosition=.F. && Show VFP Title Bar on Form && Float form - Page 79 - West Wind Web Connection Class wwHTMLForm *oHTMLForm.lFormBackgroundTransparent=.F. *oHTMLForm.nValueType = 2 oHTMLForm.ShowContainer() *** Return output to a string lcHTML = oHTMLForm.GetOutput() *** Show output in browser ShowHTML(lcHTML) How it works: The wwForm class allows rendering of live isual FoxPro classes as DHTML. The basic idea is that you instantiate a Visual FoxPro form, then pass a reference to the form instance or any container object to the wwForm class which runs through the container and renders each object as HTML. The class recurses down the containers inside of the container and renders the HTML to an internal wwHTML object or a text string (retrieved with the GetOutput() method). Field and Value mapping Fields on the form are rendered with the same name as the name of the control, so a field name of txtLastName turns into the NAME="txtLastName" on the HTML form. Container naming is respected so THISFORM.Container1.txtLastName is placed as NAME=”Container1.txtLastName”. There’s also an option that assigns the ControlSource as the name for any fields that have a controlsource property. To do so use the lUseControlSourceAsName property. By default values display the actual value of the current fields – you can also force field values to be blank or contain Active Server/Web Connection script tags that wrap the ControlSource value (<%= Guest.Name %> for example). The property to control value assignment is nValueType (1- value, 2 – blank, 3 – Script tags). HTML and Script hooks Once a form is rendered in the browser you are now running a standard DHTML form. None of your VFP code is ported. Any of the form’s buttons submit the form to the server. The link used as the Form action is set with the ::cFormAction property, which should always point to the same link as the original rendering link which contains a CASE statement for all the different button clicks of the form. To see how this works look at the IEGuest sample in wwDemo.prg. In addition there's cFormOnLoadCode which attaches code to the form's Form_OnLoad event. The class uses this internally to handle grid and page frame initialization, but you can hook up additional code here. Form Submission and Assigning values back to the form This feature works only if you use this class with a Web Connection server When a form is submitted you can automatically reassign all the values captured by the wwCGI object back to a running form. To do so you have to reinstantiate the form and locate it appropriately (select the record you are editing or add a new record when adding and display it) then use the ::SetValues() method of wwHTMLForm to repopulate the fields from the request data. Note that you can use to wwCGI::SetKey() method to override or clear input field values to avoid updating fields that you not want updated by using SetKey() with a value of WWC_NULLSTRING. The form is updated depending on your form data mode: If buffering is on you need to call your Save mechanism to save the data on the form, if data buffering is not on values are immediately stored to your tables. Make sure you have proper error controls in place and that your validation routines on your form don’t pop up traditional UI responses such as MessageBoxes etc. Hint: To quickly test a form to see how it will look in IE4 interactively without running it through the Web server simply run your form and then do (where Test is the object reference to the form): DO FORM Test DO WWFORM WITH Test - Page 80 - West Wind Web Connection Class wwHTMLForm Rules of Operation The form is rendered using IE 4.0 style sheet tags which preserve font and sizing information, enabled/disabled, visible and color values. For most common controls operation is straight forward – field operation is mapped directly to the HTML equivalents. However the following controls require special attention: Listboxes are rendered from their Item[x] collection with the display value representing the VALUE= tag. This means you can’t easily assign a Unique key to list items and will typically require a lookup on the display value to locate the appropriate item. The highlighted item in a list is also highlighted in the HTML form although the current rev of IE 4 will not automatically scroll to the selected item. Optiongroups MUST return a numeric value of the option selected; the group is treated as a single object, but each radio is rendered as a contained object with the name of the Optiongroup as the field name. IOW, the individual button objects are only rendered but not directly accessible. Images are rendered by their respective filenames, stripping off the path and converting the .BMP or .ICO extension to .GIF. Images are pathed into the directory specified by WWFORM_IMAGEPATH in Wconnect.h (default is "FormImages" below the current directory). This path is relative to the current request. It’s possible to use pathing like this: “/FormImages/” and then store all form related images in this directory. PageFrames are rendered as individual DIV tags with a separate additional tag for each tab in addition to the actual page. Each Tab’s click event contains the logic to select and activate the proper page of the PageFrame using VBScript code. The more pages you have the more code will be generated for each tab page – don’t over do pages or you’ll end up with a monster HTML document. Grids are implemented using a VB ActiveX control that wraps a ListView control. The VB wrapper was required to allow fast operation and to create a simpler interface so less code needs to be generated. Grids are read only and the first column is the ‘key’ value that is returned when you click on a selection. Selection is not automatic – you need to create a GridName_NodeClick event handler in VBScript to decide what to do when a user clicks on a grid item. You can use the cExitFormHTML property to create the VBScript code which is embedded just prior to the </FORM> tag. Since the grid is an ActiveX control users will have to download the control. The control is signed but it requires consent from the user to download the control. If the VB5 runtime is not present on the client machine the compressed runtime is downloaded separately (approx. 1meg) from the Internet (a connection is required for this to work). Form Buttons are all mapped to a single name called btnSubmit which are SUBMIT buttons. When you click on a button a request is sent back to the server based on the value specified in the ::cFormAction property. You can then use wwHTML::GetFormVar(“btnSubmit”) to figure out which button was clicked and handle it appropriately. Picture Buttons require special handling. Unlike regular buttons these buttons create a special Form Field name which is: ImgFieldName.x, which returns the x coordinate of the button. This format is a limitation of picture buttons in HTML. To check whether a picture button was clicked use logic like this: CASE !EMPTY(lower(loCGI.GetFormVar(“imgCommand1.x”))) … Image button was pressed Messy, but it works. Overriding Object Types with your own Renderers By default wwHTMLForm looks at the BaseClass property of an object to determine how to render an object. The base class is then mapped to a wwHTMLControl object that is responsible for rendering the object using its GetHTML() method that returns the full HTML rendition for the object. To override this behavior you can implement a method called OverrideInsertObjectHTML() and handle your own rendering operations. For example, say you create a class called HyperLink and you want to override the default label class that WC would use. To do this you’d create the method: FUNCTION OverrideInsertObjectHTML - Page 81 - West Wind Web Connection Class wwHTMLForm LPARAMETER loObject lcOutput="" DO CASE CASE UPPER(loObject.Class)="WWHYPERLINK" LcOutput = “This is my Hyperlink output” CASE UPPER(loObject.BASECLASS)="MyGRID" LoGridHTML=CREATE("MyGridHTML",loObject) lcOutput=loGridHTML.GetHTML() ENDCASE && not what you’d really do here <s> RETURN lcOutput And this would override the call to the standard rendering. As long as this method call returns a string result that’s not “” (or WWC_NULLSTRING if you really don’t want any output) that output is used instead of WC’s object generation code. With this you can easily extend the functionality of the default behavior without modifying WC itself. For example, you could add your own class to render TreeView controls here… What doesn’t work Most controls are rendered fine with wwHTMLForm, but there are several that do not work: ActiveX Controls (not rendered at all) Combo Boxes (rendered as drop downs) Multicolumn List boxes (use grids instead) Non square shapes How to use it: In most cases this code will look like this (simplified): FUNCTION wwMyProcess :: CustForm lcButton=loCGI.GetFormVar("btnSubmit") lcCustId=loCGI.GetFormVar("txtCustId") && This field might be visible=.f. on the VFP form DO CASE CASE lcButton = "EDIT" DO FORM CustForm NAME oForm LINKED oForm.Navigate(lcCustId) oForm.EditMode() *** Create an wwHTMLForm object and set the behavior and pass an HTML object oHTMLForm=CREATE("wwHTMLForm",oForm,THIS.oHTML) oHTMLForm.lShowAsFullHTML=.T. oHTMLForm.lShowFormCaption=.T. oHTMLForm.lAbsolutePosition=.F. oHTMLForm.lUseControlSourceAsName=.T. oHTMLForm.cFormAction="wc.dll?wwDemo~CustForm" oHTMLForm.ShowContainer() && Render the form! CASE lcButton = "SAVE" DO FORM CustForm NAME oForm LINKED oForm.Navigate(lcCustId) oForm.EditMode() *** Create an wwHTMLForm object and set the behavior oHTMLForm=CREATE("wwHTMLForm",oForm,THIS.oHTML) oHTMLForm.lShowAsFullHTML=.T. oHTMLForm.lShowFormCaption=.T. oHTMLForm.lAbsolutePosition=.F. oHTMLForm.lUseControlSourceAsName=.T. oHTMLForm.cFormAction="wc.dll?wwDemo~CustForm" - Page 82 - West Wind Web Connection Class wwHTMLForm *** set the values of the form from the values in the wwCGI object oForm.SetValues(loCGI) *** You can now override any values or check for validity oForm.txtState.value = oForm.ZipLookup(oForm.txtZip.Value) *** If Buffering is enabled on the form write or revert the data IF oForm.ValidateInput() oForm.SaveRecord() ELSE oForm.RevertRecord() ENDIF oForm.ViewMode() oHTMLForm.ShowContainer() ENDCASE && Render the form! RETURN This code is essentially a handler for the form's actions. Note that your form needs no special subclasses or control. The method names to navigate and control the form are arbitrary. The form is simply rendered based on the baseclass object type for each of the controls. To control the form you use a small stub Web Connection method. As you can also see this will not work with all forms – the interface must be such that you can control the form externally via method calls or property settings such as the Navigate(), ViewMode(), Editmode(), SaveRecord() and RevertRecord() methods used in the example above. If your existing form does not have such an interface intertwining user interface and business logic and UI code you will have to create an 'external' interface so you can control the form. However, with proper design this approach allows you to build the vast majority of your form logic totally inside of Visual FoxPro without having to worry about any HTML or even Web Connection code! The Web Connection code only is responsible for 'driving' the form with some minimal validation code. Notice the wwHTMLForm::SetValues() method. This method takes a wwCGI object as a parameter that can repopulate a form from the values retrieved by a previously rendered form. If your form does not use buffering the control source of each field is immediately updated, which I wouldn't recommend <s>. Better to update the form, then double check the values, then call a separate Save routine to actually dump the buffer to disk. You don't have to use this method – you can do your form validation first then populate the form or simply update the data directly; the choice is yours. A simple sample program is provided on the demo page in the wwDemo.prg program as wwDemo::IEGuest(). Additional samples are wwDemo::IEFormDemo and IEFormDemo2. Grids Grids are read only with this mechanism, so all editing that you perform off of grids need to bring up another form that's responsible for editing the code. Grids are actually implemented as a wrapper around a ListView control. You can click on the leftmost item and capture that click with the object's wwItemClick method, but you need to do so with VBScript (or JavaScript) code. The trick is to insert some VBScript into the actual <FORM> submission to allow setting a variable that you can read in your client request. You can then submit the form and test for this value. WwHTMLForm supports adding VBScript (or any HTML markup for that matter) via the cExitFormHTML property, which inserts whatever is assigned here just prior to the </FORM> tag. Note that by default wwHTMLForm creates a form called wwForm, which you can override with cFormName. I modified the Control sample to demonstrate this. The form contains a row level display of a customer and a grid that displays all of the customers. You can click on the grid to select a customer to display. Here the same form is displayed with the new customer info on the first page. You can check out this demo in wwDemo::IEFormDemo2(). ************************************************************************ * wwDemoProcess :: IEFormDemo2 - Page 83 - West Wind Web Connection Class wwHTMLForm ********************************* *** Function: Demonstrates a simple implementation of HTML Form. *** Shows off use of Page Frame and grid display. ************************************************************************ THIS.oHTML.HTMLHeader(,'HTML VFP Form Rendering Demo using PageFrame') THIS.oHTML.SendLn('<CENTER>') *** Retrieve Grid Selection if one was made lcId = THIS.oCGI.GetFormVar('grdSubmit') *** Pass ID to the form DO FORM IEDemoForm NAME oCust WITH lcId LINKED NOSHOW oHTMLForm=CREATEOBJECT('wwHTMLForm',oCust,THIS.oHTML) oHTMLForm.lShowAsFullHTML=.F. oHTMLForm.lShowFormCaption=.T. oHTMLForm.lAbsolutePosition=.F. oHTMLForm.cFormAction='/wconnect/wc.dll?wwdemo~IEFormDemo2' *** Now allow capturing the grid selection by creating a hidden *** form variable and storing the result to it before submitting *** the form oHTMLForm.cExitFormHTML = ; [<input type='HIDDEN' NAME='grdSubmit'>] + CR +; [<script language='VBScript'>] + CR +; [Sub masterpageframe_page3_grid1_wwItemClick(lcKey,lcText,lnIndex)] + CR +; [ wwForm.grdSubmit.Value = lcText] + CR + ; [ call wwForm.submit()] + CR + ; [end sub] + CR +; [</script>] oCust.Refresh oHTMLForm.ShowContainer() THIS.oHTML.SendLn('</CENTER>') THIS.oHTML.HTMLFooter(PAGEFOOT) ENDFUNC * IEFormDemo Note that the addition of the cExitFormHTML and adding the following code to the form's Init: LPARAMETER lcId SET TALK OFF SET NOTIFY OFF IF !EMPTY(lcID) LOCATE FOR Custno = PADL(lcId,8) IF !FOUND() LOCATE ENDIF ENDIF was all I had to do to make the selection work... If you're working with multiple forms (bringing up another form to display the actual detail info) you can handle it by simply calling another request from your starting wwProcess Method. - Page 84 - West Wind Web Connection Class wwHTMLForm Exposed Properties: Property/Default oContainer oHTML lShowAsFullHTML=.F. cHTMLBackGround="#FFFFFF" lShowFormCaption=.F. lAbsolutePosition=.F. nValueType lUseControlSourceAsName=.F. lShowFormBackgroundTransparent=.F. cFormName="wwForm" cFormAction="" cFormMethod="POST" cFormTarget="" cExitFormHTML="" Function Object reference to the object to render. Passed to Init(). An optional existing wwHTML object reference to output to. Passed to Init() Determines whether the Form as rendered as a complete HTML form or only as an object embedded inside of an HTML page. If rendering a full HTML document this is the background color for areas not covered by the form. This can be an RGB color setting as the default or a background image. Determines whether the form's caption is displayed as a blue title bar. By default the bar is not shown. Determines whether the form is placed inside the browser at an absolute position as determined by the form's Top and Left properties or relative at the current location in the HTML document. Determines how field values are displayed: 1 – The actual value of the live form (default) 2 – Blank. Use this for form you want to customize by hand. 3 – Script Tags. Creates a script tag for the control source using Web Connection/Active Server script tags (<%= Guest.Name %>). By default form fields are named the same as the form fields on the form. The full name of a form is used minus the THISFORM/frmName object reference. If this flag is set .T. wwForm uses the Control Source instead of the field name. This allows easier mapping of tables/business objects in an automated fashion. By default the form is drawn based on the background of the form. When this flag is true the form is shown transparent omitting the form BackColor setting. Name of the form as specified in the <FORM> tag. This matters only if you plan to insert your own scripting code that needs access to form objects, which requires Form.Object.Value= syntax. You can optionally specify a FORM ACTION= that executes when the form is submitted. If this value is set the FORM ACTION is embedded, otherwise no <FORM> tag is created. If a <FORM> tag is created this METHOD= is used. The target frame for the <FORM> tag if used. This is hook to allow you to insert additional HTML before the </FORM>. You can add hidden vars to the form here in order to handle special situations like New records. Exposed Methods: wwHTMLForm::Init The class constructor for the wwHTMLForm class assigns object references to the container object to be rendered and the HTML output source to be used. Syntax Return oHTMLForm.Init(oContainer, oHTML) Nothing - Page 85 - West Wind Web Connection Class wwHTMLForm Arguments OContainer An object reference to the container to be rendered. Typically this will be a form reference but you can reference any container on a form. OHTML An object reference to an wwHTML or wwHTMLString object that is used for output of the HTML. This parameter is optional – if not passed a wwHTMLString object is automatically generated and you can then use the GetOutput() method to retrieve the HTML text. Example loHTML=THIS.oHTML DO FORM CustForm NAME oForm LINKED oHTMLForm=CREATE("wwHTMLForm",oForm,loHTML) Remarks See Also wwHTMLForm::GetOutput() wwHTMLForm::GetOutput This method retrieves the HTML text generated by the class. This method only applies if you're passing an wwHTMLString object or no HTML object at all. Syntax Return Arguments Example oHTMLForm.GetOutput() HTML as a string None DO FORM CustForm NAME oForm LINKED oHTMLForm=CREATE("wwHTMLForm",oForm) oHTMLForm.ShowContainer() lcOutput=oHTMLForm.GetOutput() Remarks See Also wwHTMLForm::Init() wwHTMLForm::ShowContainer This is the main method of the wwHTMLForm class. It is responsible for converting the form to HTML and is the Go Do it function. Output is sent to the current HTML object. Syntax Return Arguments Example oHTMLForm.ShowContainer() Nothing None loHTML=THIS.oHTML DO FORM CustForm NAME oForm LINKED oHTMLForm=CREATE("wwHTMLForm",oForm) oHTMLForm.ShowContainer() lcOutput=oHTMLForm.GetOutput() Remarks See Also See notes above on how field names are converted on the HTML form. wwHTMLForm::SetValues() - Page 86 - West Wind Web Connection Class wwHTMLForm wwHTMLForm::SetValues This method allows you to update the values of the form from a wwCGI object. The form must have been created with wwHTMLForm::ShowContainer() call for compatibility of names. The form fields are updated from the values in the wwCGI object. Depending on your buffering mode on the form data is either updated directly or buffered for separate saving at a later time. Syntax Return Arguments Example oHTMLForm.SetValues(oCGI) Nothing oCGI An object reference to an wwCGI that must come of a form created with the ShowContainer() method. loHTML=THIS.oHTML loCGI=THIS.oCGI DO FORM CustForm NAME oForm LINKED oHTMLForm=CREATE("wwHTMLForm",oForm) oHTMLForm.ShowContainer() oHTMLForm.SetValues(loCGI) lcOutput=oHTMLForm.GetOutput() Remarks See Also See notes above on how field names are converted on the HTML form. wwHTMLForm::ShowContainer() wwHTMLForm::OverrideInsertObjectHTML This method is a hook to override the wwHTMLForm class' HTML generation for each of the VFP form controls. By default wwHTMLForm looks at the form's base class to determine how to render the form. You can override this behavior by subclassing the wwHTMLForm object and implementing this method. The method is called when each object is rendered and should return the HTML as string text that's to be embedded in the form. You can return a null string ("") to force wwHTMLForm to continue with its form processing on the object or WWC_NullString to force no output at all for the object. By default this method is empty and returns "" so the wwHTMLForm class renders the HTML. Syntax Return Arguments Example oHTMLForm.OverrideInsertObjectHTML(oObject) HTML string for the current control "" to use the default control rendering WWC_NullString to create no output at all OObject An object reference to the VFP form control to render. FUNCTION OverrideInsertObjectHTML LPARAMETER loObject lcOutput="" DO CASE CASE loObject.Class="MyAutoRenderingHTMLClass" LcOutput=loObject.RenderHTML() CASE UPPER(loObject.BASECLASS)="GRID" LoGridHTML=CREATE("wwGridHTML",loObject) lcOutput=loGridHTML.GetHTML() ENDCASE RETURN lcOutput This method will override wwHTMLForm's object rendering for the CASE statement entries, but continue to use the default functionality on all other cases. This hook allows - Page 87 - West Wind Web Connection Class wwHTMLForm creating new object types or for you to use any HTML rendering you build into your own base classes. Remarks See Also wwHTMLForm::ShowContainer() wwHTMLForm::OverrideSetValue This method is a hook to override the wwHTMLForm class' SetValue mechanism when updating a running VFP form from a wwCGI object. This method allows you to hook into the update mechanism that's responsible for updating the value so you can provide custom update functionality for special class types or even specific form variables. By default wwHTMLForm calls the protected SetValue() method which looks at the base class and accordingly sets the value of the control. This method allows overriding of the value to set. If the method returns .T. default processing does not occur, if the method returns .F. default processing occurs in addition to the method code executed. . Syntax Return oHTMLForm.OverrideSetValue(oObject) .t. or .f. to indicate whether the default SetValue() processing should take place after the method call. Arguments Example FUNCTION OverrideSetValue LPARAMETER loObject llRetval=.F. && By default don't override DO CASE CASE UPPER(loObject.Class) = "MYCHECKBOX" loObject.Value=.T. loObject.Caption="Different Caption" llRetVal=.T. && Override default processing ENDCASE RETURN llRetVal Remarks See Also wwHTMLForm::SetValues() - Page 88 - West Wind Web Connection Class wwVFPScript Class wwVFPScript Parent Class: Relation Source: wwVFPScript.prg Related Classes: Request, Response, Session, Server PRE-RELEASE – implementation subject to change The wwVFPScript class provides a scripting mechanism similar to the one found in Microsoft Active Server Pages providing Visual FoxPro based scripting environment. Note that this is a pure Visual FoxPro implementation and thus the functionality is approximated and not necessarily exact. The most common Active Server Objects are implemented along with the common collections and methods that go with these objects. The Web Connection implementation allows use of either the Active Server objects or the native Web Connection objects and of course any Visual FoxPro language constructs. This scripting implementation is somewhat different from the scripting mechanism provided by the MergeText/ExpandTemplate/ShowMemoPage methods available in the wwHTML Class. The main difference is that the wwVFPScript class uses compiled code rather than the interpreted code used by MergeText. While this means much better performance, especially for pages that contain looping constructs or lots of code, it also brings with it the requirement to compile pages. This means that pages can be run, interactively be debugged and evaluated in the development version of Visual FoxPro, but require pre-compilation into .FXP files for execution under the runtime environment. A tool and HTML link to compile pages is provided, but remember that the Development version of VFP needs to be present even if your application runs with the VFP runtime. How it works The scripting engine works as a separate object inside of the Web Connection framework that works in conjunction with the Web Connection HTML object. A .WCS page is called using a Server based script map, which is captured by Web Connection in the wwServer::Process method as follows: DO CASE CASE lcParameter == "WWDEMO" DO wwDemo with THIS.oCGI, THIS CASE lcParameter == "WWMAINT" DO wwMaint with THIS.oCGI, THIS OTHERWISE *** Check for .WC or .WCS script mapped files lcPhysicalPath=THIS.oCGI.GetPhysicalPath() DO CASE CASE ATC(".WC",lcPhysicalPath) > 0 OR ATC(".FXP",lcPhysicalPath) > 0 DO wwScriptMaps with THIS.oCGI,THIS To load this page you’d simply do: /wconnect/wwScript.wcs or /wconnect/wwScript.fxp A scriptmap is a server implemented mechanism that provides a mapping of a script file extension (.wcs or .wc for Web Connection) to an ISAPI dll. In this case, .WC, .WCS and .FXP are mapped to the Web Connection DLL (wc.dll) in the physical path of c:\http\wconnect\wc.dll (your base path may vary depending on where you installed the HTML files). Now whenever you reference a file with a .WCS extension it will always execute the DLL. Furthermore, when you do this the Web path will not be changed – you can access a .WCS page anywhere without having to explicitly tell it to look for the DLL in a specific directory. So: /wwScript1.wcs or /wconnect/wwScript2.wcs both are valid with only a single copy of the WC.DLL in /scripts/wc.dll. - Page 89 - West Wind Web Connection Class wwVFPScript Web Connection scripting sets up two separate scriptmaps: .WCS for the source file and .FXP for the compiled version. If you’re running under the runtime of VFP they both do the same thing, which is to run the compiled .FXP file. Under the development environment you can explicitly use the .FXP file as the script page and it will not try to evaluate the page first, but rather always run the compiled file. As a result any changes made to the .WCS file are not respected until you recompile the page. If you load the .WCS page under the development environment Web Connection first converts the page into code then runs the newly created page. Notice that this compilation step can cause access problems if multiple simultaneous sessions access the same .WCS page at the same time, since the simultaneous compilation can cause problems. Thus, for production environments compiled pages are the only reliable way to use this feature. When a scriptmap request is made on the Web server it fills in a server variable called Physical Path with the full DOS path for the script that was called. So in the example above you might get: c:\http\wwScript1.wcs or c:\http\wconnect\wwScript2.wcs. You can retrieve this path with loCGI.GetPhysicalPath() and voila you now know which page was requested by the server. Once you can use the page on disk it’s now ready to be executed or interpreted. Notice above that we’re calling wwScriptMaps.prg which is a subclassed wwProcess Implementation that looks like this: ************************************************************************ * wwScriptMaps :: Process *************************** FUNCTION Process LOCAL lcParameter, lcOutFile, lcIniFile, lcOldError PRIVATE poProcess, poSession, poServer, poHTML, poCGI lcPhysicalPath = THIS.oCGI.GetPhysicalPath() *** PRIVATE refs to Web Connection Objects poSession = THIS.oSession poProcess = THIS poServer = THIS.oCGIServer poHTML = THIS.oHTML poCGI = THIS.oCGI DO CASE CASE ATC(".WCS",lcPhysicalPath) > 0 OR ATC(".FXP",lcPhysicalPath) > 0 llRuntime = ATC("RUNTIME",Version()) > 0 or ATC(".FXP",lcPhysicalPath) > 0 lcFXP = ForceExt(lcPhysicalPath,"FXP") IF llRunTime lcPhysicalPath = lcFXP ENDIF *** WCS - Script Text FXP - Compiled WCT - Intermediate oScript = CREATE("wwVFPScript",lcPhysicalPath,THIS.oHTML,THIS.oCGI) oScript.lAlwaysUnloadScript = .T. *** Convert Page to VFP Code IF !llRunTime oScript.ConvertPage() && Creates a .WCT file ENDIF oScript.RenderPage() *** ##FOXCODE pages CASE ATC(".WC",lcPhysicalPath) > 0 poCGI=THIS.oCGI poHTML=loHTML THIS.oHTML.ExpandTemplate(lcPhysicalPath) OTHERWISE *** Unhandled method - display error page THIS.ErrorMsg("Invalid or unsupported scriptmap","") THIS.oCGIServer.SendMail(MAILSERVER,; - Page 90 - West Wind Web Connection Class wwVFPScript WWC_ADMINISTRATOR_EMAIL,; WWC_ADMINISTRATOR_EMAIL,; WWC_ADMINISTRATOR_EMAIL,"", ; "Web Connection Error Message - Invalid Script Map",; THIS.oCGI.cQueryString) ENDCASE RETURN .T. This code first checks to see whether we want to deal with a runtime file (VFP runtime is in use or a .FXP file was passed) or with the development environment. If we’re running a .WCS file in the development environment the page is converted to VFP code on every request with the wwVFPScript::ConvertPage() method. This method takes the scripted code in the WCS file and creates something that Visual FoxPro can compile. Internally Web Connection uses VFP’s TEXTMERGE functions to do this by delineating the script code with TEXT/ENDTEXT and embedded expressions. The code generated isn’t pretty, but if you’re running the dev version you can look at the .WCT files generated in the same directory as the .WCS file. Once the page has been converted to code Web Connection tries to run the page with wwVFPScript::RenderPage(). This does the equivalent of DO (yourpage.wct). In the process the .WCT page is compiled into a .FXP file that is also stored in the same directory as the .WCS script file. A sample script page Before we look at how the scripting works lets look at a simple script page – wwScript.wcs: <HTML> <h2>Hello World</h2> The Time is: <%= Time() %> <p> <% For x= 1 to 12 %> Loop Number: <%= x %><br> <% ENDFOR %> <p> <% *** Demonstrate using WC objects lcCompany = poCGI.GetUrlEncodedParameter("Company") && WC Syntax lcCompany = Request.QueryString("Company") && ASP Syntax SELECT company,careof FROM TT_CUST INTO Cursor TQuery ; WHERE UPPER(Company) = UPPER(lcCompany) Response.Write(poHTML.ShowCursor(,,,.T.)) && Use of WC wwHTML method %> <PRE> User Agent: <%= Request.ServerVariables("User-Agent") %> Server Software: <%= Request.ServerVariables("Server Software") %> User ID: <%= Request.QueryString("Company") %> </PRE> </HTML> This page looks very much like an Active Server Page using the same syntax convention, but employing Visual FoxPro code instead of VBScript or Jscript. This page runs through Web Connection rather than through ASP.DLL! As with ASP <% %> delineates scripted code. Between these separators any Visual FoxPro code can be embedded. A slight variation of the syntax with <%= %> means to evaluate a single expression, so you can put <%= TIME() %> for example. Expressions do not have to be character based, but for proper formatting it’s recommended you do your own conversions to character as needed. Note either type of script tags cannot be nested (nor does it really make sense) – if you do you’ll likely receive an error in your VFP code. Notice that you can break structured VFP statements with separate script tags like this: <% For x= 1 to 12 %> Loop Number: <%= x %><br> - Page 91 - West Wind Web Connection Class wwVFPScript <% ENDFOR %> All output is sent to the current HTML output device via the Response object. Response.Write is responsible for this operation. In fact the <%= %> syntax mentioned before is really a shortcut for a Response.Write construct and performs exactly the same task. Thus: <% lcOutput = “Hello World” %> <% Response.Write(lcOutput)%> <%= lcOutput %> are identical. Accessing Objects – ASP Objects and Web Connection Objects Web Connection provides access to both ASP object simulations or all of the Web Connection native objects. The ASP objects are implemented in VFP code by calling back on the appropriate Web Connection objects and are provided mainly for familiarity for those that have already worked with Active Server. All Web Connection objects are also available (poProcess, poServer, poSession, poHTML, poCGI) and you can of course create and destroy any Web Connection objects directly in your code. The need to compile Up to now we’ve discussed converting and running a script page, but as you’ve probably noticed there is a compilation step that takes place implicitly when you first DO yourpage.wct. For this reason the development version is required to dynamically run pages that can be changed. When running a .WCS page in the development version you can make a change to the text file that contains the script (.wcs page) and simply refresh the browser to immediately see your change. When running under the runtime a compiled file is required so changing the text file requires recompilation with the development version. However, once a page has been compiled into a .FXP the page can be run by the runtime version of Visual FoxPro – just when making changes do you need to make sure the page is recompiled with the dev version. To simplify recompilation there’s a utility in the .\tools directory called WCSCOMPILE.PRG that you can use to recompile pages quickly. It takes advantage of the wwVFPScript Class’s CompilePage() method to quickly generate a compiled version of a program. The syntax is: DO WCSCOMPILE WITH [<cWCSPage>|<cScriptPath>] You can either specify a single page or set of wildcarded pages, or an entire path. REMEMBER: This has to be run from the development version of Visual FoxPro. There’s also a method in wwUtils that actually does the lowlevel work. Its syntax is: WCSCompile(ScriptPath,lSilent) Both of these require the VFP development environment in order to compile pages. However, if you are running a runtime application or Automation server and you also have the Visual FoxPro development version (5.0 or later) installed, a new method in the wwMaint module will invoke the VFP server application and run WCSCompile from there. Here’s what that code looks like: * wwMaint :: CompileWCS FUNCTION CompileWCS loCGI = THIS.oCGI lcFileSpec = loCGI.GetCGIParameter(3) IF EMPTY(lcFileSpec) lcFileSpec = loCGI.GetFormVar("txtFileSpec") ENDIF IF EMPTY(lcFileSpec) lcPhysicalPath = loCGI.GetPhysicalPath() lcFileSpec = ADDBS(JustPath(lcPhysicalPath))+"*.wcs" ENDIF o=CREATEOBJECT("VisualFoxPro.Application") o.DoCmd("SET DEFAULT TO "+SYS(5)+CURDIR()) o.DoCmd("SET PATH TO .\classes; .\eclasses; .\tools") - Page 92 - West Wind Web Connection Class wwVFPScript *** Load Web Connection Classes o.DoCmd("DO WCONNECT") *** Compile .WCS Active Server Script Pages lcErrors = o.Eval("wcscompile('"+lcFileSpec+"',.t.)") o = .F. IF EMPTY(lcErrors) lcErrors = "No Errors..." ENDIF THIS.ErrorMsg("Scripts Compiled",; [ <font face="Verdana" size=3>ScriptPath: ]+lcFileSpec+CR+CR+; "<HR><PRE>"+ lcErrors + "</PRE></FONT>") ENDFUNC * wwMaint :: CompileWCS This code in wwMaint allows you to compile pages through an HTML link given that the dev version of VFP is installed. Using OLE Automation of VFP this code then calls the WCSCompile() function to compile the specified script in the dev version. You can specify the files to compile either as part of the URL (via the 3rd parameter) or a form link. By bookmarking a parameter link you can have one step compilation of pages. For example: /wconnect/wc.wc?wwMaint~WCSCompile~\http\wconnect\*.wcs - Page 93 - West Wind Web Connection Class wwSession Class wwSession Parent Class: Relation Source: wwSession.prg The wwSession class provides a state mechanism for tracking people through a 'visit' of a site. The most common example would be to track a customer through a shopping site. Since HTTP is stateless you have no way to track the user from request to request. With the use of HTTP Cookies or Ids passed as part of the URL you can track people through a site. This class provides a mechanism for storing and retrieving session specific values for a particular user by creating an entry in a table that has a timeout. Realize that you still need to manually set the cookie from your code using the wwHTTPHeader object (see example below). Methods for creating, reading and timing out the session are provided. You can genericly attach character variables to a session object, the values of which are stored in a free form memo field using the SetSessionVariable() method. The variables can be retrieved at any time with the GetSessionVariable() method. How it works The wwSession class is a wrapper around the wwSession table which stores all of the session information. The structure of this table is: CREATE TABLE ( THIS.cDataPath+THIS.cTableName ); (SESSIONID C (9),; USERID C (8),; FIRSTON T ,; LASTON T ,; VARS M ,; BROWSER M,; IP M,; CDATA1 M ,; CDATA2 M ) The table is created the first time you try to use any of the methods of the session object – you can use the Reindex() method to clean up and purge the session file. The SessionId is the unique identifier for each session. Using the NewSession() method a new ID is generated and an entry is created in the table. The resulting SessionId should be used as the Cookie you pass back to the browser. On the next hit you can check for this Cookie and use it to check for a valid session using the IsValidSession() method. wwSession doesn't explicitly use the UserId field, but you can assign this field as a parameter of NewSession() and use it to cross reference a Session user with a user in an actual user table or security descriptor table. To optionally log the Browser and IP address you can assign a reference to a wwCGI object to the oCGI property. CDATA1 and CDATA2 are not used but can be used by you to store additional data without explicitly adding fields. The following example uses a wwSession object: ************************************************************************ * wwDemo :: PagedCustomerList ********************************* *** Function: Demonstrates use of the wwSession object, Cookies the *** wwShowCursor's Paging mode to display a query in paged *** format. The code below stores the Filter of the query *** in a Session variable which is retrieved on each page *** hit to re-run the query and jump to the appropriate *** page. - Page 94 - West Wind Web Connection Class wwSession ************************************************************************ FUNCTION PagedCustomerList LOCAL lcCookie, loSession, loHeader, loHTML, loCGI loCGI=THIS.oCGI loHTML=THIS.oHTML *** Ideally this object should be: *** THIS.oCGIServer.AddObject("oSession","wwSession") *** in wwServer :: SetServerProperties loSession=CREATE("wwSession") loSession.nSessionTimeout=1800 && Seconds - 1/2 hour *** Retrieve the Cookie lcCookie=loCGI.GetCookie("WWDEMOID") *** We'll need to create a custom HTTP header so we can potentially *** add the Cookie to it loHeader=CREATE("wwHTTPHeader") loHeader.DefaultHeader() *** Check if we have a valid Session IF !loSession.IsValidSession(lcCookie) *** Nope create it lcCookie=loSession.NewSession() *** And add a Cookie to the Request Header loHeader.AddCookie("WWDEMOID",lcCookie) ENDIF *** Now try retrieving the Query Parameters *** Values on relevant if we're running from the form on the 'first hit' lcCompany=loCGI.GetFormVar("txtCompany") lcName=loCGI.GetFormVar("txtName") *** Retrieve the page number - wc.dll?wwDemo~PagedCustomerList~PageNo lnCurrentPage=VAL(loCGI.GetCGIParameter(3)) IF lnCurrentPage=0 lnCurrentPage=1 ENDIF *** Check if we clicked the button of the form IF !EMPTY(loCGI.GetFormVar("btnSubmit")) *** Build a filter lcFilter="" IF !EMPTY(lcCompany) lcFilter="UPPER(Company) = '" + UPPER(lcCompany) + "' AND " ENDIF IF !EMPTY(lcName) lcFilter=lcFilter + "UPPER(Careof) = '" + UPPER(lcName) + "' ENDIF IF !EMPTY(lcFilter) lcFilter = lcFilter + "!DELETED()" ENDIF *** Store the filter in the Session Object loSession.SetSessionVar("CustomerQueryFilter",lcFilter) ELSE *** No - paging through file *** Retrieve the filter from the Session Variable lcFilter=loSession.GetSessionVar("CustomerQueryFilter") ENDIF IF !EMPTY(lcFilter) lcFilter= "WHERE " + lcFilter - Page 95 - AND " West Wind Web Connection Class wwSession ENDIF SELECT Company, CareOf, Phone ; FROM TT_CUST ; &lcFilter ; ORDER BY Company ; INTO CURSOR TQuery *** Create the HTML header for the page *** Note the custom HTTP header object containing the Cookie (loHeader) loHTML.HTMLHeader("Paged Customer List",,BACKIMG,loHeader) *** Create a ShowCursor Object and pass our HTML object loSC=CREATE("wwShowCursor",loHTML) *** Set the Paging parameters - 5 per page loSC.nPage_ItemsPerPage=5 loSC.nPage_ShowPage=lnCurrentPage && Which page? *** The URL to use for the Next/Prev buttons - This page loSC.cPage_PageURL="wc.dll?wwDemo~PagedCustomerList" *** Now dump the HTML loSC.ShowCursor() loHTML.HTMLFooter(PAGEFOOT) ENDFUNC * PagedCustomerList Property Function nSessionTimeout cTableName cDataPath cDelimiter oCGI The period for which a session is valid in seconds. 1800 The name of the session table. wwSession The location of the session table. .\ The delimiter used by the Vars Session variable field. #!# A reference to a wwCGI object used for retrieving the Browser and IP Address. Must be set prior to a call to NewSession(). The SessionID as retrieved by IsValidSession() or set by NewSession(). cSessionID wwSession::Init The constructor allows setting the datapath and filename for the wwSession file. The file will always be aliased as wwSession regardless of what the table name is here. Syntax Arguments oSession.Init(cTableName, cDataPath) cTableName The name of the table to use. cTableName The location for the file. Return Example loSession=CREATE("wwSession") See Also - Page 96 - West Wind Web Connection Class wwSession wwSession::Reindex Packs and reindexes the wwSession file. You can optionally pass a date/time value to tell this method to purge all entries before that time. Syntax Arguments Return Example See Also oSession.Reindex (dtPurge) tPurge Purges entries prior to this date/time Optional .T. or .F. if no exclusive lock loSession=CREATE("wwSession") loSession.Reindex() wwMaint::ReindexSystemFiles wwSession::NewSession Creates a new session entry and returns a session ID Syntax Arguments Return Example See Also oSession.NewSession(cUserId) cUserId A user ID that crosslinks to a user table for your application. Optional. nothing lcCookie=THIS.oCGI.GetCookie("WWDEMOID") loSession=CREATE("wwSession") IF !IsValidSession(lcCookie) lcCookie=loSession.NewSession() ENDIF wwSession::IsValidSession() wwSession::IsValidSession Checks to see if a session exists. Syntax Arguments Return Example See Also oSession.IsValidSession(cSessionId) cSessionId The SessionId to check for. Typically this will be an HTTP Cookie retrieved from the wwCGI object. .T. or .F. lcCookie=THIS.oCGI.GetCookie("WWDEMOID") loSession=CREATE("wwSession") IF !IsValidSession(lcCookie) lcCookie=loSession.NewSession() ENDIF wwSession::NewSession() - Page 97 - West Wind Web Connection Class wwSession wwSession::SetSessionVar Creates or sets a dynamic Session variable. The variables are stored in the Vars memo field and can only be retrieved using the GetSessionVar method. All variables must be text strings. Syntax Arguments oSession.SetSessionVar(cVarName, cValue) cVarName Name of the dynamic variable or key. This is the identifier. cValue Return Example The value to set the variable to. nothing lcCookie=THIS.oCGI.GetCookie("WWDEMOID") loSession=CREATE("wwSession") IF !IsValidSession(lcCookie) lcCookie=loSession.NewSession() ENDIF See Also lcFilter=loSession.GetSessionVar("QueryFilter") IF EMPTY(lcFilter) lcFilter="WHERE Company='S'" loSession.SetSessionVar("QueryFilter",lcFilter) ENDIF wwSession::GetSessionVar() wwSession::GetSessionVar Retrieves a dynamic Session variable from the wwSession table's Var field. Syntax Arguments Return Example oSession.GetSessionVar(cVarName) cVarName Name of the dynamic variable or key to retrieve the value for. Value as a string or "" if not found or empty. lcCookie=THIS.oCGI.GetCookie("WWDEMOID") loSession=CREATE("wwSession") IF !IsValidSession(lcCookie) lcCookie=loSession.NewSession() ENDIF See Also lcFilter=loSession.GetSessionVar("QueryFilter") IF EMPTY(lcFilter) lcFilter="WHERE Company='S'" loSession.SetSessionVar("QueryFilter",lcFilter) ENDIF wwSession::SetSessionVar() wwSession::GetUserId Retrieves the user id from the session. Syntax oSession.GetUserId() Arguments - Page 98 - West Wind Web Connection Class wwSession Return Example User ID or "" if not found or empty lcCookie=THIS.oCGI.GetCookie("WWDEMOID") loSession=CREATE("wwSession") IF !IsValidSession(lcCookie) lcCookie=loSession.NewSession(wwUsers.UserId) ENDIF See Also lcID=loSession.GetUserId() wwSession::NewSession() wwSession::GetField Retrieves a value from any field of the wwSession table. This is equivalent to doing lvValue=wwSession.Field, but this method is provided here for consistency. Syntax Arguments Return Example oSession.GetField (cFieldName) cFieldName Name of the field to retrieve. Field may be of any type. The value is EVALUATEd Field value lcCookie=THIS.oCGI.GetCookie("WWDEMOID") loSession=CREATE("wwSession") IF !IsValidSession(lcCookie) lcCookie=loSession.NewSession(wwUsers.UserId) ENDIF lcAddress=loSession.GetField("SessionAddress") See Also - Page 99 - West Wind Web Connection Class wwIPStuff Class wwIPStuff Parent Class: Custom wwIPStuff.vcx Source: The wwIPStuff class holds a number of Internet related utility routines that can be used with any Visual FoxPro application. The class provides a wrapper around the wwIPStuff.dll file which is distributed with this package and provides the low level interface to WinInet and Winsock for implementing the various protocols. NOTE: You also need the WININET.DLL file, which is a Windows system file that gets installed with Internet Explorer and various other Internet related applications (not with Netscape, though). This file is freely distributable and can be downloaded from ftp://ftp.west-wind.com/wininet.zip. You need this file if you cannot get wwIPStuff.dll to load when issueing the DECLARE in the Init() method of the wwIPStuff class. The failure will be: 'Cannot find entry point to function…'. The class provides the following features: SMTP SendMail capability both in blocking and asynchronous modes Support for Blind CCs and one Mime Base64 encoded file attachment Domain lookup by IP Address Reverse domain lookup of IP address from domain name Blocking FTPSend and FTPGet operations FTP Directory FTP File Delete HTTP GET – retrieve URLs to a text string HTTP POST via the extended HTTPConnect/AddPostKey/HTTPGetEx/HTTPClose methods. Allows sending data to a Web server. HTTP functions support: HTTPS requests, Authentication and returning of HTTP Headers Low Level HTTP Get allows retrieving HTTP headers and multiple Get operations without reconnecting to the server. Events for HTTP download status HTTP Data class that allows running VFP database queries over HTTP (requires Web Connection server) File Encoding/Decoding routines that allow passing files over the Internet using HTTP Dialing and hanging up a RAS connection Low Level Interface to DynaZip DLLs so no OCX is required. How it works The wwIPStuff class is little more than a wrapper around the wwIPStuff.dll which abstracts many Internet Protocol operations (with exception of the HTTP functions which are implemented as pure VFP code calling WinInet). The DLL expands on the functionality provided there by providing support for SMTP and a front end that is capable of being called by Visual FoxPro's simple API calling interface using the DECLARE DLL mechanism. The VFP class provides a front for the DLL so you don't have to worry about the logistics of accessing the functionality. All parameter passing and return value validation is performed by the class which also provides a property/method interface to the static functions in the DLL. When initially created a wwIPStuff object sets the path to the DLL which is used in all subsequent requests. The Init() of the class also loads the DLL and the Winsock drivers into memory on instantiation. Once loaded Winsock stays resident for quicker access of subsequent requests onto the DLL. - Page 100 - West Wind Web Connection Class wwIPStuff How to use it Using the wwIPStuff class is accomplished by creating an instance of the class and setting the properties for the appropriate method calls. The following example shows all of the functionality available: SET PROCEDURE TO wwUtils ADDITIVE SET CLASSLIB TO wwIPStuff ADDITIVE CLEAR o=CREATE("wwIPStuff") Sending SMTP Mail o.cMailServer="mail.yourserver.net" o.cSenderEmail="rstrahl@west-wind.com" o.cSenderName="Bill Bopp" o.cRecipient="rstrahl@swest-wind.com,rstrahl@agorge.net" o.cCCList="rstrahl@xwest-wind.com,looser@nobody.com" o.cBCCList="rstrahl@west-wiund.com" o.cSubject="wwIPStuff Test Message" o.cMessage="Who said this had to be difficult?" o.cAttachment="c:\config.sys" *? o.SendMailAsync() && Send message and return immediately w/o result llResult = o.SendMail() && Send again - wait for completion IF !llResult Wait window o.cErrorMsg ENDIF Sending and receiving files via FTP The FTP class is implemented as a separate class and named wwFTP. LoFTP = CREATE(“wwFTP”) ? o.FTPGetFile("ftp.west-wind.com","pkunzip.exe","c:\temp\pkzip.exe") *** Or you can use syntax like this: o.cFTPServer="ftp.west-wind.com" o.cFTPSource="c:\wipeit.bat" o.cFTPTarget="/uploads/wipeit.bat" *** Use passwords if Anonymous is not allowed. * o.cUsername="bozo" * o.cPassword="looser" ? o.FTPSendFile() The FTPGetFileEx and FTPSendFileEx methods also support downloads while providing event method calls to allow progress reporting and aborting a download: PUBLIC o o=CREATE("myFTP") wait window nowait "Alt-x to abort download..." ON KEY LABEL ALT-X o.lCancelDownload = .T. IF o.FTPConnect("ftp.west-wind.com") # 0 ? o.nError ? o.cErrorMsg RETURN ENDIF IF o.FtpGetFileEx("wconnect.zip","c:\temp\wconnect.zip") - Page 101 - # 0 West Wind Web Connection Class wwIPStuff ? o.nError ? o.cErrorMsg RETURN ENDIF ON KEY LABEL ALT-X RETURN *** Implementation of Message Display and abort code Define class myFtp as wwFTP Function OnFTPBufferUpdate LPARAMETER lnBytesDownloaded,lnBufferReads,lcCurrentChunk DO CASE CASE lnBufferReads > 0 wait window "Downloaded: " + TRANSFORM(lnBytesDownloaded)+ " bytes (Alt-X to cancel)" nowait CASE lnBufferReads = -1 wait window "Download aborted..." timeout 2 ENDCASE RETURN ENDDEFINE Retrieving HTTP requests to strings (HTTP GET) You can simply retrieve a Web page or any HTTP data over the Web with: ? o.HTTPGet("http://www.west-wind.com/") lcData=o.HTTPGet(http://www.west-wind.com/logstats.dat) remember that the content return does not need to be HTML!!! Sending and Retrieving HTTP requests to strings (HTTP POST) o.HTTPConnect("www.west-wind.com ") o.AddPostKey("Company","A") o.AddPostKey("FromDate","01/01/96") @lcBuffer = "" *** Send the POST data and retrieve HTTP result lnResult = o.HTTPGetEx("/wconnect/wc.dll?wwDemo~ShowHours",@lcBuffer) IF lnResult = 0 wait window nowait o.cErrorMsg ENDIF *** Print out the HTTP header for the request ? o.cHTTPHeader o.HTTPClose() && Close the connection Sending and Receiving files over HTTP: The following demonstrates how you can use a Visual FoxPro client (non-HTML) to connect to a VFP Web server and send files between the two to essentially run queries over the Web: Server Code using a standard Web Connection Request (can also be done with ASP, FoxISAPI etc.): Function CustList && httpProcess::CustList SELECT * FROM TT_CUST WHERE &lcFilter INTO TABLE Texport - Page 102 - West Wind Web Connection Class wwIPStuff *** Format the the file and memo field and store to a string lcFileText = oIp.EncodeDBF("Texport.dbf",.T.) *** Send Binary data to client as Web server response loHTML.Send(lcFileText) Client Code (plain VFP application): *** Connect to server once o.HTTPConnect("www.west-wind.com") *** Presize the buffers! lcText=SPACE(100000) lnText=LEN(lcText) *** Read the results send by the server – result is encoded file o.HTTPGetEx("/wconnect/wc.dll?http~CustList",@lcText,@lnText) *** decode the file and save to Timport.dbf IF o.DecodeDBF(lcText,"Timport.dbf") *** Show the result USE Timport BROWSE ELSE wait window "File could not be converted" ENDIF o.HTTPClose() Domain Name Lookup *** Domain Lookups from IP Address and Reverse Domain Lookups ? o.GetDomainFromIp("205.162.195.2") ? o.GetIpFromDomain("ftp.west-wind.com") The FTP and SMTP methods can be used either with the property interface or by passing parameters directly to the methods. Exposed Properties: SMTP properties: cMailServer The IP Address or domain name of the SMTP server that is responsible for sending the message. The server must support 'pure' SMTP mail services and must not require a login prior to sending messages. cSendername Display name of the person sending the message. This option is often overridden by the mail server with the actual user account, but some servers leave the name as set here. cSenderEmail The sender's Email address. cRecipient Either a single recipient email address or a list of comma delimited addresses. Limited to 1024 characters. cCCList Either a single CC recipient email address of a list of comma delimited addresses. Limited to 1024 characters. cBCCList Blind CCs are sent messages but do not show on the recipient or CC listing of the receiver. Limited to 1024 characters. - Page 103 - West Wind Web Connection Class wwIPStuff cSubject The message subject or title. cMessage The actual message body text. cAttachment The name of the file that is to be attached to the message. This property must be filled with a valid path pointing at the file to attach. cContentType A content type that is used when sending the message. The default is text/plain, which is standard email format. You can change the content type to text/html for example to force messages to be sent as HTML documents that can be read in HTML capable email readers such as Outlook Express. FTP Properties: cFTPServer IP Address or domain name of the FTP server to work with cFTPSource The source file to send from. When uploading the source is the local file, when downloading the source is the remote file. cFTPTarget The target file to send to. When uploading the target is the remote file, when downloading the target is the local file. nFTPBinary Binary mode flag. 1 – binary file (default). 2 – ASCII Text. cUsername Username of the user to connect to the FTP site. If you want to connect anonymously leave out the username and password cPassword The user's password. Note: both user name and password are required if loging onto a secured FTP directory. HTTP Properties: lSecureLink Flag that determines whether the link attempts to use HTTPS. Same as flag on HTTPConnect method. nHTTPConnectType This flag determines how an Internet Connection is established by WinInet. 1 – Direct HTTP, 3 – Proxy, 0 – Preconfig. The default is 1 which means a plain HTTP connection will be used. If you're running through a Proxy Server you have to use a value of 3 – this value will also work with plain HTTP connections, but is available only for systems running Internet Explorer 4.0 or later. 0 – Uses Preconfigured settings from Internet Explorer and requires that IE is installed on the machine. nHTTPPort The port used to establish a connection. This value is 0 by default which means the default ports are used for normal and secure HTTP connections. If this value is set with a value other than 0, that port is used. Note this setting only works with synchronous HTTPConnect/HTTPGetEx operation. nConnectionTimeout - Page 104 - West Wind Web Connection Class wwIPStuff Timeout on an HTTP Connection prior to receiving/sending data (5) . This value is not respected by the current versions of WinInet, but maybe in future versions of Windows updates. cHTTPHeaders Property that will receive the HTTP Header when calling HTTPGetEx. The header is filled prior to any data being retrieved and an OnHTTPBufferUpdate event fires with 0 size and 0 chunk values that you can capture. lHTTPCancelDownload Used with HTTPGetEx() this flag can be set in the OnHTTPBufferUpdate() event handler to cancel the current HTTP request. nHTTPWorkBufferSize The size of the buffer used by HTTPGetEx to retrieve data. HTTPGetEx reads data from the wire into a temporary buffer. The size of this buffer determines how often control returns to the class code. Whenever a block completes wwIPStuff calls OnHTTPBufferUpdate to let you know that more data has arrived. Exposed Methods: wwIPStuff::Init The class constructor for the wwServer class sets up the basic options for the server class by specifying the program to execute when a CGI request is received. Note: Parameters have changed in version 1.65! Syntax Return Example Arguments oIP=CREATE(“wwIPStuff”,cDLLPath) Nothing oIP=CREATE("wwIPStuff","c:\SysDLLS\") CDLLPath The path where the wwIPStuff.dll file resides. If left out either the current path or Windows SYSTEM path is used. The path must be terminated with a trailing backslash. wwIPStuff::GetDomainFromIp This method retrieves a domain name from an IP address that is passed as a parameter. If the domain cannot be resolved either because the machine is not connected to a DNS server or because the domain cannot be resolved the value returned is an empty string (“”). Syntax Arguments Return Example See Also oIP.GetDomainFromIp(cIPAddress) CIPAddress The IP Address for to resolve. Must be in ‘dot’ notation with four sets of digits between 1 and 255. Example: “111.111.111.120” Domain Name or “” if the address could not be resolved lcDomain=oIP.GetDomainFromIP(“205.162.195.252”) wwIPStuff::GetIpFromDomain - Page 105 - West Wind Web Connection Class wwIPStuff wwIPStuff::GetIPFromDomain This method retrieves an IP Address from a domain name that is passed as a parameter. If the IP address cannot be resolved either because the machine is not connected to a DNS server or because the domain cannot be resolved the value returned is an empty string (“”). Syntax Arguments Return Example See Also oIP.GetDomainFromIp(cDomain) cDomain The Domain name to resolve. Example: “www.west-wind.com” Domain Name or “” if the address could not be resolved lcDomain=oIP.GetIpFromDomain(“ftp.west-wind.com”) wwIPStuff::GetDomainFromIp wwIPStuff::SendMail wwIPStuff::SendMailAsync This method allows sending of SMTP mail. The message parameters can be set either via direct parameters passed or by using the class properties selectively to set the message properties one at a time. SendMail does a blocking mail send that waits for completion while SendMailAsync does not. Syntax Return Arguments oIP.SendMail(cMailServer, cSenderDisplayName,; cSenderEmailAddress, cRepientList, cCCList,cBCCList; cSubject, cMessage, ; cAttachment, cContentType) .T. or .F. SendMailAsync always returns .T. CmailServer The domain name or IP address of the mail server that will handle sending the message. The mail server must be accessible via a TCP/IP connection at the designated IP address and you must have a valid account on this mail server to successfully send email. IP Addresses are in the format “205.111.111.2”. CsenderDisplayName The return address name that is displayed on the email message when received. This is the display name only, not the email address. Note that most mail servers override this with the name set up on the sending email account. CsenderEmailAddress The actual return address email address that is displayed on the email message. This should be the address that you want replies to be sent to. CRecipientList The list of recipients represented as a comma delimited string. All recipients should be entered as fully qualified email addresses. CCCList List of CCs represented as a comma delimited string. All recipients should be entered as fully qualified email addresses. cBCCList List of blind CCs represented as a comma delimited string. All recipients should be entered as fully qualified email addresses. Blind CCs are sent messages, but do not show up on either the Recipient or CC display of an email message. cSubject - Page 106 - West Wind Web Connection Class wwIPStuff The subject for the email message. cMessage The actual message text. This string can be of any length and can contain line breaks as necessary. cAttachment You can attach a single file to the message. The attachment must point to a file on disk with a full path. CContentType Remarks The message's content type. You can attach a single file to the message. The attachment must point to a file on disk All parameters are optional and you are encouraged to use the class properties by the same name as the parameters to set SMTP options for sending. The SendMail method sends messages by waiting for completion and returning .T. or .F. based on the result. You can check wwIPStuff::cErrorMsg for the error code and description returned from the mail server. The SendMailAsync method creates a new thread and lets the Send operation occur in the background. The routine immediately exits and no result code is returned. Example oIp.SendMailAsync("mail.bozo.com", "Rick Strahl", ; "rstrahl@west-wind.com",; lcEmail,"rstrahl@west-wind.com", ; "Web Connection generated E-Mail Sample",; "Message Body Text goes here…") wwIPStuff::FTPGetFile This method retrieves a file from an FTP server. This method operates in blocking mode waiting for completion of the file transfer before returning a result code. File properties can either be set with the wwIPStuff properties or by passing the parameters explicitly. Syntax oIP.FTPGetFile(cFTPServer, cSource, cTarget,; nBinary, cUsername, cPassword) Return 0 on success – Win32 API error code otherwise Arguments cFTPServer The domain name or IP address of the FTP server. The server must be accessible via a TCP/IP connection at the designated IP address. cSource The file to download from the FTP server. cTarget The filename and path where you want to save the file to. nBinary (optional) Determines whether the file is sent in Binary (default) or ASCII format. Values are 1 for binary or 0 for ASCII. cUsername (Optional) If the FTP server requires a login a username and password must be specified. If the username and password are left out anonymous login is requested on the FTP server. cPassword (Optional) see cUsername. Remarks FTPGetFile sends file in blocking mode waiting for transfer completion and a result code. Example oIp.FTPGetFile ("ftp.west-wind.com",; "ww_web.zip",; - Page 107 - West Wind Web Connection Class wwIPStuff "c:\download\ww_web.zip") wwIPStuff::FTPSendFile This method sends a file to an FTP server. This method operates in blocking mode waiting for completion of the file transfer before returning a result code. File properties can either be set with the wwIPStuff properties or by passing the parameters explicitly. Syntax oIP.FTPSendFile(cFTPServer, cSource, cTarget,; cUsername, cPassword) Return 0 on success – Win32 API error code otherwise Arguments cFTPServer The domain name or IP address of the FTP server. The server must be accessible via a TCP/IP connection at the designated IP address. cSource The file to send to the FTP server. cTarget The filename and path where you want to save the file to on the FTP server. Note the path must be FTP server relative using forward slashes. cUsername (Optional) If the FTP server requires a login a username and password must be specified. If the username and password are left out anonymous login is requested on the FTP server. cPassword (Optional) see cUsername. Remarks Example FTPGetFile sends file in blocking mode waiting for transfer completion and a result code. oIp.FTPSendFile ("ftp.west-wind.com",; "c:\uploads\ww_web.zip",; "/uploads/ww_web.zip",; "bozo",; "looser") wwIPStuff::FTPDeleteFile This method deletes a file from an FTP server. File paths can be relative and files require the proper rights in order to be deleted. This method operates in blocking mode waiting for completion of the file transfer before returning a result code. File properties can either be set with the wwIPStuff properties or by passing the parameters explicitly. Syntax oIP.FTPDeleteFile(cFTPServer, cFileToDelete, cUsername, cPassword) Return 0 on success – Win32 API error code otherwise Arguments cFTPServer The domain name or IP address of the FTP server. The server must be accessible via a TCP/IP connection at the designated IP address. cFileToDelete The file to delete from the FTP server. The file name may have a server relative path (using server specific / slashes). cUsername (Optional) If the FTP server requires a login a username and password must be specified. If the username and password are left out anonymous login is requested on the FTP server. - Page 108 - West Wind Web Connection Class wwIPStuff cPassword (Optional) see cUsername. Remarks Example FTPDeleteFile blocks until completion. oIp.FTPDeleteFile ("ftp.west-wind.com",; "/uploads/tempfile.zip",; "bozo","looser") wwIPStuff::aFTPDir This method retrieves a list of files for a given path spec. Unlike the VFP ADIR() function this method only returns a 1D array of filenames and does not support attributes explicitly. In other words, all files matching a filespec are returned. Syntax noIP.aFTPDir(@aFTPFiles, cFTPServer, cFileSpec, cUsername, cPassword) Return Numbe of files matching filespec or 0 if not found. Arguments aFTPFiles An array that receives the resulting list of files. This parameter must be passed by reference. cFTPServer The domain name or IP address of the FTP server. The server must be accessible via a TCP/IP connection at the designated IP address. cFileSpec The path to retrieve files for. The path may include wildcard characters for file names. cUsername (Optional) If the FTP server requires a login a username and password must be specified. If the username and password are left out anonymous login is requested on the FTP server. cPassword (Optional) see cUsername. Remarks Example FTPDeleteFile blocks until completion. lnFiles = oIp.FTPDir("ftp.west-wind.com",; "/uploads/*.*",; "bozo","looser") wwIPStuff::HTTPGet This method retrieves an HTTP request such as an HTML document or file from a Web server. This method can be useful to retrieve information from another Web server and use that information inside of your application. You could infact read streaming data information by occasionally polling data in remote file and updating your VFP form with a call to this method off a timer. This method returns ASCII text only – HTML is uninterpreted and presented as text. Syntax Return Arguments oIP.HTTPGet (cUrl, nMaxBuffer) Result string of HTTP Get or "" cUrl The full URL that is to be retrieved. The URL cannot be relative, it must be a full including protocol, server and relative path. nMaxBuffer (Optional – Default: 16384) The size of the buffer that is allocated to retrieve the data. If you know you're retrieving a - Page 109 - West Wind Web Connection Class wwIPStuff large buffer increase the size here. Remarks Example If the data returned exceeds the buffer the data is truncated. HTTPGet blocks until completion. lcText=oIp.HTTPGet("http://www.west-wind.com/") wwIPStuff::HTTPConnect This HTTP method initiates a low level HTTP request for use with HTTPGetEx by establishing an IP Session and connecting to a target server. Syntax oIP.HTTPConnect (cDomainOrIPAddress,cUsername, cPassword, lSecure) Return 0 on success or a Win32 error code. If the value is non-zero check oIP.cErrorMsg. Arguments cDomainOrIPAddress Specify the site you want to access: www.west-wind.com for example. cUsername, cPasswords If the link you're trying to access requires Authentication (Basic Authentication or NT Challenge Response) specify the account info here. Optional lSecure If you're accessing a secure link on the server (HTTPS) set this paramater to .t. Optional Remarks Example lnResult=oIp.HTTPConnect("www.west-wind.com") wwIPStuff::HTTPGetEx This method retrieves an HTTP request such as an HTML document or file from a Web server. You must first use HTTPConnect() to open a connection to a server before using this method. This method supports POSTing data to the server using the AddPostKey() method. Each value to POST must be added with this method first before sending the request. This method returns ASCII text only – HTML is uninterpreted and presented as text. Syntax Return Arguments oIP.HTTPGetEx(cRequestPage, @cBuffer, @nSize, cHeaders) 0 on success or a Win32 error code. If the value is non-zero check oIP.cErrorMsg. cRequestPage The name of the page or link to retrieve on the server connected to with HTTPConnect. @cBuffer This is the buffer that receives the result from the server. The buffer's size must be passed in the nSize parameter. The buffer is filled by the function call and the size returned in nSize. @nSize This value specifies the input buffer size and also receives the result buffer size when the request returns. If this value is set to 0 the buffer will be sized automatically to the size of the request retrieved. Optional cHeaders This allows you to add special headers to a request, such as special content types, Cookies, page expiration etc. Use Key: Value pairs (Content-Type: text/html). Optional - Page 110 - West Wind Web Connection Class wwIPStuff Remarks Example See Also If the data returned exceeds the buffer the data is truncated. HTTPGetEx blocks until completion. loIP = CREATE("WWIPStuff") loIP.HTTPConnect("www.west-wind.com") lcBuffer = "" lnSize = 0 loIP.HTTPGetEx("/default.asp ",; @lcBUffer,@lnSize) loIP.HTTPClose() RETURN wwIPStuff::OnHTTPBufferUpdate; wwIPStuff::cHTTPHeaders wwIPStuff::OnHTTPBufferUpdate The HTTPGetEx method fires events whenever the buffer is updated. This event is a notification method that you can override to provide a status display. Note, that this will work effectively only if you pass HTTPGetEx a BufferSize of 0 which creates a dynamically sized buffer with small chunks. If you pass a dedicated buffer size all data is retrieved in one chunk and you only get one event notification. This event also fires when HTTPGetEx retrieves the HTTP header prior to retrieving data. In this case both the nBytes and nBufferReads parameters are passed in as 0. Syntax Return Arguments OnHTTPBufferUpdate(nBytesRead,nBufferReads,cBuffer) Nothing. This method is an Event Method. nBytesRead Returns the total number of bytes that have been read so far by this request. nBufferReads Returns the number of reads that have been made so far. 0 - The HTTP Header for the request > 0 – The actual block count cBuffer Returns the currently read buffer. If your output contains text or other content that can be built piecemeal you may be able to show some of the data as it comes in without waiting for completion of the download. Remarks Example The first call to this method may take a little bit. WinInet pulls an internal buffer off the wire prior to passing control to the user code to retrieve the buffer. The frequency of calls to this method is determined by the nHTTPWorkBuffer value. The bigger the buffer the fewer times this method is called. In order to capture the OnHTTPBufferUpdate you have to either create a subclass (as the example show below) or drop the wwIPStuff class onto a form visually and event event code into the event. DEFINE CLASS MyWWIPStuff as wwIPStuff FUNCTION OnHTTPBufferUpdate LPARAMETER lnBytesRead, lnChunk, lcBuffer DO CASE *** If this chunkcount is 0 it's HTTP Header CASE lnChunk = 0 ACTI SCREEN CLEAR - Page 111 - West Wind Web Connection Class wwIPStuff ? "The HTTP Header is:" ? lcBuffer && or use THIS.cHTTPHeaders *** If your request set the Content-Length header *** You can retrieve the size of the content! lnRequestSize = EXTRACT(lcBuffer,CHR(13)+CHR(10) +; "Content-length: ",CHR(13)) CASE lnChunk > 1 THISFORM.edtBox.value = THISFORM.edtBox.Value + lcBuffer CASE lnChunk = -1 && Done MessageBox("Download Complete") ENDCASE wait wind TRANS (lnBytes,"999,999,999") + " bytes" nowait *** If you want partial UI operation use DoEvents DoEvents RETURN ENDDEFINE loIP = CREATE("MyWWIPStuff") loIP.HTTPConnect("www.west-wind.com") loIP.nHTTPWorkBufferSize = 2048 && Updates by this chunk size lcBuffer = "" lnSize = 0 loIP.HTTPGetEx("/default.asp ",; @lcBUffer,@lnSize) See Also loIP.HTTPClose() RETURN wwIPStuff::nHTTPWorkBufferSize; wwIPStuff::cHTTPHeaders wwIPStuff::HTTPGetExAsync Like the above HTTPGetEx method except it can run asynchronously. The method returns immediately from the HTTP call, while the HTTP call continues to run in the background. You can force the HTTP call to create a message file that contains the actual result from the HTTPGetEx. It'll return either the complete HTTP result or an error message. This method supports POSTing data to the server using the AddPostKey() method. Each value to POST must be added with this method first before sending the request. This method returns ASCII text only – HTML is uninterpreted and presented as text. Syntax Return Arguments oIP.HTTPGetExAsync(cPage, cResultFile, nResultSize) nothing cPage The server relative page (default.asp or /wconnect/wc.dll?wwDemo~TestPage) cResultFile Optional. If you want the output of the request to be written to a file you can specify a file here. Note you should use unique filenames if you're firing more than one HTTP request asyncronously. By default no file is created. nResultSize Optional. Allows you to specify the size of the result buffer that determines how much data is pulled for the HTTP request. This value cannot be 0 – 0 will automatically resize - Page 112 - West Wind Web Connection Class wwIPStuff the buffer to 256 bytes. The buffer is sized to this value and written to disk if cResultFile is specified. Otherwise the buffer is ignored. Default: 256 Remarks You can set the cUsername and cPassword properties and lSecureLink properties on HTTPConnect to set security options on the request. You can use AddPostKey() to add POST variables to the request. It's possible to build an async event driven application using a timer and this method. See the wwHTTPAsync object in wwipstuff.vcx. Requires wwIPStuff.dll. Make sure you don't quit VFP while a request is still running in the background or VFP will crash! Example *** Demonstrate Async operation with cancel dialog o = CREATE("wwIPSTUFF") o.HTTPConnect("www.west-wind.com") o.AddPostKey("Test","Rick") o.nTimeout = 20 && in seconds plExit = .F. DO CancelForm && Modeless cancel form – sets plExit o.HTTPGetExAsync("/webconnection.asp", "c:\temp\westwind.htm", 20000) DO WHILE !FILE("c:\temp\westwind.htm") AND !plExit DoEvents ENDDO See Also IF FILE("c:\temp\westwind.htm") lcFileText = File2Var("c:\temp\westwind.htm") ACTI SCREEN ? lcFileText ELSE wait window "Operation cancelled… ENDIF wwHTTPAsync Control Class wwIPStuff::AddPostKey This method is used to add any information that needs to be POSTed to a Web server. You can post form variables or any data you see fit including entire files. The data is URLEncoded by this method and automatically picked up by the HTTPGetEx method when called. Syntax Return Arguments oIP.AddPostKey(cKey, cValue) nothing cKey The key or identifier for the data to be posted. If filling HTML forms the key will be the NAME of the form variable. cValue The actual value to send to the server. This value can be any size and can contain binary data. Remarks Example The data in cValue is URLEncoded once received. The encoding process can be slow on large value fields. Ip.AddPostKey("txtCompany","West Wind Technologies") - Page 113 - West Wind Web Connection Class wwIPStuff wwIPStuff::HTTPClose Closes an HTTP request opened with HTTPConnect. Syntax oIP.HTTPClose() Return nothing Arguments none Remarks Example oIP.HTTPClose() wwIPStuff::EncodeDBF Converts a file or DBF or DBF + Memo file into a single text string that you can easily send down the connection with loHTML.Send(). wwIPStuff::DecodeDBF() can be used on the receiving end to retrieve the string back into a file. Syntax Return Arguments oIP.EncodeDBF (cFileName, lHasMemo) binary string that contains a header plus the binary data of the file cFilename The filename to encode lHasMemo If this flag is set the memo file is automatically added to the encoded data to allow simple packaging of the file. Remarks Example Header contains ID, filename and length of the binary data SELECT * FROM TT_CUST WHERE &lcFilter INTO TABLE Texport lcFileText = oIp.EncodeDBF("Texport.dbf",.T.) *** Send Binary data to client loHTML.Send(lcFileText) wwIPStuff::DecodeDBF Converts a file or DBF or DBF + Memo file into a single text string that you can easily send down the connection with loHTML.Send(). wwIPStuff::DecodeDBF() can be used on the receiving end to retrieve the string back into a file. Syntax Return Arguments oIP.DecodeDBF (cBuffer, cFileName) .T. or .F. cBuffer The text string that contains the file plus header as created by EncodeDBF() cFileName The full filename to create. If the encoded file includes a memo simply specify the .DBF file – the memo is automatically created. Remarks Example The file to create must not be open or the file cannot be created. lcFileText = oIP.HTTPGet("http://localhost/wc.wc?http~CustList") IF oIp.DecodeDBF(lcFileText,"TcustList.dbf") SELE TT_Cust APPEND FROM TcustList - Page 114 - West Wind Web Connection Class wwIPStuff ENDIF Low Level HTTP Methods *** Connect to server once o.HTTPConnect("www.microsoft.com") *** Presize the buffers! lcText=SPACE(16384) lnText=LEN(lcText) lcHeader=SPACE(2048) lnHeader=LEN(lcHeader) *** Read many times SET MEMOWIDTH to 256 o.HTTPGetEx("/",@lcText,@lnText) ? lcText && Contains the actual HTML of the page o.HTTPGetHeader("/",@lcHeader,@lnHeader) ? lcHeader o.HTTPClose() ************************************************************************ * wwIPStuff :: HTTPGetHeader ********************************* *** Function: Retrieves just the HTTP header of a page request. *** Assume: Must call HTTPConnect/HTTPClose to manage connection *** to Server *** Pass: tcPage The Server relative page to view *** tcHeader Buffer to receive headers (by reference) *** tnSize Size of the Buffer (by Reference) *** Return: Win32API Error Code ************************************************************************ wwIPStuff::RasDial Dials an installed Remote Access Session entry. Syntax Return Arguments oIP.RasDial(cRasEntry) .T. or. F. cRasEntry Name of a RAS connection as set up in Dial Up Networking under Window/NT. You can find the names in your RAS phonebook. Remarks On failure a dialog box is displayed that describes the error. A connection can only be closed by using the same handle that opened it. wwIPStuff stores the handle as a class property, so in order to close the connection you need to keep the instance that dialed open until you close the connection. Example oIP.RasDial("Gorge Net") - Page 115 - West Wind Web Connection Class wwIPStuff wwIPStuff::RasHangup Hangs up a Ras Connection based on a handle created with RasDial. Syntax oIP.RasHangup() Return .T. or. F. Arguments none Remarks A connection can only be closed by using the same handle that opened it. wwIPStuff stores the handle as a class property, so in order to close the connection you need to keep the instance that dialed open until you close the connection. Example oIP.RasHangup() wwIPStuff::GetSystemErrorMsg This method converts the Win32API error number of the last operation to a string error message. Syntax Return Arguments oIP.GetSystemErrorMsg([nErrorNo,lAPIError]) Result error string or "" nEerrorNo The error to return a string for. If not specified the last error generated by a WinInet call is retrieved. Optional lAPIError By default this method returns WinInet error codes. If this flag is set to .t. a Win32API error code can be retrieved. Optional Remarks Example Based on the value of the nError property which gets set on error conditions. You should check this flag for a non-zero value before calling this method. wait window oIp.GetSystemErrorMsg(6) - Page 116 - West Wind Web Connection Class wwFTP Class wwFTP Parent Class: wwIPStuff Source: wwIPStuff.vcx For documentation please see the wconnect.chm HTML Help file for details. - Page 117 - West Wind Web Connection Class wwHTTPAsync Class wwHTTPAsync Parent Class: Timer Source: wwIPStuff.vcx The wwHTTPAsync class implements asynchronous HTTP retrieval that allows you to run HTTP requests while continuing on with your application. When the request is complete the NavigateComplete event is fired to let you know that the request has finished processing. The request result is returned to you in form of a string. How it works This class is implemented using a timer and the wwIPStuff::wwHTTPGetExAsync method which creates an output file when the request is complete. The timer class polls for the completion file and when found fires the NavigateComplete method which you can attach code to. The class handles file cleanup when the request file is read. In addition the DLL also tries to delete the result file if it sticks around for 20 seconds after completion. IOW, if you decide to cancel a download cleanup will still commence. As with any Aysnc function, be careful not to quit Visual FoxPro while a background request is still running. Each request is handled on a new thread. A new thread is fired in the DLL, which then runs the actual HTTP request link and downloads the data to file. If an error occurs an error message is downloaded. Error messages start with the text Error: followed by the actual error message. To use the control simply drop the wwHTTPAsync control onto a form and set the appropriate properties either in the property window or programmatically. The following example demonstrates how you might use the control. Drop the control onto a form. You can add the following code to a button event, which starts the Async request. loIP = THISFORM.oAsyncDownload loIP.nTimeout = 300 loIP.cServer = www.west-wind.com loIP.cLink = "/default.asp " loIP.nBuffersize = 500000 THISFORM.oAsyncDownload.StartRequest() Once started the control will run the Async request while leaving your application active and operational. It will then fire the OnDownloadComplete event, which you can override on the control: * oAsyncObject::OnDownloadComplete LPARAMETER lcRetrievedData *** Take the retrieved data File2Var("c:\temp\download.htm",lcRetrievedData) *** Take the text and display it in a Web Browser control THISFORM.oBrowser.Navigate("file://c:\temp\download.htm") wait window "Download Complete!" - Page 118 - West Wind Web Connection Class wwHTTPAsync Properties and Methods Property What it does cUsername The name of the server to contact. Example: www.west-wind.com or 111.111.111.111. The server relative link to access. Example: / or /default.asp or /wconnect/wc.dll?wwDemo~TestPage~&UID=123 The buffer that receives the output from the request. This value can also be retrieved directly from the NavigateComplete() method as a parameter. The max size of the buffer to be returned. If the buffer is greater than the size the buffer is truncated. 0 is not allowed as in wwIPStuff object. Default: 64k Username for Authentication Optional cPassword Password for Authentication lSecure Whether to use SSL lBusy Check this to see whether a request is in process. nTimeout This value determines how long the request is waited for in seconds. If this timeout value is exceeded the request is terminated with a timeout error message. An object reference to the actual wwIPStuff object that does all of the work. You can set some of the non-exposed properties on this object directly. cServer cLink cResultBuffer nBufferSize oIP Optional Method StartRequest NavigateComplete CancelRequest AddPostKey Optional What it does Starts the request. This method returns immediately and sets the lBusy flag to indicate busy status. No Parameters This method is called when the request is complete. This method takes two parameters: lcResultBuffer The full HTTP result of the request. If an error occurs this parameter will contain an error message in the format Error: Error Message. llError Set to .T. if there was an error during a request. Cancels the current request and resets the control. Cancel request is also called internally if the request times out or an error occurs. Allows you to add Post key value pairs to the request to allow sending data to the Web server. See wwIPStuff::PostKey for more details. - Page 119 - West Wind Web Connection Class wwHTTPData & wwHTTPFile Class wwHTTPData & wwHTTPFile Parent Class: aHTTPData Source: wwIPStuff.vcx This class uses the wwIPStuff class to provide a generic data transfer and query mechanism for Visual FoxPro clients accessing a Web Connection back end server. This client server implementation supplies methods for the client code and the server side code that need to run for communication over HTTP to occur. Web Connection also includes a generic wwProcess module (wwHTTPData) that handles data transfers the basic data transfers generically. This wwProcess subclass will be described here as well. How it works The primary function of this class is to allow a client to run a SQL query or command on the server and return the data back to the client. When running a query from the client side you basically provide a SQL string that will be executed on the server. In addition you can specify the result cursor name, a MaxBuffer size, secure connection over SSL and wether the file is zipped (this feature requires you own a copy of DynaZip and have the DZ DLLs installed in your SYSTEM directory). In addition, you can specify a user logon and password which can be matched to a user set up on the Web server. All of this is accomplished by setting a few properties on the object, most of which are optional. When all is set up you simply call the Execute() method to run your SQL Query. The server responds to the request by instantiating the same class and using the S_Execute() method to unparse your request. The SQL Statement is run and the result is returned back via HTTP to the client. The server sets various error messages if the either the query or any part of the request fails along the way. When the file reaches the client it decodes the downloaded file and creates a cursor from it, which is handed back to you to use. All cleanup is performed for you, so this operation is not a lot different from running a native Visual FoxPro query. The Client Side The client side of this object is responsible for collecting the data necessary to allow the server to check security, decide whether Zipping is used and what query to execute. The client side VFP code looks like this: *** Demonstrate running query over the Web o=CREATE("wwHTTPData") o.cServername = "localhost" * o.cHTTPLink= "/wconnect/wc.dll?wwHTTPData~Execute" o.nMaxBufferSize = 100000 o.cUsername = "rstrahl" o.cPassword = "mypassword" o.lIsZipped = .T. && Requires DynaZip libraries o.cSQL = "SELECT * FROM Tt_cust" o.Execute() && Default value IF o.lError ? o.cSQL ? o.cErrorMsg RETUR ENDIF BROWSE *** You can also do inserts and Updates like this o.cSQL = [INSERT INTO Timebill (custno) VALUES ("123123")] o.Execute() - Page 120 - West Wind Web Connection Class wwHTTPData & wwHTTPFile IF o.lError ? o.cSQL ? o.cErrorMsg ENDIF Note that most of these parameters are optional. The only required ones are the query and the server name. The HTTPLink is actually the default, but if you build your own handler you will have to change this value to point at your request instead (wwHTTPData is not enabled by default for security reasons – you can turn it on in wcDemoServer::Process() inside of the CASE statement in wcMain.prg). The username and password must match what you have set up on your server – again this depends on whether you check for this stuff or not, but the default link uses a username stored in wcmain.ini to check for a validated account (either specific or generic ("Any") or no security ("")). When all is set, specify a SQL statement and call the Execute() method to send the query. If all goes well you'll receive a result cursor in the case when you ran a SELECT or CREATE TABLE command. Otherwise no cursor is returned. You should check the lError flag after each request to make sure that request succeeded. If an error occurred you can check the cErrorMsg property for a reason the request failed. The Server Side A Web Connection server can access the same object used on the client side to send the data. The server has to deal with the security validation and then uses the S_Execute() method to actually run the query and send the data back to the client: ************************************************************************ * wwHTTPDataProcess :: Execute ********************************* *** Function: Generic Execute request handler routine that can *** be used to pull data from the wire. *** Typically called from a wwHTTPData client in VFP ************************************************************************ FUNCTION Execute *** Authentication is optional – here we pull the authorized user from *** wcmain.ini in the [wwHTTPData] section *** Supported values in the INI - Any - Any Authorized user *** Username - A specific user *** "" - None - no Authentication lcAuthUser = THIS.GetAppIniVar("AuthUser","wwHTTPData") *** Create Data Object and call Server Side Execute method (wrapper for Process Method) loData = CREATE("wwHTTPData") loData.S_Execute(THIS,lcAuthUser) ENDFUNC * wwHTTPDataProcess :: Execute This is a standard Web Connection process class subclass. In fact you can find this generic handler in wwHTTPData.prg. If you want a generic query engine you can simply enable this request processor (set the CASE "WWHTTPDATA" in wcMain's CASE structure in the Process() method). Or, if you would like to customize operation you can implement this type of request in any of your own request handlers. The S_Execute() method creates its own HTML output so all you really have to do is call the method for actually running the query. 3 lines of code! How much simpler can you get? You can add pre and post processing code, but you may not add any additional HTML output as the S_Execute() method communicates with the matching Execute() call on the client side. - Page 121 - West Wind Web Connection Class wwHTTPData & wwHTTPFile Security Security is a huge issue with this setup. You're basically opening up much of FoxPro for remote access. For this reason think about security issues very, very carefully. Since the interface described here is generic (although you can simply change the names of the generic metods on the server to get around this simple problem) anybody who knows the link can potentially access your data - not a good idea! Basic Authentication To get around this Web Connection implements security for these methods via Basic Authentication and an option to specify which user account is allowed access. The server determines the account and the client application (note the application, not the user) must specify the account and password explicitly. Since this information will be hidden inside of your compiled information it provides protection from somebody simply accessing the data link without authorization. For example, you can set up the server so that it will allow only a certain user account to access this link. As part of the request you create, you specify the AuthUser account as part of the call to S_Execute(). The method will the validate the user and allow access to only that particular user. Alternately you can set cAuthuser to Any validated account or a blank string in which case no checking is performed at all. The latter option is not recommended in any situation and the former only if you've cleared the standard NT accounts like Guest that start out with generic passwords. To make this work the client side call has specify a username and password. This is passed to the server via the HTTP Basic Authentication scheme just like on a Web page asking for Authorization. For an application you'd probably want to set up a special user account on the server that you use for all queries or file transfers performed. The username and password is then compiled into your client application and invisible to prying eyes. Secure Sockets Layer (SSL) Data that travels over the wire can be encrypted with SSL if you have an SSL certificate by specifying the lSecure flag. This will protect your data from sniffers and protocol analyzers. Uploading Files via HTTP with wwHTTPFile You can also use the wwHTTPFile class to upload files from a VFP application to a Web Connection Server. The process here is similar to the query routines, but instead of retrieving information only a file is uploaded to the server. The file can be automatically zipped (if DynaZip is installed) . Here's the code to upload a file to the server: o=CREATE("wwHTTPFile") o.cServername = "localhost" * o.cHTTPLink = "/wconnect/wc.dll?wwHTTPData~SendFile" && Default Value o.nMaxBufferSize = 100000 o.cUsername = "rstrahl" o.cPassword = "mypassword" o.lIsZipped = .T. o.cSourceFile = "c:\wwapps\wc2\wcmain.prg" o.cTargetFile = "c:\temp\wcmain.prg " && Only works if server allows full path o.SendFile() IF o.lError ? o.cErrorMsg RETURN ENDIF RETURN Note that the cTargetFile option is dependent on how the server is set up. If the server has the cForceSavePath property set files are automatically forced into the directory specified there and the cTargetFile value specified here is ignored. It's recommended that you do this and set the path to a work/temporary directory so that there's no chance of the client doing something like: o.cTargetFile = c:\winnt\system32\explorer.exe - Page 122 - West Wind Web Connection Class wwHTTPData & wwHTTPFile Property/Method What it does wwHTTPData cSQLCursor SQL Statement to be sent to the server. This can be SELECT, INSERT, UPDATE and CREATE TABLE. The name of the result cursor. Default: THTTPQuery cSourceFile The Source File to send to the server. Required cTargetFile The file to copy to. If not specified the source file is used and sent to the current server directory. If the server has defined a cForcedSavePath value the path is stripped from the filename. Default: Blank This server side method is used on the server side to determine whether the client is allowed to specify a full or relative file path. If this property is not empty any path specified by the client will be stripped and replaced with the path specified in this property. Default: Blank cSQL wwHTTPFile cForcedSavePath Generic aHTTPData (applies to both above classes) cServerName Name of the Web Server to access. cHTTPLink cUsername/cPassword Server relative link to the Web Connection request that fires. Defaults: /wconnect/wc.dll?wwHTTPData~Execute for wwHTTPData /wconnect/wc.dll?wwHTTPFile~SendFile for wwHTTPFile Username and Password used for Authentication on the server. lSecure Determines whether the request uses SSL lIsZipped lError Determines whether the request zips the query result or file to send. Requires DynaZip libraries (third party). Maximum size of the data to transfer over the wire. This is a safety setting that makes sure huge data sets are not sent. Specify 0 to allow any size data. Set to .t. if an error occurs. cErrorMsg Holds an error message if lError is .T. nMaxBufferSize wwHTTPData::Execute This method is responsible for actually calling the remote server and causing it to run the query. Syntax Return Arguments oHTTPData.Execute(cSQLStatement) .T. or .F. cSQLStatement Optionally provide a SQL statement here. The statement passed here overrides the cSQL property setting. Optional Remarks Make sure all properties are set prior to calling this method. Example o.cSQL = "SELECT * FROM Tt_cust" o.Execute() IF o.lError ? o.cSQL ? o.cErrorMsg RETURN ENDIF - Page 123 - West Wind Web Connection Class wwHTTPData & wwHTTPFile BROWSE wwHTTPData::S_Execute Server Side Execute method that encapsulates a full Web Connection request to handle running the specified query and returning the resulting result cursor back to the calling client. Syntax Return Arguments oHTTPData.S_Execute(oProcess,cAuthUser) .T. or .F. oProcess Web Connection wwProcess object (pass as THIS). cAuthUser User account that must be sent and authenticated by the client. The client sends username and password and the request validates these through the Web Server with Basic Authentication. Maybe: "Any", "Username" or "", where username is a valid NT user account. Note this value must match the exact Authenticated Username. Use the Web Connection Demo's Authentication Demo to see what full Authentication names are for a given account. Remarks Example Method call is fully self contained Web Connection request. You cannot add any HTML output in your request code! Function MyWCRequestMethod lcAuthUser = THIS.GetAppIniVar("AuthUser","wwHTTPData") * lcAuthUser = "rstrahl" loData = CREATE("wwHTTPData") loData.S_Execute(THIS,lcAuthUser) RETURN wwHTTPFile::SendFile Generic SendFile method takes the specified file and encodes it, zips it if specified and sends the file to the server via HTTP request. Syntax Return Arguments oHTTPFile.SendFile() .T. or .F. oProcess Web Connection wwProcess object (pass as THIS). cAuthUser User account that must be sent and authenticated by the client. The client sends username and password and the request validates these through the Web Server with Basic Authentication. Maybe: "Any", "Username" or "", where username is a valid NT user account. Note this value must match the exact Authenticated Username. Use the Web Connection Demo's Authentication Demo to see what full Authentication names are for a given account. Remarks Example Make sure all properties are set prior to calling this method. o.cServername = "localhost" o.cSourceFile = "c:\wwapps\wc2\wcmain.prg" o.cTargetFile = "c:\temp\wcmain.prg" - Page 124 - West Wind Web Connection Class wwHTTPData & wwHTTPFile o.SendFile() IF o.lError ? o.cErrorMsg RETURN ENDIF wwHTTPFile::S_SendFile Server Side SendFile method accepts the file sent by the client side SendFile. The file is decoded and stored depending on the cForcedSavePath directory setting or the file path provided by the client Syntax oHTTPFile.S_SendFile(oProcess,cAuthUser) Return .T. or .F. Arguments o Remarks Method call is fully self contained Web Connection request. You cannot add any HTML output in your request code! Example Function MyWCRequestMethod lcAuthUser = THIS.GetAppIniVar("AuthUser","wwHTTPData") loFile = CREATE("wwHTTPFile") *** Always force file to an Uploads directory loFile.cForcedSavePath = SYS(5) + CURDIR() + "Uploads\" loFile.S_SendFile(THIS,lcAuthUser) RETURN - Page 125 - Class wwPDF – Adobe Acrobat File Creation West Wind Web Connection Class wwPDF – Adobe Acrobat File Creation Enterprise Edition only Source: wwPDF.prg One big issue when working with Web Applications is the inability to print efficiently from a Web browser. The problem is that the Web Browser has no understanding of the data on the page and hence breaks text without concern for data groups and general layout. It's also difficult to create complex reports that display well in HTML. It's much easier to to do this with the VFP report writer. One way to create a report for viewing over the Web is to print it to an Adobe Acrobat file, which can be viewed on the client side with the Acrobat Reader. The resulting document is rendered exactly like the actual report preserving the rich text formatting (fonts, bold/italic, colors, alignment etc) and providing a searchable, editable (with the proper Adobe software) document that can be printed from the viewer. The viewer is freely downloadable from the Adobe Web site (www.adobe.com). Adobe also sells software that allows creation of Acrobat documents and one of the features of this package is a printer driver that allows converting of standard printer output to an Acrobat document. Unfortunately, this printer driver is not very well behaved and the implementation for providing programmatic access is very badly implemented. It can be done, but beware of some of the issues. The following class encapsulates the process into an easily accessible class. How to use it: The class is easy to use once the Adobe software is configured properly (see next section). The class provides easy methods for calling reports and printing them to a PDF file or creating QuickReports on the fly. SET PROCEDURE TO WWAPI ADDITIVE SET PROCEDURE TO WWPDF ADDITIVE oPDF=CREATE("wwPDF","WINNT") * If the defaults don't work locate the INI file * manually and then pass the path * oPDF.SetAcrobateIniFile("c:\winnt\system32\WINNT\SYSTEM\spool\DRIVERS\W32X86\3\__pdf.ini") *** Set Locking or Print Delay Timeout oPDF.nTimeout = 20 && Seconds (default is 10) SELECT * from TT_CUST INTO CURSOR TQuery llResult = oPDF.PrintReport("Report.frx","c:\temp\MyPdf.pdf","FOR Customer = '"+lcCust+"'") *** You can also print the PDFFile to a string *** for sending back as HTTP result output * lcFileText = oPDF.PrintReportToString("Report.frx") SELECT Company, Careof, Phone from TT_Cust into cursor Tquery *** You can also create quick reports without an FRX llResult = oPDF.QuickReport("c:\temp\MyPDF.pdf") - Page 126 - Class wwPDF – Adobe Acrobat File Creation West Wind Web Connection Adobe PDFWriter Configuration This class works by dynamically switching the printer driver and updating the PDF configuration file. The class requires that you have Adobe Acrobat and the PDFWriter software installed. This class has been tested with version 3.02 of the Adobe PDFWriter driver. Make sure the PDFWriter printer driver is installed and that the printer driver has its port set to LPT1 and not FILE. File will force a file name popup from the printer driver in addition to the PDF driver file requirements. Find C:\WINNT\system32\spool\DRIVERS\W32X86\2\__pdf.ini. Note this file may exist in other places - just the W32X86 directory or any numbered subdir thereof. 2 seems to be the space where it's expected. There may be multiple copies of this file - the right one should have a bunch of flags in it and should show the last document you printed with a date and whatever you typed for the title. This class will look for the file: Win95: WINDOWS\Win.ini WinNT: WINNT\SYSTEM\spool\DRIVERS\W32X86\2\__pdf.ini Add the following two settings: PDFFilename=c:\temp\__wwPdf.pdf bDocInfo=0 (where \temp\ points at your temp directory) and reboot if you've printed to the driver during the current logon. Using this class will make permanent changes to the way Acrobat prints. In particular it will always print to the file you specify or the default (TEMP\__wwpdf.pdf). To change this you have delete these keys and then reboot. These settings surpress all dialog boxes and always print to the file specified. Note that you can't change this on the fly - you have to reboot after you make a change here. Actually, it looks like you can change the values once the keys exist, but it's not very consistent. Note: The Acrobat driver can only print one report to the PDFWriter at a time on a given machine. The class provides a semaphor locking scheme that queues reports, but be aware that this can cause serious performance issues if you're printing lots of reports while running multiple Web Connection instances ************************************************************************ * wwPDF :: SetAcrobatIniFile ********************************* *** Function: Sets the path to the PDFWRiter configuration file. *** This method is also called from the Init of the class. *** *** Default Paths by Acrobat: *** Win95: WINDOWS\Win.ini *** WinNT: WINNT\SYSTEM\spool\DRIVERS\W32X86\2\__pdf.ini *** *** Assume: THIS IS THE MOST IMPORTANT SETTING! MAKE SURE YOU MATCH *** THIS TO YOUR INI FILE. START WITH THE DEFAULT SETTINGS *** BY PLATFORM AND IF THAT FAILS TRY THE FULL INI FILE PATH. *** NOTE: This setting will permanently change your Acrobat *** configuration. *** *** Pass: lcAcrobatIniFile "WINNT","WIN95" or *** full path to Acrobat __PDF.INI (NT) *** or Win.ini (Win95) *** llForceInteractive to bring up dialogs *** Return: .T. or .F. - Page 127 - Class wwPDF – Adobe Acrobat File Creation West Wind Web Connection ************************************************************************ ************************************************************************ * wwPDF :: PrintReport ********************************* *** Function: The worker function. This method actually goes out *** sets the printer and prints the report. Use this *** instead of a REPORT form command. *** Assume: *** Pass: lcReport Name of the FRX Report to run *** lcOutputFile Filename to print the PDF output to *** lcExtraReportClauses - Any extra tags like FOR, WHEN etc. *** Return: .T. or .F. ************************************************************************ ************************************************************************ * wwPDF :: SetLandscapeMode ********************************* *** Function: Sets or unsets landscape mode *** Pass: llPortrait - Optional Pass .F. only if you want to go *** back to portrait *** Return: nothing ************************************************************************ ************************************************************************ * wwPDF :: PrintReportToString ********************************* *** Function: Prints a report to string *** Pass: lcReport Name of the FRX Report to run *** lcOutputFile Filename to print the PDF output to *** lcExtraReportClauses - Any extra tags like FOR, WHEN etc. *** Return: PDF file as a string or "" on failure ************************************************************************ ************************************************************************ * wwPDF :: QuickReport ********************************* *** Function: Prints a report from a cursor without an FRX *** courtesy of Randy Pearson, Cycla Corp *** Pass: lcOutputFile Filename to print the PDF output to *** lcExtraReportClauses - Any extra tags like FOR, WHEN etc. *** Return: .T. or .F. ************************************************************************ ************************************************************************ * wwPDF :: QuickReportToString ********************************* *** Function: Prints a PDF report to string without an FRX *** courtesy of Randy Pearson, Cycla Corp *** Pass: lcExtraReportClauses - Any extra tags like FOR, WHEN etc. *** Return: PDF file as a string or '' on failure ************************************************************************ - Page 128 - West Wind Web Connection Support Classes Support Classes In addition to the main Web related classes described above Web Connection also includes a set of support classes and functions in WWUTILS.PRG. Class wwAPI Contained in: wwapi.prg The API Class provides various Windows API based interfaces used in Web Connection for accessing the registry, INI files, getting system paths, setting thread priority, retrieving error messages and a few other functions. ************************************************************************ * wwAPI :: GetSystemErrorMsg ********************************* *** Function: Returns the Message text for a Win32API error code. *** Pass: lnErrorNo - WIN32 Error Code *** Return: Error Message or "" if not found ************************************************************************ ************************************************************************ * wwAPI :: MessageBeep ********************** *** Function: MessageBeep API call runs system sounds *** Pass: lnSound Uses FoxPro.h MB_ICONxxxxx values *** Return: nothing ************************************************************************ ************************************************************************ * wwAPI :: ReadRegistryString ********************************* *** Function: Reads a string value from the registry. *** Pass: tnHKEY - HKEY value (in CGIServ.h) *** tcSubkey - The Registry subkey value *** tcEntry - The actual Key to retrieve *** Return: Registry String or .NULL. on not found ************************************************************************ ************************************************************************ * wwAPI :: EnumRegistryKey ************************** *** Function: Returns a registry key name based on an index *** Allows enumeration of keys in a FOR loop. If key *** is empty end of list is reached. *** Pass: tnHKey HKEY_ root key *** tcSubkey Subkey string *** tnIndex Index of key name to get (0 based) *** Return: "" on error - Key name otherwise ************************************************************************ ************************************************************************ * Registry :: WriteRegistryString ********************************* *** Function: Writes a string value to the registry. *** If the value doesn't exist it's created. If the key *** doesn't exist it is also created, but this will only *** succeed if it's the last key on the hive. *** Pass: tnHKEY - HKEY value (in WCONNECT.h) - Page 129 - West Wind Web Connection Support Classes *** tcSubkey - The Registry subkey value *** tcEntry - The actual Key to write to *** tcValue - Value to write or .NULL. to delete key *** tlCreate - Create if it doesn't exist *** Assume: Use with extreme caution!!! Blowing your registry can *** hose your system! *** Return: .T. or .NULL. on error ************************************************************************ ************************************************************************ FUNCTION GetProfileString ************************* *** Function: Read Profile String information from a given *** text file using Windows INI formatting conventions *** Pass: pcFileName Name of INI file *** pcSection [Section] in the INI file ("Drivers") *** pcEntry Entry to retrieve ("Wave") *** If this value is a null string *** all values for the section are *** retrieved seperated by CHR(13)s *** Return: Value(s) or .NULL. if not found ************************************************************************ ************************************************************************ * wwAPI :: WriteProfileString ********************************* *** Function: Writes a value back to an INI file *** Pass: pcFileName Name of the file to write to *** pcSection Profile Section *** pcKey The key to write to *** pcValue The value to write *** Return: .T. or .F. ************************************************************************ ************************************************************************ * wwAPI :: GetProfileSections ********************************* *** Function: Retrieves all sections of an INI File *** Pass: @laSections Empty array to receive sections *** lcIniFile Name of the INI file *** lnBufSize Size of result buffer (optional) *** Return: Count of Sections ************************************************************************ ************************************************************************ * wwAPI :: GetTempPath *********************** *** Function: Returns the OS temporary files path *** Return: Temp file path with trailing "\" ************************************************************************ ************************************************************************ * wwAPI :: GetEXEFileName ********************************* *** Function: Returns the Module name of the EXE file that started *** the current application. Unlike Application.Filename *** this function correctly returns the name of the EXE file *** for Automation servers too! *** Return: Filename or "" (VFP.EXE is returned in Dev Version) ************************************************************************ ************************************************************************ * wwAPI :: GetComputerName ********************************* *** Function: Returns the name of the current machine *** Return: Name of the computer - Page 130 - West Wind Web Connection Support Classes ************************************************************************ ************************************************************************ * wwAPI :: GetSystemDir ********************************* *** Function: Returns the Windows System directory path *** Return: Windows System directory or "" if failed ************************************************************************ ************************************************************************ * WinApi :: ShellExecute ********************************* *** Function: Opens a file in the application that it's *** associated with. *** Pass: lcFileName - Name of the file to open *** lcWorkDir - Working directory *** lcOperation *** Return: 2 - Bad Association (invalid URL) *** 31 - No application association *** 29 - Failure to load application *** 30 - Application is busy *** *** Values over 32 indicate success *** and return an instance handle for *** the application started (the browser) ************************************************************************ ************************************************************************ * wwAPI :: GetCurrentThread ********************************* *** Function: Returns handle to the current Process/Thread *** Return: Process Handle or 0 ************************************************************************ ************************************************************************ * wwAPI :: GetThreadPriority ********************************* *** Function: Gets the current Priority setting of the thread. *** Use to save and reset priority when bumping it up. *** Pass: tnThreadHandle ************************************************************************ ************************************************************************ * wwAPI :: SetThreadPriority ********************************* *** Function: Sets a thread process priority. Can dramatically *** increase performance of a task. *** Pass: tnThreadHandle *** tnPriority 0 - Normal *** 2 - Highest Priority *** 15 - Time Critical *** 31 - Real Time (doesn't work Win95) ************************************************************************ ************************************************************************ * wwAPI :: Sleep ********************************* *** Function: Puts session into idle state *** Pass: tnMilliseconds *** Return: nothing ************************************************************************ Class wwEval Program File: wwEval.prg - Page 131 - West Wind Web Connection Support Classes The wwEval class provides a safe interface for evaluating expressions and running entire code blocks inside of running programs. Expressions are evaluated and checked for errors that occur. This class is used exclusively for executing all HTML embedded FoxPro expressions. The Execute method wraps Rand Pearson's CodeBlck class (also included in the wwEval.prg file). ************************************************************************ DEFINE CLASS wwEval as Custom ***************************** *** Custom Properties lError=.F. nError=0 cResultType="C" vErrorResult="Error" Result="" ************************************************************************ * wwEval :: Evaluate ********************************* *** Function: Actually evaluates expression. *** Pass: lcExpression - Expression to evaluate *** Return: Result ************************************************************************ ************************************************************************ * wwEval :: ExecuteCommand ********************************* *** Function: Macro Expands a single command. More efficient than *** than Execute which uses CodeBlock. *** Pass: lcCommand - Command to run *** Return: nothing ************************************************************************ ************************************************************************ * wwEval :: Execute ********************************* *** Function: Executes a block of code using Randy Pearson's CodeBlock *** class. *** Pass: lcCode Any block of Visual FoxPro code. *** Return: Result of the code ************************************************************************ ************************************************************************ * wwEval :: MergeText ********************* *** Function: This function provides an evaluation engine for FoxPro *** expressions and Codeblocks that is tuned for Active *** Server syntax. It works with any delimiters however. This *** parsing engine is faster than TEXTMERGE and provides *** extensive error checking and the ability to run *** dynamically in the VFP runtime (ie uncompiled). Embed any *** valid FoxPro expressions using *** *** <%= Expression%> *** *** and any FoxPro code with *** *** <% CodeBlock %> *** *** Expressions ideally should be character for optimal *** speed, but other values are converted to string *** automatically. Although optimized for the delimiters *** above you may specify your own. Make sure to set the *** llNoAspSyntax parameter to .t. to disallow the = check - Page 132 - West Wind Web Connection Support Classes *** for expressions vs code. If you use your own parameters *** you can only evaluate expressions OR you must use ASP *** syntax and follow your deleimiters with an = for *** expressions. *** Assume: Delimiter is not used in regular text of the text. *** Uses: wwEval class (wwEval.prg) *** Codeblock Class (wwEval.prg) *** Pass: tcString String to Merge *** tcDelimeter Delimiter used to embed expressions *** Default is "<%" *** tcDelimeter2Delimiter used to embed expressions *** Default is "%>" *** llNoAspSytnax Don't interpret = following first *** parm as expression. Everything is *** evaluated as expressions. *** *** Example: lcResult = loEval.MergeText(HTMLDocs.MemField) ************************************************************************* ************************************************************************ * wwEval :: SetResultType ********************************* *** Function: Set the Result Type for the Evaluated expression. *** Pass: lcType Valid FoxPro Type *** Return: nothing ************************************************************************ ************************************************************************ * wwEval :: SetErrorResult ********************************* *** Function: Set the Default value that is returned if the Eval *** fails. *** Pass: lvErrorResult Result value to assign *** Return: nothing ************************************************************************ ************************************************************************ * wwEval :: IsError ********************************* *** Function: Returns error status of previous eval operation *** Return: .T. or .F. ************************************************************************ ************************************************************************ * wwEval :: GetErrorNumber ********************************* *** Function: Returns the error number of the previous eval operation *** if an error occurred. *** Return: Error number or 0 ************************************************************************ Example: -------loEval=CREATE("wwEval") loEval.cResultType="C" loEval.vErrorResult="Error" *** Generates an error loEval.Evaluate("SYSx(0)") IF !loEval.lError wait window loEval.Result ELSE *** Handle the error here wait window loEval.vErrorResult + STR(loEval.nError) - Page 133 - West Wind Web Connection Support Classes ENDIF RETURN - Page 134 - West Wind Web Connection Procedure Library wwUtils Procedure Library wwUtils Function File2Var This handy function converts files to memory variables and back. Files can be read into memory for easy string manipulation and easily be written back out using this function. Note: This function is safe for multi-user access of files – VFP 6.0's STRTOFILE and FILETOSTR are not! ************************************************************************ FUNCTION File2Var ****************** *** Function: Takes a file and returns the contents as a string or *** Takes a string and stores it in a file if a second *** string parameter is specified. *** Pass: tcFilename - Name of the file *** tcString - If specified the string is stored *** in the file specified in tcFileName *** Return: file contents as a string or nothing if storing to file ************************************************************************ Function Extract This function extracts a text string from between a pair of delimiters or the end of a string. ************************************************************************ FUNCTION Extract ****************** *** Function: Extracts a text value between two delimiters *** Pass: lcString - Entire string *** lcDelim1 - The starting delimiter *** lcDelim2 - Ending delimiter *** lcDelim3 - Alternate ending delimiter *** llEndOk - End of line is OK *** Return: Text between delimiters or "" ******************************************************************************************** Function MergeText This function parses Templates using Active Server type scripting expressions. Also see: wwEval::MergeText, which is faster as it doesn't make external object calls. ************************************************************************ FUNCTION MergeText ****************** *** Function: This function provides an evaluation engine for FoxPro *** expressions and Codeblocks that is tuned for Active *** Server syntax. It works with any delimiters however. This *** parsing engine is faster than TEXTMERGE and provides *** extensive error checking and the ability to run *** dynamically in the VFP runtime (ie uncompiled). Embed any *** valid FoxPro expressions using *** *** <%= Expression%> *** *** and any FoxPro code with *** *** <% CodeBlock %> *** *** Expressions ideally should be character for optimal - Page 135 - West Wind Web Connection Procedure Library wwUtils *** speed, but other values are converted to string *** automatically. Although optimized for the delimiters *** above you may specify your own. Make sure to set the *** llNoAspSyntax parameter to .t. to disallow the = check *** for expressions vs code. If you use your own parameters *** you can only evaluate expressions OR you must use ASP *** syntax and follow your deleimiters with an = for *** expressions. *** Assume: Delimiter is not used in regular text of the text. *** Uses: wwEval class (wwEval.prg) *** Codeblock Class (wwEval.prg) *** Pass: tcString String to Merge *** tcDelimeter Delimiter used to embed expressions *** Default is "<%" *** tcDelimeter2Delimiter used to embed expressions *** Default is "%>" *** llNoAspSytnax Don't interpret = following first *** parm as expression. Everything is *** evaluated as expressions. *** *** Example: lcresult MergeText(lcTemplateHTML) ************************************************************************* Function AparseString This function parses a delimited string into an array. The array must be passed by referenence and cannot be a VFP object property. ************************************************************************ PROCEDURE AParseString ********************** *** Function: Parses a delimited string into an array *** Pass: laResult Array containing the result strings (@) *** lcString The full string to parse *** lcDelimiter The delimiter string or character *** Return: Count of strings or 0 if null string is passed ************************************************************************* Function Path Adds or deletes a path from FoxPro's SET PATH. ************************************************************************ PROCEDURE PATH *************** *** Function: Adds or deletes items from the path string *** Pass: pcPathName Path name to add or delete *** pcMethod *"ADD","DELETE" *** Example: DO PATH WITH ".\Classes" *** Return: New Path or "" ************************************************************************ Function OpenExclusive Attempts to open a table for exclusive use. If successful returns .T. else returns .F. Uses wwEval class safely execute the file open operation. ************************************************************************ FUNCTION OpenExclusive ********************** *** Function: Tries to open a table exclusively. Selects the ALIAS *** if successful. - Page 136 - West Wind Web Connection Procedure Library wwUtils *** Assume: No extension may be specified *** Returns .F. for other reasons like file !found etc. *** Pass: lcTable - Name of table to open exclusively *** Return: .T. or .F. ************************************************************************ Functions URLEncode and URLDecode These function encode and decode text based on MIME encoding used by CGI/ISAPI request buffers. ************************************************************************ FUNCTION URLDecode ****************** *** Function: URLDecodes a text string to normal text. *** Assume: Uses wwIPStuff.dll if the string is larger than 1024 *** Pass: lcText Text string to decode *** Return: Decoded string or "" ************************************************************************ ******************************************************** PROCEDURE URLEncode ******************* *** Function: Encodes a string in URL encoded format *** for use on URL strings or when passing a *** POST buffer to wwIPStuff::HTTPGetEx *** Assume: Uses wwIPStuff.dll to encode *** Pass: tcValue String to encode *** Return: URLEncoded string or "" ******************************************************** IsComObject Checks the registry to see if a COM object or ActiveX control is installed. ******************************************************** PROCEDURE IsCOMObject ********************* *** Function: Checks to see if a COM object *** or ActiveX control exists *** Assume: Uses wwAPI *** Pass: lcProgId - Prog Id of the Class *** lcClassId - (Optional) If passed in *** by reference gets ClassId *** lcClassDescript - (Optional) *** Return: .T. or .F. ******************************************************** RegisterOleServer This method allows you to register any DLL/OCX based com object that you would normally have to run RegSvr32 against through code. ************************************************************************ FUNCTION RegisterOleServer ************************** *** Function: Registers an OLE server or OCX control *** Pass: lcServerPath - Full path and filename of OCX/OLE Server *** llUnregister - .T. to unregister *** lcClassId - (optional) check for class Id - if *** exist don't reregister *** Return: .T. or .F. - Page 137 - West Wind Web Connection Procedure Library wwUtils ************************************************************************* DCOMCnfgServer This function allows you to configure Automation Server access rights under Windows NT 4.0 without having to run the DCOMCnfg.exe utility. This function registers an existing server and creates the security context under which the server runs. NOTE: It's still necessary to configure DCOMCnfg at least once to give the server Launch and Access permissions either individually or through the Default Security settings. ************************************************************************ PROCEDURE DCOMCnfgServer *********************** *** Function: Sets the security attributes of an Automation server *** to Interactive User *** Assume: Only works for Interactive user for now *** uses wwAPI *** Pass: lcProgId - Program ID for the server (wcdemo.wcdemoserver) *** lcRunAs - User Account (Default: Interactive User) *** Return: nothing ************************************************************************* Function GetAppStartPath Returns an applications startpath based on the EXE file that launched it. Works in all circumstances including Automation servers compiled as EXE or DLL servers ************************************************************************ FUNCTION GetAppStartPath ********************************* *** Function: Returns the FoxPro start path *** of the *APPLICATION* *** under all startmodes supported by VFP. *** Returns the path of the starting EXE, *** DLL, APP, PRG/FXP *** Return: Path as a string with trailing "\" ************************************************************************ Function DomainName Extracts a domain name from an URL. ************************************************************************ FUNCTION DomainName ******************* *** Function: Retrieves a Domain name from an URL *** Assume: URL contains // (as in http://west-wind.com/Test.htm) *** Pass: lcUrl - URL to retrieve name from *** llNoStripWWW - Don't strip www. *** Return: Domain Name or "" ************************************************************************* Function GoURL Goes to the specified URL by firing up the default browser and loading the specified location. **************************************************** FUNCTION GoUrl ****************** *** Function: Starts associated Web Browser *** and goes to the specified URL. *** If Browser is already open it *** reloads the page. - Page 138 - West Wind Web Connection Procedure Library wwUtils *** Assume: Works only on Win95 and NT 4.0 *** Pass: tcUrl - The URL of the site or *** HTML page to bring up *** in the Browser *** Return: 2 - Bad Association (invalid URL) **************************************************** Function ShowHTML Takes text input and displays the HTML text in the default browser. Also works with _ScreenX if available or any other IE 4 WebBrowser control which you can pass as an object reference in the third parameter. Order is: Object reference passed, _ScreenX if available or to the default browser. ************************************************************************ FUNCTION ShowHTML ***************** *** Function: Takes an HTML string and displays it in the default *** browser. *** Assume: Uses a file to store HTML temporarily. *** For this reason there may be concurrency issues *** unless you change the file for each use *** Pass: lcHTML HTML to display *** lcFile Temporary File to use (Optional) *** loWebBrowser Web Browser control ref (Optional) ************************************************************************ Function StripHTML Removes HTML formatting from an HTML document. ************************************************************************ PROCEDURE StripHTML ******************* *** Function: Removes HTML tags from the passed text and converts *** it to plain text. Note formatting is totally removed! *** Assume: only <br> and <p> are translated *** any < or > in the HTML besides tags will break this *** function. *** Pass: lcText HTML Text to strip *** Return: Stripped HTML text ************************************************************************* Function HTMLColor This function returns an HTML Color string from a Visual FoxPro RGB color value. ************************************************************************ FUNCTION HTMLColor ********************************* *** Function: Converts a FoxPro Color to an HTML Hex color value *** Pass: lnRGBColor - FoxPro RGB color number - RGB(255,255,255) *** llNoOutput *** Return: Hex HTML Color String "#FFFFFF" ************************************************************************ Function DateToC Like VFP's DOTC except blank dates are returned as blank strings rather than " / / ". ************************************************************************ PROCEDURE DateToC ****************** *** Function: Converts a date to string displaying empty dates as blanks - Page 139 - West Wind Web Connection Procedure Library wwUtils *** rather than displaying the empty date format *** Pass: ldDate - Date to display *** Return: Date String or "" if invalid date ************************************************************************* Functions JustFname, JustStem, JustExt, JustPath, ForcePath and AddBs Fox implementations of the FOXTOOLS functions so that Foxtools does not have to be loaded. ************************************************************************ FUNCTION JustFname ****************** *** Function: Returns just the filename portion of a path spec *** Pass: lcFullPath *** Return: Filename ************************************************************************* ************************************************************************ FUNCTION JustStem ***************** *** Function: Returns just the Filename without extension. *** Pass: lcFile - File name or filename and path *** Return: file stem ************************************************************************* ************************************************************************ FUNCTION JustExt ****************** *** Function: Returns just a file extension *** Pass: lcFile - Name of the file or full path + file *** Return: Extension or "" ************************************************************************* ************************************************************************ FUNCTION JustPath ****************** *** Function: Returns just the path portion of a path spec *** Assume: Path is returned with a trailing slash *** Pass: lcFullPath *** Return: Filename ************************************************************************* ************************************************************************ FUNCTION AddBS ****************** *** Modified: 07/21/96 *** Function: Add BackSlash to path. *** Pass: lcPath - Path to append Backslash to *** Return: ************************************************************************* ************************************************************************ FUNCTION ForcePath ********************************* *** Function: Forces a path expression to the path specified by *** to allow mapping for network drives *** to the INI and output files. *** Pass: lcPath - Path to work with *** lcNewPath - Path to override with *** Notes: Does not guarantee valid path name!!! *** Return: changed path or same path if no drive was specified *** in the path string. ************************************************************************ - Page 140 - West Wind Web Connection Procedure Library wwUtils Function IsDir This function returns .T. if a specified path exists. ************************************************************************ FUNCTION IsDir ****************** *** Modified: 10/09/97 *** Function: Checks to see whether a directory exists *** Pass: lcPath - Path to check *** Return: .T. or .F. ************************************************************************* Function FileSize ************************************************************************ FUNCTION FileSize ****************** *** Function: Returns the size of a file *** Pass: lcFileName *** Return: the size of the file or -1 on error ************************************************************************ Function ProgLevel Return the current Visual FoxPro Call Stack level. This is a useful function to check on Automation Servers where call stack corruption can occur when an Automation server crashes but doesn't unload. Also allows checking for recursive functions that can blow the 128 call stack limit of VFP. ************************************************************************ PROCEDURE ProgLevel ****************** *** Function: Returns the current Calling Stack level. Used to check *** recursive Error calls in Error methods. ************************************************************************* Function PropertyDump This method allows a quick view of an object's properties and values as a text string. I use this frequently to see object state from a running program without having to fire up the debugger and dig through the objects. ************************************************************************ PROCEDURE PropertyDump ********************** *** Function: Dumps all of an objects properties to a string separated *** by Carriage Returns *** Pass: loObject *** Return: string of all property name and values ************************************************************************* Function InputForm Creates a simple input form dialog that can be used to enter single line values of any type. Used in the Setup program and in various support utilities. ************************************************************************ FUNCTION InputForm ****************** *** Function: Creates a simple Input form that returns a value *** Assume: Consists of this function and Form Class *** Pass: lcValue Initial value to retrieve *** lcMessage The request message *** lcCaption Form Caption (_Screen.Caption) *** lnFormWidth Width of the form - Page 141 - West Wind Web Connection Procedure Library wwUtils *** lnFieldWidth Widht of the input field *** lcFormat Format string for the input field *** Return: Value or ("" or -1) ************************************************************************ Function PEMStatus Provides PEMSTATUS() compatibility for version 3.0 of Visual FoxPro. Note only parameter 5 is implemented to return .t. or .f. if a method/property exists. ************************************************************************ PROCEDURE PEMSTATUS ******************* *** Modified: 06/11/96 *** Function: Simulates PEMSTATUS for VFP 3.0 * *** Native PEMSTATUS() overrides in 3.0b and later *** Note: Only PEMSTATUS(object, method, 5) is implemented *** Pass: loObject - Object parameter to check PEMs for *** lcMethod - Method or Property to check for *** lnValue - Not used - like PEMSTATUS(o,m,5) *** Return: .T. or .F. if object exists ************************************************************************ - Page 142 - West Wind Web Connection Other Tools Other Tools A set of tools is provided in the Tools directory. These tools are in rough form. I've been using these for a variety of applications and have included them here only because they can save a lot of time for some purposes. Just be aware that they are not polished nor documented very well. Some assembly may be required <g>... West Wind Web Monitor This utiltity is a separate standalone application that can be downloaded from the registered download directory or is available as shareware for non-registered users at http://www.west-wind.com/webtools.htm. It provides the ability to monitor a Web site by accessing a Web link and checking the resulting string for a match. If a match is not found the program will use a list of email addresses to email you or your pager (if it has email paging capabilities). Web Server Configuration Component Enterprise Edition only The Enterprise edition includes a tool to configure various Web servers programmatically from your VFP code. The utility provides the ability to create Virtual Directories and scriptmaps by calling simple class methods. The wwWebServer class can be found in \tools\Webserver.vcx. The class also contains a specific for IIS 4 configuration to access the IIS Admin objects and Active Directory for configuring all aspects of IIS. The IISAdmin class provides access to all properties of IIS 4 while the wwActiveDirectory base class allows lower level access to Active Directory properties in general. Here's how it works: oWS = CREATEOBJECT("wwWebServer","IIS4") oWS.CreateVirtual("wconnect","c:\westwind\wconnect\") oWS.CreateScriptMap(".wc","c:\westwind\wconnect\wc.dll") Dependicies: wconnect.h wwAPI.prg Methods SetServerType Function This method should be called to determine which Web Server to configure for. Valid values are: IIS4, IIS3, PWS3, PWS4, WEBSITE, WSISAPI, COMMERCE, CB WebSite and WSISAPI, COMMERCE and CB are each identical. PWS NT Workstation should use the IIS values – the PWS keys only apply to the Win95 versions. This property is also set by the Init if a parameter is passed: oWS = CREATEOBJECT("wwWebServer","IIS4") GetWebRootPath GetTempPath CreateVirtual Returns the directory of the Root Web. This can be used to prompt users for new virtual directories that should be created off the Web Root by default. Retrieves the temporary directory for the user's machine. Since Web Connection uses temp files for file based messaging this setting is important and must be set in the wc.ini file and the application's startup Ini file. Creates a Virtual Directory by passing the name of the virtual and a path to create it on. The directory is created with Execute rights set. Note that this method always creates the virtual on the default Web server if multiple servers exist. Parameters: - Page 143 - West Wind Web Connection Other Tools lcVirtual The name of the virtual directory to create. lcPath The path to make a virtual lcIIS4Path If you're using IIS4 you can specify an ADS path that specifies a non-default Web server. For example: LOCALHOST/W3SVC/2/ROOT CreateScriptMap Returns: .T. or .F. Allows creation of a script map that links a file extension to a specific ISAPI extension. Parameters: lcScriptMap The extension to use as a scriptmap. Example: .WC lcDLLPath The full system path of the DLL to map. lcIIS4Path If you're using IIS4 you can specify an ADS path that specifies a non-default Web server. For example: LOCALHOST/W3SVC/2/ROOT Returns: .T. or .F. Text Wrapper To make it easier to create HTML code from existing pages Web Connection provides a tool called Text Wrapper. This little utility is contained in WRAPPER.SCX in the TOOLS directory and allows you to capture text stored on the clipboard and wrap the text with a set of strings before and after the string. It’s very handy for quickly creating loHTML.SendLn( [ text line1 ] ) for an entire page of HTML text. This utility makes it easy to go from HTML page to code, allowing you to easily add fields and calculations to the generated code. Using Send/SendLn is the fastest output method available. A great way to produce the fastest possible HTML output is to use highlevel methods like wwHTML::ShowCursor to quickly generate HTML output from a cursor or table then use the WRAPPER form to capture the generated HTML code and build more optimized, hand code from it. ShowCursor is great for quickly generating output, but unfortunately it's more than 2 times slower than the equivalent hand coded wwHTML.SendLn statement code. For more detailed information see WRAPPER.TXT in the TOOLS directory. ScriptMap The ScriptMap program file allows you to quickly create new script maps for IIS. You pass the full path of the DLL and the name of the extension you want to be script mapped (.WC for example). When you run the Web Connection install a .wc script map is automatically created for the wc.dll. Script maps allow you to hide the .DLL extension from your site as well as providing a nice way to use a DLL in one directory throughout your site without having to deal with the path issues involved with the plain DLL interface. Script mapped links act as if the file DLL actually lived in the current directory so no path changes take place. LogCount The CGILog program summarizes hit counts on the CGILog file by query string 'parameter'. This function is extremely useful for figuring out what operations happen most frequently on a server. ************************************************************************ PROCEDURE CGICount - Page 144 - West Wind Web Connection Other Tools ****************** *** Function: Summarizes CGI hits on a site based on the first *** parameter. *** Assume: First Parameter is the Application name *** Parameters are separated by ~ chars *** Sample: wwcgi.dll?wwdemo~Test_Page *** Pass: lcFile Logfile created by Web Connection *** lcParmChar Parameter separator ("~") *** lnGroupParm Which parameter to group on (1) *** Return: Cursor TCGISummary filled with summary ************************************************************************* To use: DO LogCount WITH "CGILOG" - Page 145 -