Copyright: Copyright (C) <your-name> 1998. All rights reserved.
Citation: Copyright (C) <your-name> 1998. All rights reserved.


About MidWare

Author:

François PIETTE

Rue de Grady 24

4053 Embourg

Belgium

Fax: +32-4-365.74.56

Home page:

http://www.rtfm.be/fpiette/midwareuk.htm

Latest release can always be downloaded.

EMail:

francois.piette@pophost.eunet.be

francois.piette@rtfm.be

Support:

Support is done using MidWare support mailing list.

See http://www.rtfm.be/fpiette/supportuk.htm for details.

Please avoid private EMail !

Registration

If you use MidWare, you must mail me a picture postcard showing the area you lives in and some beautiful stamps for my kids who are stamp collectors. Do not use an envelop, I collect USED postcards sent to me. My mail address is: Rue de Grady 24, 4053 Embourg, Belgium.

Copyright:

MidWare is copyrighted by François Piette. You may use it freely for personal use and non commercial applications. If you wants to use it for commercial application, you must obtain author's permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY FRANCOIS PIETTE "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


MidWare Disclaimer
THIS SOFTWARE IS PROVIDED BY FRANCOIS PIETTE "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR

ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


MidWare last update
Last Update

This help file has been updated on june 13, 1999.

Latest MidWare release can be downloaded from:

     http://www.rtfm.be/fpiette/midwareuk.htm


MidWare Theory

Have you heard the term - MIDDLEWARE? It's the Application Layer you put in the "middle" of your multi-tiered architecture software, allowing the various layers or "Tiers" to talk to each other. Middleware is the "glue" used to build efficient and scalable N-Tier Client/Server programs.

I have developed a middleware framework called MidWare. It consists of a set of components and units which allow you to create an Application Server and related thin Client application, in just a few minutes. All without worrying about Client connections, data formatting and other details which make a multi-tiered Client/Server program so difficult to write. MidWare also include CGI, ISAPI and ASP modules for web applications.See MidWare Web Technology page.

How does it work ?

A MidWare Application Server is based on:

- A Server component

- An Object Request Broker (ORB)

- A set of Server objects you write

A MidWare Client Application is based on:

- One or more application Server Client objects

- One or more TMWBuffer object

- Zero or more TMWTable objects

Although there is not much documentation, you DO get full source code and some sample applications. Source code is heavily commented, so you should read the source carefully and try to understand how it works. If you have questions, there is a related mailing list available for support.

How to build an Application Server

How to build a Client

About Multi-tasking

About Global Data

Components

Applications

Server side demo Apps

There are two Server demo programs: SrvTst and SrvDemo. The first one uses a TServerObject object added to the the ORB at runtime, using AddServerObject.

The second is more visual: A TServerObject is dropped on the main Server form and linked with the object inspector to the ORB. (Using AddServerObject results in a bit smaller programs while dropping an object on a form is more RAD, but can be annoying for large projects where you have a lot of TServerObjects.)

Description for each TServerObject used by the sample Servers:

TServerObjectUPPER (SrvObj1)

simply converts data received to uppercase and sends it back to the Client

TServerObjectTHREAD (SrvObj2)

has a thread which does a lengthy request (just sleeps for 5 seconds)

TServerObjectGETClient (SrvObj3)

will access a TTable, fetch some data based on a key sent by the Client and return the fetched data to the Client. See TServerObjectSETClient for reverse operation: update data table.

TServerObjectGETClientLIKE (SrvObj4)

uses a TQuery and returns the entire result set to the Client.

TServerObjectGETFILE (SrvObj5)

will get a file and return a single blob field to the Client. See TSObjSENDFILE for reverse operation.

TSObjGETIMAGE (SrvObj6)

is much like TServerObjectGETClient and uses a TTable to fetch data from a table.

TSObjGETIMAGELIKE (SrvIbj7)

is much like TServerObjectGETClientLIKE and uses a TQuery to fetch data using a SQL statement.

TSObjSENDFILE (SrvObj8)

receives a file name and data from a Client and saves data into the specified filename at the Server side. The Filename is the first field from the Client and theData is the second field from the Client (a single field can hold MB of data !). See TServerObjectGETFILE for reverse operation.

TServerObjectSETClient (SrvObj9)

receives data from a Client and updates a TTable with that data. See TServerObjectGETClient for reverse operation: fetch data from table.

TServerObjectSQL (SObjSQL)

uses a TQuery to execute a SQL statement sent by the Client and returns the result set to the Client. It also demonstrates how to retrieve data set in the object inspector at design time (CopyFromReference).

* Remember that you dropped a single TServerObjectSQL on the form, but many Clients can be served and therefore many instances may be used, so data from the reference object dropped on the form has to be copied to instanciated objects. This object also demonstrates how to create properties visible in the object inspector at design time: (a DatabaseName property is created and used.) TServerObjects are not different from any other component.

TServerObjectSQLTHREAD (SObjThrd)

is much like TServerObjectSQL except that it uses a thread to execute the request in the background. Without the thread, the Server is blocked from servicing a Client while the query is executing. With a thread, the query is done in the background while other Clients are being serviced.

Note: Using threads with TServerObject is easy (see TServerObjectTHREAD for a trivial example), but using BDE within a thread is quite complex. Using the BDE, you need different TSession and TDatabase components for each thread, which in turn require unique identifications, a private directory for temporary files and a shared directory for Paradox lock files, etc.

Client side demo apps

The first demo Client ( CliTst ) is very simple: just a few edit boxes to let the user enter some data and a few button to act on that data.

The TblDemo Client uses a DBGrid to show data retrieved from the Server.

BufTst is a demo which shows how to use TMWBuffer alone.

The BioLife demo uses BioLife data from Delphi demo database. It shows how to retrieve data from a MidWare Server, including memo fields and images. BioLife uses SrvDemo as the application Server. You must copy biolife.db, biolife.mb, biolife.px from delphi\demos\data to the directory where the SrvDemo is run.

ChatSrv and ChatCli are the two parts of a multi-user Server based Chatting application. This demonstrates that MidWare can be used for any kind of application, including groupware applications.

How to build an Application Server

An Application Server is just a program like any other Delphi program. It contains a main form and code to handle the related processing.

In a MidWare Application Server, most of hard work is done by the MidWare components. The effective application work is done by specialized components derived from TServerObject. You may use the existing TServerObject or design new ones yourself. The MidWare request broker will instanciate your TServerObject as needed when requests are received from Clients.

To build an Application Server, you have to design TServerObject descendant which will receive the request sent by the Client, then do the processing, database access and whatever else is needed to built the reply. You make a TServerObject for each request. Each request has a name or function code which is used by the Client to identify which request they want to execute.

Once you made the TServerObject, you build a new form, then drop a TAppServer and a TRequestbroker object on it. At runtime, you link all you Server objects to the Request Broker (just a function call). And that's it! Your Server is ready!! (This is how the SrvDemo is made)

How to build a Client

To build a Client, open a new form, drop a TAppSrvClient, a TMWBuffer and other standard components to build a user interface. Then on some event like a button click, build a TAppSrvClient request (just a function code with parameters) and call the Send method to send it to the application Server. You'll get an event back when the result has arrived from the Server. Extract the data from the TMWBuffer and update your user interface. (This is how the CliTst demo application is made)

Alternatively, (if you want to use standard data aware components to build your user interface) you can link the TMWBuffer to a TMWTable, link the TMWBuffer to a TDataSource and the TDataSource to a TDBGrid and a TDBNavigator. (This is how the demoTblTst is made)

About multitasking

MidWare Server is based on an event driven architecture. Internally, it uses an asynchronous TWSocket component (See ICS package) to do all the communication related operations. MidWare communication operations never block the Server. They will take place in the background as long as windows message pump is operating correctly.

When a request is received, the MidWare request broker will locate a TServerObject class that has the responsibility of executing Client requests. It then will instanciate a new TServerObject and call its related Execute method. When the Execute method returns, the MidWare request broker will process the next request.

When the TServerObject Finish method is called, the MidWare request broker will pass the result set to the main Server for sending it to the Client. This will not block the Server, even if result set has several megabytes !

While a TServerObject is executing, nothing else can happen in the Server. A good TServerObject is written so that the Execute method, is as fast as possible. When processing takes a long time, it is not a good idea to do it in the Execute method. Rather, use a thread or an event driven component to execute it in the background. Start the thread or event driven component from the Execute method and call the Finish method from thread termination code or the component request done event.

You can find a good example in TServerObjectSQLTHREAD where a thread is launched to execute a lengthy SQl request. Moving the processing from the Execute method to a thread is not difficult at all, but depending on what processing is involved, it may require some additional work. For example, BDE is very easy to use in single threaded programs, but there is more work required to make it works in a multithreaded environment. This is a BDE issue, not a MidWare issue! The BDE requires a separate TSession and separate TDatabase component for each thread.


TAppServer
TAppServer Component

Properties  Events  Methods

Unit

ApServer

Description

TAppServer is the communication kernel for all MidWare application servers. This component handle all the communication work for the application server, keeping track of user connections and sessions. A complete application server is made of a TAppserver component, a TRequestBroker (Object Request Broker) component and a set of TServerObject descendent components.


TAppServer Properties

TAppServer  Events  Methods

Banner

ClientCount

ClientCountLabel

ClientTimeout

ClientWSocket

ConnectCount

DisplayMemo

Handle

Options

Port

RequestBroker

RequestCount

SrvWSocket

TimeoutInterval


TAppServer Events

TAppServer  Properties  Methods

OnAfterProcessRequest

OnAfterSendReply

OnBeforeProcessRequest

OnBeforeSendReply

OnClientConnected

OnClientClosed

OnClientCommand

OnClientTimeout

OnClientBgException

OnDisplay

OnServerBgException


TAppServer Methods

TAppServer  Properties  Events

DisconnectAll

Start

Stop


TAppServer Banner
TAppServer.Banner

property Banner : String;

Description

The banner property is the text that is sent to the client when the connection has been established. Default value is 'Welcome to MidWare server'.


TAppServer ClientCount
TAppServer.ClientCount

property ClientCount : Integer;

Description

ClientCount gives the actual number of connected clients.


TAppServer ClientCountLabel
TAppServer.ClientCountLabel

property ClientCountLabel : TLabel;

Description

If assigned, this property will be used by TAppServer component to display the number of client connected. This helps make an application server without writing any line of code.


TAppServer ClientTimeout
TAppServer.ClientTimeout

property ClientTimeout : LongInt;

Description

ClientTimeout gives the time in seconds before the server disconnect a client without activity. The default value is 300 seconds. See also TimeoutInterval.


TAppServer ClientWSocket
TAppServer.ClientWSocket

property ClientWSocket[nIndex : Integer] : TClientWSocket;

Description

ClientWSocket is a run-time read-only indexed property whose value is the reference to each connected client TClientWSocket component. This gives access to the socket handling client connection. Normaly not used at application level.


TAppServer ConnectCount
TAppServer.ConnectCount

property ConnectCount  : LongInt;

Description

ConnectCount gives the total number of connection received since server startup.


TAppServer DisconnectAll
TAppServer.DisconnectAll

public procedure DisconnectAll;

Description

DisconnectAll will disconnect every connected client. Do not confuse  with the Stop procedure.


TAppServer DisplayMemo
TAppServer.DisplayMemo

property DisplayMemo   : TCustomMemo;

Description

If assigned, this property will be used by TAppServer component to display messages during work. This helps make an application server without writing any line of code.


TAppServer Handle
TAppServer.Handle

property Handle : HWND;

Description

The Handle property is the windows handle for the hidden window the component uses for internal messages.


TAppServer OnAfterProcessRequest
TAppServer.OnAfterProcessRequest

Occurs when a request has been processed.

type

TProcessRequestEvent = procedure (Sender     : TObject;

                                  CliWSocket : TClientWSocket;

                                  var CmdBuf : PChar;

                                  var CmdLen : integer) of object;

property OnAfterProcessRequest  : TProcessRequestEvent;

Description

The OnAfterProcessRequest is called when a request has been processed by a TServerObject. It main purpose is to cleanup resources allocated in the OnBeforeProcessRequest event.


TAppServer OnAfterSendReply
TAppServer.OnAfterSendReply

Occurs just after a reply has been sent.

type

TClientEvent = procedure (Sender       : TObject;

                          CliWSocket   : TClientWSocket) of object;

property OnAfterSendReply  : TClientEvent;

Description

The OnAfterSendReply event is called once the reply header and body has ben written to the internal buffer for sending in the background. It's the right place to deallocate any resource allocated in the OnBeforeSendReply.


TAppServer OnBeforeProcessRequest
TAppServer.OnBeforeProcessRequest

