RTC SDK Tutorial 1
RTC SDK Tutorial 1
9n
DeltaSoft
RealThinClient SDK
Quick-Start Guide
RealThinClient SDK
Write stable Clients, Servers and ISAPI extensions in Delphi 4 - 2006
Server:
Client:
RealThinClient SDK V1.9n
2
RealThinClient SDK V1.9n
HTTP protocol: RTC Clients will never have to be specially configured to get
No Firewall problems through corporate firewalls and reach the internet. Simply by
setting the UseProxy property to True, Data Client
connection will use a connection provider which uses the
same settings to read and send its data to the internet, as
MS Internet Explorer does for browsing the Web. This
means that Clients can work in any corporate LAN and have
full access to the internet.
3
RealThinClient SDK V1.9n
Plug-In Framework: All Client and Server code you write using RTC SDK is
write your own plug-ins ready to be used as building blocks or plug-ins in any
or use 3rd-party plug-ins application that uses RTC SDK. For example, you can
combine a Web Server, Messenger server, Application
server, Database server and your own functions in one Data
Server, even when those components weren't specially
designed to share the same Server space. Because of the
easy-to-use plug-in framework on top of which all RTC
Components are built, you can link unlimited number of
functionality and data providing components like
RtcDataProvider, RtcServerModule and/or
RtcDataServerLink to one Data Server connection
component, enhancing that server's functionality with each
new component. And by keeping code in separate units
(Data Modules), you can even provide your own plug-ins
(and sell those plug-ins) to anyone who uses the RTC SDK
Library.
4
RealThinClient SDK V1.9n
RtcHttpServer: implements the HTTP protocol over TCP/IP and is used to compile
RTC components into a stand-alone server application (extends TRtcDataServer).
All high-level server-side RTC components use TRtcDataServer descendants to
communicate with HTTP Clients (RTC Clients, Web Browsers, SOAP Clients, etc).
Best practice is to write all your code using high-level server-side RTC components
separated on different data modules, then use one extra DataModule where you will
use one RtcHttpSever to compile the functionality into a stand-alone server
application (EXE).
RtcISAPIServer: implements the ISAPI interface and is used for writing extensions
for ISAPI-compatible web servers (extends TRtcDataServer). All high-level server-
side RTC components use TRtcDataServer descendants to communicate with
HTTP Clients (RTC Clients, Web Browsers, SOAP Clients, etc). Best practice is to
write all your code using high-level server-side RTC components separated on
different data modules, then use one extra DataModule where you will use one
RtcISAPISever to compile the functionality into one ISAPI extension (DLL).
RtcDataProvider: used to implement events which will handle HTTP requests and
prepare responses (for example, client requests a file, which has to be read from a
local drive and written out as a response). Each Data Provider only responds to his
requests, ignoring the rest. This makes Data Providers work as plug-ins for the
Server, which can be used alone or in combination with other RTC components to
create a powerful and multifunctional Server.
5
RealThinClient SDK V1.9n
RtcDataServerLink: very useful when you have a number of Data Provider or Server
Module components spread across units, because it groups related Data Provider
components and links them to their Data Server connection. If you only have one or
any small number of Data Provider components, you can link them directly to Data
Server connection component, without the need of a RtcDataServerLink.
6
RealThinClient SDK V1.9n
Unless you decide to implement your own communication protocol by using low-
level connection components, this is the component that will be responsible for
direct communication with your servers: it sends requests prepared by higher-level
client-side RTC components like RtcDataRequest and RtcClientModule, then
accepts responses and uses the same higher-level components to process those
responses. Check Data Request components (Client side) for more info.
If you define client-side functions and link them to this RtcClientModule, this will be
the execution point of those client-side remote functions. No special implementation
needed. Client-side remote functions are functions which server can call on the
client-side as a result of client's calls to a server-side function.
RtcResult: process results received from remote function call(s). Using the
"OnResult" event, which receives the connection (Sender:TRtcConnection),
parameters sent (Param:TRtcValue) and the result received (Result:TRtcValue), you
can easily write the code to process the result. Maybe only do a simple check if
function executed successfully, or show a message dialog, or create a separate
form containing all data received, or fill received content into other component on the
same form or datamodule (for example, fill ClientDataSet with records from a
database).
RtcDataClientLink: very useful when you have a number of Data Request or Client
Module components spread across units, because it groups related client request
components and links them to their Data Client connection. If you only have one or
two data request components, you can link them directly to Data Client connection
component, without the need of a RtcDataClientLink.
7
RealThinClient SDK V1.9n
RealThinClient SDK : Data types used with Sessions and Remote Functions
RTC SDK supports all native and complex data types for working with Sessions and Remote
Functions. You can use any data type to store and access data in a session and/or to send
and receive data between clients and servers using RTC remote functions.
method: isType Returns type of data stored in a specific variable, used mostly in
check if and what kind of data has client sent as parameters to a
remote function call and to check if and what kind of data has
server sent back to the client as a result from a remote function
call.
type: rtc_Null Returns True if parameter is not set (it is "NULL"). You can set
access: isNull "isNull" to True to clear the variable/parameter.
type: rtc_Boolean
Boolean value (Delphi type: boolean)
access: asBoolean
type: rtc_Integer
Integer value (Delphi type: longint)
access: asInteger
type: rtc_LargeInt
Large Integer value (Delphi type: int64)
access: asLargeInt
type: rtc_Float
Float value (Delphi type: double)
access: asFloat
type: rtc_Currency
Currency value (Delphi type: currency)
access: asCurrency
type: rty_DateTime Date and Time value. Always use this type to work with Dates
access: asDateTime and Times (Delphi type: TDateTime)
type: rtc_String
String value (Delphi type: AnsiString, up to 2GB in size)
access: asString
type: rtc_Text Text value, automatically coded and encoded using UTF-8
access: asText (Delphi type: AnsiString)
type: rtc_WideString
Wide String value (Delphi type: WideString, up to 2GB in size)
access: asWideString
type: rtc_Variable
Use to send/receive variable names (Delphi type: AnsiString)
access: asVariable
8
RealThinClient SDK V1.9n
type: rtc_ByteStream Use to work with Streams. When you use "newByteStream", an
create: newByteStream in-memory stream will be created, which you can access using
access: asByteStream "asByteStream". When used with remote functions, data stored in
a stream will be sent/received between client/server as any other
data type.
type: rtc_Record Use to work with records. In records, each element is accessed
create: newRecord using a name (string). Each element in a record can be of any
access: asRecord type (even an array, record, dataset or function call).
type: rtc_Array Use to work with arrays. In arrays, each element is accessed
create: newArray using an index of type integer. Each element in an array can be of
access: asArray any type (even an array, record, dataset or function call).
9
RealThinClient SDK V1.9n
Introduction
If you want to use RealThinClient SDK components, the best place to start is this
QuickStart guide. After going through the online lessons, you should also go through
the QuickStart examples included in the RTC SDK package (QuickStart folder). You can
download the Open Source RTC SDK package before you get a commercial license.
Once you finish examining the QuickStart examples, I suggest browsing through the
FAQ and Support section. Even if you won't be reading all the articles, you should at
least get the feeling about the information included there. Another good source of
information are RTC SDK Demos, which are included in the RTC SDK package and
have a lot of examples and best practices for using the RealThinClient SDK.
And, last but not least, the most extensive source of information on the RealThinClient
SDK are Help files. Some of the information is spread across the files, but if you know
which class you need, you will most likely be able to find what you are looking for.
When you start working on your project, the FAQ will come in handy when you have to
do something specific (use Sessions, accept form post data, write and call remote
functions, etc). The FAQ is continually being extended, as more questions come in.
If you have a question for which you were unable to find the answer in the QuickStart
g u id e , Q u ickS ta rt e xa m p le s, th e F A Q o r th e S u p p o rt se ctio n … a n d se a rch in g th ro u g h
the Help files didn't give you the answers you need, don't hesitate to post your question
to the Developer Support section.
Licensed RTC SDK Bronze, Silver and Gold users can also send their question(s)
directly to me by E-Mail at [email protected]. Please include your Share*it order
number when asking questions by E-Mail.
10
RealThinClient SDK V1.9n
1 Start Delphi and open the appropriate rtcSDK_XY.dpk (Delphi Package) file,
located in the Lib folder.
2 Compile and install the package.
3 From Delphi menu, under Environment Options, select the "Library" tab and
add the full path to the "Lib" folder to "Library path".
4 You can then open any Demo project (from Demos folder) and compile it. If it
doesn't compile because of "missing files", you need to check and correct the
Library path in Environment Options and try again.
11
RealThinClient SDK V1.9n
When you run the project, your Server will immediately start to Listen on Port 80 (if you
used the Port number from this lesson).
NOTE: In case your Server doesn't start normally and you end-up with "Error 10048 in
function bind: Address already in use." exception, it means that you have another Web
Server running on Port 80 already.
Since only one application can listen on a specific port, you either have to change the
ServerPort in this example (maybe use Port 81) and compile the project again, or stop
the other WebServer before running this example, so you can use Port 80.
12
RealThinClient SDK V1.9n
NOTE: If you have changed the Port number to something different from 80 (standard
HTTP port), you will also have to use this port number in your browser. For example, if
you used Port 81, your URL should look like this:
http://localhost:81/time
This lesson continues where Server Lesson 1 stops. You will see in this lesson how two
data providers work together and how you can use multiple "Write" calls to send
complex content out. You can scroll down for the complete source code and textual
version of this lesson.
or small files or files where you feel can fit safely in your server's memory (for example,
up to 32K) or to prepare web site output, there's no need to split the transfer. You can
write the file out directly from the OnDataReceived event of your RtcDataProvider
component. You can also use the Write method consecutively.
Let's add a new RtcDataProvider component to our server app, which will produce a site
with a list of all square values from 1 to 100.
13
RealThinClient SDK V1.9n
If everything went ok, you should see a list of square values. You can also see that the
other data provider is till working by going to http://localhost/time
The same way, you can send binary data out. The only thing you need to do is read the
data into a string from the file. I will show you how to do this, in the next lesson.
14
RealThinClient SDK V1.9n
NOTE: We want to send a file out ONLY if other data providers didn't accept the request.
To achieve this, we have defined our place in the check order using the CheckOrder
property. Our assumption here is that that all other RtcDataProvider components have a
lower CheckOrder.
function GetFullFileName(fname:string):string;
var
DocRoot:string;
begin
// Get the executable file's folder name ...
DocRoot:=ExtractFilePath(ExpandFileName(ParamStr(0)));
// Make sure the file doesn't end with '\' ...
if Copy(DocRoot,length(DocRoot),1)='\' then
Delete(DocRoot,length(DocRoot),1);
// We want to use a sub-folder named '\data' ...
DocRoot:=DocRoot+'\data';
// Requests use "/" instead of "\" ...
fname:=StringReplace(fname,'/','\',[rfreplaceall]);
// Create file name containing full path
Result:=ExpandFileName(DocRoot+fname);
{ Check if the file is inside our folder
(don't want people to use "..\" to move out of this folder) }
if UpperCase(Copy(Result,1,length(DocRoot)))<>
UpperCase(DocRoot) then
Result:=''; // return empty file name.
end;
15
RealThinClient SDK V1.9n
{ We assume that the files will be short and we will be sending them
out in one run. In that case, we can simply send the whole file
out from our OnDataReceived event. }
var
fname:string;
begin
with TRtcDataServer(Sender) do
if Request.Complete then
begin
fname:=Request.Info['fname'];
if File_Exists(fname) then
Write(Read_File(fname))
else
{ 'Write' will ensure that
response is sent, even if empty. }
Write;
end;
end;
16
RealThinClient SDK V1.9n
I assumed that the file is small enough to be read in one call and sent out directly,
without splitting the thing in multiple events. With larger files, there is a small
modification we will have to do. I will come to this in the next lesson.
17
RealThinClient SDK V1.9n
Let's go and change the example from Lesson 3 a bit, so we can also send large files
with it. We will define a memory limit of 16K for a single event call, to keep our memory
usage as low as 16K for any client requesting a file from our server.
1 We will change the OnCheckRequest event for our last RtcDataProvider component, to
set the Response.ContentLength value to the file size. To do this, double-click on the
last RtcDataProvider component to jump to the OnCheckRequest event provider.
There is only a small addition to the event, but to keep it all in one place, here's the
complete new event implementation:
var
fname:string;
begin
with TRtcDataServer(Sender) do
begin
fname:=GetFullFileName(Request.FileName);
if (fname<>'') and (File_Exists(fname)) then
begin
Accept;
18
RealThinClient SDK V1.9n
2 Then, we will update the OnDataReceived event of our RtcDataProvider, to send only
limited amount of data out (let's set that limit to 16KB). And here is the updated
OnDataReceived event handler:
var
fname:string;
len:cardinal;
begin
with TRtcDataServer(Sender) do
if Request.Complete then
begin
// Check if we have to send more data.
if Response.ContentLength>Response.ContentOut then
begin
fname:=Request.Info['fname'];
// Only continue if the file hasn't changed in size.
if File_Size(fname)=Response.ContentLength then
begin
// calculate how much we still need to send.
len:=Response.ContentLength - Response.ContentOut;
// Limit the length to send at once to 16KB
if len>16000 then len:=16000;
// Send 'len' bytes from our file,
// starting at position "Response.ContentOut"
Write( Read_File(fname, Response.ContentOut, len) );
end
else
{ Disconnect the client, because our file
has changed and we have sent
the wrong header and file beginning out. }
Disconnect;
end;
end;
end;
3 We will use the same event handler method we defined for OnDataReceived for our
OnDataSent event. To do this, from the Object Inspector's Window, we can simply copy
the event name for the OnDataReceived event to the OnDataSent event.
Warning: do not remove the OnDataReceived event. Both events (OnDataReceived and
OnDataSent) should use the same implementation. That's all there is to it.
19
RealThinClient SDK V1.9n
What will happen exactly? First, the "OnCheckRequest" event will be called, which will
check if a file with requested name exists, then accept the request and set the
"Response.ContentLength" property (our file size) and write the response header out
(by calling "WriteHeader").
Then, "OnDataReceived" event will be called, but we won't react to it until we receive
the complete request body (Request.Complete).
After we get the complete request, we will send up to 16K of our file out. If the file is
larger than 16K, "OnDataSent" event will be called every time our data has been sent
out and it is safe to continue sending the next package.
On each call to our "OnDataSent" event, we will send up to 16K bytes of data out, until
our "Response.ContentOut=Response.ContentLength".
To test how this works, you can place a large file into the "/data" sub-folder, open your
favorite Internet browser and request the file. You will not see the difference at the client
side between the old and the new implementation, but the new implementation will only
use up to 16K of memory, while the old one will put the whole file into memory before
sending.
If you had the pleasure of writing dynamic HTML content using PHP, Java or some
other language, you already know something about HTTP headers
Task Command
Request method (GET, PUT, HEADER, etc) Request.Method
File name requested Request.FileName
Query variables coming after filename (the Request.Query[ variable_name ]
thing coming after '?' in the Http request)
Host (domain) name requested (the thing Request.Host, or Request['Host']
coming after "http://" and before the file name)
Type of the content received Request.ContentType, or
Request['Content-type']
20
RealThinClient SDK V1.9n
Task Command
Total Length of the Content client is sending: Request.ContentLength, or
Request['Content-length']
Read data received as contant body Read
Content bytes received in the request so far: Request.ContentIn
For more info on the TRtcDataServer.Request property, check the Help for these
classes:
-TRtcServerRequest
-TRtcRequest
- TRtcHttpHeader
Task Command
Type of the content you want to send out. Response.ContentType, or
Response['Content-type']
Length of the content you want to send out. Response.ContentLength, or
Response['Content-length']
If length was not set manually, it will be calculated automatically depending on the length
of the content that was written in the first event.
Task Command
Status code you want to send, Default = 200 Response.StatusCode
Status text you want to send, Default = OK Response.StatusText
For more info on the TRtcDataServer.Response property, check the Help for:
- TRtcServerResponse
- TRtcResponse
- TRtcHttpHeader
For more info on the TRtcHttpServer component, check the Help for these classes:
- TRtcHttpServer
- TRtcDataServer
- TRtcServer
- TRtcConnection
For more info on the TRtcISAPIServer component, check the Help for these classes:
- TRtcISAPIServer
- TRtcDataServer
- TRtcServer
- TRtcConnection
21
RealThinClient SDK V1.9n
For more info on the TRtcDataProvider component, check the Help for these classes:
- TRtcDataProvider
- TRtcAbsDataServerLink
I find that all things that can be done using the Object Inspector at design-time, should
be done using the Object Inspector at design-time, because it is much easier to do. And
for that, RtcDataServerLink is there to make it easier for you to connect a group of
RtcDataProvider or RtcServerModule components to your RtcDataServer connection
component (for example, RtcHttpServer).
Since there will be only one RtcDataServer component for the whole server app, but you
will most likely have a number of data modules with a number of RtcDataProvider and
RtcServerModule components on them, which all have to be linked to that one
RtcDataServer (and you can not do this at design-time if RtcDataServer is on a different
form or module), you can place a RtcDataServerLink component on every data module
(or form) where your components with server's functionality (RtcDataProvider,
RtcServerModule, RtcFunctionGroup, RtcFunction, etc) are and link those components
to that RtcDataServerLink. Then, at runtime, before you call RtcHttpServer.Listen (or
from the OnCreate event of your ISAPI Extension's main DataModule), you can set the
Server property for your RtcDataServerLink components, and don't have to do this in for
each RtcDataProvider or RtcServerModule component.
22
RealThinClient SDK V1.9n
4 from the "RTC Client" tab, put one RtcHttpClient on your main form:
set MultiThreaded = True
set ReconnectOn.ConnectLost = True
set ServerAddr = www.realthinclient.net
set ServerPort = 80
set UseProxy = True
5a from the "RTC Client" tab, put one RtcDataRequest on your form:
set Client = RtcHttpClient1
set AutoRepost = 2
set AutoSyncEvents = True
with TRtcDataClient(Sender) do
begin
// make sure our request starts with "/"
if Copy(Request.FileName,1,1)<>'/' then
Request.FileName:='/'+Request.FileName;
// define the "HOST" header
if Request.Host='' then
Request.Host:=ServerAddr;
Memo1.Text:='Requesting "'+Request.FileName+
'" from "'+ServerAddr+'".';
// send request header out
WriteHeader;
end;
23
RealThinClient SDK V1.9n
with TRtcDataClient(Sender) do
begin
if Response.Started then
begin
{ Executed only once per request,
when we start receiving the response. }
// Clear the info we wrote here in our "OnBeginRequest"
Memo1.Clear;
Memo1.Lines.Add('Status code: '+
IntToStr(Response.StatusCode));
Memo1.Lines.Add('Status text:'+
Response.StatusText);
Memo1.Lines.Add('ALL Headers:');
Memo1.Lines.Add(Response.HeaderText);
Memo1.Lines.Add('Content Length:');
Memo1.Lines.Add(IntToStr(Response.ContentLength));
Memo1.Lines.Add('Content body:');
Memo1.Lines.Add('START >');
end;
{ Could be executed more than once, depending on the content size }
// add content received now.
Memo1.Text:=Memo1.Text+Read;
if Response.Done then
begin
{ Executed only once per request,
when we have just received it all. }
Memo1.Lines.Add('< END');
end;
end;
24
RealThinClient SDK V1.9n
if Key=#13 then
with RtcDataRequest1 do
begin
Request.Method:='GET';
// request the file defined in the Edit field
Request.FileName:=Edit1.Text;
Edit1.SelectAll;
Post; // Post the request
end;
If everything went ok, after you start the project, you should see the HTML code of the
index file from the www.realthinclient.net server and be able to use the Edit field to enter
any file name and get its content inside the memo field after pressing the Enter key.
In this example, content is received piece-by-piece and filled into the Memo field by
adding the text Read to Memo's text and special care had to be taken to avoid clearing
the memo in the middle of receiving. If you want to receive all content at once, you can
change the "OnDataReceived" event for your RtcDataRequest1 to this:
with TRtcDataClient(Sender) do
if Response.Done then
begin
{ This will be called only once for every request.
That will be when we receive the complete response. }
// Clear the info we wrote in our "OnBeginRequest"
Memo1.Clear;
Memo1.Lines.Add('Status code: '+ IntToStr(Response.StatusCode));
Memo1.Lines.Add('Status text:'+ Response.StatusText);
Memo1.Lines.Add('ALL Headers:');
Memo1.Lines.Add(Response.HeaderText);
Memo1.Lines.Add('"CONTENT-LENGTH" Header:');
Memo1.Lines.Add(Response['CONTENT-LENGTH']);
Memo1.Lines.Add('Content Length as integer:');
Memo1.Lines.Add(IntToStr(Response.ContentLength));
Memo1.Lines.Add('Content body:');
// add all content received
Memo1.Lines.Add( Read );
end;
25
RealThinClient SDK V1.9n
Other interesting events when receiving data are the "OnResponseDone" and
"OnConnectLost" events. "OnResponseDone" event will be triggered after the last
"OnDataReceived" event (after all data has been received), while the "OnConnectLost"
event gets called in case your connection drops after executing the OnBeginRequest
event, but before you received the complete response in the OnDataReceived event.
To store received data in a stream, you can open the stream from the "OnDataReceived"
event when "Response.Started", append (to the stream) everything you "Read" from the
"OnDataReceived" event and close the stream from "OnResponseDone" and
"OnConnectLost" events.
26
RealThinClient SDK V1.9n
You will notice that this is the same thing we did for sending files and dynamic content
out. If you want to have a server that does multiple things, not only process remote
function calls, you can also start from point (5) on any of other Server lessons, to add
remote function capabilities.
4 from the RTC Server tab, put one RtcFunctionGroup on your form:
You will use one FunctionGroup for each Form or Module where you want to
implement remote functions.
5 from the RTC Server tab, put one RtcServerModule on your form:
set Server = RtcHttpServer1
set FunctionGroup = RtcFunctionGroup1
set ModuleFileName = '/mytest'
6a from the RTC Server tab, put one RtcFunction on your form:
set FunctionGroup = RtcFunctionGroup1
set FunctionName = 'hello'
27
RealThinClient SDK V1.9n
4 from the "RTC Client" tab, put one RtcHttpClient on your main form:
set AutoConnect = True
set MultiThreaded = True
set ReconnectOn.ConnectLost = True
set ServerAddr = localhost
set ServerPort = 80
set UseProxy = True
5a from the "RTC Client" tab, put one RtcClientModule on your form:
set Client = RtcHttpClient1
set AutoRepost = 2
set AutoSyncEvents = True
set ModuleFileName = '/mytest'
5b from the "RTC Client" tab, put one RtcResult on your form
28
RealThinClient SDK V1.9n
7 Start the Server (from Server Lesson 5), then Compile and Run this client
project.
If everything went ok, after you start both projects, when you enter some text in
the Edit field and press the Enter key, you will receive a response in your Memo
component.
In this example, we are passing a single string parameter ('name') and receive a
single string as a result. You can pass any kind of data to the server as
parameters and receive any structure as the result. Please check the FAQ for
more info.
29
RealThinClient SDK V1.9n
1 From the "Lib" folder (in RTC), open the "rtcISAPIProject.dpr" project. You will
use this project as a template for creating ISAPI Extensions.
2 Save this project in a folder of your choice, under a name of your choice.
Use the "Save Project as ..." option from the File menu to save this as your new
ISAPI extension project. After you have saved this project in a folder of your
choice, to complete your ISAPI extension creation, you will need one
DataModule with one rtcISAPIServer component on it.
4 from the RTC Server tab, put RtcISAPIServer on your new DataModule.
Now you have your first ISAPI extension ready, but it needs something to do.
You do not have to call Listen, nor set any properties for the RtcISAPIServer
component, since everything will be handled by your WebServer (RTC will
simply process requests).
For demonstration purposes, we will add the same "/Time" DataProvider to this
main DataModule (the same thing we did in the first Server Lesson).
30
RealThinClient SDK V1.9n
If everything went ok, there should be a new DLL in your Project's folder, ready to be
installed in your WebServer. After you install this DLL in your WebServer and start the
WebServer, you should be able to access this extension as any other ISAPI Extension
and use the "/TIME" request to get current Server's time.
To be able to write server-side code which can be compiled as a stand-alone server and
as ISAPI extension, you will place all your components on DataModules instead of
Forms and link them to one rtcDataServerLink (using the "Link" property of each
component) instead of linking them directly to a Server connection component.
All RTC SDK components will work the same, no matter if they are connected to a
RtcHttpServer or a RtcISAPIServer component. As long as you write your server-side
code in DataModules, you can create two projects: (1) one as a standard Windows
application which will use a RtcHttpServer component and (2) another as ISAPI
Extension project which will use a RtcISAPIServer component.
By linking your components from DataModules to the connect component your project
needs, you have one code which works as a stand-alone server and as ISAPI Extension.
Please check the "File_Server" and "App_Server" demos for more info.
31
RealThinClient SDK V1.9n
The best place to start looking for answers is on the RTC Forums, which are located
here: http://www.realthinclient.com/forum
32