Occurs before a client request is processed, just after it has been received.

type

TProcessRequestEvent = procedure (Sender     : TObject;

                                  CliWSocket : TClientWSocket;

                                  var CmdBuf : PChar;

                                  var CmdLen : integer) of object;

property OnBeforeProcessRequest : TProcessRequestEvent;

Description

The OnBeforeProcessRequest event is triggered just before anything is done with a request received from the client. This is the right place to add code for decryption/decompression. If needed, the event handler can allocate memory or resources and change the values on the arguments (passed by var) to fit the requirement. Allocated resources must be freed from the OnAfterProcessCommand.


TAppServer OnBeforeSendReply
TAppServer.OnBeforeSendReply

Occurs just before a reply is sent to the client.

type

TClientEvent = procedure (Sender       : TObject;

                          CliWSocket   : TClientWSocket) of object;

property OnBeforeSendReply : TClientEvent;

Description

The OnBeforeSendReply event is called when a reply is ready to be transmitted to the client. A reply is made of a header and a body which are accessible thru the ClientWSocket property. The event has the possibility to process the header and body to encrypt or compress them. It can even allocate some memory for holding the processed header and body. Use the OnAfterSendReply to free any allocated memory. The processed data must *not* contains CR/LF pair as it is used by the client to delimit the reply. If processed data has CR/LF, then it must be escaped in some way.


TAppServer OnClientConnected
TAppServer.OnClientConnected

Occurs when a client connect to the server.

type

TClientEvent = procedure (Sender     : TObject;

                          CliWSocket : TClientWSocket) of object;

property OnClientConnected : TClientEvent;

Description

This event is triggered when a client connect to the server. It could be used to disconnect unwanted client or any other processing that must be done when a new client connect, such as updating the server user interface to show how many clients are connected.


TAppServer OnClientClosed
TAppServer.OnClientClosed

Occurs when a client disconnect from the server.

type

TClientEvent = procedure (Sender     : TObject;

                          CliWSocket : TClientWSocket) of object;

property OnClientClosed : TClientEvent;

Description

Occurs when a client disconnect from the server. The event handler could be used to update the server's user interface or to do any other post-processing or cleaning task.


TAppServer OnClientCommand
TAppServer.OnClientCommand

Occurs when a client's request is received, and before it is processed.

type

TClientCommandEvent = procedure (Sender     : TObject;

                                 CliWSocket : TClientWSocket;

                                 CmdBuf     : PChar;

                                 CmdLen     : LongInt) of object;

property OnClientCommand : TClientCommandEvent;

Description

Clients connects to the server to send commands (also called requests) and wait for server responses. The OnClientCommand is triggered when such a command arrives, before it gets executed. The event handler can use the command for any purpose, it can even change it.


TAppServer OnClientTimeout
TAppServer.OnClientTimeout

Occurs when a client is disconnected because of lack of activity.

type

TClientTimeoutEvent = procedure (Sender       : TObject;

                                 CliWSocket   : TClientWSocket;

                                 var CanClose : Boolean) of object;

property OnClientTimeout : TClientTimeoutEvent;

Description

When a client had no more activity during some time specified by the ClientTimeout property, it is automatically disconnected. If this occurs, the OnClientTimeout event is triggred.

The argument CanClose passed by var if initialized to TRUE. The event handler may reset it to FALSE so that the client is not disconnected.


TAppServer OnClientBgException
TAppServer.OnClientBgException

Occurs when an exception is triggered in the background by client socket.

type

TClientBgException = procedure (Sender     : TObject;

                                CliWSocket : TClientWSocket;

                                E          : Exception) of object;

property OnClientBgException : TClientBgException;

Description

Client communication is handled by a TWSocket descendent component which works in the background. Sometimes, an exception is triggered in the middle of nowhere. Really means the exception is triggered at the lowest message pump level. It is interesting to handle this exception, at least to record it to some log file. It may happend that some exception affect winsock in such a way that no client is able to connect again. You can Stop and Start the server to solve that problem.


TAppServer OnDisplay
TAppServer.OnDisplay

Occurs when server need to display a message.

type

TDisplayEvent = procedure (Sender : TObject; Msg : String) of object;

property OnDisplay : TDisplayEvent;

Description

Sometimes, the server can display some infos about his internal working. Each time the server wants to display that info, it triggers the OnDisplay event. There is no need to have an event handler connected to this event. If you add an event handler, it is probably to display the messages on the server's user interface, or just to log it into a file. Messages to be displayed can be generate by the TAppServer component or any TServerObject used in the server.


TAppServer OnServerBgException
TAppServer.OnServerBgException

Occurs  when an exception in server socket occurs in the background.

type

TAppServerBgExceptionEvent = procedure (Sender : TObject;

                                        E : Exception) of object;

property OnServerBgException : TAppServerBgExceptionEvent;

Description

The OnBgException event is triggered when an exception occurs in the background (occuring in an event handler called from the message pump). If not handled, those exceptions are simply ignored.  It is interesting to handle this exception, at least to record it to some log file. It may happend that some exception affect winsock in such a way that no client is able to connect again. You can Stop and Start the server to solve that problem.


TAppServer Options
TAppServer.Options

type

    TAppServerOption  = (asoAutoStart,

                         asoDisplayCommands,

                         asoDisplayClientCount);

    TAppServerOptions = set of TAppServerOption;

property Options : TAppServerOptions;

Description

Options are used by TAppServer to modify behaviour.

  asoAutoStart          Server starts automatically

  asoDisplayCommands    Server display commands

  asoDisplayClientCount Server display client count


TAppServer Port
TAppServer.Port

property Port : String;

Description

The port property gives the port number or service name used by the server to listen for client connection. It can be a numeric value or a string value which must be present in the 'services' file. You should not use any port number already used in your computer. Default value is 2106.


TAppServer RequestBroker
TAppServer.RequestBroker

property RequestBroker : TRequestBroker;

Description

The server component receive client requests, data parameters and send replies to client. But it delegate the request dispatching to a dedicated component: TRequestBroker.


TAppServer RequestCount
TAppServer.RequestCount

property RequestCount  : LongInt;

Description

RequestCount gives the total number of requests received since server startup


TAppServer SrvWSocket
TAppServer.SrvWSocket

property SrvWSocket : TWSocket;

Description

SrvWSocket is the underlaying TWSocket component used to listen for for client connections.


TAppServer Start
TAppServer.Start

public procedure Start;

Description

The start procedure will start the server. The server will accept new client connections. See also Stop.


TAppServer Stop
TAppServer.Stop

public procedure Stop;

Description

The Stop procedure will stop the server which will no more accept new clients, but will not disconnect already connected clients. See also Start.


TAppServer TimeoutInterval
TAppServer.TimeoutInterval

property TimeoutInterval : LongInt;

Description

The server periodically check for client timeout. It uses a single TTimer component for this check. The TimeoutInterval is this timer interval and efault to 30 seconds. This means that every 30", the server will goes thru the client list and check for timeout. A smaller value gives better accuracy in timeout detection, but produce some overhead, specially if the number of client is large.


TOPIC_261
type

TClientWSocketClass  = class of TClientWSocket;

protected FClientClass  : TClientWSocketClass;

Description

FClientClass is a very important property if you are going to derive components from TAppServer and TClientWSocket. FClientClass is used by TAppServer to know which component to instanciate to handle client connection. It default to TClientWSocket. If you wants to extend client handling functionnalities, you have to derive your own component from TClientWSocket and TAppServer and override FClientClass in your TAppServer descendent with the value equal to your TClientWSocket descending component. So your own TAppServer component will instanciate your own TClientWScoket component !


TAppSrvClient

Properties   Methods   Events

Unit

ApsCli

Description

TAppSrvClient is used on the client side to connect to the application server. His main purpose is to send a request to the application server and receive answers from the application server. TAppSrvClient establish and manage connection and dialog with MidWare application server.


TAppSrvClient Properties

TAppSrvClient  Properties   Methods   Events

Answer

AnswerStatus

Connected

Function Code

Handle

Port

Request

RequestBody

RequestBodyLen

RequestHeader

RequestHeaderLen

Server

SocksAuthentication

SocksPassword

SocksPort

SocksServer

SocksUserCode

State

WSocket


TOPIC_4
TAppSrvClient Events

TAppSrvClient  Properties   Methods   Events

OnAfterProcessReply

OnAfterSendRequest

OnBeforeProcessReply

OnBannerRcvd

OnBeforeSendRequest

OnRequestDone

OnSessionClosed

OnSessionConnected

OnSocksAuthState

OnSocksConnected

OnSocksError


TOPIC_11
TAppSrvClient Methods

TAppSrvClient  Properties   Methods   Events

Close

Send


TOPIC_28
TAppSrvClient.Answer

property Answer  : TMWBuffer;

Description

The Answer property holds the answer from the application server. It is organized as the request: records made of fields. See TMWBuffer description for more details.

Answer property is to be accessed from the OnRequestDone event handler, when the application server has returned his response.

Example:

procedure TForm1.AppSrvClient1RequestDone(

  Sender : TObject;

  Error  : Integer);

var

    nRec : Integer;

begin

    if Error <> 0 then begin

        Memo1.Lines.Add('Error #' + IntToStr(Error));

        Exit;

    end;

    Memo1.Lines.Add('Answer status = ' + AppSrvClient1.AnswerStatus);

    nRec := 0;

    AppSrvClient1.Answer.First;

    while not AppSrvClient1.Answer.Eof do begin

        Inc(nRec);

        Memo1.Lines.Add(IntToStr(nRec) + ': ' +

                            AppSrvClient1.Answer.RecordToString);

        AppSrvClient1.Answer.Next;

    end;

end;


TOPIC_12
TAppSrvClient.AnswerStatus

property AnswerStatus : String;

Description

The AnswerStatus property hold the ResultStatus returned back by the application server. It plays the same role as the function code in the request. The meaning for the value is left to the application author. The server and client code does'nt use it. It is just passed from the server to the client. By convention the server use numeric values like those used by the HTTP or FTP protocols.


TOPIC_41
TAppSrvClient.Close

procedure Close;

Description

Close the communication with the application server. Closing communication will lower pressure on application server, but will require time to establish it again for next request. This may be a problem on the internet. Communication will be established much faster if you use an IP address instead of a hostname because there is no need for name resolution which is often a very long process.

On a LAN, there is no problem to close communication after each request, specially if you use an IP address and not a hostname.

Note: Using IP address in a program is not recommanded because IP addresses may change. You should use a hostname and resolve the hostname to an IP address at startup and then use the IP address for the program duration.


TOPIC_14
TAppSrvClient.Connected

property Connected : Boolean;

Description

The connected property tell if connection with the server is alive.


TOPIC_20
TAppSrvClient.FunctionCode

property FunctionCode : String;

Description

The function code is a string which is used by the application server to know which server object to instanciate to execute the request. It can be anything but default in the server to the server object name without the leading TServerObject. For example if you made a server object whose class name is TServerObjectGETCLIENT then the function code will be GETCLIENT. This behaviour can be overriden in  the server object by overriding the BuildFunctionCode procedure. The function code is case insensitive and must not contain any space or control characters.


TOPIC_13
TAppSrvClient.Handle

property Handle  : HWND;

Description

The handle for the hidden window used to send and receive internal messages for component work. Normal operation do not require use of this handle.


TOPIC_36
TAppSrvClient.OnAfterProcessReply

Occurs after a reply has been processed

type

TProcessReplyEvent  = procedure (Sender : TObject; var CmdBuf : PChar; var CmdLen   : Integer) of object;

property OnAfterProcessReply  : TProcessReplyEvent

Description

Use to cleanup allocated resources in the OnBeforeProcessReply event handler.


TOPIC_38
TAppSrvClient.OnAfterSendRequest

Occurs just after a request has been sent to server.

property OnAfterSendRequest   : TNotifyEvent

Description

Use to cleanup allocated resources in the OnBeforeSendRequest event handler


TOPIC_39
TAppSrvClient.OnBannerRcdv

Occurs when banner is received from server

property OnBannerRcvd         : TProcessBannerEvent

Description

The event handler could be used to verify the received banner to be sure we are connected to the right server, or to display it for the user, or to log it to a log file. Could also be simply ignored !


TOPIC_35
TAppSrvClient.OnBeforeProcessReply

Occurs when a reply has been received and before it is processed.

type

TProcessReplyEvent  = procedure (Sender : TObject; var CmdBuf : PChar; var CmdLen   : Integer) of object;

property OnBeforeProcessReply : TProcessReplyEvent

Description

The event OnBeforeProcessReply is triggered when a reply have been received from the server, just before it is processed for header and body extraction. This event is the right place to decrypt or decompress data sent by the server. The event handler can allocate some resource or memory and change the parameters passed. To free resource and memory, use the OnAfterProcessReply event which will pass the same arguments.


TOPIC_37
TAppSrvClient.OnBeforeSendRequest

Occurs before a request is ready to be sent to server.

property OnBeforeSendRequest  : TNotifyEvent

Description

The OnBeforeSendRequest event is triggered just before a request and his parameters are sent to the server. The event handler can process the header (RequestHeader, RequestHeaderLen) and the parameters (RequestBody, RequestBodyLen) to encrypt or compress them. If needed, the event handler can reallocate the data elsewhere. If needed, the OnAfterSendRequest event handler can be used to free allocated resources.


TOPIC_29
TAppSrvClient.OnRequestDone

Occurs when a request has been statisfied and result set is available

type

TRequestDone = procedure (Sender : TObject; Error : Integer) of object;

property OnRequestDone : TRequestDone;

Description

When the application server sent the answer to the client, the OnRequestdone event is triggered. The corresponding event handler is the right place to test for success or failure, and to parse the answer to extract the returned info to update the user interface or do whatever needs to be done with the request's result. See sample code. It is also the right place to close communication using Close methods.

There are two levels of errors: at client side and at server side. The argument Error gives an error code related to client side, AnswerStatus gives an error code of phrase related to server side. Values for the Error argument may be any operating system error code, more specifically winsock errors (in the range 10000 to 12000). See windows documentation for error list.

Most common errors are:

10061: Connection refused. Probably server do not run, or server IP address or port number is wrong.

10065: Host unreachable. Probably TCP/IP setup incorrectly done.

10053, 10054, 10057: Connection error. Probably phone hangup, carrier lost, cable broken, server hung and all such failures.


TOPIC_34
TAppSrvClient.OnSessionClosed

Occurs when connection with application server has been closed.

property OnSessionClosed : TSessionClosed

Description

The event OnSessionConnected is triggered when the connection has been closed. The event handler is the right place to update some status bar to let the user know he is disconnected from the server.


TOPIC_30
TAppSrvClient.OnSessionConnected

Occurs when connection is established with application server.

Type

TSessionConnected = procedure (Sender: TObject; Error: word) of object;

property OnSessionConnected : TSessionConnected

Description

The event OnSessionConnected is triggered when the connection has been established with the application server. The event handler is the right place to update some status bar to let the user know he is connected with the server.


TOPIC_31
TAppSrvClient.OnSocksConnected

Occurs when connected to socks server (firewall)

type

TSessionConnected = procedure (Sender: TObject; Error: word) of object;

property OnSocksConnected : TSessionConnected

Description

The event OnSocksConnected is triggered when the connection has been established with the socks server. The event handler is the right place to update some status bar to let the user know he is connected with the firewall.


TOPIC_32
TAppSrvClient.OnSocksError

Occurs when a socks error has been detected.

Type

TSocksErrorEvent     = procedure(Sender : TObject; Error : Integer; Msg : String) of Object;

property OnSocksError  : TSocksErrorEvent

Description

OnSocksError event is triggered when an error related to socks connection has been detected.


TOPIC_33
TAppSrvClient.OnAuthState

Occurs during socks authentication process.

type

TSocksAuthStateEvent = procedure(Sender : TObject; AuthState : TSocksAuthState) of object;

TSocksAuthState  = (socksAuthStart, socksAuthSuccess, socksAuthFailure, socksAuthNotRequired);

property OnSocksAuthState : TSocksAuthStateEvent

Description

OnSocksAuthState event is triggered for each state in socks authentication process.


TOPIC_22
TAppSrvClient.Port

property Port : String;

Description

This is the port number used by the server to listen for clients. It defaults to 2106 but can be anything. It can even be a symbolic name provided that name is in the 'services' table.


TOPIC_7
TAppSrvClient.Request

property Request : TMWBuffer;

Description

The request property holds the parameters sent to the application server. The application server uses the function code to know which server object must be instanciated, and pass the paraemters to this server object. Parameters can be anything and ar emade of records made of fields. See TMWBuffer object description for details.

Example:

    AppSrvClient1.Request.Rewrite;

    AppSrvClient1.Request.WriteFields(FALSE, ['PIETTE', 'FRANCOIS']);

    AppSrvClient1.FunctionCode := 'GETCLIENT';

    AppSrvClient1.Send;


TOPIC_18
TAppSrvClient.RequestBody

property RequestBody : PChar;

Description:

RequestBody gives the address where the message body is stored just before sending it to the application server. This property is interesting when used from OnBeforeSendRequest event handler. See OnBeforeSendRequest description for more details.

See also: RequestHeader, RequestHeaderLen, RequestBodyLen, OnBeforeSendRequest, OnAfterSendRequest.


TOPIC_19
TAppSrvClient.RequestBodyLen

property RequestBodyLen : Integer;

Description:

RequestBodyLen gives the message body length just before sending it to the application server. This property is interesting when used from OnBeforeSendRequest event handler. See OnBeforeSendRequest description for more details.

See also: RequestHeader, RequestHeaderLen, RequestBody, OnBeforeSendRequest, OnAfterSendRequest.


TOPIC_16
TAppSrvClient.RequestHeader

property RequestHeader : PChar;

Description:

RequestHeader gives the address where the message header is stored just before sending it to the application server. This property is interesting when used from OnBeforeSendRequest event handler. See OnBeforeSendRequest description for more details.

See also: RequestHeaderLen, RequestBody, RequestBodyLen, OnBeforeSendRequest, OnAfterSendRequest.


TOPIC_17
TAppSrvClient.RequestHeaderLen

property RequestHeaderLen : Integer;

Description:

RequestHeaderLen gives the message header length just before sending it to the application server. This property is interesting when used from OnBeforeSendRequest event handler. See OnBeforeSendRequest description for more details.

See also: RequestHeader, RequestBody, RequestBodyLen, OnBeforeSendRequest, OnAfterSendRequest.


TOPIC_40
TAppSrvClient.Send

procedure   Send;

Description

Send a FunctionCode  and Request (parmeters) to the application server. This is the main TAppSrvClient component function. Communication with MidWare application server is established if needed. Connection can be later closed using Close method.

Send is asynchronous. Execution is almost instantaneous: control return back immediately while sending occurs in the background. Eventually, when request is done, either OK or with some error, then the OnRequestDone event is triggered.

Asynchonous operation allows multitasking without using threads. That's important because most VCL is not thread safe. Asynchonous operation let you do some work while your request are processed. You may even start several requests at once. But asynchronous operation may be somewhat new to traditionnal programmers which like sequential programming. Asynchronous programming can be made easy using some kind of "finite state machine" to keep track of the processing state and know what to do next when an operation has been completed. This give very powerful applications.

For those who really wants blocking operation, asynchronous operation may be transformed in blocking operation by means of a loop and a flag. Before sending a request, you set a flag to false, then you loop calling Application.ProcessMessages until the flag is set to true or some timeout occured. You set then flag to true in the OnRequestDone event handler.


TOPIC_21
TAppSrvClient.Server

property Server : String;

Description

This is the IP address or hostname for the application server. It is generaly much faster to use the IP address than the hostname because it avoid name resolution each time the communication is established. Name resolution takes time, specially if there are some problem with the DNS. It's better to get the IP address from the server host name at application startup and use the IP address after.

If server and client are on the same computer, use 127.0.0.1 or 'localhost'.


TOPIC_27
TAppSrvClient.Authentication

property SocksAuthentication : TSocksAuthentication;

Description:

SocksAuthentication specifies which socks5 authentication method to use.


TOPIC_26
TAppSrvClient.Password

property SocksPassword : String;

Description:

SocksPassword is the password used for Socks5 connection.


TOPIC_24
TAppSrvClient.SocksPort

property SocksPort : String;

Description:

Socks5 port number.


TOPIC_23
TAppSrvClient.SocksServer

property SocksServer : String;

Description:

IP or hostname for socks5 server.


TOPIC_25
TAppSrvClient.UserCode

property SocksUsercode : String;

Description:

Socks5 usercode.


TOPIC_15
TAppSrvClient.State

property State : TClientState;

TClientState = (cstReady, cstDnsLookup, cstConnecting, cstWaitingResponse);

Description:

State property gives the component state:

cstReady

Component is ready

cstDnsLooup

Component is waiting for hostname to be resolved to IP address

cstConnecting

Component is waiting for the connection the be established

cstWaitingResponse

Component  is waiting response from application server


TOPIC_6
TAppSrvClient.TWSocket

property WSocket : TWSocket;

Description

WSocket is the reference to the underlaiying TWSocket component used for communication with the application server. You don't need to access it for normal operation. Befaore using it, you must be sure to understand how TAppSrvClient works internally.


TClientWSocket
TClientWSocket Component

Properties  Events  Methods

unit

    ApSrvCli

Description

TClientWSocket is a specialized TWSocket used to handle client connection with application server. A new TClientWSocket is instanciated by TAppServer when a client connect to the server. TClientWSocket is destroyed after client disconnect.

Do not confuse TClientWSocket with TAppSrvClient which is the client application side. TClientWSocket is used on the server side to handle client connections, TAppSrvClient is used on the client side to connect to the application server. Both components are talking to each other.

User code in an ordinary application server never create a TClientWSocket instance. Instead, it uses instances created by TAppServer and accessed thru his ClientWSocket indexed property or thru reference passed by events such as OnClientCommand.


TClientWSocket Properties

TClientWSocket  Events  Methods

Banner

Busy

CommandCount

CommandTimeout

ConnectedSince

HSocket

LastCommandTime

LocalPort

PeerAddr

RcvBuf

RcvSizeInc

RcvSizeMax

ReplyHeader

ReplyHeaderLen

ReplyBody

ReplyBodyLen

UserData

TClientSocket has more properties inherited from the ancestor TWSocket component.


TClientWSocket Events

TClientWSocket  Properties  Methods

OnBgException

OnCommand

OnDisplay

OnOverflow

OnSessionClosed

OnTimeout

TClientSocket has more events inherited from the ancestor TWSocket component.


TClientWSocket Methods

TClientWSocket  Properties  Events

CheckCommandTimeout

Dup

SendReply

StartConnection

TClientSocket has more methods inherited from the ancestor TWSocket component.


TClientWSocket Banner
TClientWSocket.Banner

property Banner : String;

Description

The banner to be sent to the client upon connection. Must be a single line.


TClientWSocket Busy
TClientWSocket.Busy

property Busy : Boolean;

Description

Busy is TRUE while a the previous request is still executing.


TCLientWSocket CheckCommandTimeout
TClientWSocket.CheckCommandTimeout

procedure CheckCommandTimeout; virtual;

Description

Procedure used by TAppServer to check for inactivity timeout.


TClientWSocket CommandTimeout
TClientWSocket.CommandCount

property CommandCount : LongInt;

Description

Number of commands issued by the client. Useful for statistics or accounting purposes.


TClientWSocket CommandTimeout
TClientWSocket.CommandTimeout

property CommandTimeOut : TDateTime;

Description

Timeout value. If the client stay inactive for this period of time, the server will disconnect it. See also CheckCommandTimeout.


TClientWSocket ConnectedSince
TClientWSocket.ConnectedSince

property ConnectedSince : TDateTime;

Description

Gives the time when the client connected.


TClientWSocket Dup
TClientWSocket.Dup

procedure Dup(newHSocket : TSocket); virtual;

Description

Dup associate a winsock handle to a TClientWSocket component. Calling Dup is the same as assigning HSocket property. It is used by TAppServer when his litening socket has received a connection from a client and returned a handle to the underlaying winsock DLL.


TClientWSocket HSocket
TClientWSocket.HSocket

property HSocket : TSocket;

Description

HSocket is the underlaying winsock DLL handle for the connection handled by TClientWSocket component. It may be unassigned (nul) if there is no connection is established.


TClientWSocket LastCommandTime
TClientWSocket.LastCommandTime

property  LastCommandTime : TDateTime;

Description

Gives the time of the last command received from client.


TClientWSocket LocalPort
TClientWSocket.LocalPort

property LocalPort : string;

Description

LocalPort gives the port number (or service name) associated by winsock on the local computer for the connection made by client. If unassigned (nul) before connecting, then winsock will choose a free port automatically otherwise, winsock will use provided value.


TClientWSocket OnBgException
TClientWSocket.OnBgException

Occurs when an exception is thrown in the background.

type

TBgExceptionEvent = procedure (Sender : TObject;

                               E : Exception;

                               var CanClose : Boolean) of object;

property OnBgException : TBgExceptionEvent;

Description

A background exception is an exception that occurs in the middle of nowhere. It is detected at the lowest level in message handling. If not assigned and event handler, the default behaviour will be to close the socket.


TClientWSocket OnCommand
TClientWSocket.OnCommand

Occurs when a command has been received from client.

type

TCommandEvent = procedure (Sender : TObject;

                           CmdBuf : PChar;

                           CmdLen : Integer) of object;

property OnCommand : TCommandEvent;

Description

Triggered when a client request (command) has been received. It is used by TAppServer to trigger command processing. A client request is simply a line of text delimited by a CR/LF pair.


TClientWSocket OnDisplay
TClientWSocket.OnDisplay

Occurs when a message has to be displayed on the user interface.

type

TDisplayEvent  = procedure (Sender : TObject; Msg : String) of object;

property OnDisplay : TDisplayEvent;

Description

Triggered when the component wants to display something on the user interface. TAppServer install a handler that relay display to his own OnDisplay event handler.


TClientWSocket OnOverflow
TClientWSocket.OnOverflow

Occurs when the input buffer is overflowed and can't be enlarged.

type

TOverflowEvent = procedure (Sender : TObject; var CanAbort : Boolean) of object;

property OnOverflow : TOverflowEvent;

Description

Triggered when the input buffer is overflowed and can't be enlarged. Default action is to abort the connection. Overflow may occurs when the is no more memory available.


TClientWSocket OnSessionClosed
TClientWSocket.OnSessionClosed

Occurs when client disconnect from server.

type

TSessionClosed    = procedure (Sender: TObject; Error: word) of object;

property OnSessionClosed : TSessionClosed;

Description

Occurs when client disconnect from server or has been disconnected.


TWSocket OnTimeout
TClientWSocket.OnTimeout

Occurs when client will be disconnected because of no activity.

type

TTimeoutEvent  = procedure (Sender : TObject; var CanClose : Boolean) of object;

property OnTimeout : TTimeoutEvent;

Description

Triggered when the client timedout as is about to be disconnected by TAppServer. Default action is to allow disconnection.


TClientWSocket PeerAddr
TClientWSocket.PeerAddr

property PeerAddr : String;

Description

Store the client's IP address. The value is cached.


TClientWSocket RcvBuf
TClientWSocket.RcvBuf

property RcvBuf : PChar;

Description

The actual buffer used to store incomming data. It is dynamically allocated as needed. If it can't be expanded then an OnOverflow event is triggered.


TClientWSocket RcvdCount
TClientWSocket.RcvdCount

property RcvdCount : LongInt;

Description

Returns the number of characters received and not yet read. It may be unaccurate if called from OnDataAvailable event after a first call to receive or ReceiveFrom because winsock will not update his internal count until out of his event handler (FD_READ).


TClientWSocket RcvSize
TClientWSocket.RcvSize

property RcvSize : integer;

Description

Size of buffer used to receive commands (requests). See RcvBuf property.


TClientWSocket RcvSizeInc
TClientWSocket.RcvSizeInc

property RcvSizeInc : Integer;

Description

When RcvBuf is too small, it will be enlarged by RcvSizeInc bytes automatically until RcvSizeMax is reached. An OnOverflow event is triggered if buffer can't be enlarged.


TClientWSocket RcvSizeMax
TClientWSocket.RcvSizeMax

property RcvSizeMax : Integer;

Description

When RcvBuf is too small, it will be enlarged by RcvSizeInc bytes automatically until RcvSizeMax is reached. An OnOverflow event is triggered if buffer can't be enlarged.


TClientWSocket ReplyHeader
TClientWSocket.ReplyHeader

property  ReplyHeader : PChar;

Description

ReplyHeader point to the header built by the TAppServer based on reply status. See also ReplyHeaderLen, ReplyBody and ReplyBodyLen.


TClientWSocket ReplyHeaderLen
TClientWSocket.ReplyHeaderLen

property ReplyHeaderLen : Integer;

Description

ReplyHeaderLen is the length in byte for the header. See also ReplyHeader, ReplyBody and ReplyBodyLen.


TClientWSocket ReplyBody
TClientWSocket.ReplyBody

property ReplyBody : PChar;

Description

ReplyBody point to the answer to be sent to the client. See also ReplyHeader, ReplyHeaderLen and ReplyBodyLen.


TClientWSocket ReplyBodyLen
TClientWSocket.ReplyBodyLen

property ReplyBodyLen : Integer;

Description

ReplyBodyLen is the length in bytes for the answer. See also ReplyHeader, ReplyHeaderLen and ReplyBody.


TClientWSocket SendReply
TClientWSocket.SendReply

procedure SendReply; virtual;

Description

SendReply procedure will send ReplyHeader and About MidWare followed by a CR/LF pair. This constitute the entire reply message sent to a client.


TClientWSocket StartConnection
TClientWSocket.StartConnection

procedure StartConnection;

Description

First method to be invoked on client connection. It initializes internal working and send the banner to the client.


TClientWSocket UserData
TClientWSocket.UserData

property UserData : LongInt;

Description

UserData is not used by the component nor the TAppServer component. It is reserved for application use to carry global data between application server main code and TServerObject.


TMWBuffer
TMWBuffer component

Properties  Methods  Events

Unit

RFormat.pas

Description

TMWBuffer if a very important component in MidWare technology. TMWBuffer implement data storage and formatting for transmission. Data echanged between client and server is exactly TMWBuffer content, byte for byte.

TMWBuffer can be seen as a data table in memory. This table is organized as records made of variable field number, each field having a variable length.

TMWBuffer provides methods and properties to read, write and sort data. Data is stored in a very simple format: a buffer dynamically allocated from memory that contains all fields and records. Fields and records boundaries are marked with delimiters. If control characaters or delimiters are found within data, they are escaped. Three delimiters are used: escape delimiter, field delimiter and record delimiter. They are placed at start of buffer in order to consitute a kind of dictionnary.

By default, MidWare use those delimiters (decimal code):

    Field  18

    Record 20

    Escape 127

Escape delimiter is also used to mark meta data information within data buffer. Meta data is field type or general purpose meta data such as field layout.

If an escape character is followed by another escape character, then data contains a single character. Table below indicate the meaning of an escape character followed by another character:

    C  Carriage return

    L  Line feed

    F  Field delimiter

    R  Record delimiter

    N  Null character

    T  Field type follow (used for blobs: S=String)

Other uppercase characters are marking start of variable length general purpose meta data. End of meta data is marked with escape character and corresponding lower case letter.


TMWBuffer Properties

AutoExpand

Bof

DataBuffer

DataBufferCount

DataBufferSize

Eof

FieldCount

Fields

FieldSize

FieldType

HasData

HeaderSize

MetaData

RecordCount


TMWBuffer Events

TMWBuffer has no event !


TMWBuffer Methods

AppendMetaData

Assign

AppendBinaryField

AppendFields

AppendRecord

AppendStreamField

Delete

ExpandBuffer

First

FreeBookmark

GetBookmark

GetStreamField

GotoBookmark

Last

LoadFromFile

LoadFromStream

Locate

Next

Prior

RecordToString

Rewrite

SaveToFile

SaveToStream

Seek

Sort

StringToRecord

StringToRecords

Tell

WriteDataBuffer

WriteFields

WriteRecordMarker

WriteStreamField


TMWBuffer AppendMetaData
TMWBuffer.AppendMetaData

procedure AppendMetaData(Delim : Char; Src : PChar; Len : LongInt);

Description

AppendMetaData will add variable length, general purpose meta data at the end of current field. Meta data is delimited by an escape character followed by an uppercase letter at start and escape character followed by lower case character at the end. Not all letters can be used because some are intended for other purpose. See TMWBuffer description for more details.

Delim argument is uppercase character that has to be used for delimiter.

Src argument is pointer to meta data. Could be anything, including binary data.

Len argument gives the number of bytes pointed by Src argument.


TMWBuffer Assign
TMWBuffer.Assign

procedure Assign(Source: TPersistent);

Description

The Assign method copies data from a TMWBuffer component to another.


TMWBuffer AutoExpand
TMWBuffer.AutoExpand

property AutoExpand : LongInt;

Description

AutoExpand property tells the component if the data buffer can be expanded when it is too short for the data that needs to be written to it. The value gives to AutoExpand is the number of bytes that are append at the end of buffer. It default to 256 bytes. If you plan to append lots of data, you should consider making AutoExpand value much larger. If you know how much data to have to add, you could make AutoExpand slightly larger (because of delimiters and escaped characters). If you make AutoExpand to small, then performance is low because there will be a lot of memory reallocation. If you make it to large, memory will be wasted.


TMWBuffer AppendBinaryField
TMWBuffer.AppendBinaryField

procedure AppendBinaryField(Data : Pointer; Len : Integer; FldType : TMWFieldType);

Description

Write binary data as field content.


TMWBuffer AppendFields
TMWBuffer.AppendFields

procedure AppendFields(Args : array of const);

Description

Append fields to the current record. See also WriteFields.


TMWBuffer AppendRecord
TMWBuffer.AppendRecord

procedure  AppendRecord(From : TMWBuffer);

Description

Append a single record from another TMWBuffer. See also Assign that duplicate all data from another TMWBuffer.


TMWBuffer AppendStreamField
TMWBuffer.AppendStreamField

type

TMWFieldType = (mwString, mwBlob);

procedure AppendStreamField(Data : TStream; FldType : TMWFieldType);

Description

Append a stream field to current record. See also WriteStreamField.


TMWBuffer Bof
TMWBuffer.Bof

property Bof : Boolean;

Description

Bof property is TRUE when current position has reached begin of file. See also Eof, First, Last, Next and Prior methods.

Example

The following code iterate MWBuffer data starting from last record up to first record.

    MWBuffer1.Last;

    while not MWBuffer1.Bof do begin

        Memo1.Lines.Add(MWBuffer1.RecordToString);

        MWBuffer1.Prior;

    end;


TMWBuffer DataBuffer
TMWBuffer.DataBuffer

property DataBuffer : PChar;

Description

Gives access to the underlaying data buffer. Normal application should not access this property but use methods and properties to read and write data. DataBuffer will change during component life because buffer may be expanded as data has to be written.

Writing this value is allowed and force a buffer for data storage. Property DataBufferSize must also be properly set if DataBuffer is written. If the buffer is forced then the component cannot expand it as needed to write fields.

Setting DataBuffer to nil will free buffer memory if it was allocated by the component. A new buffer will be allocated when needed.


TMWBuffer DataBufferCount
TMWBuffer.DataBufferCount

property DataBufferCount : LongInt;

Description

The size in bytes of the data present in the buffer. Do not confuse DataBufferCount with DataBufferSize which is the total buffer size while DataBufferCount is the number of bytes really used in the buffer.

If you copy data directly to the buffer, bypassing the component, then you must update DataBufferCount to reflect how much data is into the buffer.


TMWBuffer DataBufferSize
TMWBuffer.DataBufferSize

property DataBufferSize : LongInt;

Description

The size in bytes of the current buffer. Assigning a value to this property will allocate or reallocate the buffer. Buffer address is given by DataBuffer property. How much data is already stored in buffer is given by DataBufferCount property.


TMWBuffer Delete
TMWBuffer.Delete

procedure  Delete;

Description

Delete the current record. Deleted records are physically lost. Deleteing a record may take some time because all data from next record to end of buffer has to be moved. This is quite fast if buffer contains only a few KB, but may take time if there are MB of data !


TMWBuffer ExpandBuffer
TMWBuffer.ExpandBuffer

function ExpandBuffer(pSize : PInteger; Requested : LongInt) : Boolean;

Description

ExpandBuffer method check how much free space is left and will try to expand data buffer as needed. If operation is successful then ExpandBuffer returns TRUE. If there is not enough free space available and buffer can't be expanded, then ExpandBuffer will returns FALSE. If buffer is expanded, DataBuffer may change (memory manager will try to keep data at same address as much as possible, data will be copied if buffer has to be moved to another location).

Requested argument specifies how much free space is requested. If less is remaining then buffer will be expanded by the requested value rounded nearest the greater multiple of AutoExpand property value. If AutoExpand is 0, then buffer will not be expanded and function retrun FALSE.

pSize argument must be nil or point to an integer that will receive how much free data space is left after the operation.


TMWBuffer Eof
TMWBuffer.Eof

property Eof : Boolean;

Description

Eof property is TRUE when current position has reached end of file. See also Bof, First, Last, Next and Prior methods.

Example

The following code iterate MWBuffer data starting from first record up to last record.

    MWBuffer1.First;

    while not MWBuffer1.Eof do begin

        Memo1.Lines.Add(MWBuffer1.RecordToString);

        MWBuffer1.Next;

    end;


TMWBuffer FieldCount
TMWBuffer.FieldCount

property FieldCount : Integer;

Description

Returns the number of fields in the current record.

FieldCount may take some time because it simply iterate all data in current record to count the number of field delimiters.


TMWBuffer,Fields
TMWBuffer.Fields

property Fields[nIndex : Integer] : String;

Description

The indexed Fields[] property gives access to the current record's fields. Fields are numbered starting from 0 up to FieldCount - 1. Fields property always returns data as a string. For blobs, use GetStreamField. See also FieldSize and FieldType.

Existing fields can be written by assigning Fields[]. The current value is replaced by new data. To add more fields, use AppendFields or WriteFields.

Example

procedure TForm1.Button1Click(Sender: TObject);

var

    Fld, Last : Integer;

begin

    Last := MWBuffer1.FieldCount - 1;

    for Fld := 0 to Last do

        Memo1.Lines.Add(MWBuffer1.Fields[Fld]);

end;


TMWBuffer FieldSize
TMWBuffer.FieldSize

property FieldSize[nIndex : Integer] : Integer;

Description

Return field size in bytes.


TMWBuffer FieldType
TMWBuffer.FieldType

type

TMWFieldType = (mwString, mwBlob);

property FieldType[nIndex : Integer] : TMWFieldType;

Description

Read only indexed property returning filed type for a given field in current record.


TMWBuffer First
TMWBuffer.First

procedure First;

Description

First method makes the first record the current one. See also Eof, Bof, First, Last, Next and Prior methods.

Example

The following code iterate MWBuffer data starting from first record up to last record.

    MWBuffer1.First;

    while not MWBuffer1.Eof do begin

        Memo1.Lines.Add(MWBuffer1.RecordToString);

        MWBuffer1.Next;

    end;


TMWBuffer FreeBookmark
TMWBuffer.FreeBookmark

procedure FreeBookmark(Bookmark: TBookmark);

Description

Free resources used for bookmark keeping. See GetBookmark.


TMWBuffer GetBookMark
TMWBuffer.GetBookmark

function GetBookmark: TBookmark;

Description

Get a bookmark on current record. Use the value with GotoBookmark. When no more used, call FreeBookmark to release used resources.


TMWBuffer GetStreamField
TMWBuffer.GetStreamField

type

TMWFieldType = (mwString, mwBlob);

function GetStreamField(FieldNb : Integer; Data : TStream; var FieldType : TMWFieldType) : integer;

Description

Get a stream (blob) field value from the buffer. Same as the Fields[] property but works with blob fields.


TMWBuffer GotoBoomark
TMWBuffer.GotoBookmark

procedure GotoBookmark(Bookmark: TBookmark);

Description

Return the current position to the bookmark setup by GetBookmark.


TMWBuffer HasData
TMWBuffer.HasData

property HasData : Boolean;

Description

HasData property is TRUE when TMWBuffer contains data. This is mostly used when writing data to TMWBuffer without using component's methods. For example, to supply external data, you set DataBuffer, DataBufferSize, DataBufferCount and HasData properties.


TMWBuffer HeaderSize
TMWBuffer.headerSize

property HeaderSize : LongInt;

Description

Size in byte of the header in the data buffer. Default to 0.


TMWBuffer
TMWBuffer.IsValidFields

function IsValidFields(nIndex : Integer) : Boolean;

Description

IsValidFields check if a field number is valid for use with Fields indexed property. IsValidFields returns TRUE is current record contains the specified field.


TMWBuffer Last
TMWBuffer.Last

procedure Last;

Description

Last method will make the lsat record the current one. See also Eof, Bof, First, Last, Next and Prior methods.

Example

The following code iterate MWBuffer data starting from last record up to first record.

    MWBuffer1.Last;

    while not MWBuffer1.Bof do begin

        Memo1.Lines.Add(MWBuffer1.RecordToString);

        MWBuffer1.Prior;

    end;


TMWBuffer LoadFromFile
TMWBuffer.LoadFromFile

procedure LoadFromFile(FileName : String);

Description

Load TMWBuffer content from a files created with SaveToFile or SaveToStream.


TMWBuffer LoadFromStream
TMWBuffer.LoadFromStream

procedure LoadFromStream(Stream : TStream);

Description

Load TMWBuffer content from a stream created by SaveToStream or SaveToFile.


TMWBuffer Locate
TMWBuffer.Locate

function Locate(const KeyFields: String; const KeyValues: Variant; Options: TLocateOptions): Boolean;

Description

Locate a record by sequential search. KeyFields is field list, byte values, 1 based.


TMWBuffer MetaData
TMWBuffer.MetaData

property MetaData[nIndex : Integer; Delim : Char] : String;

Description

Read only indexed MetaData property gives access to the current record's meta data (application defined).


TMWBuffer Next
TMWBuffer.Next

procedure Next;

Description

Next method makes the next record the current one. See also Eof, Bof, First, Last, Next and Prior methods.

Example

The following code iterate MWBuffer data starting from first record up to last record.

    MWBuffer1.First;

    while not MWBuffer1.Eof do begin

        Memo1.Lines.Add(MWBuffer1.RecordToString);

        MWBuffer1.Next;

    end;


TMWBuffer Prior
TMWBuffer.Prior

procedure Prior;

Description

Prior method makes the previous record the current one. See also Eof, Bof, First, Last, Next and Prior methods.

Example

The following code iterate MWBuffer data starting from first record up to last record.

    MWBuffer1.First;

    while not MWBuffer1.Eof do begin

        Memo1.Lines.Add(MWBuffer1.RecordToString);

        MWBuffer1.Next;

    end;


TMWBuffer RecordCount
TMWBuffer.RecordCount

property RecordCount : Integer

Description

Readonly property RecordCount retunrs the number of records stored in TMWBuffer. See also FieldCount.


TMWBuffer RecordToString
TMWBuffer.RecordToString

function RecordToString : String;

Description

Return the current record expressed as a string. Handy for quick display. Do not works very well with blob fields. See StringToRecord for reverse operation.


TMWBuffer Rewrite
TMWBuffer.Rewrite

procedure Rewrite;

Description

Clear buffer content and prepare for new writing.

Example

begin

    MWBuffer1.Rewrite;

    MWBuffer1.WriteFields(TRUE, ['Hello', 'World']);

    ProcessRequest(MWBuffer1);

    MWBuffer1.Rewrite;

    MWBuffer1.WriteFields(TRUE, ['Another', 'Request']);

    ProcessRequest(MWBuffer1);

end;


TMWBuffer SaveToFile
TMWBuffer.SaveToFile

procedure SaveToFile(FileName : String);

Description

Save TMWBuffer data to a file. File format is simple: first eight bytes are 'MWBUFFER' string, next char is a version number, currently '1', next eight bytes are DataBufferCount expressed in hexadecimal format. Remaining bytes are exact TMWBuffer content copy. Internally, SaveToFile is implemented using SaveToStream with a TFileStream. See also LoadFromFile and LoadFromStream.


TMWBuffer SaveToStream
TMWBuffer.SaveToStream

procedure  SaveToStream(Stream : TStream);

Description

Save TMWBuffer data to a stream. Format is simple: first eight bytes are 'MWBUFFER' string, next char is a version number, currently '1', next eight bytes are DataBufferCount expressed in hexadecimal format. Remaining bytes are exact TMWBuffer content copy. See also SaveToFile, LoadFromFile and LoadFromStream.


TMWBuffer Seek
TMWBuffer.Seek

procedure Seek(nPos : TPosition);

Description

Set current record to the one indicated by nPos which results from a previous call to Tell method.


TMWBuffer Sort
TMWBuffer.Sort

type

TMWBufferSortBuildKey = function (MWBuffer : TMWBuffer) : String;

procedure   Sort(BuildKey : TMWBufferSortBuildKey; Ascending : Boolean);

Description

Sort will sort TMWBuffer content. Sort is based on keys. Keys are built by an external function passed as BuildKey argument. Sort will scan all records, calling BuildKey to build an array of keys. The array is sorted and TMWBuffer data reorganized accordingly.

If BuildKey is nil, then a default function is used instead. This default function use first fireld as key.

Example

procedure TForm1.Button1Click(Sender: TObject);

begin

    MWBuffer1.Sort(MyBuildKeyFunction, TRUE);

end;

function MyBuildKeyFunction(MWBuffer : TMWBuffer) : String;

begin

    Result := MWBuffer.Fields[0] + ' ' +

              MWBuffer.Fields[1];

end;


TMWBuffer StringToRecord
TMWBuffer.StringToRecord

function StringToRecord(Src : String; var Start : Integer) : integer;

Description

Reverse operation for RecordToString. Append a new record. Start parsing the string from a given index. Update this position. Return the number of fields copied.         Accept fields delimited by single or double quotes. See also StringToRecords for several records.


TMWBuffer StringToRecords
TMWBuffer.StringToRecords

procedure StringToRecords(Src : String);

Description

Same as StringToRecord, but applied for several records. Use semicolon as record delimiter.


TMWBuffer Tell
TMWBuffer.Tell

function Tell : TPosition;

Description

Return the internal position for the current record. The returned value can be used with the Seek method.


TMWBuffer WriteDataBuffer
TMWBuffer.WriteDataBuffer

procedure WriteDataBuffer(Src : PChar; Len : LongInt);

Description

Append data from a buffer to the record buffer. Delimiter characters found in data are 'escaped'. Add ending field delimiter, two record delimiters (EOF) and a nul byte. Update DataBufferCount. If Len argument is positive or nul, then copy the specified length else if Len < 0 then copy until nul byte (nul terminated string).

WriteDataBuffer is a low level function not normally used in applications. Use AppendFields or WriteFields instead.


TMWBuffer WriteFields
TMWBuffer.WriteFields

procedure WriteFields(NewRec : Boolean; Args : array of const);

Description

WriteFields will write fields to the next record or append fields to the current record as per NewRec argument.

Example

    MWBuffer1.Rewrite;  // Clear TMWBuffer content

    MWBuffer1.WriteFields(TRUE, ['Hello', 'World'];

    for I := 1 to 3 do

        MWBuffer1.WriteField(FALSE, [I]);

    MWBuffer1.WriteField(FALSE, ['Finished']);

    MWBuffer1.WriteFields(TRUE, ['Another', 'Record'];

This sample code will write two records. The first will contains 6 fields: 'Hello', 'World', '1', '2', '3', 'Finished'. The seond will contain two fields: 'Another', 'Record'.


TMWBuffer WriteRecordMarker
TMWBuffer.WriteRecordMarker

procedure WriteRecordMarker;

Description

Terminate the current record. Can make an empty record. Normaly not used by an applications.


TMWBuffer WriteStreamField
TMWBuffer.WriteStreamField

procedure WriteStreamField(NewRec : Boolean; FldType : TMWFieldType; Data : TStream);

Description

Write a single stream (blob) field. This function can be used to place a complete file (for example a BMP file) into a single field.

Example

var

    Data : TStream;

begin

    Data := TFileStream.Create(FileName,

                               fmOpenRead + fmShareDenyNone);

    Data.Seek(0, 0);

    MWBuffer1.WriteFields(TRUE, [FileName]);

    MWBuffer1.WriteStreamField(FALSE, mwString, Data);

    Data.Destroy;

    ...

    ...

end;

This code will append a record to MWBuffer1 with two fields. The first will contain a file name, the second will contains the complete file. The file is loaded into the field as a blob using a file stream.


TMWTable component
TMWTable

Properties   Methods  Events

Unit

MWdatSet.pas

Description

TMWTable component is much like standard Delphi TTable or TQuery components. TMWTable is used as an interface between data and your program or visual interface.

TMWTable is a TDataSet descendent so you can use it with data-aware controls such as TDBEdit and TDBGrid. Just like you use TQuery or TTable.

TMWTable is an interface that present MidWare communication buffer (TMWBuffer component) as a standard Delphi data table. It let you navigate thru all records and fields. You can and locate data, insert, delete or edit data. TMWTable has no storage for data: all data is stored in TMWBuffer component.

TMWTable has no knowledge of table structure. You must specify it using FieldLayout property. You can fill this property at design time if you know what it will be at runtime, or you may fill it at runtime once you know the value. The value may be known at runtime because your client application query the application server for field layout. You may also sent field layout in first record in result set, feed it to the property and then delete it from result set.


TMWTable properties

TMWTable  Properties   Methods  Events

Active

AppSrvClient

AutoCalcField

CanModify

Data

FieldLayout

FunctionCode

MWBufferFieldCount

ReadOnly

RecordSize

Params

TimeOut

See also Delphi help about TDataSet: TMWTable inherit from TDataSet.


TMWTable methods

TMWTable  Properties   Methods  Events

Close

CreateBlobStream

DesignTimeRequest

ExecuteRequest

Locate

Lookup

Send

See also Delphi help about TDataSet: TMWTable inherit from TDataSet.


TMWTable events

TMWTable  Properties   Methods  Events

AfterCancel

AfterClose

AfterDelete

AfterEdit

AfterInsert

AfterOpen

AfterScroll

BeforeCancel

BeforeClose

BeforeDelete

BeforeEdit

BeforeInsert

BeforeOpen

BeforeScroll

OnCalcFields

OnDisplayInfo

OnDeleteError

OnEditError

OnNewRecord

OnPostError

OnRequestDone

See also Delphi help about TDataSet: TMWTable inherit from TDataSet.


TMWTable Active
TMWTable.Active

property Active : Boolean;

Description

Active property is TRUE when TMWTable is opened and FALSE when TMWTable is closed. Setting Active property will open or close TMWTable according to the value set.


TMWTable AfterCancel
TMWTable.AfterCancel

Occurs after an application completes a request to cancel modifications to the current record.

property AfterCancel: TDataSetNotifyEvent;

Description

Write an AfterCancel event handler to take specific action after an application cancels changes to the current record. AfterCancel is called by the Cancel method after it updates the cursor position, releases the lock on the current record if necessary, and sets the dataset state to dsBrowse. If an application requires additional processing before returning control to a user after a Cancel event, code it in the AfterCancel event.


TMWTable AfterClose
TMWTable.AfterClose

Occurs after an application closes a dataset.

property AfterClose: TDataSetNotifyEvent;

Description

Write an AfterClose event handler to take specific action immediately after an application closes a dataset. AfterClose is called after a dataset is closed and the dataset state is set to dsInactive.


TMWTable AfterDelete
TMWTable.AfterDelete

Occurs after an application deletes a record.

property AfterDelete: TDataSetNotifyEvent;

Description

Write an AfterDelete event handler to take specific action immediately after an application deletes the current record in a dataset. AfterDelete is called by Delete after it deletes the record, sets the dataset state to dsBrowse, and repositions the cursor on the record prior to the one just deleted.

AfterDelete can also be used to keep track of user changes in data and build a request to update tables at server side.


TMWTable AfterEdit
TMWTable.AfterEdit

Occurs after an application starts editing a record.

property AfterEdit: TDataSetNotifyEvent;

Description

Write an AfterEdit event handler to take specific action immediately after dataset enters edit mode. AfterEdit is called by Edit after it enables editing of a record, recalculates calculated fields, and calls the data event handler to process a record change. AfterEdit event handler can be used to keep track of edited data to build a request to be sent back to MidWare application server to update tables at server side.


TMWTable AfterInsert
TMWTable.AfterInsert

Occurs after an application inserts a new record.

property AfterInsert: TDataSetNotifyEvent;

Description

Write an AfterInsert event handler to take specific action immediately after an application inserts a record. AfterInsert is called by Insert and Append after inserting or appending a new record. This could be used to keep track of all inserted or appended data to build a request to be sent back to MidWare application server to update table at server side.


TMWTable AfterOpen
TMWTable.AfterOpen

Occurs after an application completes opening a dataset and before any data access occurs.

property AfterOpen: TDataSetNotifyEvent;

Description

Write an AfterOpen event handler to take specific action immediately after an application opens the dataset. AfterOpen is called after the cursor for the dataset is opened and the dataset is put into dsBrowse state.


TMWTable AfterScroll
TMWTable.AfterScroll

Occurs after an application scrolls from one record to another.

property AfterScroll: TDataSetNotifyEvent;

Description

Write an AfterScroll event handler to take specific action immediately after an application scrolls to another record as a result of a call to the First, Last, MoveBy, Next, Prior, FindKey, FindFirst, FindNext, FindLast, FindPrior, and Locate methods. AfterScroll is called after all other events triggered by these methods and any other methods that switch from record to record in the dataset.


TMWTable AppSrvClient
TMWTable.AppSrvClient

property AppSrvClient : TAppSrvClient;

Description

To execute a request at design time, TMWTable need an TAppSrvClient component which will handle communication with MidWare application server.


TMWTable AutoCalcFields
TMWTable.AutoCalcFields

property AutoCalcFields: Boolean;

Description

Set AutoCalcFields to control when the OnCalcFields event is triggered to update calculated fields during dataset processing. A calculated field is one that derives its value from the values of one or more fields in the dataset, sometime with additional processing.


TMWTable BeforeCancel
TMWTable.BeforeCancel

Occurs before an application executes a request to cancel changes to the current record.

property BeforeCancel: TDataSetNotifyEvent;

Description

Write a BeforeCancel event to take specific action before an application carries out a request to cancel changes. BeforeCancel is called by the Cancel method before it cancels a dataset operation such as Edit, Insert, or Delete.

An application might use the BeforeCancel event to record a user’s changes and build a request to send updates to MidWare application server.


TMWTable BeforeClose
TMWTable.BeforeClose

Occurs before an application executes a request to close the dataset.

property BeforeClose: TDataSetNotifyEvent;

Description

Write a BeforeClose event to take specific action before an application closes a dataset. Calling Close or setting the Active property to False results in a call to the BeforeClose event handler.


TMWTable BeforeDelete
TMWTable.BeforeDelete

Occurs before an application attempts to delete the current record.

property BeforeDelete: TDataSetNotifyEvent;

Description

Write a BeforeDelete event handler to take specific action before an application deletes the current record. BeforeDelete is called by Delete before it actually deletes a record.

Making use of this event an application might, for example, display a dialog box asking for confirmation before deleting the record. On denial of confirmation, the application could abort the deletion by calling the Abort procedure.

BeforeDelete can also be used to keep track of user changes in data and build a request to update tables at server side.


TMWTable BeforeEdit
TMWTable.BeforeEdit

Occurs before an application enters edit mode for the current record.

property BeforeEdit: TDataSetNotifyEvent;

Description

Write a BeforeEdit event handler to take specific action before an application enables editing of the current record. For example, an application might keep a log of database edits, and therefore might record the edit request, time, and user in a BeforeEdit event before entering edit state. This log can be used to generate update command to be send back to MidWare application server.


TMWTable BeforeInsert
TMWTable.BeforeInsert

Occurs before an application enters insert mode.

property BeforeInsert: TDataSetNotifyEvent;

Description

Write a BeforeInsert event handler to take specific action before an application inserts or appends a new record. BeforeInsert is called by Insert or Append before they set the dataset into dsInsert state.


TMWTable BeforeOpen
TMWTable.BeforeOpen

Occurs before an application executes a request to open a dataset.

property BeforeOpen: TDataSetNotifyEvent;

Description

Write a BeforeOpen event handler to take specific action before an application opens a dataset for viewing or editing. BeforeOpen is triggered when an application sets the Active property to True for a dataset or an application calls Open.


TMWTable BeforeScroll
TMWTable.BeforeScroll

Occurs before an application scrolls from one record to another.

property BeforeScroll: TDataSetNotifyEvent;

Description

Write a BeforeScroll event handler to take specific action immediately after an application scrolls to another record as a result of a call to the First, Last, MoveBy, Next, Prior, FindKey, FindFirst, FindNext, FindLast, FindPrior, and Locate methods. BeforeScroll is called before all other events triggered by these methods and any other methods that switch from record to record in the dataset.


TMWTable CanModify
TMWTable.CanModify

property CanModify: Boolean;

Description

CanModify readonly property returns TMWTable ReadOnly value.


TMWTable CreateBlobStream
TMWTable.CreateBlobStream

function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; virtual;;

Description

Call CreateBlobStream to obtain a stream for reading and writing the value of the field specified by the Field parameter. The Mode parameter indicates whether the stream will be used for reading the field’s value (bmRead), writing the field’s value (bmWrite), or modifying the field’s value (bmReadWrite).


TMWTable Data
TMWTable.Data

property  Data : TMWBuffer;

Description

Data property is a link to TMWBuffer component used to hold all data. TMWTable is just an interface, it doesn't contains any data. You can think of it as being a presentation layer.

TMWTable must be closed if you wants to change Data property. Data is presented as a table using FieldLayout property to describe columns.


TMWTable DesignTimeRequest
TMWTable.DesignTimeRequest

procedure DesignTimeRequest;

Description

DesignTimeRequest procedure will execute the request specified at design time. To execute the same request at runtime, you must call DesignTimeRequest.


TMWTable ExecuteRequest
TMWTable.ExecuteRequest

procedure ExecuteRequest;

Description

Call ExecuteRequest procedure to execute design time request. Be aware that ExecuteRequest will modify AppSrvClient properties and event handler.


TMWTable FieldLayout
TMWTable.FieldLayout

property FieldLayout  : TFieldLayout;

TFieldLayout = String;

const

  FieldTypesOrdinals : array [0..12] of TFieldType =

     (ftString, ftInteger, ftSmallInt, ftWord,     ftDateTime,

      ftDate,   ftTime,    ftFloat,    ftCurrency, ftBoolean,

      ftBlob,   ftMemo,    ftGraphic);

  FieldTypesNames : array [0..12] of String =

     ('Char', 'Integer', 'SmallInt', 'Word',     'DateTime',

      'Date', 'Time',    'Float',    'Currency', 'Boolean',

      'Blob', 'Memo',    'Graphic');

Description

FieldLayout property is used to describe columns content. It is a string made of semi-colon separated list of data. There is three items per column. First item is column name, second item is column data type, third item is colmun width.

Data types are designated by keywords (See FieldTypesNames above) or single letter for compatibility with old version ('C' -> 'Char', 'D' -> 'Date', 'N' -> 'Numeric', 'F' -> 'Float', 'L' -> 'Boolean'). It is not recommended to use those single letter data types. Data types keywords correspond to stnadard Delphi TFieldType data type. Conversion is as per table FieldTypesOrdinals above.

You don't need to know the string representation if you use the object inspector at design time because there is a property editor that let you design the field layout interactively. You need to use string representaion at runtime if you wants to load/save it from/to an ini file or the registry or transport it from the application server to your client application.

FieldLaout value may be different from what is really stored inside TMWBuffer. Non existant fields will be empty, extra fields will not be shown. TMWTable can't always accurately show TMWBuffer content because TMWBuffer has a variable structure: number of fields may vary from record to record and field length can be anything from 0 bytes to several megabytes while a TMWTable present records with fixed number of fields each one of fixed size.


TMWTable FunctionCode
TMWTable.FunctionCode

property FunctionCode : String;

Description

FunctionCode and Params properties are the design time request. It's main purpose is to populate data aware controls link to TMWTable at design time. It can also be executed at runtime using ExecuteRequest.


TMWTable Locate
TMWTable.Locate

function Locate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): Boolean;

Description

Implements a method for searching a dataset for a specified record and makes that record the current record. This function returns False, indicating that a matching record was not found and the cursor is not repositioned.


TMWTable OnLookup
TMWTable.Lookup

function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant;

Description

Implements a method to retrieve field values from a record that matches specified search values. This function returns False, indicating that a matching field was not found.


TMWTable MWBufferFieldCount
TMWTable.MWBufferFieldCount

property  MWBufferFieldCount : Integer;

Description

The number of fields. Based on FieldLayout property. See also FieldCount property inherited from TDataSet (see Delphi TDataSet help).


TMWTable OnCalcFields
TMWTable.OnCalcFields

Occurs when an application recalculates calculated fields.

property OnCalcFields: TDataSetNotifyEvent;

Description

Write an OnCalcFields event handler to take specific action when an application recalculates calculated fields. A calculated field is one that derives its value from the values in one or more fields in the dataset, sometimes with additional processing.


TMWTable OnDeleteError
TMWTable.OnDeleteError

Occurs when an application attempts to delete a record and an exception is raised.

type

  TDataAction = (daFail, daAbort, daRetry);

  TDataSetErrorEvent = procedure(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction) of object;

property OnDeleteError: TDataSetErrorEvent;

Description

Write an OnDeleteError event handler to handle exceptions that occur when an attempt to delete a record fails. E is a pointer to the database error object that contains the exception error message so that an application can display an error message. Action indicates how the handler should respond to the error.

See Delphi help about TDataSet.OnDeleteError for more details.


TMWTable OnDisplayInfo
TMWTable.OnDisplayInfo

Occurs when TMWTable wants to display debugging informations.

type

    TDisplayInfo = procedure (Sender: TObject; const Msg: String) of Object;

property OnDisplayInfo: TDisplayInfo

Description

This is used for debugging purpose and should normally not be used in an application. The event handler should display string message somehow on the user interface or log it to some file.


TMWTable OnEditError
TMWTable.OnEditError

Occurs when an application attempts to modify or insert a record and an exception is raised.

type

  TDataAction = (daFail, daAbort, daRetry);

  TDataSetErrorEvent = procedure(DataSet: TDataSet; E: EDatabaseError;var Action: TDataAction) of object;

property OnEditError: TDataSetErrorEvent;

Description

Write an OnEditError event handler to handle exceptions that occur when an attempt to edit a record fails. E is a pointer to the database error object that contains the exception error message so that an application can display an error message. Action indicates how the handler should respond to the error.

See Delphi help about TDataSet.OnEditeError for more details.


TMWTable OnNewRecord
TMWTable.OnNewRecord

Occurs when an application inserts or appends a new dataset record.

property OnNewRecord: TDataSetNotifyEvent;

Description

Write an OnNewRecord event handler to take specific actions as an application inserts or appends a new record. OnNewRecord is called as part of the actual insert or append process. An application might use the OnNewRecord event to set initial values for a record or as a way of implementing cascading insertions in related datasets.


TMWTable OnPostError
TMWTable.OnPostError

Occurs when an application attempts to modify or insert a record and an exception is raised.

type

  TDataAction = (daFail, daAbort, daRetry);

  TDataSetErrorEvent = procedure(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction) of object;

property OnPostError: TDataSetErrorEvent;

Description

Write an OnPostError event handler to handle exceptions that occur when an attempt to edit a record fails. E is a pointer to the database error object that contains the exception error message so that an application can display an error message. Action indicates how the handler should respond to the error.

See Delphi help about TDataSet.OnPostError for more details.


TMWTable OnRequestDone
TMWTable.OnRequestDone

Occurs when design time request has been satisfied and a result set is available.

type

TRequestDone  = procedure (Sender : TObject; Error        : Integer) of object;

property OnRequestDone : TRequestDone

Description

When design time request has been executed, then event OnRequestDone is triggered. You may use it for example to update user interface.


TMWTable Params
TMWTable.Params

property Params : TRequestParams;

TRequestParams = String;

Description

FunctionCode and Params are design time request. It's main purpose is to populate data aware controls link to TMWTable at design time. It can also be executed at runtime using ExecuteRequest.

Request parameters are normally a TMWBuffer. Here for use from within the IDE, the Params property is a string that will be turned into a TMWBuffer before being used. Conversion is done using quoted strings with semi-colon field delimiters. Exmaple "This is first";"and second";"fields".


TMWTable ReadOnly
TMWTable.ReadOnly

property ReadOnly: Boolean;

Description

ReadOnly property is used to get or set TMWtable read only status. See also CanModify.


TMWTable RecordSize
TMWTable.RecordSize

property RecordSize: Word;

Description

The record size property gives the size of the record. It is a readonly computed value based on the FieldLayout property. Remember that the data is stored TMWBuffer component which has variable length record as each TMWBuffer record can have a variable number of fields each one having a variable length.


TMWTable TimeOut
TMWTable.TimeOut

property Timeout : Integer;

Description

When executing a request at design time, TMWTable will stop waiting for answer after Timeout seconds.


TRequestBroker
TRequestBroker Component

Properties  Events  Methods


TRequestBroker Properties

TRequestBroker  Events  Methods

DisplayMemo

IniFileName

UserData

ObjectCount

ObjectCountLabel

Options


TRequestBroker Events

TRequestBroker  Properties  Methods

OnDisplay

OnObjCreate

OnObjDestroy


TRequestBroker Methods

TRequestBroker  Properties  Events

AddServerObject

AddServerObjectWithReference

BrokeRequest

EnumServerFunction


TRequestBroker AddServerObject
TRequestBroker.AddServerObject

procedure AddServerObject(ServerObjectClass : TServerObjectClass);

Description

AddServerObject should be called from the main application server code, at startup to build the request broker object table. This table associates objects and request. Each TServerObject has a FunctionCode (which default to the server object name without the leading TServerObject). Note hat the argument for AddServerObject is an object class, not an object instance.

AddServerObject must not be called when TServerObject are dropped on the server's form. It is intended for object added at runtime.

See also AddServerObjectWithReference.


TRequestBroker AddServerObjectWithReference
TRequestBroker.AddServerObjectWithReference

procedure AddServerObjectWithReference(ServerObjectClass    : TServerObjectClass; ServerObjectInstance : TServerObject);

Description

AddServerObjectWithReference does the same job as AddServerObject and also initialize the reference in added TServerObject to make TServerObject.CopyFromReference works correctly. AddServerObjectWithReference should not be used in normal application servers.


TRequestBroker BrokeRequest
TRequestBroker.BrokeRequest

type

    TSendResponseToClient =

        procedure (Dest     : TObject;

                   ORB      : TRequestBroker;

                   Status   : Integer;

                   Response : PChar;

                   Len      : Integer) of object;

procedure BrokeRequest(Sender : TObject; RqBuffer : PChar; RqLength : Integer; Tag : TObject; SendResp : TSendResponseToClient);

Description

BrokeRequest is the ORB main method. This is the method which does all the work: creack header, find and instanciate TServerObject, execute server object code and send result back to the client.

RqBuffer and RqLength argument are the request buffer address and length. Tag is a reference to internal TWSocket component used for communication with client. SendResp is a pointer to the method which will be used to send result set back to client.

BrokeRequest should not be used in a normal application server because it is invoked automatically by TAppServer component when a client send a request.


TRequestBroker DisplayMemo
TRequestBroker.DisplayMemo

property DisplayMemo : TCustomMemo;

Description

TRequestbroker component use DisplayMemo property to display informative messages. This is useful to build an application server with virtually no programming. See also ObjectCountLabel.


TRequestBroker EnumServerFunctions
TRequestBroker.EnumServerFunction

type

    TEnumServerFunctions =

        function (Sender : TObject;

                  FunctionCode : String) : Boolean of object;

procedure  EnumServerFunctions(CallBack : TEnumServerFunctions);

Description

This method is used to enumerate all server functions. The main purpose is to built some way to display all the server functionnalities such as function code list.


TRequestBroker IniFileName
TRequestBroker.IniFileName

property IniFileName : String;

Description

Used to pass an INI file name to TServerObject. Not used by MidWare code, but handy in real world applications.


TRequestBroker UserData
TRequestBroker.UserData

property UserData : LongInt;

Description

UserData is not used by the request broker nor the application server component TAppServer. It is there for the application server's writer to pass global data between the main application server code and each TServerObject, such as TTable of any other data.


TRequestbroker ObjectCount
TRequestBroker.ObjectCount

property ObjectCount : Integer;

Description

Readonly property. Number of currently instanciated server objects. Useful for information purpose or to estimate server load.


TRequestBroker ObjectCountLabel
TRequestBroker.ObjectCountLabel

property ObjectCountLabel : TLabel;

Description

TRequestbroker component use ObjectCountLabel property to display ObjectCount property value. This is useful to build an application server with virtually no programming. See also DisplayMemo.


TRequestbroker OnDisplay
TRequestBroker.OnDisplay

Occurs when the component need to display something on the user interface such as error or informatinal messages.

type

    TDisplayEvent = procedure (Sender : TObject; Msg : String) of object;

property OnDisplay : TDisplayEvent;


TRequestBroker OnObjCreate
TRequestBroker.OnObjCreate

Occurs when an object has been instanciated.

type

    TInstanciationEvent = procedure (Sender : TObject; ServerObject : TServerObject) of object;

property OnObjCreate : TInstanciationEvent;

Description

OnObjCreate can be used to update the user interface or to log server activity into a log file.


TRequestBroker OnObjDestroy
TRequestBroker.OnObjDestroy


TRequestBroker Options
TRequestBroker.Options


TServerObject

Properties  Events  Methods

TServerObject is the ancestor (abstract class) for all objects responsible for doing the application server work. The ORB create instances of server object, pass client request to them and call their Execute method. When the server object work is done, it must call the Finish method to send the response back to the client. This can be done either from the Execute method or form any other point later in time.

Writing an application server is mostly writing TServerObject. Application server performance entirely depends on TServerObject performance.


TServerObject Properties

TServerObject  Events  Methods

FFunctionCode

FIniFileName

FRequestBuffer

FResponseBuffer

FResponseSize

FResultStatus

FUserData

FORBDataPtr

FServerObjectClass

RequestBroker


TServerObject Events

TServerObject  Properties  Methods

FOnRequestDone

FOnDisplay


TServerObject Methods

TServerObject  Properties  Events

BuildFunctionCode

CopyFromReference

Execute

Finish

GiveRequest

Initialize

TriggerDisplay


TServerObject BuildFunctionCode
TServerObject.BuildFunctionCode

procedure BuildFunctionCode; virtual;

Description

BuildFunctionCode will initialize FFunctionCode with the function code handled by the ServerObject. Default to the class name without TServerObject.

BuildFunctionCode is called by the ORB (Object Request Broker) when building his object table. Most TServerObject do not need to override this method unless it wants to have a FFunction code not derived from the class name.

Example:

procedure TMyServerObject.BuildFunctionCode;

begin

    FFunctionCode := 'MYCUSTOMFUNCTIONNAME';

end;


TServerObject CopyFromReference
TServerObject.CopyFromReference

procedure CopyFromReference(Reference : TServerObject); virtual;

Description

CopyFromReference is called by the ORB when TServerObject has been instanciated and before the Execute method is called. A TServerObject is a component that can be dropped on a TForm at design time and have properties assigned using the IDE byt the programmer at design time. At runtime, new instances are created to satisfy client requests. Those instances are created by the ORB when needed. CopyFromReference is called by the ORB to give a chance to TServerObject to copy property values from the reference object dropped on the form.

Use of CopyFromReference is only needed if you write a TServerObject that has new published properties or events. In that case, you must use override CopyFromReference to copy those properties and events from the reference object dropped on the server form to the newly instanciated object.


TServerObject Execute
TServerObject.Execute

procedure Execute; virtual;

Description

The ORB (Object Request Broker, TRequestBroker component) call Execute     method to make the server object do his work: execute the request and produce a response. You MUST override this method and place the effective code for the server object work. A TServerObject without Execute method do nothing !

Execute method is one of the most important method of a TServerObject. In fact, it is often the only procedure you will write in your TServerObject. The overall performance for your server directly depends on the performance of this procedure. The best Execute method is one that execute almost instantaneously.

There are two design possibilities:

a) Execute method will do all the work that TServerObject has to do

b) Execute method will start processing and return immediately.

Option (b) can be split into two sub-options:

b1) Execute start an asynchonous (event driven) component or object

b2) Execute start a thread to do the job

While a TServerObject is executing his Execute method, no other object can be instanciated. Multitasking is almost down while Execute is executing. This is why you'd better do the work outside of the Execute method, using an asynchonous, event driven component or object, or a thread.

Once a TServerObject has finished his work, it must call Finish method to return data back to the client. If Finish is called from within Execute, it must be the last statement before returning from Execute. Using option (b) above, Finish is not called from Execute, but from thread termination code, or asynchonous component final event (often called OnRequestDone).

When Execute method gets control, parameters from client is received in the FRequestBuffer property. Most TServerObject retrieve parameters to know what to do. For example data to append to a database or key used to fetch data from database.

TServerObject has to produce an result set and an answer to return back to the client. Result set is to be stored in FResponseBuffer. Answer is to be stored in FResultStatus property. FResultStatus is a string. The value is never used by MidWare framework and is left to the application designer. But by convention it is often used like the FTP and HTTP protocols: FresultStatus begin by a number which gives some error code. Sample programs in MidWare package use '200' as a normal result, any other value being some kind of error.

Examples

The following sample is a trivial Execute method. It take no parameters and return a result set made of a single record with a single field:

procedure TServerObjectHelloWorld.Execute;

begin

    FResponseBuffer.WriteFields(TRUE, ['Hello World']);

    FResultStatus := '200';

    Finish;

end;

The following sample is an Execute method that convert input data (request parameters) to uppercase:

procedure TServerObjectUpperCase;

var

    I : Integer;

begin

    // While loop to iterate thru all records

    while not FRequestBuffer.Eof do begin

        // For loop to iterate thru all fields

        for I := 0 to FRequestBuffer.FieldCount - 1 do

            FResponseBuffer.WriteFields(

                  I = 0,

                  [UpperCase(FRequestBuffer.Fields[I])]);

        FRequestBuffer.Next;

    end;

    FResultStatus := '200';

    Finish;

end;

Following sample use a TTable to access a database. TTable is dropped on server's main form and initialized by main server code. This is done for simplicity but it is not recommended because it make a TServerObject dependent upon a given server. See FUserData property for a recommended implementation.

procedure TServerObjectGETCLIENT.Execute;

var

    UData : PUserDataRecord;

    Fld   : Integer;

    Key   : String;

begin

    CliTable.Active := TRUE;

    Key := UpperCase(FRequestBuffer.Fields[0]);

    CliTable.IndexName := 'LAST';

    CliTable.SetKey;

    CliTable.FieldByName('LAST').AsString := Key;

    if CliTable.GotoKey then begin

        // Data found

        FResultStatus := 200;

        // Copy all fields from the table to the response set

        for Fld := 0 to CliTable.FieldCount - 1 do

            FResponseBuffer.WriteFields(

                FALSE, [CliTable.Fields[Fld]]);

    end

    else begin

        // Data not found

        FResultStatus := 400;

        FResponseBuffer.WriteFields(

             FALSE, [Key, 'not found']);

    end;

    Finish;

end;


TOPIC_163
TServerObject.FunctionCode

protected FFunctionCode : String;

Description

The FunctionCode is used by the ORB to know how to dispatch client requests to the various server objects he has in his table. By default the FunctionCode is derived from the server object class name and is the class name without the leading TServerObject. You can override the BuildFunctionCode method to change that behaviour. The function code is case insensitive.


TOPIC_169
TServerObject.FIniFileName

protected FIniFileName : String;

Description

Initialized by ORB with INI filename. Used for persistant data.


TServerObject Finish
TServerObject.Finish

procedure Finish; virtual;

Description

The server object MUST call this method to signal the ORB (Object Request Broker, TRequestBroker component) that the server's object work is done and the response is ready to be sent to the client. You can call Finish just before returning from the Execute method, or at some later moment if the server object continue processing in the background after the Execute method has returned control back to the ORB (this means you have written an event driven server object or a multi-threaded server object). While Execute method code runs, no other client is serviced. If the processing is long, you probably wants to start a thread to do the processing in the background and call Finish method at a later time, or wants to write a fully event-driven server object which works by sending messages.


TServerObject FRequestBuffer
TServerObject.FRequestBuffer

protected FRequestBuffer : TMWBuffer;

Description

FRequestBuffer is a TMWBuffer component holding all parameters from client request.


TServerObject FResponseBuffer
TServerObject.FResponseBuffer

protected FResponseBuffer : TMWBuffer;

Description

FResponseBuffer is a TMWBuffer component that TServerObject must fill with result set. See also FResultStatus which is used to hold a string answer indicating succes or failure. See Execute description for a discussion about this topic.


TServerObject FResponseSize
TServerObject.FResponseSize

protected FResponseSize : Integer;

Description

FResponseSize is the initial size for FResponseBuffer. It default to 1024. You can change that value in your TServerObject by overriding Create method and assign a different value. You may also set FResponseBuffer.AutoExpand to some value other than default one which is 1024.


TServerObject FResultStatus
TServerObject.FResultStatus

protected  FResultStatus : Integer;

Description

ResultStatus returned to client. MidWare framework never use that value. It is up to the application designer to choose appropriate values. All MidWare samples use a numeric value based on the model used by the HTTP protocol: 200 means OK, 400 means error. See HTTP protocol reference. FResultStatus value is returned in the client's TAppSrvClient.AnswerStatus property as a string.


TServerObject FUserData
TServerObject.FUserData

protected FUserData : LongInt;

Description

Reserved for the TServerObject descendent writer. It is generally used to pass global data from the application server to the various server object. For example TTable or any other global data. Using FUserData is far better way of programming than using global variables.

FUserData is declared as a LongInt (32 bits). You can use it to store a pointer and use that pointer with appropriate casting. An example of use is to create a record with all global data, and pass the address of this record into FUserData. Define this record in a separate unit. So all TServerObject may access global data.


TServerObject FORBDataPtr
TServerObject.FORBDataPtr

type

    TORBData = record

        SendResp  : TSendResponseToClient;

        Tag       : TObject;             // CliWSocket

        Item      : Integer;

        ORB       : TRequestBroker;      // RequestBroker

        AppServer : TObject;             // AppServer

    end;

    PORBData = ^TORBData;

protected FORBDataPtr : PORBData;

Description

FORBDataPtr is a pointer to data allocated by the ORB.


TServerObject FServerObjectClass
TServerObject.FServerObjectClass

type

    TServerObjectClass = class of TServerObject;

protected FServerObjectClass : TServerObjectClass;

Description

FServerObjectClass is initialized in constructor with ClassType for the current TServerObject. It is later used by RequestBroker to instanciate the TServerObject. Normaly not used by TServerObject descendent.


TServerObject FOnRequestDone
TServerObject.FOnRequestDone

protected FOnRequestDone : TNotifyEvent;

Description

FOnRequestDone is an internal event used by ORB to do some work at the end of TServerObject processing. Finish method will trigger the event handler. Normally not used in a descendent TServerObject.


TServerObject FOnDisplay
TServerObject.FOnDisplay

type

    TDisplayEvent = procedure (Sender : TObject; Msg : String) of object;

protected FOnDisplay : TDisplayEvent;

Description

FOnDisplay is used for debugging purpose. It allows a TServerObject to display informations using ORB same event.


TServerObject GiveRequest
TServerObject.GiveRequest

protected  procedure GiveRequest(RqBuffer : PChar; RqLength : Integer); virtual;

Description

The ORB (Object Request Broker, TRequestBroker component) call this method to pass a request from the client to the server object. Normally not used in TServerObject descending components.


TServerObject Initialize
TServerObject.Initialize

protected procedure Initialize; virtual;

Description

The ORB (Object Request Broker, TRequestBroker component) call this method when the server object must be initialized. This is done only ONCE per server run. This procedure can be overriden to place any code needed to initialize global data for the server object.


TServerObject RequestBroker
TServerObject.RequestBroker

property RequestBroker : TRequestBroker;

Description

RequestBroker property tell TServerObject component which ORB it depends from. This property is only used when TServerObject is dropped on a form without being explicitely added at runtime. See TRequestBroker.AddServerObject.


TServerObject TriggerDisplay
TServerObject.TriggerDisplay

protected procedure TriggerDisplay(Msg : String); virtual;

Description

Triggers the FOnDisplay event, if assigned.


My first server

This is a step by step procedure to build our first server. Let's assume that we just wants a server able to return current date and time expressed as a string. Incredibly, we will write only FOUR lines to build such as server.

Step 1: Start a new project

Create a new application. Use Delphi "Menu/File/New application" and then "Menu/File/Save project as". When asked, replace "unit1.pas" by "FirstSv1.pas" and "project1.dpr" by "FirstSv.dpr".

Step 2: Create a main form

Make Form1 visible and using Delphi Object Inspector, change form's name from "Form1" to "MainForm" and form's caption from "MainForm" to "My First Server". Adjust form size so that it is raisonably small, something like 250x400 pixels.

Step 3: Create a user interface

Drop a TPanel on the form, change his align property to alTop and his name to ToolBarPanel, delete his caption property and set the height to 41 pixels. Then drop a TMemo on the form, name it DisplayMemo, change align to alClient.

On ToolBarPanel, drop 2 lables. Change label1.caption to "Client Count". Change label2.name to "ClientCountLabel". Drop two more labels on ToolBarPanel. Change label2.Caption to "Object Count" and Label3.Name to "ObjectCountLabel". Now you have an ordinary Delphi form. Save your work Menu/File/Save all. The compile and run, just to verify that everything is OK. Delphi must compile everything without error not warnings.

Step 4: Make it a server

Now let's enter real application server design. Easy ! Drop a TAppServer component and also a TRequestBroker on the form. Set AppServer1 RequestBroker property equal to "RequestBroker1", Options.asoAutoStart property to TRUE, ClientCountLabel property to "ClientCountLabel", DisplayMemo property to "DisplayMemo" and Banner property to "Welcome to my first Midware server". Set RequestBroker1 DisplayMemo property to "DisplayMemo" and ObjectCountLabel property to "ObjectCountLabel". Save your work, compile: Menu/Save all, then hit Ctrl-F9. Delphi should compile without error nor warnings.

Step 5:Server already works

Let's verify that our server is already working ! Run the server: hit F9 in Delphi. Then run Windows Telnet application (Start/Run/telnet). Arrange telnet and server windows so that they don't overlap. Make them smaller if necessary. Using telnet, connect to "127.0.0.1", port 2106 using VT100. You you receive and see the server's banner setup in step 4. If you don't see it, then verify previous steps. If you see the banner, notice that ClientCountLabel" display "1" because there is one client connected. Now send some request to the server: in telnet type "hello" then enter. You will probably not see what you type, but immediately after you hit enter, you'll get server's reply: "401 ***hello*Unknown request***" where the stars are control code displayed by telnet as blocks. On the server form, you'll see your request displayed: "127.0.0.1 hello". Everything is ok. Quit telnet and alse the server.

Step 6: A nice icon

This step is optional. Without icon, our TServerObject will use default icon. Start Image Editor from Delphi "Menu/Tools/Image Editor". From Image Editor, do "File/New/Component Resource File". Then "Menu/Resource/New/Bitmap" and create a 24x24 bitmap with VGA colors. Now rename bitmap1 to "TSOBJGETDATETIME". Do rename, use "Menu/Resource/Rename". Double click on the bitmap name to edit it. Draw some nice icon :-) then save your work under the name "SObjTime.dcr" in the same directory as your project. Close Image Editor and return to Delphi.

Step 7: Let Delphi create a TServerObject component

Now the code ! A TServerObject is just a component. We start a new component using Delphi component wizard: "Menu/Component/New Component". In Ancestor edit box, enter TServerObject. In Class Name edit box, enter TSObjGetDateTime. In Palette page edit box, enter "fpiette" or any other page you like. In Unit File Name edit box, enter full path name for SObjTime.pas (the path and file name must match what you gave when saving the image with Image Editor: component pas and dcr files must be in the same directory). Value in Search path should already be ok. Now click on "install" button. You have now the choice to install your TServerObject into an existing package, or a new one. You probably wants to put all your TServerObject in a single package. Click OK. Delphi will  create the new component, insert it into the package you specified and rebuild the package. After a few seconds, Delphi should tell that the component palette has been updated with your TServerObject. Click OK. You should see the source code for SObjTime.pas opened in Delphi editor. This is the basic component framework. You should also find the component icon in the component palette. Select it and drop it on your server form. Delphi will name it SObjGetDateTime1. That's ok. Change his RequestBroker property to "RequestBroker1".

Step 8: TServerObject works immediately

We will check that our server now understand "GETDATETIME" function code. We will again use telnet like in step 5 to connect to our server. This time instead of "hello", we will enter "getdatetime" and see that server answer "404 ***Base TServerObject called***". This is OK and means we forgot to add our own code. We will do it in next step. If you get a 401 answer, then maybe you made a typo error, either in telnet or we you built TServerObject. Go to previous step and verify everything.

Step 9: add application specific code to TServerObject

We have to write code to execute the assigned task for our TServerObject: get and return current date and time. Go to Delphi editor in SObjTime window. Find TSObjGetDateTime class declaration and add a line to the public section, like this:

   public

      procedure Execute; override;

Then implement the Execute method. Just before the "end." and the end of the source file, add the following code:

    procedure TSObjGetDateTime.Execute;

    begin

        FResultStatus := 200;

        FResponseBuffer.WriteFields(TRUE, [DateTimeToStr(Now)]);

        Finish;

    end;

The code is simple: FResultStatus will be the status code returned to the client. It will replace 404 code we seen in previous step. By convention, 200 means OK. FResponseBuffer is an object handled by the base class, used to hold the result set returned back to the client. We use WriteFields method to write a new record (this is the first argument) with a string value equal to the current date and time using standard Delphi functions Now and DateTimeToStr.

Step 10: finished server work nice and fast

When code is entered, compile the project and run (F9). Then again use telnet to connect to our first server and issue GETDATETIME command. This time, our server should anwser something like: "200 ***12/06/99 19:03:35***". Obviously, the value returned should be current date and time ! You can issue more commands with telnet and see that it works marvelously. If you stay to long without sending any command, our server will automatically disconnet the client. Telnet will complains that he lost connection. That's normal behaviour.

You can also start several telnet instances and connect using each one and see that it work OK with all. See on the server main form the client count increasing. If you have a network installed, you may also try from other computers. This time do not use 127.0.0.1 to connect with telnet, but the effective IP address or hostname for the computer running our first server. You may wants to use command line PING to check that TCP/IP is properly setup and working between each computer.


TOPIC_226


TClientWSocket GetPeerAddr
TClientWSocket.GetPeerAddr


TOPIC_262


TOPIC_263