<?xml version="1.0" encoding="iso-8859-1"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Matlus ISAPI, TCP/IP and Webservice Related Tutorials</title><link>http://exposureroom.com/members/skumar/</link><atom:link href="http://rss.exposureroom.com/MemberJournalRssProvider.aspx/skumar/tutorials/" rel="self" type="application/rss+xml" /><description><![CDATA[<ul>
<li>ISAPI</li>
<li>TCP/IP</li>
<li>HTTP</li>
<li>SOAP/XML/WebServices</li>
<li>N-tier Applications and Zero configuration thin Clients</li>
</ul>
You should be able to find information, tutorials and articles on the technologies listed above and their implementation in Delphi on this site. Whereever is makes sense, you should find on-line demos and/or downloadable project source code.

Please Rate the tutorials/articles wherever possible. This will help me improve the quality of material you see here.
]]></description><pubDate>Wed, 15 Feb 2012 07:51:16 GMT</pubDate><generator>ExposureRoom RSS Feed Generator v1.0</generator><language>en</language><item><title>Setting up IIS 7.0 - Ftp 7.5 for IIS Manager Users</title><pubDate>Wed, 16 Dec 2009 16:20:50 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/81/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/81/</guid><description><![CDATA[<div>&nbsp;</div>
<div>This tutorial is about setting up IIS Ftp 7.5 using IIS Manger Users under Window 7 or Windows 2008. I also assume you want to use User Isolation of "User name directory"&nbsp;or similar. The documentation I have found has been scarce or incomplete. Note that this tutorial is not about showing you how to use the IIS Management UI for IIS 7.0. I assume you know how to use the IIS Management UI for IIS 7.0</div>
<div>&nbsp;</div>
<h3>Setting up an Ftp Site</h3>
<div>Make sure you've installed&nbsp;<a href="http://learn.iis.net/page.aspx/310/what-is-new-for-microsoft-and-ftp-75/" rel="nofollow" target="_blank">Ftp 7.5</a> for your operating system (32bit or 64 bit). Then set up an Ftp site. you can find a step by step <a href="http://learn.iis.net/page.aspx/301/creating-a-new-ftp-site/" rel="nofollow" target="_blank">here</a>. It's not the greatest tutorial but it should work.</div>
<div>&nbsp;</div>
<h3>User Isolation</h3>
<div>Besides, actually setting up user isolation using the UI in IIS Manager, you also need to create a few folders and then give the user NetworkService the proper rights to these folders and to the IIS config files.</div>
<div>&nbsp;</div>
<div>You need to create the following folders as sub folder of your Ftp site's root folder. First create a folder called </div>
<pre>LocalUser</pre>
<div>Then under LocalUser, create a folder called</div>
<pre>public</pre>
<div>Under LocalUser again, create a folder with the name of the username of a windows user on the machine. You'll use this to test the ftp site. In order to test a with a windows user, you also need o have Basic Authentication turned on for yout ftp site. Do this using the Ftp Authentication icon for the Ftp you created.</div>
<div>&nbsp;</div>
<div>
<h3>Setting up the correct permissions</h3>
</div>
<div>To grant Special permissions to the user NetworkService to the Ftp Root folder (using a command prompt): </div>
<div>
<pre>CACLS "%SystemDrive%\inetpub\ftproot" /G "Network Service":C /T /E
Next the user NetworkService needs to be given permission to the config folder and two config files
CACLS "%SystemDrive%\Windows\System32\inetsrv\config" /G "Network Service":R /E
CACLS "%SystemDrive%\Windows\System32\inetsrv\config\administration.config" /G "Network Service":R /E
CACLS "%SystemDrive%\Windows\System32\inetsrv\config\redirection.config" /G "Network Service":R /E
</pre>
</div>
<div>Now you should be able to log on to the ftp site you created using the credentials of a windows user.</div>
<h3>IIS Manager Authentication</h3>
<div>For Windows 2008 you can follow this tutorial in order to configure Ftp with IIS Manager Authentication</div>
<a href="http://learn.iis.net/page.aspx/321/configure-ftp-with-iis-70-manager-authentication/" rel="nofollow" target="_blank">
<div>Configure FTP with IIS 7.0 Manager Authentication</div>
<div></div>
</a>&nbsp;
<div>Windows 7 does not have the UI that you'll find in Windows 2008. The other issue is that you can't simply modify the administration.config file because the password is normally saved in a hashed format.</div>
<div>&nbsp;</div>
<div></div>
But you can create IIS Manager Users&nbsp;using Managed Code. Below is a simple method you can add to your class of choice. In order for this code to work a few references need to be added to your project.<br>
<div>Add the following <strong>Reference Path</strong> to your project</div>
<div>C:\Windows\System32\inetsrv\</div>
<div>&nbsp;</div>
<div>Then added the following <strong>References</strong>:</div>
<div>Microsoft.Web.Administration</div>
<div>Microsoft.Web.Management</div>
<div>&nbsp;</div>
<div>Next,&nbsp;add the following <strong>namspaces</strong> to</div>
<div>using Microsoft.Web.Management.Server;<br>
using Microsoft.Web.Administration;&nbsp;</div>
<div>&nbsp;</div>
<div>The following is an explanation of the parameters this method expects.&nbsp;</div>
<div><code><strong>configurationPath</strong></code> - This is the name of the Ftp site. So you if called your Ftp site "Default Ftp Site", then pass in this string as the first parameter</div>
<div><code>username</code> - The username of the new user you want to create</div>
<div><code>password</code> - the password for the new user&nbsp;</div>
<div>&nbsp;</div>
<pre>private void CreateFtpUser(string configurationPath, string username, string password)
{
&nbsp;&nbsp;&nbsp;/* First Create the User for the ftp site */
&nbsp;&nbsp;&nbsp;ManagementUserInfo userInfo = ManagementAuthentication.CreateUser(username, password);
&nbsp;&nbsp;&nbsp;ManagementAuthorization.Grant(userInfo.Name, configurationPath, false);
&nbsp;&nbsp;&nbsp;/* Next set up the permissions for this user (Read/Write) */
&nbsp;&nbsp;&nbsp;using (ServerManager serverManager = new ServerManager())
&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Configuration config = serverManager.GetApplicationHostConfiguration();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConfigurationSection authorizationSection =
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config.GetSection("system.ftpServer/security/authorization", configurationPath);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConfigurationElementCollection authorizationCollection =
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;authorizationSection.GetCollection();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConfigurationElement newElement =
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;authorizationCollection.CreateElement("add");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newElement["accessType"] = @"Allow";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newElement["users"] = username;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newElement["permissions"] = @"Read, Write";
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;authorizationCollection.Add(newElement);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;serverManager.CommitChanges();
&nbsp;&nbsp;&nbsp;}
}
</pre>
<p>Be sure to create a sub folder under the LocalUser folder (under your ftp site's root folder)for the users you create using the code above. The username of the user and the folder name should be the same.</p>
<div>In order to be able to use IIS Manager Users with your Ftp site, you need to have the IisManagerAuth provider enabled for your Ftp site. Do this using the Ftp Authentication icon for your Ftp site and choose Customer Providers... from the actions pane.</div>
<div>&nbsp;</div>
<div>At this point, you should be able to log in to your Ftp site using the users</div>
<div>&nbsp;</div>
]]></description><category>Programming</category><category>Ftp 7.5</category><category>IIS 7.0</category></item><item><title>Building your First WebService in Delphi</title><pubDate>Wed, 23 Jan 2008 10:10:55 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/1/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/1/</guid><description><![CDATA[If you've been reading the Webservice articles on this site in the order that they are listed, then this is your first Webservice. As WebServices go, this is not the simplest of WebServices, but my thinking was that I could take you through the paces of building a Webservice that addresses some of things you'll need to know when building "real world" WebServices while at the same time not overwhelm you with all these new things. If you haven't read the previous articles, I strongly suggest you do. This tutorial assumes you have read those articles or know about the things that were discussed there. 
<p>In this tutorial, we'll start with building a WebService client for an existing WebService. Then we'll build the WebService itself. This way, you don't have to get both projects up and running before you can have any fun at all. </p>
<h2>Building the WebService Client</h2>
<p>So lets start by building a WebService client for an existing Webservice. Just to get our feet wet as it were. If you go to <a title="xmethods" href="http://www.xmethods.com/ve2/index.po" rel="nofollow">Xmethods.com</a> you'll see there are a number of WebServices people have posted links for. We'll use one of these services for starters. </p>
<p>You might notice that I'm being partial here. I've chosen the <a title="Send an Email WebService" href="http://www.xmethods.com/ve2/ViewListing.po?" rel="nofollow" key="uuid:E7B84967-6183-4746-2B3D-E04259314FF5">Send an Email</a>&nbsp;WebService. We'll write a simple client for this WebService. Before we can begin to use any WebService, we need to have the WSDL file. With Delphi, you simply need the URL to a WSDL file. You could use a physical WSDL file as well, but the Expert available to us, allows us to supply the URL to a WSDL file so we'll use this capability. The expert will generate the Interface files for us. </p>
<h2>WSDL File</h2>
<p>Let's take a brief look at the WSDL file. The URL for the WSDL file is <a title="IemailService" href="http://webservices.matlus.com/scripts/emailwebservice.dll/wsdl/IemailService" rel="nofollow">http://webservices.matlus.com/scripts/emailwebservice.dll/wsdl/IemailService</a>. If you're using I.E, you can click on this link to see the WSDL file inside your browser. Without going into too many details (the WSDL spec. can be quite complex for the faint hearted), lets take a look at some of the elements you should be aware of. </p>
<p>
<ol>
<li>The <b>&lt;message&gt;</b> element. The <code>name</code> attribute contains the name of the method with the word <code>Request</code> added to it. This is part of the spec. This is not the element that really tells you the name of the method however. That comes later 
<li>the <b>&lt;part&gt;</b> element's <code>name</code> attribute tells you the name of the parameters while the <code>type</code> attribute tells you the type of the parameters. 
<li>Next, take a look at the next <b>&lt;message&gt; </b>element. The <code>name</code> attribute has the name of the method with the word <code>Response</code> at the end of it. Once again, this is as per spec. 
<li>Under this element the <b>&lt;part&gt; </b>element's <code>name</code> attribute tells you what is being returned and the <code>type</code> attribute tells you the type of this return value. 
<li>The next important element is the <b>&lt;operation&gt; </b>element. This is the element that really gives you the remote method name. In this case <code>SendMail</code>. 
<li>The <b>&lt;soap:operation&gt; </b>element has an attribute called <code>soapAction</code>. You'll see this mentioned once again later in this tutorial. The <code>value</code> of this attribute is generated for you automatically by the Delphi 6 SOAP framework. In particular by the <code>TWSDLHTMLPublish</code> component at the server end. This is the component that actually generated this WSDL file in the first place.(if you examine the URL for this WSDL file, you'll notice that it points to an action in the ISAPI.) 
<li>The <b>&lt;service&gt;</b> element and it's <code>name</code> attribute are the next elements to look at. We'll see these again when building the client later. In particular, when populating the <code>THTTPRIO</code> component's <code>Service</code> and <code>Port</code> properties. </li></li></li></li></li></li></li></ol>
<p>That's probably some of the more important things to look for in a WSDL file when building a Webservice client. Of course, things can get a bit funky when you run into problems with namespaces etc. when dealing with services that were either built according to an older or newer SOAP specification, or different development tool. These are some of the issues you're going to have to live with when living on the bleeding edge of technology. </p>
<p>I'd also like to take this opportunity to highlight another aspect that relates to XML. Now you don't need to get too involved with this at this point in time. It'll all come together soon enough. So if you don't understand it now, it's ok. For the moment there is no real need to <b>have</b> to understand it. I'm talking about <b>Namespaces</b>. Any good book on XML will give you a more detailed explanation. However, I'll explain things as they relate to SOAP and in particular the WSDL file in question. Right at the start of this WSDL file, you'll see some namespaces being declared. In I.E. they will be highlighted in red (You must have wondered about this when you first show the WSDL file right?). Namespaces are declared as attributes of an element. In this case the <b>&lt;definitions&gt;</b> element like</p><pre><code>xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" </code></pre>
<p>
<p>This declaration now gives us a namespace called <b><code>soap</code></b>. Further down in the WSDL file there are a few elements that start with the word <code>soap</code>. For example, <b>&lt;soap:operation&gt;</b>. This is really the <b>&lt;operation&gt;</b> element in the <b><code>soap</code></b> namespace. You can tell this by the virtue of the fact that there is a <b>:</b> (colon) between the word <code>soap</code> and <code>operation</code>. Hope that makes some sense at this point. </p>
<h2>WebService Client Project</h2>
<ol>
<li>Start a new project 
<li>Then <code>File | New | Other</code> 
<li>In the New Items dialog, choose the <code>WebServices</code> tab 
<li>Choose the <code>WebServices Importer</code> 
<li>Click OK </li></li></li></li></li></ol>
<p><a href="http://www.matlus.com/images/FirstWebService1.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService1.jpg" border="0"></a> <br><b>Figure 1: Selecting the WebServices Importer</b> </p>
<p>This should show you the Wizard. </p>
<p><a href="http://www.matlus.com/images/FirstWebService4.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService4.jpg" border="0"></a> <br><b>Figure 2: Showing the WebService Importer Wizard</b> </p>
<p>In the <code>WSDL Location</code> field, type in the URL for the WSDL File for the Send an Email WebService. This should be <code>http://webservices.matlus.com/scripts/emailwebservice.dll/wsdl/IEmailService</code>. Once you've done that (make sure the URL you type in is exactly as shown), click on the <code>Generate</code> button. Delphi will now create a new unit for you and the Interface declaration for the Send an Email WebService. This unit will look like this: </p>
<p>
<div class="codeblockouter">
<div class="codeblockInner"><code></code><pre><font face="Courier New"><font color="#0000ff"><b>Unit</b></font> <font color="#000080">Unit2</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font> <font color="#000080">Types</font><font color="#ff0000">,</font> <font color="#000080">XSBuiltIns</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>type</b></font>

  <font color="#000080">IEmailService</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>interface</b></font><font color="#ff0000">(</font><font color="#000080">IInvokable</font><font color="#ff0000">)</font>
    <font color="#ff0000">[</font><font color="#008000">'{C355CCC3-4CD4-4577-A0D2-88FBB9B2801E}'</font><font color="#ff0000">]</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">SendMail</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">ToAddress</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">;</font> <font color="#0000ff"><b>const</b></font> <font color="#000080">FromAddress</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">;</font> <font color="#0000ff"><b>const</b></font> <font color="#000080">ASubject</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">;</font> <font color="#0000ff"><b>const</b></font> <font color="#000080">MsgBody</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>  <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>


<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>uses</b></font> <font color="#000080">InvokeRegistry</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInterface</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">IEmailService</font><font color="#ff0000">)</font><font color="#ff0000">,</font> <font color="#008000">'urn:EmailIPortTypeInft-IEmailService'</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></div></div><pre></pre>
<p>From the code listing above, you should see that the interface is called <code>IEmailService</code> and that is has one method (a function in this case) called <code>SendMail</code>. This method, expects to see the parameters required to send an email. What is interesting to note is that this <code>Interface</code> is derived from an interface called <code>IInvokable</code>. This is new to Delphi 6. <code>IInvokable</code> is almost exactly the same as <code>IInterface</code> (or <code>IUnknown</code>) which is the base type for all Delphi Interfaces. The key difference is that it is compiled with Run time Type information using the <code>{$M }</code> compiler directive. I mentioned in the previous articles, the Delphi SOAP implementation uses RTTI and Interfaces. This is one part of that equation. </p>
<p>The next thing to note is the <code>initialization</code> section of the unit that was generated. The invocation registry is again new to Delphi 6. The Delphi 6 SOAP framework uses this "registry" to be able to automatically instantiate instances of Invokable classes (classes that implement interfaces derived from IInvokable) and Remoteable classes (we'll get to these in a later tutorial). Needless to say, that if you don't register things that need to be registered, your WebServices will not work. The Online help has a decent explanation of the <code>RegisterInterface</code> method and the parameters expected (most of them are optional). Also notice the <code>stdcall</code> directive. Currently, the Delphi default calling convention (register) is not yet supported. You could use any other calling convention that Delphi supports, such as <code>cdecl, pascal, or safecall</code>. It is not recommended that you use <code>safecall</code> since <code>safecall</code> calls are wrapped with an exception handler by the compiler and this may swallow more exceptions than you'd want to. The default is to use <code>stdcall</code> so I suggest you stick with this.</p>
<p>Lets switch to the main form of the application and drop down a <code>THTTPRIO</code> component on the form. You'll find this component in the WebServices palette. This component has 4 key properties. </p>
<ol>
<li><code>WSDLLocation</code> 
<li><code>Service</code> 
<li><code>Port</code> 
<li><code>URL</code> </li></li></li></li></ol>
<p>You either use the <code>WSDLLocation, Service and Port</code> properties or just the <code>URL</code> property. </p>
<p>
<p>Given a WSDLLocation (URL) the <code>THTTPRIO</code> component is capable of parsing out the WSDL file and populating the <code>Service</code> and <code>Port</code> property dropdown lists. So lets fill in the WSDLLocation with the same URL we used earlier. Now drop down the <code>Service</code> property's combo box and select <code>IEmailServiceservice</code>. Do the same for the <code>Port</code> property and select <code>IEmailServicePort</code>. </p>
<p><a href="http://www.matlus.com/images/FirstWebService2.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService2.jpg" border="0"></a> <br><b>Figure 3: Showing the Object Inspector with the THTTPRIO component's properties populated.</b> </p>
<p>Looking at the parameters required by the <code>SendMail</code> method of the <code>IEmailService</code>, I've built a simple GUI with the required fields as show in <b>Figure 3</b> below. </p>
<p><a href="http://www.matlus.com/images/FirstWebService3.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService3.jpg" border="0"></a> <br><b>Figure 4: Showing the simple GUI for the Send an Email WebService</b> </p>
<h2>The Code</h2>
<p>I've named the unit that Delphi created as <code>EmailIPortTypeInft</code>. You don't need to name it the same, but you do need to add this unit to the <code>uses</code> clause of the <code>implementation</code> section of your form's unit. Once you do this, in the <code>OnClick</code> event of the <code>Send</code> button you need to write some code. </p>
<div class="codeblockouter">
<div class="codeblockInner"><code></code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">uClientMain</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">Windows</font><font color="#ff0000">,</font> <font color="#000080">Messages</font><font color="#ff0000">,</font> <font color="#000080">SysUtils</font><font color="#ff0000">,</font> <font color="#000080">Variants</font><font color="#ff0000">,</font> <font color="#000080">Classes</font><font color="#ff0000">,</font> <font color="#000080">Graphics</font><font color="#ff0000">,</font> <font color="#000080">Controls</font><font color="#ff0000">,</font> <font color="#000080">Forms</font><font color="#ff0000">,</font>
  <font color="#000080">Dialogs</font><font color="#ff0000">,</font> <font color="#000080">StdCtrls</font><font color="#ff0000">,</font> <font color="#000080">Rio</font><font color="#ff0000">,</font> <font color="#000080">SoapHTTPClient</font><font color="#ff0000">,</font> <font color="#000080">ComCtrls</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TForm1</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TForm</font><font color="#ff0000">)</font>
    <font color="#000080">HTTPRIO1</font><font color="#ff0000">:</font> <font color="#000080">THTTPRIO</font><font color="#ff0000">;</font>
    <font color="#000080">Label1</font><font color="#ff0000">:</font> <font color="#000080">TLabel</font><font color="#ff0000">;</font>
    <font color="#000080">Button1</font><font color="#ff0000">:</font> <font color="#000080">TButton</font><font color="#ff0000">;</font>
    <font color="#000080">txtToAddress</font><font color="#ff0000">:</font> <font color="#000080">TEdit</font><font color="#ff0000">;</font>
    <font color="#000080">Label2</font><font color="#ff0000">:</font> <font color="#000080">TLabel</font><font color="#ff0000">;</font>
    <font color="#000080">txtFromAddress</font><font color="#ff0000">:</font> <font color="#000080">TEdit</font><font color="#ff0000">;</font>
    <font color="#000080">Label3</font><font color="#ff0000">:</font> <font color="#000080">TLabel</font><font color="#ff0000">;</font>
    <font color="#000080">txtSubject</font><font color="#ff0000">:</font> <font color="#000080">TEdit</font><font color="#ff0000">;</font>
    <font color="#000080">MemMessageBody</font><font color="#ff0000">:</font> <font color="#000080">TMemo</font><font color="#ff0000">;</font>
    <font color="#000080">Label4</font><font color="#ff0000">:</font> <font color="#000080">TLabel</font><font color="#ff0000">;</font>
    <font color="#000080">StatusBar1</font><font color="#ff0000">:</font> <font color="#000080">TStatusBar</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">Button1Click</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#808080">{ Private declarations }</font>
  <font color="#0000ff"><b>public</b></font>
    <font color="#808080">{ Public declarations }</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>var</b></font>
  <font color="#000080">Form1</font><font color="#ff0000">:</font> <font color="#000080">TForm1</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#808080">{$R *.dfm}</font>

<font color="#0000ff"><b>uses</b></font>
 <font color="#000080">EmailIPortTypeInft</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TForm1</font><font color="#ff0000">.</font><font color="#000080">Button1Click</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">Screen</font><font color="#ff0000">.</font><font color="#000080">Cursor</font> <font color="#ff0000">:=</font> <font color="#000080">crHourGlass</font><font color="#ff0000">;</font>
  <font color="#000080">StatusBar1</font><font color="#ff0000">.</font><font color="#000080">SimpleText</font> <font color="#ff0000">:=</font> <font color="#008000">'Sending Email....'</font><font color="#ff0000">;</font>
  <font color="#000080">StatusBar1</font><font color="#ff0000">.</font><font color="#000080">Refresh</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>try</b></font>
    <font color="#0000ff"><b>if</b></font> <font color="#ff0000">(</font><font color="#000080">HTTPRIO1</font> <font color="#0000ff"><b>as</b></font> <font color="#000080">IEmailService</font><font color="#ff0000">)</font><font color="#ff0000">.</font><font color="#000080">SendMail</font><font color="#ff0000">(</font><font color="#000080">txtToAddress</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">,</font> <font color="#000080">txtFromAddress</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">,</font>
      <font color="#000080">txtSubject</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">,</font> <font color="#000080">MemMessageBody</font><font color="#ff0000">.</font><font color="#000080">Lines</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">)</font> <font color="#ff0000">&lt;&gt;</font> <font color="#800080">0</font> <font color="#0000ff"><b>then</b></font>
      <font color="#000080">StatusBar1</font><font color="#ff0000">.</font><font color="#000080">SimpleText</font> <font color="#ff0000">:=</font> <font color="#008000">'Error Sending Email.'</font>
    <font color="#0000ff"><b>else</b></font>
      <font color="#000080">StatusBar1</font><font color="#ff0000">.</font><font color="#000080">SimpleText</font> <font color="#ff0000">:=</font> <font color="#008000">'Email Sent.'</font><font color="#ff0000">;</font>
    <font color="#000080">StatusBar1</font><font color="#ff0000">.</font><font color="#000080">Refresh</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>finally</b></font>
    <font color="#000080">Screen</font><font color="#ff0000">.</font><font color="#000080">Cursor</font> <font color="#ff0000">:=</font> <font color="#000080">crDefault</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>


<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></div></div><pre></pre>
<p>
<p>Basically, you really need just one line of code. Most of the code you see in the OnClick event is really related to GUI frills. The one line of code that really does the work is: </p>
<div class="codeblockouter">
<div class="codeblockInner"><code></code><pre><font face="Courier New">    <font color="#0000ff"><b>if</b></font> <font color="#ff0000">(</font><font color="#000080">HTTPRIO1</font> <font color="#0000ff"><b>as</b></font> <font color="#000080">IEmailService</font><font color="#ff0000">)</font><font color="#ff0000">.</font><font color="#000080">SendMail</font><font color="#ff0000">(</font><font color="#000080">txtToAddress</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">,</font> <font color="#000080">txtFromAddress</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">,</font>
      <font color="#000080">txtSubject</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">,</font> <font color="#000080">MemMessageBody</font><font color="#ff0000">.</font><font color="#000080">Lines</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">)</font> <font color="#ff0000">&lt;&gt;</font> <font color="#800080">0</font> <font color="#0000ff"><b>then</b></font></font>
</pre></div></div><pre></pre>
<p>If you run this application and fill in the values to send yourself an email and hit the send button, you'll receive and email if all goes well.</p>
<h2>Behind the Scenes</h2>So what's happening? First of all, you're using a WebService that is already there for you to use. Because the service exists, you can use it without the need to build it yourself. This is one the reasons that SOAP is so exciting. SOAP has added another dimension to the word "re-usability". 
<p>Behind the scenes, the <code>THTTPRIO</code> component has built a SOAP envelope for you and sent it over to the WebService server. The server knows what to do with this SOAP envelop. This SOAP envelope (for those interested) looks like this: </p>
<div class="codeblockouter">
<div class="codeblockInner"><code></code><pre>POST http://matlus.matlus.com/scripts/emailwebservice.dll/soap/IEmailservice HTTP/1.0<br>Accept: application/octet-stream, text/xml<br>SOAPAction: "urn:EmailIPortTypeInft-IEmailService"<br>Content-Type: text/xml<br>User-Agent: Borland SOAP 1.1<br>Host: matlus.matlus.com<br>Content-Length: 759<br>Proxy-Connection: Keep-Alive<br>Pragma: no-cache<br><br>&lt;?xml version="1.0" encoding='UTF-8'?&gt;<br>  &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"<br>    xmlns:xsd="http://www.w3.org/1999/XMLSchema"<br>    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"<br>    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"&gt; <br>    &lt;SOAP-ENV:Body&gt; <br>      &lt;NS1:SendMail xmlns:NS1="urn:EmailIPortTypeInft-IEmailService" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt; <br>        &lt;NS1:ToAddress xsi:type="xsd:string"&gt;shivk@erols.com&lt;/NS1:ToAddress&gt; <br>        &lt;NS1:FromAddress xsi:type="xsd:string"&gt;Shiv Kumar&lt;shiv@matlus.com&gt;&lt;/NS1:FromAddress&gt; <br>        &lt;NS1:ASubject xsi:type="xsd:string"&gt; Testing&lt;/NS1:ASubject&gt; <br>        &lt;NS1:MsgBody xsi:type="xsd:string"&gt;This is a TEST MESSAGE&lt;/NS1:MsgBody&gt; <br>      &lt;/NS1:SendMail&gt; <br>    &lt;/SOAP-ENV:Body&gt; <br>  &lt;/SOAP-ENV:Envelope&gt;<br></pre></div></div>Let me highlight some of the things you might want/need to know. <br>
<ol>
<li>In the HTTP header take a look at the URL that was constructed - <code>http://matlus.matlus.com/scripts/emailwebservice.dll/soap/Iemailservice</code>. What is key here is the part after the <code>emailwebservice.dll</code>. On the server side, when the Service receives this Request a component called <code>THTTPSOAPDispatcher</code> fields this request (because it has PathInfo <code>/soap</code>). It then hands it over to another component called <code>THTTPPascalInvoker</code>. This component looks up the Invocation Registry and tries to match the name of the interface (<code>IEmailService</code>). If it finds a match, it instantiates an instance of the class that implements this interface. We'll get to this when we build the server side. But you should know, that this is done for you automatically by the Delphi 6 SOAP framework. 
<li>The <code>SOAPAction</code> HTTP header. This is a new HTTP header required for SOAP calls. This is one of the headers that a firewall/proxy can look for to either allow/disallow SOAP calls past it for security reasons. Of course, the SOAP spec. does not make this mandatory. I would guess that in time this header will be mandatory. 
<li>Next, within the XML Document (SOAP envelope) you should see the name of the method. 
<li>You should also see the parameters and values to these parameters that are being sent to the server. </li></li></li></li></ol>
<p>The server processed this packet and responded with another SOAP packet that looks like this </p><code></code>
<div class="codeblockouter">
<div class="codeblockInner"><pre>HTTP/1.1 200 OK<br>Server: Microsoft-IIS/5.0<br>Date: Sat, 14 Jul 2001 07:35:44 GMT<br>Content-Type: text/xml<br>Content-Length: 531<br>Content:<br><br>&lt;?xml version="1.0" encoding='UTF-8'?&gt;<br>  &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"<br>    xmlns:xsd="http://www.w3.org/1999/XMLSchema"<br>    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"<br>    xmlns:SOAP-ENC=http://schemas.xmlsoap.org/soap/encoding/&gt;<br>    &lt;SOAP-ENV:Body&gt;<br>      &lt;NS1:SendMailResponse xmlns:NS1="urn:EmailIPortTypeInft-IEmailService" SOAP-ENV:encodingStyle=http://schemas.xmlsoap.org/soap/encoding/&gt;<br>        &lt;NS1:return xsi:type="xsd:int"&gt;0&lt;/NS1:return&gt;<br>      &lt;/NS1:SendMailResponse&gt;<br>    &lt;/SOAP-ENV:Body&gt;<br>  &lt;/SOAP-ENV:Envelope&gt;<br></pre></div></div>After looking at all of this, I'm sure you'll appreciate the fact that the Delphi 6 SOAP framework hides the HTTP and XML details from you and does all of the hard work while you wrote a simple line of code! 
<p>If you really want to know what all the XML stuff is you'll need to go deeper into the SOAP spec and XML. If you want to be a good SOAP programmer you can't avoid this. For now however, we don't <b>need </b>to know. </p>
<p>What if this WebService was written in Java or C ? How would they know what to do with such as request? In particular, how do they treat <code>IEmailService</code>? As I mentioned in the previous articles, Delphi 6's SOAP implementation uses Interfaces. Other SOAP tool kits don't have to. So they will understand this request the way <b>They</b> need to. SOAP is an implementation and platform agnostic protocol. With WebServices it doesn't matter what tool the service is written in or what platform its running on. Well, this is the ideal scenario. Currently, there are interoperability issues, but we'll get there one day I'm sure. For the most part, things should work just fine. </p>
<p>With the knowledge you've gained so far, you should be able to experiment with other WebServices listed on the XMethods web site. I suggest you do this and then come back here to learn how to build the server for this WebService. </p>
<h2>THTTPRIO Explained</h2>When building a WebService client, the <code>THTTPRIO</code> component is the key component. Therefore, I'd like to explain some of the properties of this component, while we're still playing with the client side. Take a look at <b>Figure 5</b> 
<p>
<p><a href="http://www.matlus.com/images/FirstWebService5.jpg" target="_blank" rel="nofollow"><img height="125" hspace="0" src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService5.jpg" width="78" border="0"></a> <br><b>Figure 5: Showing the Properties of THTTPRIO</b> </p>
<p>We've used the <code>WSDLLocation</code> property, the <code>Service</code> property and the <code>Port</code>. Keep in mind, that for you to be able to use the <code>WSDLLocation</code> in design time (or run time) you need access to the Internet if your <code>WSDLLocation</code> is a URL. Also, you use the <code>Service</code> and <code>Port</code> properties only when using the <code>WSDLLocation</code> property. Instead of using the <code>WSDLLocation</code> property, you could use the <code>URL</code> property. When using the <code>URL</code> property, you don't need (and shouldn't) use the <code>Service</code> and <code>Port</code> properties. The value of the <code>URL</code> property will not be the same as the <code>WSDLLocation</code>. You need to use the proper value in this case. This is the <b><code>SOAP Endpoint URL</code></b>. When looking at SOAP services that listed at sites such as XMethods or SALCentral, you will see the <code>SOAP Endpoint URL</code> listed along with the WSDL file. The <code>THTTPRIO</code> component gets the WSDL file at run time, parses it out and finds the <code>SOAP Endpoint URL</code> in the WSDL File. So it goes without saying, that using the <code>URL</code> property will be slightly faster than using the <code>WSDLLocation</code> property since some round trips are saved. Keep this in mind, if you are making repeated calls to a certain WebService in your applications. Another interesting point to note is that the URL for the WSDL file and the SOAP Endpoint (only for Delphi 6 build WebServices) have a very small difference. The word <code>wsdl</code> is replaced with the word <code>soap</code>. Note that this is by default and that you have the option to change this. </p>
<p>What if you are behind a proxy/firewall either at home or work? Well, then you're going to have some issues that you'll need to circumvent. You won't be able to use the <b>WebService Importer</b> as I explained earlier. What you'll have to do is use your browser to get to the WSDL File. Save it locally, and then use this file (you can use the Browse button) to fill in the <code>WSDLLocation</code> field in the wizard. Once you've done this and the interface file(s) is created for you, your next issue will be when you attempt to fill in the properties of the <code>THTTPRIO</code> component. First, if you look at the properties shown in <b>Figure 5</b>, you'll see that the <code>THTTPRIO</code> component has a <code>Proxy</code> property as well as <code>UserName</code> and <code>Password</code> properties. You'll need to get the details from your Network administrator if you don't know what to fill in here. As an example, if you have a proxy server called <code>MyProxy</code> that uses port 8080, then the <code>Proxy</code> property needs to be filled in as <code>MyProxy:8080</code>. As explained earlier, I suggest you use the <code>URL</code> property instead of the <code>WSDLLocation</code>. If you do plan to use the <code>WSDLLocation</code> property, you need to use the file path and name instead of the URL to this file and most probably, when you deploy your client application, it's going to then need to find this WSDL file as well. </p>
<p>The <code>Agent</code> property is another interesting property. If you look at the HTTP header that was shown earlier, you'll see that the <code>User-Agent</code> HTTP header was <code>Borland SOAP 1.1</code>. Now you're free to change this to whatever else you'd like. I normally use the <code>User-Agent</code> HTTP header to distinguish my client applications from others. If you have to deal with security (proxies/firewalls), the <code>User-Agent</code> HTTP header can come in handy to allow for further filtering. For example, you can tell you network security guys, to allow HTTP requests that have a <code>Content-Type</code> of text/xml <b>ONLY</b> if the <code>User-Agent</code> is xyz and the <code>SOAPAction</code> header is abc. Etc. </p>
<p>The <code>THTTPRIO</code> component can be lifetime managed as a component or as an Interfaced object. It is managed, as a component when its owner is not nil. If you drop it on a form, its owner is the form and so it is managed as a component. This becomes important to know in the following case: </p>
<p>In the <code>OnClick</code> event of code listed above, you'll notice that we've not declared a variable of the type <code>IEmailService</code>. But what if we needed to do this? What if we needed a global variable of this type in our application? Well, we declare a variable of this type in the <code>private</code> section and use it in the <code>OnClick</code> event and elsewhere in our code. When we do this, we need to be sure to nil out this variable in the <code>destructor</code> of the form (or some other appropriate place). The code below shows and example of this. </p>
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>type</b></font>
  <font color="#000080">TForm1</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TForm</font><font color="#ff0000">)</font>
    <font color="#000080">Button1</font><font color="#ff0000">:</font> <font color="#000080">TButton</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">Button1Click</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">FormDestroy</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#000080">EmailService</font><font color="#ff0000">:</font> <font color="#000080">IEmailService</font><font color="#ff0000">;</font>
    <font color="#808080">{ Private declarations }</font>
  <font color="#0000ff"><b>public</b></font>
    <font color="#808080">{ Public declarations }</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>var</b></font>
  <font color="#000080">Form1</font><font color="#ff0000">:</font> <font color="#000080">TForm1</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#808080">{$R *.dfm}</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TForm1</font><font color="#ff0000">.</font><font color="#000080">Button1Click</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">EmailService</font> <font color="#ff0000">:=</font> <font color="#000080">HTTPRIO1</font> <font color="#0000ff"><b>as</b></font> <font color="#000080">IEmailService</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TForm1</font><font color="#ff0000">.</font><font color="#000080">FormDestroy</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">EmailService</font> <font color="#ff0000">:=</font> <font color="#0000ff"><b>nil</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div><pre></pre>
<h2>Building the Send an EMail WebService Server</h2>
<p>Before we begin with building the Send an Email Webservice, let me take you through the paces of what we will be doing. </p>
<p>We're going to start a new SOAP Server Application using the Wizard. This essentially produces a Web server extension (CGI, ISAPI etc.) that contains a Web Module and some components on it. This is really very similar to a Web Broker application. We'll choose the ISAPI option. </p>
<div class="note"><img alt="exclamation.gif" src="http://www.matlus.com/images/exclamation.gif" border="0"> If you're not familiar with ISAPI applications, I suggest you look at the tutorials on my web site related to ISAPI applications. The WebServices you'll build with the help of tutorials on this web site will mostly be ISAPI applications. Your knowledge of ISAPI Applications/debuggin etc. will be leveraged here. If you don't have experience building ISAPI applications, debugging etc. I strongly suggest you read the tutorials on my web site for this before you attempt to build WebServices. This way you'll have a firmer grasp of what is going on and this will save you (and me <g>) endless hours of frustration. 
<p>
<p>I assume you know ISAPI application development and as a result, you will find that I do not explain ISAPI related concepts in any of the WebService tutorials. </p></g></div>
<p>The standard SOAP Server application has three components on it. </p>
<ol>
<li><code>THTTPSOAPDispatcher</code> 
<li><code>THTTPSOAPPascalInvoker</code> 
<li><code>TWSDLHTMLPublish</code> </li></li></li></ol>
<p>The <code>THTTPSOAPDispatcher</code> dispatches all requests that have <code>/soap</code> in the PathInfo. It then hands the request over to <code>THTTPSOAPPascalInvoker</code>. This component really handles the bulk of the process. What is this process? Well, If you take a look at the HTTP request header from earlier, you see, that the full request looks like this: </p><pre><code>
http://matlus.matlus.com/scripts/emailwebservice.dll/soap/IEmailservice
</code>
</pre>
<p>The PathInfo part of this request is: </p><pre>/soap/IEmailservice

</pre>
<p>You learned earlier, that the <code>THTTPSOAPDispatcher</code> handles all requests, with <code>/soap</code> in it and hands it over to the <code>THTTPSOAPPascalInvoker</code>. So the <code>THTTPSOAPPascalInvoker</code> has to do something with <code>/IEMailservice</code>. So what does it do? It looks up the Invocation Registry for any registered Interfaces that match the name IEMailservice. It also parses out the content of the web request (this is the SOAP Packet from earlier) and finds the name of the method and the parameters. Once it has done that, it instantiates an instance of the class that implements this interface and calls the required method handing it the parameters it received. Remember that it's able to do all this using RTTI for interfaces (new to Delphi 6) and some old RTTI magic. Since it receives all this information in the form of a string, it is converting these strings into method calls that instantiate an instance of a class and call the required methods (very much like a scripting engine). When you build a WebService, it is your job to: </p>
<ol>
<li>Define an Interface. 
<li>Implement this interface in a class. 
<li>Register the interface and class with the invocation registry. </li></li></li></ol>
<p>That's it. The Delphi 6 SOAP framework handles the rest of it for you. What's the rest of it you might ask? </p>
<ol>
<li>Parsing the SOAP envelope. 
<li>Instantiating the required class. 
<li>Calling the required method and passing the received (parsed) parameters to it 
<li>Getting back a result from the method. 
<li>Putting the result back in a SOAP response envelope and sending it back out. 
<li>If there is an exception it constructs a SOAP Fault packet instead </li></li></li></li></li></li></ol>
<p>To put it in really simple terms! </p>
<p>I hope this short explanation has cleared things up a bit. If it has, then we're ready to move on and start with building our first Delphi 6 WebService. </p>
<h2>The SOAP Server Application</h2>
<ol>
<li>From the Delphi main menu, choose File | New | Other 
<li>Choose the WebServices tab and choose the SOAP server Application Expert 
<li>In the next dialog, leave the ISAPI/NSAPI (this is the default) Dynamic Link Library option selected and Click OK. </li></li></li></ol>
<p>
<table>
<tbody>
<tr>
<td><a href="http://www.matlus.com/images/FirstWebService6.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService6.jpg" border="0"></a></td>
<td><a href="http://www.matlus.com/images/FirstWebService7.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService7.jpg" border="0"></a></td>
<td><a href="http://www.matlus.com/images/FirstWebService8.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService8.jpg" border="0"></a></td></tr>
<tr>
<td colspan="3"><b>Figure 6: Showing the Steps involved in Creating a New SOAP Server Application</b></td></tr></tbody></table>After doing these steps, you should see something like the last image in <b>Figure 6</b>. I suggest you save this project as EmailWebService and the WebModule unit as MainU.pas. </p>
<div class="note"><img alt="exclamation.gif" src="http://www.matlus.com/images/exclamation.gif" border="0"> Note: I assume at this point that you know about building ISAPI Applications and debugging them etc. I keep stressing this because I don't want to be flooded with emails asking me questions about WebServices that really pertain to ISAPI applications. I believe the information available on my web site related to ISAPI is more than enough to help you get started with ISAPI applications and get to the point where you can now build WebServices. </div>
<p>
<h2>Defining the Interface</h2>
<p>If you've registered Delphi 6, you should then have access to some of the power toys that will be made available to you. At the time of this writing, I believe they are not yet available. Anyhow, I'll use (one of these toys) the Invokable Wizard that will help in building the WebService. Don't worry, if you don't have this wizard. What it does is it creates two new units for you, one that defines the Interface and the other that defines a class that implements this interface. I'll show you the full units, so you can create them by hand if required. Why have the interface defined in one unit and the implementation in another? Technically, there is obviously no need for this. But if you're building a client for the WebService as well (and 99% of the time you will, only if it's to test the WebService), you can include the unit that declares your interface in the client application's project as well. This will eliminate the need to import the WSDL file (one of the steps we went through while building the client). However, if you want to test your WebService completely, you're better off building the client as we did earlier. That is, treat the client as an independent part of your system, so you know that others attempting to use the WebService will be able to. </p>
<p>The Invokable Wizard can be found in the <code>New Items</code> dialog (File | New | Other | WebServices) as shown in <b>Figure 7</b> below. </p>
<p><a href="http://www.matlus.com/images/FirstWebService9.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService9.jpg" border="0"></a> <br><b>Figure 7: Showing the Invokable Wizard</b> </p>
<p>As Shown in <b>Figure 8</b> below, the Invokable Wizard presents you with another dialog. 
<p><a href="http://www.matlus.com/images/FirstWebService10.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService10.jpg" border="0"></a> <br><b>Figure 8: Showing the dialog the Invokable Wizard presents you with.</b> </p>
<p>I've filled in the values as shown there. You'll notice that the <code>InvokableClass</code> field has a combo box. I've chosen <code>TInvokableClass</code>. The other option is <code>TInterfacedObject</code>. There is a subtle difference between these two. <code>TInvokableClass</code> is derived from <code>TInterfacedObject</code> so it implements QueryInterface, AddRef and ReleaseRef. But it also has a virtual constructor. The fact that it has a virtual constructor allows the compiler to create an instance of the class using RTTI. If you need to derive from <code>TInterfacedObject</code> for some reason, you'll have to implement one extra step in your code (Ill show you that later) and register the class differently (I'll show you that too). All this, so the compiler can instantiate an instance of your class on the fly (That is <code>THTTPSOAPPascalInvoker</code> can instantiate an instance as was described earlier). </p>
<p>The two units thus created are shown below. The first one is the unit that declares the Interface - <code>IEmailService</code> and the next one declares the class that will implement this interface - <code>TEmailService</code>. </p>
<div class="codeblockouter">The unit that declares the <code>IEMailService</code> Interface 
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">EMailServiceIntf</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">Types</font><font color="#ff0000">,</font> <font color="#000080">XSBuiltIns</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">IEMailService</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>interface</b></font><font color="#ff0000">(</font><font color="#000080">IInvokable</font><font color="#ff0000">)</font>
    <font color="#ff0000">[</font><font color="#008000">'{A987FE00-E596-4733-83BB-E75ACA5FF363}'</font><font color="#ff0000">]</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">InvokeRegistry</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInterface</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">IEMailService</font><font color="#ff0000">)</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div><pre></pre>
<p>
<div class="codeblockouter">The unit that declares the <code>TEMailService</code> class 
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">EMailServiceImpl</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">EMailServiceIntf</font><font color="#ff0000">,</font> <font color="#000080">InvokeRegistry</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TEMailService</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TInvokableClass</font><font color="#ff0000">,</font> <font color="#000080">IEMailService</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInvokableClass</font><font color="#ff0000">(</font><font color="#000080">TEMailService</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div><pre></pre>
<p>Make a note of the units in the uses clause of both these units and the <code><b>initialization</b></code> section as well. If you're building these units, by hand, I suggest you do so at this point looking at the above listings. </p>
<p>To understand the "Registration" need, I suggest you look at the on-line help for more information. Notice also, that the unit that declares the Interface is very similar to the one that was generated for us using the <code>WebService Importer</code> wizard back when we started with building the client application. Minus the SendMail method and GUID obviously. </p>
<p>Lets go ahead and define the SendMail method as shown in the listing below. </p>
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">EMailServiceIntf</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>
<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">Types</font><font color="#ff0000">,</font> <font color="#000080">XSBuiltIns</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">IEmailService</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>interface</b></font><font color="#ff0000">(</font><font color="#000080">IInvokable</font><font color="#ff0000">)</font>
  <font color="#ff0000">[</font><font color="#008000">'{C56A3546-DA66-492F-9024-D78D960AB248}'</font><font color="#ff0000">]</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">SendMail</font><font color="#ff0000">(</font><font color="#000080">ToAddress</font><font color="#ff0000">,</font> <font color="#000080">FromAddress</font><font color="#ff0000">,</font> <font color="#000080">ASubject</font><font color="#ff0000">,</font> <font color="#000080">MsgBody</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">InvokeRegistry</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInterface</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">IEmailService</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>


<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div><pre></pre>
<p>Save these units using the names shown (these are the names generated for you by the Wizard if you used it). New to Delphi 6 is the ability to use Code Insight to fill in the methods of an interface in the class that implements the interface. You can even multi-select the methods shown to get Code Insight to write them all out for you as they were declared in the Interface. Note that the units need to be saved for this to work. </p>
<p>So switch to the unit that declares the class the implements the <code>IEMailService</code>, move you cursor under the "T" of <code>TEMailService</code> and hit CTRL Space. You should see the SendMail method listed in the code completion drop down. Select it and hit the Enter key and you'll see that Delphi does the rest for you. Now do the class completion (CTRL SHIFT C) </p>
<p>We're using Indy to do the sending of emails. You'll notice that Indy is now a part of Delphi 6. Those of you who have not used Indy yet, will obviously need to get to know how to use them. Our implementation of sending an email is nothing special, except for the fact that all objects are being created on the fly. You will also need to add the required units to the uses clause of your units. The listing below shows the full unit for the <code>TEmailService</code> class. Remember, this is the class that implements the interface <code>IEmailService</code>. </p>
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">EMailServiceImpl</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">InvokeRegistry</font><font color="#ff0000">,</font> <font color="#000080">XSBuiltIns</font><font color="#ff0000">,</font> <font color="#000080">EmailIServiceInft</font><font color="#ff0000">,</font> <font color="#000080">IdBaseComponent</font><font color="#ff0000">,</font> <font color="#000080">IdComponent</font><font color="#ff0000">,</font>
  <font color="#000080">IdTCPConnection</font><font color="#ff0000">,</font> <font color="#000080">IdTCPClient</font><font color="#ff0000">,</font> <font color="#000080">IdMessageClient</font><font color="#ff0000">,</font> <font color="#000080">IdSMTP</font><font color="#ff0000">,</font> <font color="#000080">IdMessage</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TEmailService</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TInvokableClass</font><font color="#ff0000">,</font> <font color="#000080">IEmailService</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>public</b></font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">SendMail</font><font color="#ff0000">(</font><font color="#000080">ToAddress</font><font color="#ff0000">:</font> <font color="#0000ff"><b>String</b></font><font color="#ff0000">;</font> <font color="#000080">FromAddress</font><font color="#ff0000">:</font> <font color="#0000ff"><b>String</b></font><font color="#ff0000">;</font>
      <font color="#000080">ASubject</font><font color="#ff0000">:</font> <font color="#0000ff"><b>String</b></font><font color="#ff0000">;</font> <font color="#000080">MsgBody</font><font color="#ff0000">:</font> <font color="#0000ff"><b>String</b></font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#808080">{ TEmailService }</font>

<font color="#0000ff"><b>function</b></font> <font color="#000080">TEmailService</font><font color="#ff0000">.</font><font color="#000080">SendMail</font><font color="#ff0000">(</font><font color="#000080">ToAddress</font><font color="#ff0000">,</font> <font color="#000080">FromAddress</font><font color="#ff0000">,</font> <font color="#000080">ASubject</font><font color="#ff0000">,</font>
  <font color="#000080">MsgBody</font><font color="#ff0000">:</font> <font color="#0000ff"><b>String</b></font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>const</b></font>
  <font color="#000080">SMTPServer</font> <font color="#ff0000">=</font> <font color="#008000">'smtp-server'</font><font color="#ff0000">;</font> <font color="#808080">{ Change this to your SMTP server }</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">IdSMTP</font><font color="#ff0000">:</font> <font color="#000080">TIdSMTP</font><font color="#ff0000">;</font>
  <font color="#000080">IdSendMsg</font><font color="#ff0000">:</font> <font color="#000080">TIdMessage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">IdSMTP</font> <font color="#ff0000">:=</font> <font color="#000080">TIdSMTP</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#0000ff"><b>nil</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">IdSendMsg</font> <font color="#ff0000">:=</font> <font color="#000080">TIdMessage</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">IdSMTP</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>try</b></font>
   <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#ff0000">-</font><font color="#800080">1</font><font color="#ff0000">;</font>
   <font color="#0000ff"><b>with</b></font> <font color="#000080">IdSendMsg</font> <font color="#0000ff"><b>do</b></font>
   <font color="#0000ff"><b>begin</b></font>
     <font color="#000080">Body</font><font color="#ff0000">.</font><font color="#000080">Text</font> <font color="#ff0000">:=</font> <font color="#000080">MsgBody</font><font color="#ff0000">;</font>
     <font color="#000080">From</font><font color="#ff0000">.</font><font color="#000080">Text</font> <font color="#ff0000">:=</font> <font color="#000080">FromAddress</font><font color="#ff0000">;</font>
     <font color="#000080">Recipients</font><font color="#ff0000">.</font><font color="#000080">EMailAddresses</font> <font color="#ff0000">:=</font> <font color="#000080">ToAddress</font><font color="#ff0000">;</font>
     <font color="#000080">Subject</font> <font color="#ff0000">:=</font> <font color="#000080">ASubject</font><font color="#ff0000">;</font>
   <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ with IdSendMsg do }</font>

   <font color="#0000ff"><b>with</b></font> <font color="#000080">IdSMTP</font> <font color="#0000ff"><b>do</b></font>
   <font color="#0000ff"><b>begin</b></font>
     <font color="#000080">Host</font> <font color="#ff0000">:=</font> <font color="#000080">SMTPServer</font><font color="#ff0000">;</font>
     <font color="#000080">Connect</font><font color="#ff0000">;</font>
     <font color="#0000ff"><b>try</b></font>
       <font color="#000080">Send</font><font color="#ff0000">(</font><font color="#000080">IdSendMsg</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
       <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#800080">0</font><font color="#ff0000">;</font>
     <font color="#0000ff"><b>finally</b></font>
       <font color="#000080">Disconnect</font><font color="#ff0000">;</font>
     <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
   <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ with IdSMTP do }</font>
  <font color="#0000ff"><b>finally</b></font>
    <font color="#000080">IdSendMsg</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
    <font color="#000080">IdSMTP</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ try }</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInvokableClass</font><font color="#ff0000">(</font><font color="#000080">TEmailService</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div><pre></pre>
<p>Add these two units to your project and we're almost done now. Pretty simple so far huh? The last thing that's left is getting the service application to respond to SOAP calls and publish the WSDL file. Remember, without a WSDL file, your WebService is practically useless to anyone else. </p>
<h2>TWSDLPublish</h2>
<p>What we need to do is select the <code>TWSDLPublish</code> component on the WebModule and set its <code>AdminEnabled</code> property to true. Now run your application and using a browser, navigate to this URL <code>http://matlus.matlus.com/scripts/EmailWebService.dll/wsdl</code>. Change the domain and path according to your setup. Just be sure you put the <code>/wsdl</code> as a path of the final URL. You should see a screen similar to that shown in Figure 9. </p>
<p>
<p><a href="http://www.matlus.com/images/FirstWebService11.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService11.jpg" border="0"></a> <br><b>Figure 9: Showing the WSDL Administration Page</b> </p>
<p>If you had not set the <code>AdminEnabled</code> property to True, you wouldn't see the <code>Administrator</code> button. Click on the <code>WSDL for IEmailService</code> link. You should now see a WSDL file in your browser. Scroll to the end of the document. You should see that the <code><b>&lt;service&gt;</b></code> element is an <code>empty tag</code> (as per XML definition). If you look at the WSDL file at the URL specified at the start of this tutorial, you should notice that the <code><b>&lt;service&gt;</b></code> element had a child element called <code><b>&lt;port&gt;</b></code> and the <code><b>&lt;port&gt;</b></code> element had a <code><b>&lt;soap:address&gt;</b></code> element as a child like so: </p>
<div class="codeblockouter">
<div class="codeblockInner"><code><pre>&lt;port name="IEmailServicePort" binding="IEmailServicebinding"&gt;
  &lt;soap:address location="http://matlus.matlus.com/scripts/EmailWebservice.dll/soap/IEmailService" /&gt;
</pre></code></div></div>
<p>We need to define the <code>Port</code> for our service. We do that by clicking on the <code>Administrator</code> button and then on the <code>WSDL for IEMailService</code> link. You should see a screen that looks like that shown in <b>Figure 10</b>. </p>
<p><a href="http://www.matlus.com/images/FirstWebService12.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService12.jpg" border="0"></a> <br><b>Figure 10: Showing the Admin Screen that allows for registering a Port for the WebService</b> </p>
<p>In the <code>PortName</code> field enter <code>IEmailServicePort</code> and in the <code>Address</code> field enter <code>http://matlus.matlus.com/scripts/EmailWebservice.dll/soap/IEMailservice</code>. Change the domain name as per your set up. Click the <code>Add</code> button. You should see a screen that looks like that shown in <b>Figure 11</b>. </p>
<p><a href="http://www.matlus.com/images/FirstWebService13.jpg" target="_blank" rel="nofollow"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=FirstWebService13.jpg" border="0"></a> <br><b>Figure 11: Showing the Admin Screen that allows for registering a Port for the WebService</b> </p>
<p>Hit the back button of your browser twice. This should show the URL <code>http://matlus.matlus.com/scripts/EmailWebService.dll/wsdl</code> in your browser. Now if you click on the <code>WSDL for IEMailService</code> link and check the WSDL file thus generated, the <code><b>&lt;service&gt;</b></code> and <code><b>&lt;port&gt;</b></code> elements are as they should be. You should note also, that this operation has generated an <code>.ini</code> file in the <code>/scripts</code> folder (the same folder in which your DLL is installed. This <code>.ini</code> file will have the same name as your ISAPI dll with the words <code>_WSDLADMIN.INI</code> appended to it. The contents of this file should be something like this: </p><pre><code>
[IWSDLPublish]
IWSDLPublishPort=http://matlus.matlus.com/scripts/EmailWebservice.dll/soap/IWSDLPublish

[IEmailService]
IEmailServicePort=http://matlus.matlus.com /scripts/EmailWebservice.dll/soap/IEmailService
</code>
</pre>
<p>When you deploy your WebService to your production server, you either need to go through these steps again, or simply copy this <code>.ini</code> file over to the production server and change the domain name parts in both sections to match that of your production server. Do not forget this step. Without this step, your WebService will be quite un-usable. </p>
<h2>TInvokableClass or TInterfacedObject</h2>
<p>Earlier, I mentioned that if you decide to use <code>TInterfacedObject</code> as the class to derive your implementation class, you'll need to do things differently. Here are the differences and why you need to do them. <code>TInterfacedObject</code> does not have a virtual constructor declared. As a result, there is no way for your application to instantiate an instance of your class at run time when it gets a SOAP request to do so. As usual, there is always an option with Delphi. (These guys think of everything). What you need to do is implement a "Factory" method for your class. This method needs to return an instance of your class as an <code><b>out</b></code> parameter. Further, for the run time to figure it out, you need to register this method when registering the class with the invocation registry so that the application can call this method to get back an instance of your class. This is how you should implement this method and register it. </p>
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>procedure</b></font> <font color="#000080">EMailServiceFactory</font><font color="#ff0000">(</font><font color="#0000ff"><b>out</b></font> <font color="#000080">obj</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">obj</font> <font color="#ff0000">:=</font> <font color="#000080">TEmailService</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInvokableClass</font><font color="#ff0000">(</font><font color="#000080">TEMailService</font><font color="#ff0000">,</font> <font color="#000080">EMailServiceFactory</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div><pre></pre>
<p>Note the change in the call to the <code>RegisterInvokableClass</code> method in the <code>initialization</code> section as well. </p>
<p>Well, that pretty much does it. This tutorial contains more explanation than the actual work involved in building a WebService with Delphi 6. It's really very simple and I hope, after you've read this tutorial, you feel the same. Testing your WebService server is a simple task, now, since you already have a client. All you need to do is change the <code>WSDLLocation</code> property of the <code>THTTPRIO</code> component in your client application (or <code>URL</code> property as the case may be) to match that of your WebService (instead on mine). The projects are available for download as a project group containing the WebService Client project and WebService server project. </p>]]></description><category>Programming</category><category>Delphi</category><category>SOAP</category><category>WebServices</category></item><item><title>Building WebService Clients By Hand</title><pubDate>Tue, 22 Jan 2008 10:45:41 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/2/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/2/</guid><description><![CDATA[This tutorial is for Delphi 5 (Pro and Enterprise) as well as Delphi 6 (Pro and Enterprise) users. This Tutorial does not use, or show you how to build WebService clients using the Delphi 6 SOAP framework. Instead, this tutorial is intended for those wanting to have a firmer understanding of SOAP/WebServices as well as show Delphi 5 and Delphi 6 Pro users, how they can build WebService Clients using the tools they've got. 
<p>Having a framework to do all the grunt work for you is great. It saves you a lot of time, hides things from you that you don't need or want to know and brings the fun back into programming. But if you're like me, then you <b>want to do</b> the grunt work initially, so you can get your hands dirty and begin to understand the underpinnings of a certain technology. </p>
<p>Actually doing the work gives you a far better understanding and also surfaces the "facts" and "half-truths" about a certain technology. Further, having actually done it <b>by hand</b>, gives you a better insight into the technology in question. So rub your hands together and get ready for the fun that lies ahead. </p>
<p>The WebService client that we are about to build is a generic SOAP Client. Currently, it can handle WebServices that have one method and expect none or one parameter. Examples of such WebServices are: 
<ol>
<li><a rel="nofollow" href="http://www.xmethods.com/detail.html?" id="98" target="_blank">WhoIS</a> 
<li><a rel="nofollow" href="http://www.xmethods.com/detail.html?" id="93" target="_blank">Shakespearean Insult Generator</a> 
<li><a rel="nofollow" title="Kazoo Training Classes " href="http://www.xmethods.com/detail.html?" id="82" target="_blank">Kazoo Training Classes</a> 
<li><a rel="nofollow" title="WordFind" href="http://www.xmethods.com/detail.html?" id="100" target="_blank">WordFind</a> 
<li><a rel="nofollow" title="FedEx Tracker" href="http://www.xmethods.net/detail.html?" id="15" target="_blank">FedEx Tracker</a> 
<li><a rel="nofollow" title="Delayed Stock Quote" href="http://www.xmethods.net/detail.html?" id="2" target="_blank">Delayed Stock Quote</a> 
<li><a rel="nofollow" title="Domain Name Checker" href="http://www.xmethods.net/detail.html?" id="6" target="_blank">Domain Name Checker</a> </li></li></li></li></li></li></li></ol>These are just some that I have tested. The "result" can be seen in the SOAP Response Page. Generally, the <code><b>&lt;result&gt;</b></code> element contains the result. 
<h3>What will you need to build this project</h3>
<ol>
<li>Delphi 5 Pro/Enterprise or Delphi 6 Pro/Enterprise 
<li>Microsoft <a rel="nofollow" title="Microsoft SOAP toolkit 2.0 Gold Release" href="http://msdn.microsoft.com/downloads/default.asp?" url="/code/sample.asp?" url="/msdn-files/027/001/580/msdncompositedoc.xml" target="_blank">SOAP toolkit 2.0 Gold Release</a> 
<li><a rel="nofollow" title="Indy Version 8.0" href="http://www.nevrona.com/indy" target="blank">Indy version 8.0</a> </li></li></li></ol>
<h3>What will you have learnt by the end</h3>Yes, that's a good question. I mean, what's the point in all the work you're about to do right? 
<ol>
<li>You'll learn how to use the <b>Microsoft DOM Parser, to build and parse XML Documents</b> 
<li>You'll learn how to use the Indy <b>TIdHTTP component</b> 
<li>You'll learn about <b>WSDL Files</b> and how to "read" them 
<li>You'll learn about the <b>SOAP protocol</b> 
<li>You'll learn how to use the I.E. <b>ActiveX Browser control</b> </li></li></li></li></li></ol>
<div class="note">This tutorial, does not expect you to use the Microsoft SOAP toolkit, but rather only use the DOM Parser. If you are familiar with another XML parser, then feel free to use this parser instead. You'll have to make the necessary changes to your code however. </div>
<h3>Importing the MSXML type library</h3>After you've downloaded the Microsoft SOAP Toolkit, you need to import the type library using the Delphi IDE. 
<table cellspacing="2" cellpadding="2">
<tbody>
<tr>
<td align="middle"><a rel="nofollow" href="http://www.matlus.com/images/ImportingMSXML1.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=ImportingMSXML1.jpg" border="0"></a></td>
<td align="middle"><a rel="nofollow" href="http://www.matlus.com/images/ImportingMSXML2.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=ImportingMSXML2.jpg" border="0"></a></td>
<td align="middle"><a rel="nofollow" href="http://www.matlus.com/images/ImportingMSXML3.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=ImportingMSXML3.jpg" border="0"></a></td></tr>
<tr>
<td>Step 1</td>
<td>Step 2 - Select the Library and Click Create Unit</td>
<td>Step 3 - You should see the file in the Editor - Save it</td></tr></tbody></table>
<p>
<h3>Let the games begin</h3>
<div class="note">This tutorial is not yet complete, but the project source files are available for download at the end of this article. </div>
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep1.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep1.jpg" border="0"></a> <br><b>Image1 - The First Step - Get the URL to a WSDL File</b> 
<p>
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep2.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep2.jpg" border="0"></a> <br><b>Image2 - Enter the URL for the WSDL File</b> 
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep3.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep3.jpg" border="0"></a> <br><b>Image3 - Clicking on the Get WSDL Button retrieves the WSDL File, Parses it and populates the fields</b> 
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep4.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep4.jpg" border="0"></a> <br><b>Image4 - If the WebService Method Requires a Parameter, then Enter a Valid Value</b> 
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep5.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep5.jpg" border="0"></a> <br><b>Image5 - Clicking on the Make SOAP Request Button Executes the SOAP method</b> 
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep6.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep6.jpg" border="0"></a> <br><b>Image6 - The SOAP Request that was sent to the WebService</b> 
<p><a rel="nofollow" href="http://www.matlus.com/images/SOAPClientStep7.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=SOAPClientStep7.jpg" border="0"></a> <br><b>Image7 - The SOAP Response that came back from the WebService</b> ]]></description><category>Programming</category><category>Delphi</category><category>SOAP</category><category>WebServices</category></item><item><title>WebServices and Complex Types</title><pubDate>Mon, 21 Jan 2008 10:52:07 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/3/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/3/</guid><description><![CDATA[You saw in the previous tutorial - Building your first WebService how simple it it with Delphi 6 to build WebServices. This tutorial assumes you've read that tutorial or know of the things that were discussed there. 
<p>Sending back strings, integers etc. as a result of a WebService method is really simple. You didn't have to do anything special to accomplish this. In this tutorial, we'll see how we can: </p>
<ol>
<li><b>Send</b> back custom objects 
<li>Define and raise custom Exceptions </li></li></ol>
<p>As soon as you read the things we're going to learn how to do in this tutorial, you must have thought to yourself: </p>
<ul>
<li>If we send back an <b>Object</b> how will clients written in tools other then Delphi deal with these objects? 
<li>Riase an Exception? What, on a Remote Client? What if the client is not a Delphi client? How will it know what to do with a Delphi Exception? 
<li>What if the Client is running on a platform other than Windows? </li></li></li></ul>
<p>If you asked any or all of these questions, then you've been paying attention <g>. That's good news. Read on, and you'll have the answers to questions you ask. <p>
<h2>WebService Methods Returning Objects</h2>The WebService we will build in this tutorial has two methods. The WSDL file for this WebService can be found at <a rel="nofollow" href="http://webservices.matlus.com/scripts/XMLDataSetWebService.dll/wsdl/IDatasetXML" target="_blank">http://webservices.matlus.com/scripts/XMLDataSetWebService.dll/wsdl/IDatasetXML</a>. One of these methods (<code>GetSchemaInfo</code>) returns an array of objects. The object is a custom Delphi object. The class declaration of this object is shown below. 
<p>
<div class="codeblockouter">The <code>TFieldInfo</code> object 
<div class="codeblockinner"><code><pre><font face="Courier New"><font color="#0000ff"><b>type</b></font>
  <font color="#000080">TFieldInfo</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TRemotable</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#000080">FIsKeyField</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">;</font>
    <font color="#000080">FFieldSize</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
    <font color="#000080">FFieldName</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
    <font color="#000080">FFieldType</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>published</b></font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">FieldName</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FFieldName</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FFieldName</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">FieldType</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FFieldType</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FFieldType</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">FieldSize</font><font color="#ff0000">:</font> <font color="#000080">Integer</font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FFieldSize</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FFieldSize</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">IsKeyField</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FIsKeyField</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FIsKeyField</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

  <font color="#000080">TFieldInfoArray</font> <font color="#ff0000">=</font>   <font color="#0000ff"><b>array</b></font> <font color="#0000ff"><b>of</b></font> <font color="#000080">TFieldInfo</font><font color="#ff0000">;</font></font>
</pre></code></div></div>As shown above, <code>TFieldInfoArray</code> is declared as an array of type <code>TFieldInfo</code>. Depending on the number of fields in the table, the method will return those many elements in the array. Take a look at the SOAP Request and Response shown below. 
<p>
<div class="codeblockouter">Showing the HTTP Header and Content (SOAP Request) for the <code>GetSchemaInfo</code> method. 
<div class="codeblockinner"><code><pre>POST http://webservices.matlus.com/scripts/xmldatasetwebservice.dll/soap/IDatasetXML HTTP/1.0
Accept: application/octet-stream, text/xml
SOAPAction: "urn:DatasetXMLIntf-IDatasetXML#GetSchemaInfo"
Content-Type: text/xml
User-Agent: Borland SOAP 1.1
Host: webservices.matlus.com
Content-Length: 535
Proxy-Connection: Keep-Alive
Pragma: no-cache

&lt;?xml version="1.0" encoding='UTF-8'?&gt;
&lt;SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"&gt;
  &lt;SOAP-ENV:Body&gt;
    &lt;NS1:GetSchemaInfo xmlns:NS1="urn:DatasetXMLIntf-IDatasetXML" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;
      &lt;NS1:TableName xsi:type="xsd:string"&gt;Customer&lt;/NS1:TableName&gt;
    &lt;/NS1:GetSchemaInfo&gt;
  &lt;/SOAP-ENV:Body&gt;
&lt;/SOAP-ENV:Envelope&gt;
</pre></code></div></div>
<div class="codeblockouter">Showing the HTTP Header and Content (SOAP Response) for the <code>GetSchemaInfo</code> method. 
<div class="codeblockinner"><code><pre>HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Fri, 20 Jul 2001 04:34:23 GMT
Content-Type: text/xml
Content-Length: 4676
Content:

&lt;?xml version="1.0" encoding='UTF-8'?&gt;
&lt;SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"&gt;
  &lt;SOAP-ENV:Body&gt;
    &lt;NS1:GetSchemaInfoResponse
      xmlns:NS1="urn:DatasetXMLIntf-IDatasetXML"
      SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:NS2="http://www.w3.org/2001/XMLSchema"&gt;
      &lt;NS1:return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="NS2:TFieldInfo[13]"&gt;
        &lt;NS1:item href="#1"/&gt;
        &lt;NS1:item href="#2"/&gt;
        &lt;NS1:item href="#3"/&gt;
        &lt;NS1:item href="#4"/&gt;
        &lt;NS1:item href="#5"/&gt;
        &lt;NS1:item href="#6"/&gt;
        &lt;NS1:item href="#7"/&gt;
        &lt;NS1:item href="#8"/&gt;
        &lt;NS1:item href="#9"/&gt;
        &lt;NS1:item href="#10"/&gt;
        &lt;NS1:item href="#11"/&gt;
        &lt;NS1:item href="#12"/&gt;
        &lt;NS1:item href="#13"/&gt;
      &lt;/NS1:return&gt;
      &lt;NS2:item id="1" xsi:type="NS2:TFieldInfo"&gt;
        &lt;NS2:FieldName xsi:type="xsd:string"&gt;CustNo&lt;/NS2:FieldName&gt;
        &lt;NS2:FieldType xsi:type="xsd:string"&gt;ftFloat&lt;/NS2:FieldType&gt;
        &lt;NS2:FieldSize xsi:type="xsd:int"&gt;0&lt;/NS2:FieldSize&gt;
        &lt;NS2:IsKeyField xsi:type="xsd:boolean"&gt;False&lt;/NS2:IsKeyField&gt;
      &lt;/NS2:item&gt;
      &lt;NS2:item id="2" xsi:type="NS2:TFieldInfo"&gt;
        &lt;NS2:FieldName xsi:type="xsd:string"&gt;Company&lt;/NS2:FieldName&gt;
        &lt;NS2:FieldType xsi:type="xsd:string"&gt;ftWideString&lt;/NS2:FieldType&gt;
        &lt;NS2:FieldSize xsi:type="xsd:int"&gt;30&lt;/NS2:FieldSize&gt;
        &lt;NS2:IsKeyField xsi:type="xsd:boolean"&gt;False&lt;/NS2:IsKeyField&gt;
      &lt;/NS2:item&gt;
      &lt;NS2:item id="3" xsi:type="NS2:TFieldInfo"&gt;
        &lt;NS2:FieldName xsi:type="xsd:string"&gt;Addr1&lt;/NS2:FieldName&gt;
        &lt;NS2:FieldType xsi:type="xsd:string"&gt;ftWideString&lt;/NS2:FieldType&gt;
        &lt;NS2:FieldSize xsi:type="xsd:int"&gt;30&lt;/NS2:FieldSize&gt;
        &lt;NS2:IsKeyField xsi:type="xsd:boolean"&gt;False&lt;/NS2:IsKeyField&gt;
      &lt;/NS2:item&gt;
    &lt;/NS1:GetSchemaInfoResponse&gt;
  &lt;/SOAP-ENV:Body&gt;
&lt;/SOAP-ENV:Envelope&gt;
</pre></code></div></div>
<p><a rel="nofollow" href="http://www.matlus.com/images/DataSetXMLWebService1.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=2&amp;imagefile=DataSetXMLWebService1.jpg" border="0"></a> <br><b>Figure 1: Showing part of the WSDL file that defines the complexType</b> 
<p>The SOAP request is a standard request (for this WebService) calling the <code>GetSchemaInfo</code> method and sending it the <code>TableName</code>, <code>Customer</code>. The response by the WebService is what we need to take a closer look at. As I mentioned earlier, this method returns an array of objects. In XML terms, as you can see from the WSDL file or <b>Figure 1</b>, this is a <code><b>complexType</b></code> that is defined as an array. So you see, that the object is really defined like a Delphi record or C/C   struct. When a Delphi client receives this kind of data it gets converted into an object instance (more about this later). The <code>Customer</code> table in this case has 13 fields. You can see this from the HTTP response shown earlier. I've shown only the first 3 fields to save space, but the line: </p>
<div class="codeblockouter">Showing part of the HTTP Header and Content (SOAP Response) that tells us to expect 13 elements in the <code>TfieldInfoArray</code>. 
<div class="codeblockinner"><pre><code>
&lt;NS1:return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="NS2:TFieldInfo[13]"&gt;
</code></pre></div></div>tells us to expect 13 elements in the array <code>TFieldInfoArray</code>. If the client is a Java Client, then it will handle this response the way it needs to. It may or may not treat this response as an array of objects. That depends on the implementation of the framework used. Delphi 6's SOAP framework works with interfaces and objects. When you do SOAP with Delphi 6, you are really doing Remote Object Invocation. (That's where <code>TRIO</code> got it's name from. This is similar to RMI in Java with the advantage that the protocol is a standard. 
<p><a rel="nofollow" href="http://www.matlus.com/images/DataSetXMLWebService2.jpg" target="_blank"><img src="http://www.matlus.com/scripts/website.dll/GetThumbnailImage?reduction=1&amp;imagefile=DataSetXMLWebService2.jpg" border="0"></a> <br><b>Figure 2: SOAP is just a Wire Protocol</b> </p>
<p>Remember that SOAP is a wire protocol. What that means is that the actual communication between two end points is taking place using the SOAP protocol. What happens before the message leaves one end and what happens once the messages gets to the other end is left totally up the implementation specific details of the two end points. What is key is that everyone should be on the same page as far as their interpretation of the SOAP specification is concerned. Once the messages gets across the wire it's up to that end point how you deal with it. Even though SOAP has the word <b>Object</b> in it, is not necessary that there are any objects involved. When a Delphi built WebService server receives a SOAP Request, it instantiates an instance of an object. It doesn't matter what kind of client made a request or what platform the client is running on. Similarly, if a WebService responds with a SOAP Response as shown earlier, a Delphi WebService Client, will instantiate an instance of an array of objects with 13 elements in it. It doesn't matter what language the WebService was written in or what platform it is running on. That's just the way Delphi implements SOAP. </p>
<p>We saw in the - <a rel="nofollow" title="Building your First WebService in Delphi" href="http://www.matlus.com/scripts/website.dll/Tutorials?DelphiWebServices&amp;BuildingYourFirstWebservice&amp;3" target="_blank">Building your First WebService</a> tutorial (from here on in reffered to as "the previous tutorial), how Delphi built WebServices and clients figure out what these objects are and how to instantiate them and which objects to instanciate. In this case, the difference is that the WebService is returning an object. How the client figures out what this object is and how to instanciate which object, we'll see later in this tutorial (hint - the object needs to be registered with the Invocation Registry and needs to be derived from a specific class). </p>
<h2>Building the Server</h2>I won't go into the step by step instructions on how to start with building a WebService application with Delphi 6 Enterprise. If you've not built WebServices with Delphi before, I suggest you read the previous Tutorial. 
<p>The first thing we're going to need is to define our Interface. You can use the Wizard (available to registered users) or code the unit by hand. The method <code>GetDatasetAsXML</code> expects to see and SQL SELECT statement as a parameter and it returns the result of the query in the form of an XML document. The second method, <code>GetSchemaInfo</code> expects to see the name of a table (in this case a table that exists in the dbdemos.mdb Access database) and returns the schema of the table in the form of an array of <code>TFieldInfo</code> objects (one element per field). </p>
<p>
<div class="note"><img alt="exclamation.gif" src="http://www.matlus.com/images/exclamation.gif" border="0"> Returning an XML document as a result of a WebService method is not recommended. This is because the WSDL file indicates that this method will return a string. Someone building a client for this service simply looking at the WSDL file (which is really how WebServices are supposed to work.) will have no indication that this "string" is in fact going to be an XML document. </div>
<p>
<div class="opinion"><img alt="Suggestion.gif" src="http://www.matlus.com/images/Suggestion.gif" border="0"> When designing WebServices it is important to keep the spirit of WebServices. 
<ul>
<li>WSDL - always think, "Will just the WSDL file be enough for anyone else to use my WebService?" 
<li>Interoperability - People using other development tools and/or platforms should be able to access your WebService. </li></li></ul>If you feel you don't need to comply with these two points. You probably don't need to use WebServices. That is, if you're building the client and server for personal consumption, as a result you can ignore the above "requirements", there are probably better solutions for your needs. Remember, XML is a very verbose protocol and as a result tends to be very slow. The number of bytes being transferred between client and server is very large and there is a fair amount of processing on both the client and server in constructing the XML document and parsing it. There are solutions (I'll present one of them soon if I haven't already by the time you read this) that are much lighter than XML and can use HTTP and so still gain the benefits that SOAP provides but require a lot less bandwidth and processing power and as a result are more scalable. If you need to expose and API to a system you're building, to the out side world then WebServices is a good choice. If you're using WebServices for a Client/Server or n-tier system then WebServices is <b>not</b> the answer. You might want to take a look at this article on ZDNet <a rel="nofollow" href="http://techupdate.zdnet.com/techupdate/stories/main/0,14179,2836041,00.html" target="_blank">Fat protocols slow Web services</a>. </div>
<p>
<div class="codeblockouter">The <code>IDataSetXML</code> Interface Unit. 
<div class="codeblockinner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">DatasetXMLIntf</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">Types</font><font color="#ff0000">,</font> <font color="#000080">XSBuiltIns</font><font color="#ff0000">,</font> <font color="#000080">uFieldInfo</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">IDatasetXML</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>interface</b></font><font color="#ff0000">(</font><font color="#000080">IInvokable</font><font color="#ff0000">)</font>
    <font color="#ff0000">[</font><font color="#008000">'{C7785514-F56F-40AD-B943-950A162296BE}'</font><font color="#ff0000">]</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">GetDatasetAsXML</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">SelectSQL</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">GetSchemaInfo</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">TableName</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">TFieldInfoArray</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">InvokeRegistry</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInterface</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">IDatasetXML</font><font color="#ff0000">)</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>You should notice that there is an additional unit (<code>uFieldInfo</code>) in the <code>Uses</code> clause of this unit. This is the unit in which the <code>TFieldInfo</code> class is declared. 
<p>
<div class="codeblockouter">The <code>uFieldInfo</code> Unit. 
<div class="codeblockinner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">uFieldInfo</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">InvokeRegistry</font><font color="#ff0000">,</font> <font color="#000080">XSBuiltIns</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TFieldInfo</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TRemotable</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#000080">FIsKeyField</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">;</font>
    <font color="#000080">FFieldSize</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
    <font color="#000080">FFieldName</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
    <font color="#000080">FFieldType</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>published</b></font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">FieldName</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FFieldName</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FFieldName</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">FieldType</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FFieldType</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FFieldType</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">FieldSize</font><font color="#ff0000">:</font> <font color="#000080">Integer</font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FFieldSize</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FFieldSize</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">IsKeyField</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FIsKeyField</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FIsKeyField</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

  <font color="#000080">TFieldInfoArray</font> <font color="#ff0000">=</font>   <font color="#0000ff"><b>array</b></font> <font color="#0000ff"><b>of</b></font> <font color="#000080">TFieldInfo</font><font color="#ff0000">;</font>


<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">RemClassRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterXSClass</font><font color="#ff0000">(</font><font color="#000080">TFieldInfo</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">,</font> <font color="#008000">'TFieldInfo'</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">RemTypeRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterXSInfo</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">TFieldInfoArray</font><font color="#ff0000">)</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">,</font> <font color="#008000">'TFieldInfoArray'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>finalization</b></font>
  <font color="#000080">RemClassRegistry</font><font color="#ff0000">.</font><font color="#000080">UnRegisterXSClass</font><font color="#ff0000">(</font><font color="#000080">TFieldInfo</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">RemTypeRegistry</font><font color="#ff0000">.</font><font color="#000080">UnRegisterXSInfo</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">TFieldInfoArray</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>The things to notice here are the <code>initialization</code> and <code>finalization</code> sections, and the fact that the class <code>TFieldInfo</code> is derived from <code><b>TRemotable</b></code>. <code>TRemotable</code> is the base class for classes that can be passed as parameters or return values in a Web Service application. Again, this class is compiled with RTTI and has a virtual constructor that is used by the <code>TPascalInvoker</code> as explained in the previous tutorial. 
<p>
<div class="note"><img alt="exclamation.gif" src="http://www.matlus.com/images/exclamation.gif" border="0"> For ComplexTypes to work, you need to apply a fix to the <code>WebServExp.pas</code> source code file. This is an unofficial fix that I have made and is not supported. So far I have not seen any repercussions to implementing this fix. When Borland releases a patch or fix for this, please be sure to implement their fix rather than this. The WSDL generated without this fix is not correct as it does not include the definition for the complexTypes. </div>
<div class="codeblockouter">The following code listing shows the unofficial fix for the <code>WebServExp.pas</code> source code File. 
<div class="codeblockinner"><code><pre><font face="Courier New"><font color="#0000ff"><b>function</b></font> <font color="#000080">TWebServExp</font><font color="#ff0000">.</font><font color="#000080">FindSchema</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">ObjectTypeInfo</font><font color="#ff0000">:</font> <font color="#000080">PTypeinfo</font><font color="#ff0000">;</font> <font color="#0000ff"><b>const</b></font>
<font color="#000080">TnsURI</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">Index</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">False</font><font color="#ff0000">;</font>
  <font color="#808080">//Do not register Empty TnsURI or tkSet or any predefined type from XMLSchema</font>
<font color="#808080">{ TODO -oShiv Kumar -cBUG :</font>
<font color="#808080">Complex Types are not generated if this code is NOT commented.</font>
<font color="#808080">Don't know the implications of doing this, but so far have not had issues. }</font>

<font color="#808080">{  if ((TnsURI = '') or (ObjectTypeInfo.Kind = tkSet) or (TnsURI =</font>
<font color="#808080">SXMLSchemaURI_1999) or  (TnsURI = SXMLSchemaURI_2000_10) or</font>
<font color="#808080">    (TnsURI = SXMLSchemaURI_2001))  then</font>
<font color="#808080">  begin</font>
<font color="#808080">    Result := True;</font>
<font color="#808080">    Exit;</font>
<font color="#808080">  end;</font>
<font color="#808080">}</font>
  <font color="#0000ff"><b>for</b></font> <font color="#000080">Index</font> <font color="#ff0000">:=</font> <font color="#800080">0</font> <font color="#0000ff"><b>to</b></font> <font color="#000080">Length</font><font color="#ff0000">(</font><font color="#000080">SchemaArray</font><font color="#ff0000">)</font> <font color="#ff0000">-</font><font color="#800080">1</font> <font color="#0000ff"><b>do</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#0000ff"><b>if</b></font> <font color="#000080">SchemaArray</font><font color="#ff0000">[</font><font color="#000080">Index</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">TypeInfo</font> <font color="#ff0000">=</font> <font color="#000080">ObjectTypeInfo</font> <font color="#0000ff"><b>then</b></font>
    <font color="#0000ff"><b>begin</b></font>
      <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">True</font><font color="#ff0000">;</font>
      <font color="#000080">Exit</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

  <font color="#808080">//Add new type</font>
  <font color="#000080">Index</font> <font color="#ff0000">:=</font> <font color="#000080">Length</font><font color="#ff0000">(</font><font color="#000080">SchemaArray</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">SetLength</font><font color="#ff0000">(</font><font color="#000080">SchemaArray</font><font color="#ff0000">,</font> <font color="#000080">Index</font><font color="#ff0000"> </font><font color="#800080">1</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">SchemaArray</font><font color="#ff0000">[</font><font color="#000080">Index</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">TypeName</font> <font color="#ff0000">:=</font> <font color="#000080">ObjectTypeInfo</font><font color="#ff0000">.</font><font color="#000080">Name</font><font color="#ff0000">;</font>
  <font color="#000080">SchemaArray</font><font color="#ff0000">[</font><font color="#000080">Index</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">NameSpace</font> <font color="#ff0000">:=</font> <font color="#000080">TnsURI</font><font color="#ff0000">;</font>
  <font color="#000080">SchemaArray</font><font color="#ff0000">[</font><font color="#000080">Index</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">TypeInfo</font> <font color="#ff0000">:=</font> <font color="#000080">ObjectTypeInfo</font><font color="#ff0000">;</font>
  <font color="#000080">SchemaArray</font><font color="#ff0000">[</font><font color="#000080">Index</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">XSGenerated</font> <font color="#ff0000">:=</font> <font color="#000080">False</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>
<p>
<h2>More on TRemotable</h2>Some of you might have wondered after seeing the Interface declaration, especially the method: 
<p>
<p>
<div class="codeblockouter">
<div class="codeblockinner"><code><pre><font color="#0000ff"><b>function</b></font> <font color="#000080">GetSchemaInfo</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">TableName</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">TFieldInfoArray</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
</pre></code></div></div>Who is responsible for freeing the instance of <code>TFieldInfoArray</code> that is being returned? If this method were a regular method, then the calling method is responsible. In this case however, the calling method is a remote application, and what's more, it doesn't have to be a Delphi client that calls on this WebService. The answer is that when <code>TRemotable</code> descendants are created in a method that was called remotely using an <code>Invokable interface</code>, the instance is <b>automatically freed</b> after the value of the <code>TRemotable</code> descendant is marshaled for transport back to the client. So you don't need to worry about this aspect of it. 
<p>What if a <code>TRemotable</code> type is a parameter to a method instead of being returned as a result? On the Client end (Delphi Clients), the client is responsible for creating and instance of it before making the method call and freeing the instance after it is finished using it. On the server end, the instance is once again automatically created and freed. Of course, for all of this to work, both the client and server need to register the class with the Invocation Registry. This is very important. Take a look at the on-line help for the methods <code>RegisterXSClass</code> and <code>RegisterXSInfo</code>. </p>
<div class="codeblockouter">The unit <code>DatasetXMLImpl</code> that implements the <code>IDataSetXML</code> Interface. 
<div class="codeblockinner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">DatasetXMLImpl</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>interface</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">Classes</font><font color="#ff0000">,</font> <font color="#000080">DatasetXMLIntf</font><font color="#ff0000">,</font> <font color="#000080">InvokeRegistry</font><font color="#ff0000">,</font> <font color="#000080">uFieldInfo</font><font color="#ff0000">,</font> <font color="#000080">DB</font><font color="#ff0000">,</font> <font color="#000080">ADODB</font><font color="#ff0000">,</font> <font color="#000080">msxmldom</font><font color="#ff0000">,</font>
  <font color="#000080">xmldom</font><font color="#ff0000">,</font> <font color="#000080">XMLIntf</font><font color="#ff0000">,</font> <font color="#000080">XMLDoc</font><font color="#ff0000">;</font>

<font color="#0000ff"><b>type</b></font>
  <font color="#000080">ENotSelectSQL</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">ERemotableException</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#000080">FSQLStatememnt</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
    <font color="#000080">FNotes</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
    <font color="#000080">FReason</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>public</b></font>
    <font color="#0000ff"><b>constructor</b></font> <font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">IllegalSQLStatement</font><font color="#ff0000">,</font> <font color="#000080">AReason</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>published</b></font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">SQLStatement</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FSQLStatememnt</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FSQLStatememnt</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">Notes</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FNotes</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FNotes</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">Reason</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FReason</font> <font color="#0000ff"><b>write</b></font> <font color="#000080">FReason</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

  <font color="#000080">TDatasetXML</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TInvokableClass</font><font color="#ff0000">,</font> <font color="#000080">IDatasetXML</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#000080">XMLDocument1</font><font color="#ff0000">:</font> <font color="#000080">TXMLDocument</font><font color="#ff0000">;</font>
    <font color="#000080">ADOConnection1</font><font color="#ff0000">:</font> <font color="#000080">TADOConnection</font><font color="#ff0000">;</font>
    <font color="#000080">ADODataset1</font><font color="#ff0000">:</font> <font color="#000080">TADODataset</font><font color="#ff0000">;</font>
    <font color="#000080">DocumentElement</font><font color="#ff0000">:</font> <font color="#000080">IXMLNode</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">CreateDataAccessObjects</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">FreeDataAccessObjects</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">GenerateDataSection</font><font color="#ff0000">(</font><font color="#000080">Dataset</font><font color="#ff0000">:</font> <font color="#000080">TDataSet</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">GenerateSchemaSection</font><font color="#ff0000">(</font><font color="#000080">Dataset</font><font color="#ff0000">:</font> <font color="#000080">TDataSet</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">GenerateDataAsXML</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>public</b></font>
    <font color="#808080">{ IDatasetXML }</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">GetDatasetAsXML</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">SelectSQL</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">GetSchemaInfo</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">TableName</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">TFieldInfoArray</font><font color="#ff0000">;</font> <font color="#0000ff"><b>stdcall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>implementation</b></font>

<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">TypInfo</font><font color="#ff0000">,</font> <font color="#000080">SysUtils</font><font color="#ff0000">;</font>

<font color="#808080">{ TDatasetXML }</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">CreateDataAccessObjects</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">ADOConnection1</font> <font color="#ff0000">:=</font> <font color="#000080">TADOConnection</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#0000ff"><b>nil</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">ADODataset1</font> <font color="#ff0000">:=</font> <font color="#000080">TADODataset</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#0000ff"><b>nil</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">XMLDocument1</font> <font color="#ff0000">:=</font> <font color="#000080">TXMLDocument</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#0000ff"><b>nil</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">ADOConnection1</font><font color="#ff0000">.</font><font color="#000080">Provider</font> <font color="#ff0000">:=</font> <font color="#008000">'Microsoft.Jet.OLEDB.4.0'</font><font color="#ff0000">;</font>
  <font color="#000080">ADOConnection1</font><font color="#ff0000">.</font><font color="#000080">ConnectionString</font> <font color="#ff0000">:=</font> <font color="#008000">'Provider=Microsoft.Jet.OLEDB.4.0;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'Data Source=C:\Program Files\Common Files\Borland Shared\Data\dbdemos.mdb;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'Persist Security Info=False'</font><font color="#ff0000">;</font>
  <font color="#000080">ADOConnection1</font><font color="#ff0000">.</font><font color="#000080">LoginPrompt</font> <font color="#ff0000">:=</font> <font color="#000080">False</font><font color="#ff0000">;</font>
  <font color="#000080">ADOConnection1</font><font color="#ff0000">.</font><font color="#000080">Connected</font> <font color="#ff0000">:=</font> <font color="#000080">True</font><font color="#ff0000">;</font>
  <font color="#000080">ADODataset1</font><font color="#ff0000">.</font><font color="#000080">Connection</font> <font color="#ff0000">:=</font> <font color="#000080">ADOConnection1</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">FreeDataAccessObjects</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">ADODataset1</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
  <font color="#000080">ADOConnection1</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
  <font color="#000080">XMLDocument1</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>function</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">GetDatasetAsXML</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">SelectSQL</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>if</b></font> <font color="#000080">AnsiCompareText</font><font color="#ff0000">(</font><font color="#000080">Copy</font><font color="#ff0000">(</font><font color="#000080">SelectSQL</font><font color="#ff0000">,</font> <font color="#800080">1</font><font color="#ff0000">,</font> <font color="#800080">6</font><font color="#ff0000">)</font><font color="#ff0000">,</font> <font color="#008000">'SELECT'</font><font color="#ff0000">)</font> <font color="#ff0000">&lt;&gt;</font> <font color="#800080">0</font> <font color="#0000ff"><b>then</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#0000ff"><b>raise</b></font> <font color="#000080">ENotSelectSQL</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">SelectSQL</font><font color="#ff0000">,</font> <font color="#008000">'Only SELECT SQL Statements are Allowed'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
  <font color="#000080">CreateDataAccessObjects</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>try</b></font>
    <font color="#000080">ADODataset1</font><font color="#ff0000">.</font><font color="#000080">CommandText</font> <font color="#ff0000">:=</font> <font color="#000080">SelectSQL</font><font color="#ff0000">;</font>
    <font color="#000080">ADODataset1</font><font color="#ff0000">.</font><font color="#000080">Open</font><font color="#ff0000">;</font>
    <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">GenerateDataAsXML</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>finally</b></font>
    <font color="#000080">FreeDataAccessObjects</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>function</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">GetSchemaInfo</font><font color="#ff0000">(</font>
  <font color="#0000ff"><b>const</b></font> <font color="#000080">TableName</font><font color="#ff0000">:</font> <font color="#000080">WideString</font><font color="#ff0000">)</font><font color="#ff0000">:</font> <font color="#000080">TFieldInfoArray</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">i</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">CreateDataAccessObjects</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>try</b></font>
    <font color="#0000ff"><b>with</b></font> <font color="#000080">ADODataset1</font> <font color="#0000ff"><b>do</b></font>
    <font color="#0000ff"><b>begin</b></font>
      <font color="#000080">CommandText</font> <font color="#ff0000">:=</font> <font color="#008000">'SELECT * FROM '</font> <font color="#ff0000"> </font> <font color="#000080">TableName</font><font color="#ff0000">;</font>
      <font color="#000080">Open</font><font color="#ff0000">;</font>
      <font color="#000080">FieldDefs</font><font color="#ff0000">.</font><font color="#000080">Update</font><font color="#ff0000">;</font>
      <font color="#000080">SetLength</font><font color="#ff0000">(</font><font color="#000080">Result</font><font color="#ff0000">,</font> <font color="#000080">FieldCount</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
      <font color="#0000ff"><b>for</b></font> <font color="#000080">i</font> <font color="#ff0000">:=</font> <font color="#800080">0</font> <font color="#0000ff"><b>to</b></font> <font color="#000080">FieldCount</font> <font color="#ff0000">-</font><font color="#800080">1</font> <font color="#0000ff"><b>do</b></font>
      <font color="#0000ff"><b>begin</b></font>
        <font color="#000080">Result</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font> <font color="#ff0000">:=</font> <font color="#000080">TFieldInfo</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">;</font>
        <font color="#000080">Result</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">FieldName</font> <font color="#ff0000">:=</font> <font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">FieldName</font><font color="#ff0000">;</font>
        <font color="#000080">Result</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">FieldType</font> <font color="#ff0000">:=</font> <font color="#000080">GetEnumName</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">TFieldType</font><font color="#ff0000">)</font><font color="#ff0000">,</font><font color="#000080">Integer</font><font color="#ff0000">(</font><font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">DataType</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
        <font color="#000080">Result</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">FieldSize</font> <font color="#ff0000">:=</font> <font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">Size</font><font color="#ff0000">;</font>
        <font color="#000080">Result</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">IsKeyField</font> <font color="#ff0000">:=</font> <font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">IsIndexField</font><font color="#ff0000">;</font>
      <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ for i := 0 to Dataset.FieldCount -1 do }</font>
    <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ with Dataset do }</font>
  <font color="#0000ff"><b>finally</b></font>
    <font color="#000080">FreeDataAccessObjects</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>function</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">GenerateDataAsXML</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">XMLDocument1</font><font color="#ff0000">.</font><font color="#000080">Active</font> <font color="#ff0000">:=</font> <font color="#000080">True</font><font color="#ff0000">;</font>
  <font color="#000080">DocumentElement</font> <font color="#ff0000">:=</font> <font color="#000080">XMLDocument1</font><font color="#ff0000">.</font><font color="#000080">CreateElement</font><font color="#ff0000">(</font><font color="#008000">'dataset'</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#808080">{ Set this element as the Document Element }</font>
  <font color="#000080">XMLDocument1</font><font color="#ff0000">.</font><font color="#000080">DocumentElement</font> <font color="#ff0000">:=</font> <font color="#000080">DocumentElement</font><font color="#ff0000">;</font>
  <font color="#000080">GenerateSchemaSection</font><font color="#ff0000">(</font><font color="#000080">ADODataSet1</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">GenerateDataSection</font><font color="#ff0000">(</font><font color="#000080">ADODataSet1</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">XMLDocument1</font><font color="#ff0000">.</font><font color="#000080">XML</font><font color="#ff0000">.</font><font color="#000080">Text</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">GenerateSchemaSection</font><font color="#ff0000">(</font><font color="#000080">Dataset</font><font color="#ff0000">:</font> <font color="#000080">TDataSet</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">i</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
  <font color="#000080">SchemaElement</font><font color="#ff0000">:</font> <font color="#000080">IXMLNode</font><font color="#ff0000">;</font>
  <font color="#000080">AttributeElement</font><font color="#ff0000">:</font> <font color="#000080">IXMLNode</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">SchemaElement</font> <font color="#ff0000">:=</font> <font color="#000080">DocumentElement</font><font color="#ff0000">.</font><font color="#000080">AddChild</font><font color="#ff0000">(</font><font color="#008000">'schema'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>with</b></font> <font color="#000080">Dataset</font> <font color="#0000ff"><b>do</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#000080">FieldDefs</font><font color="#ff0000">.</font><font color="#000080">Update</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>for</b></font> <font color="#000080">i</font> <font color="#ff0000">:=</font> <font color="#800080">0</font> <font color="#0000ff"><b>to</b></font> <font color="#000080">FieldCount</font> <font color="#ff0000">-</font><font color="#800080">1</font> <font color="#0000ff"><b>do</b></font>
    <font color="#0000ff"><b>begin</b></font>
      <font color="#000080">AttributeElement</font> <font color="#ff0000">:=</font> <font color="#000080">SchemaElement</font><font color="#ff0000">.</font><font color="#000080">AddChild</font><font color="#ff0000">(</font><font color="#008000">'attributeType'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
      <font color="#000080">AttributeElement</font><font color="#ff0000">.</font><font color="#000080">SetAttribute</font><font color="#ff0000">(</font><font color="#008000">'fieldName'</font><font color="#ff0000">,</font> <font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">FieldName</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
      <font color="#000080">AttributeElement</font><font color="#ff0000">.</font><font color="#000080">SetAttribute</font><font color="#ff0000">(</font><font color="#008000">'fieldType'</font><font color="#ff0000">,</font> <font color="#000080">GetEnumName</font><font color="#ff0000">(</font><font color="#000080">TypeInfo</font><font color="#ff0000">(</font><font color="#000080">TFieldType</font><font color="#ff0000">)</font><font color="#ff0000">,</font><font color="#000080">Integer</font><font color="#ff0000">(</font><font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">DataType</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
      <font color="#000080">AttributeElement</font><font color="#ff0000">.</font><font color="#000080">SetAttribute</font><font color="#ff0000">(</font><font color="#008000">'fieldSize'</font><font color="#ff0000">,</font> <font color="#000080">IntToStr</font><font color="#ff0000">(</font><font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">Size</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ for i := 0 to Dataset.FieldCount -1 do }</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ with Dataset do }</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TDatasetXML</font><font color="#ff0000">.</font><font color="#000080">GenerateDataSection</font><font color="#ff0000">(</font><font color="#000080">Dataset</font><font color="#ff0000">:</font> <font color="#000080">TDataSet</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">i</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
  <font color="#000080">DataElement</font><font color="#ff0000">:</font> <font color="#000080">IXMLNode</font><font color="#ff0000">;</font>
  <font color="#000080">RowElement</font><font color="#ff0000">:</font> <font color="#000080">IXMLNode</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">DataElement</font> <font color="#ff0000">:=</font> <font color="#000080">DocumentElement</font><font color="#ff0000">.</font><font color="#000080">AddChild</font><font color="#ff0000">(</font><font color="#008000">'data'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>with</b></font> <font color="#000080">Dataset</font> <font color="#0000ff"><b>do</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#000080">First</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>while</b></font> <font color="#0000ff"><b>not</b></font> <font color="#000080">Eof</font> <font color="#0000ff"><b>do</b></font>
    <font color="#0000ff"><b>begin</b></font>
      <font color="#000080">RowElement</font> <font color="#ff0000">:=</font> <font color="#000080">DataElement</font><font color="#ff0000">.</font><font color="#000080">AddChild</font><font color="#ff0000">(</font><font color="#008000">'row'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
      <font color="#0000ff"><b>for</b></font> <font color="#000080">i</font> <font color="#ff0000">:=</font> <font color="#800080">0</font> <font color="#0000ff"><b>to</b></font> <font color="#000080">Dataset</font><font color="#ff0000">.</font><font color="#000080">FieldCount</font> <font color="#ff0000">-</font><font color="#800080">1</font> <font color="#0000ff"><b>do</b></font>
      <font color="#0000ff"><b>begin</b></font>
         <font color="#000080">RowElement</font><font color="#ff0000">.</font><font color="#000080">SetAttribute</font><font color="#ff0000">(</font><font color="#000080">Dataset</font><font color="#ff0000">.</font><font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">FieldName</font><font color="#ff0000">,</font> <font color="#000080">Dataset</font><font color="#ff0000">.</font><font color="#000080">Fields</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">.</font><font color="#000080">AsString</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
      <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ for i := 0 to Table1.FieldCount -1 do }</font>
      <font color="#000080">Next</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ while not Eof do }</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font> <font color="#808080">{ with Table do }</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>


<font color="#808080">{ ENotSelectSQL }</font>

<font color="#0000ff"><b>constructor</b></font> <font color="#000080">ENotSelectSQL</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">IllegalSQLStatement</font><font color="#ff0000">,</font> <font color="#000080">AReason</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">FSQLStatememnt</font> <font color="#ff0000">:=</font> <font color="#000080">IllegalSQLStatement</font><font color="#ff0000">;</font>
  <font color="#000080">FNotes</font> <font color="#ff0000">:=</font> <font color="#008000">'Due to Security Reasons. Only SQL SELECT Statments are allowed.'</font> <font color="#ff0000"> </font> <font color="#008000">#13</font><font color="#008000">#10</font><font color="#ff0000"> </font>
   <font color="#008000">'Further, the WebService can Access only the DBDEMOS.mdb database'</font><font color="#ff0000">;</font>
  <font color="#000080">FReason</font> <font color="#ff0000">:=</font> <font color="#000080">AReason</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">Reason</font> <font color="#ff0000"> </font> <font color="#008000">#13</font><font color="#008000">#10</font><font color="#ff0000"> </font><font color="#000080">Notes</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>

<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">InvRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterInvokableClass</font><font color="#ff0000">(</font><font color="#000080">TDatasetXML</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">RemClassRegistry</font><font color="#ff0000">.</font><font color="#000080">RegisterXSClass</font><font color="#ff0000">(</font><font color="#000080">ENotSelectSQL</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">,</font> <font color="#008000">'ENotSelectSQL'</font><font color="#ff0000">,</font> <font color="#008000">''</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>
<p>The implementation of the <code>IDataSetXML</code> Interface is quite straightforward. We use the <code>TXMLDocument</code> component (New to Delphi 6 - read about it on the on-line help) to generate the XML being returned as a result of the <code>GetDataSetXML</code> method. Of course we could have just as easily used ADO and it's inherent capability to produce XML documents of the recordset it holds. But I did it this way for those that may not want to use ADO and secondly, since we have this new component in D6. </p>
<h2>ERemotableException</h2>First, let me say, that it is not required that you define a custom exception in your WebService projects. If an Exception (EException) is raised at the server end while executing a SOAP Request, the exception will be automatically encoded as a SOAP Fault packet and returned to the client. The client, on seeing this fault packet will raise an exception. So why then would we want to create custom remotable exceptions? Either when you need to convey more information than a simple message (published properties etc. will be encoded into the SOAP Fault packet) and/or if you need different kinds of exceptions in your application for better handling (more granular) of Exceptions. 
<p>The base class for Remotable Exceptions is <code>ERemotableException</code>. You need to derive your custom exceptions from this class and register them using the <code>RegisterXSClass</code> method. If the client of this WebService is a Delphi client, then your custom exceptions need to be register at the client side as well (this is automatically handled for you when you import the WSDL File using the expert. 
<p>The HTTP Header and content shown below is a sample <b>SOAP Fault Packet</b> of an exception of type <code>ENotSelectSQL</code> raised by the server. </p>
<p>
<div class="codeblockouter">HTTP Header and Content showing a SOAP Fault Packet. 
<div class="codeblockinner"><code><pre>HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Fri, 20 Jul 2001 10:48:43 GMT
Content-Type: text/xml
Content-Length: 1066
Content:

&lt;?xml version="1.0" encoding='UTF-8'?&gt;
&lt;SOAP-ENV:Envelope
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"&gt;
  &lt;SOAP-ENV:Body&gt;
    &lt;SOAP-ENV:Fault&gt;
      &lt;SOAP-ENV:faultcode&gt;SOAP-ENV:Server&lt;/SOAP-ENV:faultcode&gt;
      &lt;SOAP-ENV:faultstring&gt;Only SELECT SQL Statements are Allowed Due to Security Reasons.
                            Only SQL SELECT Statments are allowed.
                            Further, the WebService can Access only the DBDEMOS.mdb database&lt;/SOAP-ENV:faultstring&gt;
      &lt;NS1:detail xmlns:NS1="http://www.w3.org/2001/XMLSchema" xsi:type="NS1:ENotSelectSQL"&gt;
        &lt;NS1:SQLStatement xsi:type="xsd:string"&gt;SELEC * FROM CUSTOMER&lt;/NS1:SQLStatement&gt;
        &lt;NS1:Notes xsi:type="xsd:string"&gt;Due to Security Reasons. Only SQL SELECT Statments are allowed.
                                         Further, the WebService can Access only the DBDEMOS.mdb database&lt;/NS1:Notes&gt;
        &lt;NS1:Reason xsi:type="xsd:string"&gt;Only SELECT SQL Statements are Allowed&lt;/NS1:Reason&gt;
      &lt;/NS1:detail&gt;
    &lt;/SOAP-ENV:Fault&gt;
  &lt;/SOAP-ENV:Body&gt;
&lt;/SOAP-ENV:Envelope&gt;
</pre></code></div></div>
<p>This finishes the WebService Server. Next we'll tackle the WebService client. </p>
<div class="note"><img alt="exclamation.gif" src="http://www.matlus.com/images/exclamation.gif" border="0"> The client is really very simple in this case and so I don't go into it here. But it is available for download with the rest of this project. </div></g>]]></description><category>Programming</category><category>Work</category><category>Delphi</category><category>SOAP</category><category>WebServices</category></item><item><title>Learn how to Build ASP Objects with Delphi</title><pubDate>Sun, 20 Jan 2008 10:57:50 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/4/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/4/</guid><description><![CDATA[You will find a demo application of the project we are about to embark on at the link below. <br><br><a href="http://www.matlus.com/Vendors.htm" target="_blank">Delphi Data Access ASP Object - A List Of Vendors</a> <br><br>Here, The Data Access components are connected to the Vendors table in DBDEMOS Alias. In the Memo Field Provided you can type in a valid SQL Statement for that table to see the result in an HTML page. The ASP object is built such that is expects to see one parameters as a field in an HTML Form. This html page in turn calls on an ASP page that looks like this: <pre>&lt;HTML&gt;
&lt;HEAD&gt;
  &lt;LINK REL=STYLESHEET TYPE="text/css" href="/home-styles.css"&gt;
  &lt;TITLE&gt; Delphi ASP Object Demo&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY&gt;
&lt;CENTER&gt;&lt;H2&gt;Vendors Table from DBEMOS&lt;/H2&gt;&lt;/CENTER&gt;
&lt;HR&gt;
&lt;% Set DelphiASPObj = Server.CreateObject("DelphiASP.Vendor")
   DelphiASPObj.GetVendors
%&gt;
&lt;HR&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</pre><br><br>My project creates a file called DelphiASP.dll that is kept in the scripts folder. This library contains an object called Vendor that has a method called GetVendors. The parameter (SQL Statement) is "extracted" from the Request (ASP) object. The method GetVendors looks like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">GetVendors</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">sSQL</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">sSQL</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">Form</font><font color="#ff0000">[</font><font color="#008000">'txtSQL'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#000080">DM</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">(</font><font color="#000080">sSQL</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>
<h2>Building you first ASP object in Delphi</h2>When people talk about ASP, they really mean ASP script, usually done using Visual Interdev, Drumbeat etc. ASP scripting is very different from ASP objects. ASP scripts are much slower as they are interpreted. ASP objects on the other hand are compiled (usually DLLs). IIS uses mechanisms that help speed up ASP scripts but these by no means make them as fast as compiled objects. <br><br>A big difference between ASP objects and ISAPI is that the ASP engine needs to be loaded in memory for ASP objects to run, while ISAPI DLLs are native DLLs (ASP DLLs are COM DLLs) and require fewer resource than ASP and have less layers to go through. <br><br>VB can build ASP objects too, but VB's threading capabilities are ...umm, lets just say..pitiful. What's a thread huh?<g> Also, COM DLLs compiled with Delphi, like most things Delphi does are self contained. Yes they need the COM run time, but they don't need other DLLs, like VB DLLs or even VC COM DLLs for that matter. <br><br>Data Access speeds in Delphi once again are far better than VB. All in all, a COM DLL built in Delphi will out perform a COM DLL built in VB or VC . <br><br>How many ASP programmers do you think use ASP objects? Hardly any. Yes, they use third party objects by way of reusability. But they don't go around building their own ASP objects. They are primarily ASP scripting people. <br><br>As a Delphi programmer, you can build ASP objects that these programmers can use or you can build a whole web site using ASP objects. I'd personally, just use ISAPI, but then there are those that get caught up with buzzwords. If it weren't for buzzwords, I wouldn't be writing this article now would I? <br><br>The ASP engine that comes with Win98/Win2000 (needs to be installed for Win95.) is nothing but an ISAPI DLL. The name of the file is ASP.DLL. This DLL is loaded into memory by IIS, which in turn does the interpreting of ASP scripts or loads the ASP DLL objects into memory (along with a TON of other junk). For an ISAPI programmer (building ASP objects), this adds an unnecessary layer and slows things down due to the COM overhead. Believe you me, this overhead is a lot. Your server can do far better without this overhead. <br><br>So what's better, ASP or ISAPI? As per Microsoft (read my article - ISAPI versus CGI for quotes from the M$ web site), for speed, scalability and resources, use ISAPI, for all other things use ASP. I'd say, if you are a programmer, use ISAPI, if you're a VBer, use ASP&lt;G&gt; <br><br>Enough slandering, lets get on with our project. <br><br>In this project, we're going to build an ASP object that connects to the VENDORS table in DBDEMOS. A very simple project, but none the less, get the picture (ASP) across. <br><br>
<h2>What is needed for this project</h2>
<ol>
<li>I am personally using <b>Firebird 1.0</b> for this project as well as my whole web site. You can download Interbase 6.0 for free from <a href="http://www.interbase2000.org/" rel="nofollow">Here</a>. I'm really impressed with its speed and light weight. I've upsized the DBDEMOS database to Interbase. Using the Interbase Express components that come with Delphi (Enterprise), I'm now free of the BDE as well. But you can use the standard DBDEMOS database (paradox) for this tutorial if you wish. The methods of the data access objects are the same. Some properties differ. 
<li>You'll need to have the ASP engine installed if you are using Win95. You should probably be able to download this from the Microsoft site. 
<li>Delphi Professional or Enterprise, since I believe these are the only versions that come with the ASP object (Wizard/Expert) option. </li></li></li></ol>Before we really start building the project, lets see what exactly we're going to do. First we need to have an ActiveX library (COM DLL). To this library, we need to add an ASP object. We need to give this ASP objects a method, that will return the data from VENDORS table. <br><br>Getting ahead of ourselves a bit, lets examine the ASP file that will create our object and call its method. The ASP file looks like this: <pre>&lt;HTML&gt;
&lt;HEAD&gt;
  &lt;TITLE&gt; Delphi ASP Object Demo&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY&gt;
&lt;CENTER&gt;&lt;H2&gt;Vendors Table from DBEMOS&lt;/H2&gt;&lt;/CENTER&gt;
&lt;HR&gt;
&lt;% Set DelphiASPObj = Server.CreateObject("DelphiASP.Vendor")
   DelphiASPObj.GetVendors
%&gt;
&lt;HR&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</pre><img alt="ASPArchitecture.png" src="http://www.matlus.com/images/ASPArchitecture.png" border="0"><br><b>Figure 1: Showing the Flow of a Request made by a web browser</b> <br><br>As Shown in <b>Figure 1</b> ASP works similar to ISAPI in that it receives a request, processes it, and sends back a response in the form of HTML. The <kbd>&lt;% and %&gt;</kbd> are the ASP script delimiters. The stuff between these delimiters is processed at the server end by the ASP engine. It will be replaced by HTML after processing. So imagine, if you will, that in the ASP file above, our method's output should result in HTML that will display data from the VENDORS table. The parts, before and after the ASP script delimiters are standard HTML. 
<h2>In the ASP script</h2>Looking at the ASP file above. More notably, the ASP script, you'll notice the VB syntax that creates a COM object. <pre>  Set DelphiASPObject = Server.CreateObject("DelphiASP.Vendor")
</pre><kbd>DelphiASP</kbd> is the name of our ASP DLL file. In the DLL, we have an ASP object called <kbd>Vendor</kbd>. The next line: <pre>  DelphiASPObject.GetVendors
</pre>Once the object (<kbd>DelphiASPObject</kbd>, which is of the type <kbd>DelphiASP</kbd>) is created, we call its method - <kbd>GetVendors</kbd>. We create this method for our object and we have to implement this method. The result of this method returns a valid HTML string. And so, in this way, we've replaced the <kbd>&lt;% and %&gt;</kbd> with HTML that is then sent out through the (oh so sluggish) ASP/COM engine, then through the web server onto the (unsuspecting) client. <br><br>The Good news is that Delphi creates the .asp file for us. 
<h2>Starting the Project</h2>Lets get started with actually building the project. 
<ol>
<li>Form Delphi's File menu, choose <kbd>New</kbd> 
<li>In the New Items Dialog, switch to the <kbd>ActiveX</kbd> Page. 
<li>Choose <kbd>ActiveX Library</kbd> and then click OK. 
<li>Form the File menu choose <kbd>New</kbd> 
<li>In the New Items Dialog, switch to the <kbd>ActiveX</kbd> Page. 
<li>This time Choose <kbd>Active Server Object</kbd>. 
<li>In the New Active Server Object dialog, type is <kbd>Vendor</kbd> in the <kbd>CoClass Name</kbd> field. 
<li>If you are using IIS 5.0 or later, Change the <kbd>Active Server Type</kbd> option to <kbd>Object Context</kbd>. 
<li>Click OK </li></li></li></li></li></li></li></li></li></ol>If you're not familiar with the various options presented in the New Active Server Object dialog, I suggest you read the on-line help on those various options by hitting the F1 key while the dialog is active. <br><br>You should now see the Type Library Editor as shown in <b>Figure 2</b>. <br><br><img alt="FirstASP1.png" src="http://www.matlus.com/images/FirstASP1.png" border="0"><br><b>Figure 2: Showing the Type Library Editor of the Active Server Object.</b> <br><br>Lets save the project we've created thus far. 
<ul>
<li>Save Vendor.asp as Vendor.asp 
<li>unit1.pas as uVendor_Impl.pas 
<li>Project1.dpr as DelphiASP.dpr </li></li></li></ul>The unit, DelphiASP_TLB is the type library for our Active Server Object. Hitting the F12 key when this unit is active will toggle between the type library editor and this unit. The unit uVendor_Impl is the implementation of our Active Server Object. This is the unit in which we will write code to implement the methods we give our ASP object. Vendor.asp is the ASP file that, when called will create an instance of our ASP object and call the required method. <pre>&lt;HTML&gt;
&lt;BODY&gt;
&lt;TITLE&gt; Testing Delphi ASP &lt;/TITLE&gt;
&lt;CENTER&gt;
&lt;H3&gt; You should see the results of your Delphi Active Server method below &lt;/H3&gt;
&lt;/CENTER&gt;
&lt;HR&gt;
&lt;% Set DelphiASPObj = Server.CreateObject("Project1.Vendor") 
   DelphiASPObj.{Insert Method name here}
%&gt;
&lt;HR&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</pre>Notice, that the method name is unknown as this time and so we see<kbd>{Insert Method name here}</kbd> in its place. Once we create a method and implement it, it is our job to modify the .asp file such that is calls the right method of our object. Also notice the line <pre>&lt;% Set DelphiASPObj = Server.CreateObject("Project1.Vendor")
</pre>Since this file was created before we saved our project with a new name, we need to change <kbd>Project1</kbd> to <kbd>DelphiASP</kbd>. Lets go ahead and do that now. <br><br>The uVendor_impl.pas unit looks like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">uVendor_Impl</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>interface</b></font>
<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">ComObj</font><font color="#ff0000">,</font> <font color="#000080">ActiveX</font><font color="#ff0000">,</font> <font color="#000080">AspTlb</font><font color="#ff0000">,</font> <font color="#000080">DelphiASP_TLB</font><font color="#ff0000">,</font> <font color="#000080">StdVcl</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TVendor</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TASPObject</font><font color="#ff0000">,</font> <font color="#000080">IVendor</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>protected</b></font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">OnEndPage</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">AScriptingContext</font><font color="#ff0000">:</font> <font color="#000080">IUnknown</font><font color="#ff0000">)</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>implementation</b></font>
<font color="#0000ff"><b>uses</b></font> <font color="#000080">ComServ</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">OnEndPage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">OnEndPage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">AScriptingContext</font><font color="#ff0000">:</font> <font color="#000080">IUnknown</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#000080">AScriptingContext</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">TAutoObjectFactory</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">ComServer</font><font color="#ff0000">,</font> <font color="#000080">TVendor</font><font color="#ff0000">,</font> <font color="#000080">Class_Vendor</font><font color="#ff0000">,</font>
    <font color="#000080">ciMultiInstance</font><font color="#ff0000">,</font> <font color="#000080">tmApartment</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>Delphi has generated this unit for us. Notice that we have an object <kbd>TVendor</kbd> that is derived from <kbd>TASPObject</kbd> and implements the <kbd>IVendor</kbd> interface. So far, this is just a skeleton and it is this unit that we will write our implementation code in. <br><br>Some of you might have noticed that unlike an ISAPI/CGI project, we have no place to keep our components such as data access components. In other words, there is no web data module created for us. We could create all the components we want/need on the fly and use them that way. I prefer using a Data Module for this. So lets add new Data Module to our project. 
<ol>
<li>From the File menu, choose New 
<li>Choose <kbd>Data Module</kbd> from the New Items dialog box. 
<li>Name the Data Module - <kbd>DM1</kbd> 
<li>Save the Project. When prompted, name the unit <kbd>uDM</kbd> </li></li></li></li></ol>
<h2>Creating the GetVendors Method</h2>Since we're working with a COM object, we need to use the Type Library editor to give our object properties and methods. So lets get to the Type library Editor. If you don't see it, make the unit DelphiASP_TLB the active unit in the code editor and then hit the F12 key. <br><br>In the TreeView of the type library editor, you should notice our (COM DLL) library DelphiASP has an interface IVendor. Select IVendor in the TreeView and click on the <kbd>New Method</kbd> tool bar icon. When you see the new method, change the name to <kbd>GetVendors</kbd>. <br><br>Then click on the <kbd>Refresh Implementation</kbd> tool bar button in the type library editor. This action will create a skeleton of the implementation for us in the Delphi object that implements this interface. Namely, <kbd>Tvendor</kbd> in the unit <kbd>uVendor_Impl</kbd>. 
<h2>Implementing the GetVendors Method</h2>Most of this part is standard Delphi programming. One of the things that the base class for Delphi ASP objects (TASPObject) does is, it gives us access to the various ASP objects and methods, such as the Request and Response objects, the ASP Session object etc. So in any method within this unit, we have access to these objects. <br><br>In the implementation of the GetVendors method, we need to make sure, we generate valid HTML and hand it over to the Response object. The ASP Response object has a method called <kbd>Write</kbd> that declared as <pre>  <b>procedure</b> Write(varText: OleVariant); safecall;
</pre>Before we go any further, lets examine the difference between the ISAPI response object and the ASP response object. If we had code in an ISAPI application that looked like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New">  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font> <font color="#008000">'Hello World'</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>In</b></font> <font color="#000080">our</font> <font color="#000080">ASP</font> <font color="#0000ff"><b>object</b></font> <font color="#000080">it</font> <font color="#000080">would</font> <font color="#000080">be</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#008000">'Hello World'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>If</b></font> <font color="#000080">on</font> <font color="#000080">the</font> <font color="#000080">other</font> <font color="#000080">hand</font> <font color="#000080">we</font> <font color="#000080">had</font> <font color="#000080">this</font> <font color="#0000ff"><b>in</b></font> <font color="#000080">our</font> <font color="#000080">ISAPI</font><font color="#ff0000">:</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font> <font color="#008000">'Hello'</font><font color="#ff0000">;</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font> <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000"> </font> <font color="#008000">'World'</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>In</b></font> <font color="#000080">our</font> <font color="#000080">ASP</font> <font color="#0000ff"><b>object</b></font> <font color="#000080">it</font> <font color="#000080">would</font> <font color="#000080">be</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#008000">'Hello'</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#008000">'World'</font><font color="#ff0000">)</font><font color="#ff0000">;</font></font>
</pre></code></div></div>You will notice that you won't find any documentation on the ASP objects in Delphi. They've left it to Microsoft to document. So you'll have to refer to the Microsoft web site for any documentation for the ASP objects. One place I've found such information is in <a href="http://msdn2.microsoft.com/en-us/library/aa231199.aspx" target="New" rel="nofollow">MSDN</a> <br><br>By way of good design, we're going to leave the Data Access methods to our DataModule. In our TVendor class, we'll call methods of the DataModule. This will keep our code cleaner. To use the Data Module from within our TVendor class, we need to add the Data Module's unit to the uses clause of the interface section (yes, the interface section and not the implementation section. We''l see why later). Once we've done that, we can call methods of our DataModule by referencing it. <br><br>We have only one line of code in the implementation of the GetVendors method of our TVendor class. 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#000080">DM1</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">)</font><font color="#ff0000">;</font></font>
</pre></code></div></div><kbd>GetVendorInfoPage</kbd> is a public method of our DataModule. <br><br>The unit of our TVendor class should now look like this: <pre>&lt;% Set DelphiASPObj = Server.CreateObject("Project1.Vendor")
</pre>Since this file was created before we saved our project with a new name, we need to change <kbd>Project1</kbd> to <kbd>DelphiASP</kbd>. Lets go ahead and do that now. <br><br>The uVendor_impl.pas unit looks like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">uVendor_Impl</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>interface</b></font>
<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">ComObj</font><font color="#ff0000">,</font> <font color="#000080">ActiveX</font><font color="#ff0000">,</font> <font color="#000080">AspTlb</font><font color="#ff0000">,</font> <font color="#000080">DelphiASP_TLB</font><font color="#ff0000">,</font> <font color="#000080">StdVcl</font><font color="#ff0000">,</font> <font color="#000080">uDM</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TVendor</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TASPObject</font><font color="#ff0000">,</font> <font color="#000080">IVendor</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>protected</b></font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">OnEndPage</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">AScriptingContext</font><font color="#ff0000">:</font> <font color="#000080">IUnknown</font><font color="#ff0000">)</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">GetVendors</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>implementation</b></font>
<font color="#0000ff"><b>uses</b></font> <font color="#000080">ComServ</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">OnEndPage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">OnEndPage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">AScriptingContext</font><font color="#ff0000">:</font> <font color="#000080">IUnknown</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#000080">AScriptingContext</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">GetVendors</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#000080">DM</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">TAutoObjectFactory</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">ComServer</font><font color="#ff0000">,</font> <font color="#000080">TVendor</font><font color="#ff0000">,</font> <font color="#000080">Class_Vendor</font><font color="#ff0000">,</font>
    <font color="#000080">ciMultiInstance</font><font color="#ff0000">,</font> <font color="#000080">tmApartment</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>
<h2>Working on the DataModule</h2>We've done nothing so far with the DataModule, so lets get started. 
<ol>
<li>Drop a TQuery on the DataModule 
<li>Set its DatabaseName property to <kbd>DBDEMOS</kbd> 
<li>Set its SQL property to <kbd>SELECT * FROM VENDORS</kbd> 
<li>Set the Active property to <kbd>True</kbd> 
<li>Drop a TSession component on the DataModule and set its AutoSessionName property to <kbd>True</kbd> 
<li>Drop a TDataSetTableProducer component on the DataModule and set its DataSet property to <kbd>Query1</kbd> 
<li>Declare a public method like so: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>function</b></font> <font color="#000080">GetVendorInfoPage</font><font color="#ff0000">(</font><font color="#000080">sSQL</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">)</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>
<li>Complete the class (Ctrl SHIFT C) to create the implementation stub of this method </li></li></li></li></li></li></li></li></ol><br><br><b>Figure 3</b> show what the Data Module should look like after having completed the steps outlined above. <br><br><img alt="FirstASP3.png" src="http://www.matlus.com/images/FirstASP3.png" border="0"> <br><b>Figure 3 Showing the Data Module with its components</b> <br><br>The unit for the DataModule should be like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">uDM</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>interface</b></font>
<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">Windows</font><font color="#ff0000">,</font> <font color="#000080">Messages</font><font color="#ff0000">,</font> <font color="#000080">SysUtils</font><font color="#ff0000">,</font> <font color="#000080">Classes</font><font color="#ff0000">,</font> <font color="#000080">Graphics</font><font color="#ff0000">,</font> <font color="#000080">Controls</font><font color="#ff0000">,</font> <font color="#000080">Forms</font><font color="#ff0000">,</font> <font color="#000080">Dialogs</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TDM1</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font> <font color="#ff0000">(</font><font color="#000080">TDataModule</font><font color="#ff0000">)</font>
    <font color="#000080">Query1</font><font color="#ff0000">:</font> <font color="#000080">TQuery</font><font color="#ff0000">;</font>
    <font color="#000080">Session1</font><font color="#ff0000">:</font> <font color="#000080">TSession</font><font color="#ff0000">;</font>
    <font color="#000080">DataSetTableProducer1</font><font color="#ff0000">:</font> <font color="#000080">TDataSetTableProducer</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>private</b></font>
    <font color="#808080">{ Private declarations }</font>
  <font color="#0000ff"><b>public</b></font>
    <font color="#0000ff"><b>function</b></font> <font color="#000080">GetVendorInfoPage</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
    <font color="#808080">{ Public declarations }</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">DM1</font><font color="#ff0000">:</font> <font color="#000080">TDM1</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>implementation</b></font>
<font color="#808080">{$R *.DFM}</font>
<font color="#808080">{ TDM1 }</font>
<font color="#0000ff"><b>function</b></font> <font color="#000080">TDM1</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>The function GetVendorInfo has only one line of code 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">DataSetTableProducer1</font><font color="#ff0000">.</font><font color="#000080">Content</font><font color="#ff0000">;</font></font>
</pre></code></div></div>That's all there is to it! The output produced by this ASP object will be a simple HTML table as will be produced by the TDataSetTableProducer component. We can modify properties of this component to enhance the look of the HTML page produced. And we shall. But before we proceed . <br><br>One important thing you need to remember is that the DataModule is not going to be created automatically for us. We need to explicitly create and destroy the DataModule in our ActiveX Library projects. We'll create the DataModule in the OnStartPage method and Free it in the OnEndPage method of our TVendor class. <br><br>Also, notice the implementation of the GetVendors method of our TVendor class. We reference an object called DM and not DM1. DM has been declared as a read only property of our TVendor Class (hence the need to declare uDM in the interface section). <br><br>The uVendor_impl.pas unit now looks like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>unit</b></font> <font color="#000080">uVendor_Impl</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>interface</b></font>
<font color="#0000ff"><b>uses</b></font>
  <font color="#000080">ComObj</font><font color="#ff0000">,</font> <font color="#000080">ActiveX</font><font color="#ff0000">,</font> <font color="#000080">AspTlb</font><font color="#ff0000">,</font> <font color="#000080">DelphiASP_TLB</font><font color="#ff0000">,</font> <font color="#000080">StdVcl</font><font color="#ff0000">,</font> <font color="#000080">uDM</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>type</b></font>
  <font color="#000080">TVendor</font> <font color="#ff0000">=</font> <font color="#0000ff"><b>class</b></font><font color="#ff0000">(</font><font color="#000080">TASPObject</font><font color="#ff0000">,</font> <font color="#000080">IVendor</font><font color="#ff0000">)</font>
  <font color="#0000ff"><b>protected</b></font>
    <font color="#000080">FDM</font> <font color="#ff0000">:</font> <font color="#000080">TDM1</font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">OnEndPage</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">AScriptingContext</font><font color="#ff0000">:</font> <font color="#000080">IUnknown</font><font color="#ff0000">)</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>procedure</b></font> <font color="#000080">GetVendors</font><font color="#ff0000">;</font> <font color="#0000ff"><b>safecall</b></font><font color="#ff0000">;</font>
    <font color="#0000ff"><b>property</b></font> <font color="#000080">DM</font> <font color="#ff0000">:</font> <font color="#000080">TDM1</font> <font color="#0000ff"><b>read</b></font> <font color="#000080">FDM</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">DM</font> <font color="#ff0000">:</font> <font color="#000080">TDM1</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>implementation</b></font>
<font color="#0000ff"><b>uses</b></font> <font color="#000080">ComServ</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">OnEndPage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">FDM</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
  <font color="#000080">FDM</font> <font color="#ff0000">:=</font> <font color="#0000ff"><b>nil</b></font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">OnEndPage</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#0000ff"><b>const</b></font> <font color="#000080">AScriptingContext</font><font color="#ff0000">:</font> <font color="#000080">IUnknown</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>inherited</b></font> <font color="#000080">OnStartPage</font><font color="#ff0000">(</font><font color="#000080">AScriptingContext</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
  <font color="#000080">FDM</font> <font color="#ff0000">:=</font> <font color="#000080">TDM1</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#0000ff"><b>nil</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">GetVendors</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#000080">DM</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>initialization</b></font>
  <font color="#000080">TAutoObjectFactory</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">(</font><font color="#000080">ComServer</font><font color="#ff0000">,</font> <font color="#000080">TVendor</font><font color="#ff0000">,</font> <font color="#000080">Class_Vendor</font><font color="#ff0000">,</font>
    <font color="#000080">ciMultiInstance</font><font color="#ff0000">,</font> <font color="#000080">tmApartment</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">.</font></font>
</pre></code></div></div>
<h2>Compiling and Testing</h2>A couple of things are different from an ISAPI project here. The reason being, you're dealing with ASP and COM and not native DLLs. 
<ol>
<li>From the Project menu, choose <kbd>Options</kbd> and switch to the <kbd>Directories/Conditionals</kbd> page in the project options dialog. 
<li>Set the <kbd>Output Directory</kbd> to your web servers scripts folder (C:\inetpub\scrits) 
<li>Click the OK button </li></li></li></ol>This will produce a DLL by the name DelphiASP in the scripts folder when we compile. We still can't use the DLL. All COM DLLs need to be registered with the system. We can use the Run|Register ActiveX Server menu option or from the Type Library editor we can click the <kbd>Register Type Library</kbd> tool bar button. When you do this, you should get a confirmation dialog stating that the registration was successful. <br><br>Now we're ready to use our ASP object. Remember that it is really the .asp file that will instantiate our ASP object and call its method. Lets make sure this ASP file is the way it should be. <pre>&lt;HTML&gt;
&lt;BODY&gt;
&lt;TITLE&gt; Testing Delphi ASP &lt;/TITLE&gt;
&lt;CENTER&gt;
&lt;H3&gt; You should see the results of your Delphi Active Server method below &lt;/H3&gt;
&lt;/CENTER&gt;
&lt;HR&gt;
&lt;% Set DelphiASPObj = Server.CreateObject("Project1.Vendor") 
   DelphiASPObj.GetVendors
%&gt;
&lt;HR&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</pre>Notice the line : <kbd>DelphiASPObject.GetVendors</kbd>. Your Vendor.asp file should have that line as it is shown above. Lets also move this file (after saving the project. Saving the project, also saves the .asp file) to our web server's root folder (C:\inetpub\wwwroot). We can now call this .asp file using the following URL in a web browser: <pre>  http://mydomain/vendor.asp
</pre>Where mydomain is the PC/Machine name of your PC or IP address (localhost or 127.0.0.1 will also do). <br><br><b>Figure 4</b> shows what the generated HTML page will look like if eveything goes well. Remember, if you need to re-compile this project after the ASP object has been created, you need to treat this DLL like an ISAPI DLL in that respect. <br><br><img alt="FirstASP4.png" src="http://www.matlus.com/images/FirstASP4.png" border="0"> <br><b>Figure 4 showing the output of Vendor.asp</b> 
<h2>Enhancing the output</h2>The TDataSetTableProducer component can be used similar to the way one would use it in an ISAPI application. We can use it here to format the HTML Table produced. You have access to the <kbd>Response Editor</kbd> as well as the various events this component has. Using the Response Editor we can: 
<ol>
<li>Set the HTML Table properties 
<li>Decide which fields we want to show in the generated output 
<li>Decide the order in which the fields are to be displayed </li></li></li></ol>etc. 
<p>Using the <kbd>Response Editor</kbd>, lets set the <kbd>Border</kbd> attribute of the HTML Table to 1. Using the <kbd>OnFormatCell</kbd> event we can manipulate the HTML table even further. Here is what the <kbd>OnFormatCell</kbd> event of the TDataSetTableProducer should look like to produce an output similar to the demo you saw at the beginning of this article. 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>procedure</b></font> <font color="#000080">TDM1</font><font color="#ff0000">.</font><font color="#000080">DataSetTableProducer1FormatCell</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">;</font> <font color="#000080">CellRow</font><font color="#ff0000">,</font>
  <font color="#000080">CellColumn</font><font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font> <font color="#0000ff"><b>var</b></font> <font color="#000080">BgColor</font><font color="#ff0000">:</font> <font color="#000080">THTMLBgColor</font><font color="#ff0000">;</font> <font color="#0000ff"><b>var</b></font> <font color="#000080">Align</font><font color="#ff0000">:</font> <font color="#000080">THTMLAlign</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>var</b></font> <font color="#000080">VAlign</font><font color="#ff0000">:</font> <font color="#000080">THTMLVAlign</font><font color="#ff0000">;</font> <font color="#0000ff"><b>var</b></font> <font color="#000080">CustomAttrs</font><font color="#ff0000">,</font> <font color="#000080">CellData</font><font color="#ff0000">:</font> <font color="#0000ff"><b>String</b></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#808080">{ Color the First Column }</font>
  <font color="#0000ff"><b>if</b></font> <font color="#000080">CellColumn</font> <font color="#ff0000">=</font> <font color="#800080">0</font> <font color="#0000ff"><b>then</b></font>
    <font color="#000080">BgColor</font> <font color="#ff0000">:=</font> <font color="#008000">'Teal'</font><font color="#ff0000">;</font>
  <font color="#808080">{ Color the Second Column }</font>
  <font color="#0000ff"><b>if</b></font> <font color="#000080">CellColumn</font> <font color="#ff0000">=</font> <font color="#800080">1</font> <font color="#0000ff"><b>then</b></font>
    <font color="#000080">BgColor</font> <font color="#ff0000">:=</font> <font color="#008000">'Olive'</font><font color="#ff0000">;</font>
  <font color="#808080">{ Color the Second Row - excluding the Field Name Row }</font>
  <font color="#0000ff"><b>if</b></font> <font color="#000080">CellRow</font> <font color="#ff0000">=</font> <font color="#800080">2</font> <font color="#0000ff"><b>then</b></font>
    <font color="#000080">BgColor</font> <font color="#ff0000">:=</font> <font color="#008000">'Red'</font><font color="#ff0000">;</font>
  <font color="#808080">{ Color all instances of the Field - Preferred where the Value = False }</font>
  <font color="#0000ff"><b>if</b></font> <font color="#000080">CellColumn</font> <font color="#ff0000">=</font> <font color="#800080">10</font> <font color="#0000ff"><b>then</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#0000ff"><b>if</b></font> <font color="#000080">CellData</font> <font color="#ff0000">=</font> <font color="#008000">'F'</font> <font color="#0000ff"><b>then</b></font>
      <font color="#000080">BgColor</font> <font color="#ff0000">:=</font> <font color="#008000">'Yellow'</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>
<h2>Modifiing the ASP Object to Read Form Data</h2>What if we wanted our ASP object to respond to Data sent to it via an HTML Form? Lets modify our object, such that it receives the SQL string to use in the Query from an HTML Form as you might have seen in the Demo at the start of this tutorial. 
<p>So we're going to need: 
<ol>
<li>An HTML Page that allows us to define an SQL statement to be used by our ASP object, to generate an HTML output of the result set. 
<li>This .htm file needs to call our ASP object and pass on to it the SQL statement 
<li>Our ASP objects needs to be modified such that it looks for the SQL statement in the HTML Form's fields. </li></li></li></ol>In an ISAPI application, we would "extract" an HTML Form's fields using code like this: <pre>  sSQL := Request.ContentFields.Values['txtSQL'];
</pre>Where <kbd>sSQL</kbd> is defined as a string type and txtSQL is the name of the field in the HTML Form that contains the requested SQL Statement to be applied to a Query object. Assuming here that the method of the HTML Form is <kbd>POST</kbd> and not <kbd>GET</kbd>. 
<p>In ASP, the <kbd>Request</kbd> object is a bit different. It has a property called <kbd>Form</kbd>. The way you would access the fields of a Form in ASP is: <pre>  sSQL := Request.Form['txtSQL'];
</pre>Once we get a hold of the SQL statement that was given to us via an HTML Form, we'd like to pass this on to our <kbd>GetVendorInfo</kbd> method of our Data Module, where we can assign the SQL string to our Query object and generate a result set. 
<p>Currently, our <kbd>GetVendorInfoPage</kbd> method does not expect any parameters, so we'll have to modify it such that it expects to see a string parameter and then use this parameter to assign it to our Query object and get a result set. 
<p>The <kbd>GetVendors</kbd> method of our ASP object will now look like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>procedure</b></font> <font color="#000080">TVendor</font><font color="#ff0000">.</font><font color="#000080">GetVendors</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">sSQL</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">sSQL</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">Form</font><font color="#ff0000">[</font><font color="#008000">'txtSQL'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Write</font><font color="#ff0000">(</font><font color="#000080">DM</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">(</font><font color="#000080">sSQL</font><font color="#ff0000">)</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>and the <kbd>GetVendorInfoPage</kbd> method of our DataModule will look like this: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>function</b></font> <font color="#000080">TDM1</font><font color="#ff0000">.</font><font color="#000080">GetVendorInfoPage</font><font color="#ff0000">(</font><font color="#000080">sSQL</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">)</font> <font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#0000ff"><b>with</b></font> <font color="#000080">Query1</font> <font color="#0000ff"><b>do</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#000080">Close</font><font color="#ff0000">;</font>
    <font color="#000080">SQL</font><font color="#ff0000">.</font><font color="#000080">Clear</font><font color="#ff0000">;</font>
    <font color="#000080">SQL</font><font color="#ff0000">.</font><font color="#000080">Add</font><font color="#ff0000">(</font><font color="#000080">sSQL</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
    <font color="#000080">Open</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
  <font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">DataSetTableProducer1</font><font color="#ff0000">.</font><font color="#000080">Content</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>Remember to change the declaration of this method in the <kbd><b>interface</b></kbd> section of the DataModule to match that shown above. 
<p>This concludes the changes we need to make to our ASP object such that it receives the SQL statement via an HTML form. We still need the HTML form however. The HTML form's source code looks like this: <pre>&lt;HTML&gt;
&lt;HEAD&gt;
  &lt;TITLE&gt;Delphi ASP Demo&lt;/TITLE&gt;
&lt;/HEAD&gt;
&lt;BODY&gt;
  &lt;FORM ACTION="http://www.matlus.com/Vendor.asp" METHOD="POST"&gt;
   The &lt;B&gt;ASP Object&lt;/B&gt; is connected to the VENDORS Table in DBDEMOS. Feel Free to Change the SQL Statement below to a Valid SQL Statement for this Table.
   &lt;P&gt;
 &lt;TEXTAREA NAME="txtSQL" COLS=40 ROWS=5&gt;SELECT * FROM VENDORS&lt;/TEXTAREA&gt;
   &lt;BR&gt;
   &lt;INPUT TYPE="SUBMIT"&gt; 
  &lt;/FORM&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
&lt;/PRE&gt;
</pre>Notice the Form's <kbd>ACTION</kbd> attribute. It calls the <kbd>Vendor.asp</kbd> page, which in turn creates an instance of our ASP object, and calls its method. The Memo field's (TEXTAREA) name is important here, as it needs to match the name of the form field we're using in our ASP object <kbd>sSQL := Request.Form['txtSQL'];</kbd>. Save this .htm file as <kbd>Vendor.htm</kbd>. 
<p>To test our work, we need to load the <kbd>Vendor.htm</kbd> in our browser, set the SQL statement if required (you should test this) and clicking on the <kbd>SUBMIT</kbd> button on the Form. <b>Figure 5</b> shows what the output will look like with an SQL statement of:<kbd> SELECT VendorNo, VendorName, City, State, Zip, Preferred FROM VENDORS</kbd> 
<p><img alt="FirstASP5.png" src="http://www.matlus.com/images/FirstASP5.png" border="0"> <br><b>Figure 5 Showing the output generated by the ASP object</b> 
<p>The flaw in our design here is that there is no column 10 and so even though the <kbd>Preferred</kbd> field is amongst the one we want displayed, it is not colored yellow where the value = False. We'll leave that as an exercise for those of you who would want to see this work. 
<h2>Deploying the ASP Object</h2>In most cases, you'd be developing your ASP objects on your development machine but later you'd want to deploy the ASP object on your production web server. What you need to do in this case is register your COM DLL on the production server. To do that you need to do the following: 
<ol>
<li>Place the COM DLL (<kbd>DelphiASP.DLL</kbd> in this case) in your web server's scripts folder (C:\inetpub\scripts). 
<li>From the <kbd>Start</kbd> Menu, choose <kbd>Run</kbd> 
<li>In the dialog box presented type -<kbd>regsvr32 C:\inetpub\scrits\DelphiASP.DLL</kbd> 
<li>This action should register your COM DLL and give you a confirmation stating as such 
<li>You will of course need an ASP file that instantiates your ASP object and calls its methods as well (similar to the <kbd>Vendor.asp</kbd> file) </li></li></li></li></li></ol>
<h2>ISAPI versus ASP</h2>Unlike the ISAPI implementation in Delphi, which is event driven using Actions, ASP objects are method driven. In VB, you could use WebClasses to compliment your ASP scripts written using Visual InterDev and ASP objects in VB to achieve a somewhat event driven paradigm to web applications. This method adds one more layer to web applications written in VB that is known to slow things down even further. <br><br>The Delphi ISAPI/CGI framework, gives you all of that in a single place at break neck speeds and minimal resource utilization with incomparable scalability. So why bother with ASP. <br><br><b>A quote from the Microsoft site:</b><br>
<blockquote>While no benchmarks are really going to give you the complete story, these benchmarks can tell you something. If WebClasses are slower, they aren't really that much slower (30%). Most of the performance loss is simply due to creating and destroying WebClass instances, which is not a sufficient reason to avoid using WebClasses. Moreover, if you're not willing to give up a little performance to get some extra productivity, you shouldn't be using Visual Basic or the ASP framework-you should be writing custom ISAPI extension DLLs with C . </blockquote>In Delphi, ISAPI gives us the productivity we need. Productivity is comparable to what you would get if you were using Visual InterDev (minus the HTML Page design, but then you're not limited to using any tool for that purpose. Using HTML templates in a Delphi ISAPI frees you to use any HTML page designer to accomplish this end), with the benefits of ISAPI over any other competing technology for web based applications, without the headaches associated with ISAPI that a VC programmer relates to. In short, you got ISAPI the easy way. A way that no other development tool provides. <br><br>As a Delphi programmer do ASP only because you love to spout industry buzzwords. So why do I bother writing such an extensive Tutorial on Delphi and ASP ? First and foremost, it's nice to know that the Delphi R&amp;D team has taken the trouble to give the Delphi programmer access to ASP objects as a technology. Secondly, It's good to know that Delphi does ASP. And thrid, for those of you who can't get around the buzzword (vicious) circle, you have the option to do ASP with Delphi. </g>]]></description><category>Programming</category><category>ADO</category><category>ASP</category><category>COM</category><category>Database</category><category>Delphi</category></item><item><title>Sending ADO Recordsets to an ASP Page</title><pubDate>Sat, 19 Jan 2008 11:06:40 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/5/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/5/</guid><description><![CDATA[This project's output is similar to the previous project. But the difference here is that our ASP object sends back an ADO Recordset object and the actual generation of HTML (layout) is done in ASP script. This example is very typical of what most ASP pages are like. The grunt of the work is done in interpreted script rather than as a method of a compiled object. 
<P>One of the visitors to my site (Doug Bowman) had asked me if Delphi could send back a Recordset object, saying that this was quite easily done in VB. That statement got me real curious to say the least. But, since I didn't know what he meant, I wasn't sure what he was asking. So I in turn posed this question to Ronaldo Melo Ferraz (those of you who frequent the Borland news groups would know him as one of the top rankers, answering most of the questions, giving in depth answers, links and other valuable information). Ronaldo does some work with ASP and came up with a Delphi solution soon enough. This helped me getting started with this tutorial. I'd like to thank Doug for coming up with the "problem" and Ronaldo for giving me a solution. 
<P>I've since modified Ronaldo's code a bit to fit this tutorial as well as Doug's ASP script to change the output to look like that of the previous tutorial's. The similarity of the output should give people a good idea of how to do things in the "typical" ASP way and the "Delphi way". 
<P>The ASP page that instantiates our ASP object and gets it to return an ADO Recordset looks like this: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#ff0000>&lt;</FONT><FONT color=#000080>html</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#000080>head</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#000080>LINK</FONT> <FONT color=#000080>REL</FONT><FONT color=#ff0000>=</FONT><FONT color=#000080>STYLESHEET</FONT> <FONT color=#0000ff><B>TYPE</B></FONT><FONT color=#ff0000>=</FONT><FONT color=#ff0000>"</FONT><FONT color=#000080>text</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>css</FONT><FONT color=#ff0000>"</FONT> <FONT color=#000080>HREF</FONT><FONT color=#ff0000>=</FONT><FONT color=#ff0000>"</FONT><FONT color=#000080>http</FONT><FONT color=#ff0000>:</FONT><FONT color=#808080>//www.matlus.com/home-styles.css"&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>head</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#000080>body</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#000080>Dim</FONT> <FONT color=#000080>ASPObj</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#000080>Dim</FONT> <FONT color=#000080>rs</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#0000ff><B>set</B></FONT> <FONT color=#000080>ASPObj</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#000080>Server</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>CreateObject</FONT><FONT color=#ff0000>(</FONT><FONT color=#ff0000>"</FONT><FONT color=#000080>DelphiADO</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Recordset</FONT><FONT color=#ff0000>"</FONT><FONT color=#ff0000>)</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#0000ff><B>set</B></FONT> <FONT color=#000080>rs</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#000080>ASPObj</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ReturnADO</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#000080>Table</FONT> <FONT color=#000080>Cellspacing</FONT><FONT color=#ff0000>=</FONT><FONT color=#ff0000>"</FONT><FONT color=#800080>1</FONT><FONT color=#ff0000>"</FONT> <FONT color=#000080>Cellpadding</FONT><FONT color=#ff0000>=</FONT><FONT color=#ff0000>"</FONT><FONT color=#800080>1</FONT><FONT color=#ff0000>"</FONT> <FONT color=#000080>Border</FONT><FONT color=#ff0000>=</FONT><FONT color=#ff0000>"</FONT><FONT color=#800080>1</FONT><FONT color=#ff0000>"</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#000080>tr</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#0000ff><B>For</B></FONT> <FONT color=#000080>j</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>0</FONT> <FONT color=#0000ff><B>to</B></FONT> <FONT color=#000080>rs</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>fields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>count</FONT> <FONT color=#ff0000>-</FONT> <FONT color=#800080>1</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
    <FONT color=#ff0000>&lt;</FONT><FONT color=#000080>td</FONT> <FONT color=#000080>align</FONT><FONT color=#ff0000>=</FONT><FONT color=#ff0000>"</FONT><FONT color=#000080>center</FONT><FONT color=#ff0000>"</FONT><FONT color=#ff0000>&gt;</FONT>
      <FONT color=#ff0000>&lt;</FONT><FONT color=#000080>b</FONT><FONT color=#ff0000>&gt;</FONT><FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Write</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>rs</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>fields</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>j</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>name</FONT><FONT color=#ff0000>)</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT><FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>b</FONT><FONT color=#ff0000>&gt;</FONT>
    <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>td</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#000080>Next</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>tr</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT><FONT color=#0000ff><B>Do</B></FONT> <FONT color=#0000ff><B>Until</B></FONT> <FONT color=#000080>rs</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Eof</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#000080>tr</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#0000ff><B>For</B></FONT> <FONT color=#000080>j</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>0</FONT> <FONT color=#0000ff><B>to</B></FONT> <FONT color=#000080>rs</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>fields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>count</FONT> <FONT color=#ff0000>-</FONT> <FONT color=#800080>1</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
    <FONT color=#ff0000>&lt;</FONT><FONT color=#000080>td</FONT><FONT color=#ff0000>&gt;</FONT>
      <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Write</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>rs</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>fields</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>j</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>)</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
    <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>td</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#000080>Next</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
  <FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>tr</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT>  <FONT color=#000080>rs</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>movenext</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT><FONT color=#000080>Loop</FONT><FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>Table</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#0000ff><B>set</B></FONT> <FONT color=#000080>ASPObj</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#000080>nothing</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>%</FONT> <FONT color=#0000ff><B>set</B></FONT> <FONT color=#000080>rs</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#000080>nothing</FONT> <FONT color=#ff0000>%</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>body</FONT><FONT color=#ff0000>&gt;</FONT>
<FONT color=#ff0000>&lt;</FONT><FONT color=#ff0000>/</FONT><FONT color=#000080>html</FONT><FONT color=#ff0000>&gt;</FONT></FONT>
</PRE></CODE></DIV></DIV>Looking at the ASP script above you should notice a few things immediately. <KBD><B>DelphiADO</B></KBD> is the name of the COM DLL that contains our ASP object (this DLL needs to be registered on the target machine as described in the previous tutorial). The object, in this case is called <KBD><B>Recordset</B></KBD>. The one and only method of this object is <KBD>ReturnADO</KBD> which returns an ADO Recordset object to the calling ASP script. This ASP script then goes about "laying out" the recordset using the (ASP) <KBD>Response</KBD> object's <KBD>Write</KBD> method. This is similar to what we did inside our ASP object in the previous tutorial. Remember that this ASP script is being processed at the server end and so visitors to this .asp file will not see the actual ASP script, but rather the generated HTML. This is typical of any server side technology (ISAPI/CGI included). 
<H2>What's Required</H2>Apart from what was mentioned in the previous tutorial for ASP per se, we will need an ADO compliant database for this project. What I've done is I've migrated the Vendors table from DBDEMOS to an Access 97 database using the <B>Data Pump</B> utility that ships as a part of Delphi. This database is not included with the project download. However, Borland actually ships the equivalent of DBDEMOS as an Access database solely for the purpose of giving us Delphi programmers an ADO compliant database as a test database. I had deleted my copy of this database and so had to re-create at least the Vendors table for this tutorial. 
<H2>Getting started</H2>
<OL>
<LI>Select File | New 
<LI>Switch to the ActiveX page of the New item dialog 
<LI>Select ActiveX Library 
<LI>Click on the OK Button </LI></OL>This action will generate the skeleton for a COM DLL. 
<OL>
<LI>Change the output directory to your web server's scripts folder (C:\inetpub\scripts) 
<LI>Save this Project as <KBD>DelphiADO</KBD> 
<LI>From the File menu, select New 
<LI>Swtich to the ActiveX page again 
<LI>Choose ASPObject 
<LI>Click OK 
<LI>In the dialog box presented, fill out the fields as shown in <B>Figure 1 and click OK</B> </LI></OL><IMG src="http://www.matlus.com/images/NewASPObject.jpg" border=0> <BR><B>Figure 1 Showing the values that need to be filled/selected</B> 
<P>If you are running IIS 4.0 leave the <KBD>Active Server Type</KBD> in its default setting. For IIS 5.0 and above, choose the option as shown in <B>Figure 1</B>. 
<P>You should see the .asp page that Delphi generates for us as well as the Type Library Editor and the unit that implements the <KBD>IRecordset</KBD> interface. Delphi generates the following code for us: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>unit</B></FONT> <FONT color=#000080>Unit1</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>interface</B></FONT>
<FONT color=#0000ff><B>uses</B></FONT>
  <FONT color=#000080>ComObj</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>ActiveX</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>AspTlb</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Project1_TLB</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>StdVcl</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>type</B></FONT>
  <FONT color=#000080>TRecordset</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#0000ff><B>class</B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>TASPMTSObject</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IRecordset</FONT><FONT color=#ff0000>)</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>implementation</B></FONT>
<FONT color=#0000ff><B>uses</B></FONT> <FONT color=#000080>ComServ</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>initialization</B></FONT>
  <FONT color=#000080>TAutoObjectFactory</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>ComServer</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>TRecordset</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Class_Recordset</FONT><FONT color=#ff0000>,</FONT>
    <FONT color=#000080>ciMultiInstance</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>tmApartment</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>.</FONT></FONT>
</PRE></CODE></DIV></DIV>You will notice that our object <KBD>TRecordset</KBD> has no methods as yet. Specifically, we need a method called <KBD>ReturnADO</KBD>. 
<P>As usual, we need to use the Type Library Editor to add methods to our ASP object. 
<OL>
<LI>In the Type Library editor, select the <KBD>IRecordset</KBD> interface and add a new method by either right clicking and choosing <KBD>New Method</KBD> or clicking on the <KBD>New Method</KBD> icon on the tool bar 
<LI>Name this method - <KBD>ReturnADO</KBD> 
<LI>Swtich to the Parameters tab on the right 
<LI>Add a parameter for this method such that your Type library editor looks like that shown in <B>Figure 2</B> 
<LI>Once done, click on the <KBD>Refresh Implementation</KBD> tool bar button </LI></OL><IMG src="http://www.matlus.com/images/ASPRecordset2.jpg" border=0> <BR><B>Figure 2 showing the new method and its parameters in the Type Library editor</B> 
<P>
<P>Refreshing the implementation of the ASP object (in the type library editor) will generate the method declaration in our <KBD>TRecordset</KBD> object for the method we just added to the <KBD>IRecordset</KBD> interface. The <KBD>interface</KBD> section of the <KBD>TRecordset</KBD> object should look like that shown below. In particular, make sure the declaration of the <KBD>ReturnADO</KBD> method in your project looks like that shown here. 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>interface</B></FONT>
<FONT color=#0000ff><B>uses</B></FONT>
  <FONT color=#000080>ComObj</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>ActiveX</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>AspTlb</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>DelphiADO_TLB</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>StdVcl</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>ADOdb</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Dbtables</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>type</B></FONT>
  <FONT color=#000080>TRecordset</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#0000ff><B>class</B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>TASPMTSObject</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IRecordset</FONT><FONT color=#ff0000>)</FONT>
  <FONT color=#0000ff><B>protected</B></FONT>
    <FONT color=#0000ff><B>function</B></FONT> <FONT color=#000080>ReturnADO</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>OleVariant</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>safecall</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>It's now time for us to save our work thus far. <KBD>Unit1</KBD> should be saved as <KBD>RecordsetImpl</KBD>. We will change the script in the .asp file later, for now save it as it is. 
<P>Next, we will implement the <KBD>ReturnADO</KBD> method of our <KBD>TRecordset</KBD>. This part is really simple as we once again come back to Delphi programming. We aren't using a DataModule in this project like we did in the last one. There is no specific reason for this expect that I wanted to keep this project simple. Since we don't have a DataModule here we need to create an instance of a TADODataset on the fly, assign the required properties and then return the Recordset as the result of this function. The <KBD>RecordsetImpl</KBD> unit's listing is shown below: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>unit</B></FONT> <FONT color=#000080>RecordsetImpl</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>interface</B></FONT>
<FONT color=#0000ff><B>uses</B></FONT>
  <FONT color=#000080>ComObj</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>ActiveX</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>AspTlb</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>DelphiADO_TLB</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>StdVcl</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>ADOdb</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>type</B></FONT>
  <FONT color=#000080>TRecordset</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#0000ff><B>class</B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>TASPMTSObject</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IRecordset</FONT><FONT color=#ff0000>)</FONT>
  <FONT color=#0000ff><B>protected</B></FONT>
    <FONT color=#0000ff><B>function</B></FONT> <FONT color=#000080>ReturnADO</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>OleVariant</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>safecall</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>implementation</B></FONT>
<FONT color=#0000ff><B>uses</B></FONT> <FONT color=#000080>ComServ</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>function</B></FONT> <FONT color=#000080>TRecordset</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ReturnADO</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>OleVariant</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT>
  <FONT color=#000080>ADODataSet1</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TADODataSet</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>RecordSet</FONT>   <FONT color=#ff0000>:</FONT> <FONT color=#000080>_Recordset</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>ADODataSet1</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TADODataSet</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>nil</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>try</B></FONT>
    <FONT color=#000080>ADODataSet1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ConnectionString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Common Files\Borland Shared\Data\dbdemos.mdb;Persist Security Info=False'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>ADODataSet1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>CommandText</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'SELECT * FROM VENDORS'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>ADODataSet1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Open</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>RecordSet</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>ADODataSet1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Recordset</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>_xClone</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>RecordSet</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Set_ActiveConnection</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>nil</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Result</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>RecordSet</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>ADODataSet1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>finally</B></FONT>
    <FONT color=#000080>ADODataSet1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>initialization</B></FONT>
  <FONT color=#000080>TAutoObjectFactory</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>ComServer</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>TRecordset</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Class_Recordset</FONT><FONT color=#ff0000>,</FONT>
    <FONT color=#000080>ciMultiInstance</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>tmApartment</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>.</FONT></FONT>
</PRE></CODE></DIV></DIV>Be sure to add the <KBD>ADOdb</KBD> unit to the <KBD>uses</KBD> clause of the <KBD>interface</KBD> section of the unit. <B>To be Continued</B> 
<P>The complete project is available for download from the link below. </P>]]></description><category>Programming</category><category>ADO</category><category>ASP</category><category>COM</category><category>Delphi</category></item><item><title>Building your First ISAPI Application using Delphi</title><pubDate>Fri, 18 Jan 2008 11:06:40 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/6/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/6/</guid><description><![CDATA[<p>In this article we will take you through the steps in building an ISAPI application using Delphi 3/4/5 Client/Server (Enterprise) edition. </p>
<p><b>What do you need to start?</b> 
<ol>
<li>Delphi 3/4/5 Client/Server or Enterprise Edition 
<li>A Web Server (software). <br>You may use Microsoft's Personal Web Server (PWS) which is available for free from their web site. You may already have PWS if you use Win98 Second Edition, which comes with Personal Web Server 4.0. You may also use Microsoft's IIS on Windows NT/ Windows 2000. In any case, be sure to use a web server that supports ISAPI. If the server you use does not support ISAPI, you may work with the project as a CGI (EXE) program instead. It will not have the same resource and speed advantages that an ISAPI DLL will have, but it is certainly adequate to develop your application as a CGI program during the development phase, or if you know that the site where you employ the CGI will not be heavily trafficked. You can also use Omni httpd (you can download it from <a href="http://www.omnicron.ca/httpd/" target="newwnd" rel="nofollow">here</a>) or Falcon WebServer which is a web server written in Delphi (you can download it from <a href="http://www.blueface.com/" target="newwnd" rel="nofollow">here</a>). Both these web server should allow you to debug your ISAPI projects like any other DLL project from within the IDE. I suggest you don't run these web servers as NT services for debugging purposes. 
<li>Some basic HTML knowledge. <br>HTML is a scripting language that uses tags to delineate different parts of a document. All tags take the form of &lt;<i>tagname</i>&gt; to open the tag, and most have a closing tag &lt;/<i>tagname</i>&gt; to close the tag. Tags may are embedded in other tags. Some tags may have attributes, such as the &lt;FONT&gt; tag that has a COLOR attribute. We will use some of these tags in the exercise in this article. Your web projects will benefit greatly with an advanced knowledge of HTML/DHTML. 
<li>Knowledge of Delphi. </li></li></li></li></ol>
<p>What you do in Delphi to access databases (and other programming stuff) will be the same as what you do in your ISAPI/CGI application. To write web applications, you just need to learn the ISAPI part. Your existing Delphi programming knowledge will be leveraged. For a good Delphi programmer, wanting to start with web development, the ISAPI part is the simplest! It's actually the HTML, JavaScript, Graphics etc. that is much harder to do. In my experience in developing web sites, I spend 60-70% of my time trying to come up with good graphics and functional JavaScript to make the web pages interesting. After being used to developing front end applications, one feels handicaped trying to get a browser to do what you could so easily achieve with a front end GUI. Mind you, the simplicity of ISAPI is only for the Delphi/BC developer, thanks to the Delphi R&amp;D team. A VC programmer has a ton of work to do before he can get his ISAPI up and running! 
<p>Now that I've made you feel comfortable, let's get on with it shall we ? 
<p><b>Web Applications Concepts</b> 
<p><img alt="FirstISAPI1.png" src="http://www.matlus.com/images/FirstISAPI1.png" border="0"> 
<p>Let's explain some basic concepts and terms before we begin. 
<p>You have a browser as your "front end". The browser makes "requests" to the web server. These requests could be a request for an HTML page, or information from a database, or a combination of the two. 
<p>The request made by the browser goes to the web server. The web server will pass this request onto your ISAPI (or CGI) application which is targeted by the URL of the request.</p>
<p>(To understand the differences between creating an ISAPI DLL and a CGI EXE, please see the note at the bottom of this article.)</p>
<p>Within your ISAPI application you can "see" this request as an event that is generated. The request may have parameters passed to it. What you must program then is a response to this request, and return that response along with any requested information to the client (browser) via the web server. Your response will be in the form of an HTML string.</p>
<p>After you have installed a web server on your PC, you may "run" your web application by entering the URL in your browser. To access your URL's "domain name", use the name of your PC. Let's say the name of your PC (Computer Name) is "MyPC". To get the default home page to display, you need to type in <a href="http://mypc/" target="_blank" rel="nofollow">http://mypc/</a>, or <a href="http://MyPC.default.htm" target="_blank" rel="nofollow">http://MyPC.default.htm</a>. The web server will always look for a file called "default.htm" (or default.asp) in your web server's "root" folder if not instructed otherwise. Web servers have what is known as a "root" folder. In the case of Personal WebServer 4.0 and IIS, the "root" folder is C:\Inetpub\wwwroot. </p>
<p>The root folder is the equivalent of the "C:\" folder of the hard drive. This root folder can be any subfolder on the hard drive, but the server needs to be informed of where that root folder is. </p>
<p>The web server cannot "see" any folder higher than its root folder. This provides for security. The root folder is the starting point for the web server, and it can "see" all the folders and subfolders in its own tree. Most folders are read access only. One of the subfolders of the web server is <i>/scripts</i> (or <i>/cgi-bin</i>) and it is this folder only that has read/write/execute access by default. Your ISAPI or CGI application will reside in this folder.</p>
<p>You can access another page called "MyHTML.htm" from your web server's root folder by typing <a href="http://MyPC/MyHTML.htm" target="_blank" rel="nofollow">http://MyPC/MyHTML.htm</a> as the URL. To access a script with a name of <i>MyISAPI.DLL</i>, the URL would be <a href="http://MyPC/scripts/MyISAPI.DLL" target="_blank" rel="nofollow">http://MyPC/scripts/MyISAPI.DLL</a>. Since you have not specified any "action" (after the DLL name), the default "action" of your web application, (something you define) will be executed.</p>
<p>Let's say we had a logon screen that we wanted displayed. The action we decided for this is "<i>/logon</i>". (Note use of the forward slash.) To get the Logon page (dynamically generated by our ISAPI application) the URL would be <a href="http://MyPC/scripts/MyISAPI.DLL/logon" target="_blank" rel="nofollow">http://MyPC/scripts/MyISAPI.DLL/logon</a>. This request is sent on to PWS. PWS receives this request, loads our DLL in memory, and sends the "logon" action. In our application, this action's event will be fired. </p>
<p>The key point to understand is that it is our job to send back an HTML page in the form of a string. So in this way a form of communication is established between the client and the server. If you understand this concept, you can go on to building an ISAPI application using Delphi.</p>
<p><b>Building your first ISAPI application</b> 
<ul>
<li>Start Delphi 
<li>Choose File | New 
<li>From the dialog, choose - Web Server Application and then OK. 
<li>In the next dialog, leave the selected option as ISAPI (you have CGI and Win-CGI options as well). </li></li></li></li></ul>
<p>You should now see a new project with a Web Module and its unit. </p>
<p>At this point, I suggest you go into the project options dialog and set the "output directory" on the Directories and Conditionals page, to the scripts folder of your web server. That is - C:\Inetpub\scripts. The reason I suggest doing this is so when you compile your application, the DLL will be generated in the folder in which you need it.</p>
<ul>
<li>Save the project with the of name MyISAPI. </li></ul>
<p>The web module is where you place you Data access components. 
<ul>
<li>To add <i>actions</i> to your web application, either click on the ellipses for the "actions" property in the object inspector or double click on the web module, to display the <i>Actions editor</i>. </li></ul>
<ul>
<li>Add an action to the web module. Once you have the Actions editor active, click on the "Add new" toolbar button of the actions editor.</li></ul>
<p><img alt="FirstISAPI2.png" src="http://www.matlus.com/images/FirstISAPI2.png" border="0"> 
<ul>
<li>With the new action selected in the (Actions) editor, switch to the object inspector. You should see the properties of the selected action. The "PathInfo" property is what we need to set. In this case, we want to set the path to "/logon". Even if you type just "logon", the object inspector will change it to "/logon". 
<li>Now switch to the events page of this action item, and create an event handler for the one (and only) event you see there, called "OnAction". </li></li></ul>
<p>At the point of writing code for the OnAction event, you should notice the parameters that are passed onto you, namely, the "request" and the "response" parameters. Both of these are objects and have their own set of properties and methods. 
<p>Our "logon" action needs to return the logon screen to the browser. So what we need to do is return the HTML tags and text that will produce a logon screen in a browser. One needs to know HTML to some degree to know what tags need to be sent back to the browser to display and HTML screen. 
<p>We use the request object to find out what was requested of us, and the response object to send data back to the web browser. In this case (because this event will be fired for us) we don't need to know what was requested, since all we need to know is that a logon screen was requested. But what we do need to do is send back the logon screen. The way we do that is: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>procedure</b></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">WebModule1WebActionItem1Action</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">;</font>
  <font color="#000080">Request</font><font color="#ff0000">:</font> <font color="#000080">TWebRequest</font><font color="#ff0000">;</font> <font color="#000080">Response</font><font color="#ff0000">:</font> <font color="#000080">TWebResponse</font><font color="#ff0000">;</font> <font color="#0000ff"><b>var</b></font> <font color="#000080">Handled</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font>
    <font color="#008000">'&lt;html&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;head&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'        &lt;title&gt;User Log On&lt;/title&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;/head&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;body&gt;'</font> <font color="#ff0000"> </font>
    <font color="#808080">{ Remember to change the URL from skumar to your PC's name !! }</font>
    <font color="#008000">'&lt;form action="http://skumar/scripts/MyISAPI.dll/logUser" method="post"&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;BR/&gt;UserID&lt;input name="txtUserID"&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;BR/&gt;Password&lt;input name="txtPassword"&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;BR/&gt;&lt;BR/&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;input type="submit" value="Submit"&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;input type="reset" value="Reset"&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;/form&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;/body&gt;'</font> <font color="#ff0000"> </font>
    <font color="#008000">'&lt;/html&gt;'</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>
<p>The <i>Response.Content</i> property contains the HTML that needs to be sent back. What is sent back is an HTML Form. "Data Entry" screens in HTML are known as "Forms" and use the &lt;FORM&gt; tag to delineate the form. What happens when the "submit" button is clicked is determined by the forms' "action". In this case: <pre>&lt;FORM <b>action=http://MyPC/scripts/MyISAPI.DLL/logUser</b> method=post&gt;</pre>
<p>So when the submit button is clicked in this case, the request will be made to our ISAPI application (MyISAPI.DLL) with the "/logUser" action sent to it. So we need to have a "/logUser" action item in our application as well. So lets go back and: 
<ol>
<li>Add a new action to the web module. 
<li>Set the PathInfo property of this action item to - /logUser. 
<li>Generate an OnAction event handler for this action item. </li></li></li></ol>
<p><img alt="FirstISAPI3.png" src="http://www.matlus.com/images/FirstISAPI3.png" border="0"> 
<p>What we want to do now is verify that the user id and password are valid. To be able to do that, we need to know what the "user id" and "password" are that were sent. How do we get the user id and password so that it is available to the <i>LogUser</i> action? </p>
<p>Notice that the "method" of the &lt;FORM&gt; above is "post". When you use the "post" method of an HTML form, the parameters of the form are made available to you in the "ContentFields" property of the Request Object sent to you as a parameter in the OnAction event. The ContentFields property is of type TStrings.</p>
<p>The HTML form's "values" (values of the various fields of the form) are made available to you in the ContentFields property as Name value pairs in the format:</p>
<p>txtUserID=skumar<br>txtPassword=shiv 
<p>The "name" or left part of the equation is the name of the field, got from the &lt;INPUT&gt; tags, here txtUserID and txtPassword. The actual values sent back will be returned as the element to the right of the "=". 
<p>The TStrings object has methods to make extracting these values simple. To extract these values you need to use the following code: <pre>sUserID := Request.ContentFields.Values['txtUserID'];
sPassword := Request.ContentFields.Values['txtPassword'];
</pre>
<p>where sUserID and sPassword are declared as local string type variables. 
<p>So the whole event handler of the /loguser action item will look like: 
<div class="codeblockouter">
<div class="codeblockInner"><code><pre><font face="Courier New"><font color="#0000ff"><b>procedure</b></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">WebModule1WebActionItem2Action</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">;</font>
  <font color="#000080">Request</font><font color="#ff0000">:</font> <font color="#000080">TWebRequest</font><font color="#ff0000">;</font> <font color="#000080">Response</font><font color="#ff0000">:</font> <font color="#000080">TWebResponse</font><font color="#ff0000">;</font> <font color="#0000ff"><b>var</b></font> <font color="#000080">Handled</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><b>var</b></font>
  <font color="#000080">sUserID</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
  <font color="#000080">sPassword</font><font color="#ff0000">:</font> <font color="#0000ff"><b>string</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>begin</b></font>
  <font color="#808080">{ Extract the values for the forms' fields }</font>
  <font color="#000080">sUserID</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ContentFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'txtUserID'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
  <font color="#000080">sPassword</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ContentFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'txtPassword'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>

  <font color="#808080">{ Validate the UserID and Password fields }</font>
  <font color="#0000ff"><b>if</b></font> <font color="#ff0000">(</font><font color="#000080">sUserID</font> <font color="#ff0000">=</font> <font color="#008000">''</font><font color="#ff0000">)</font> <font color="#0000ff"><b>or</b></font> <font color="#ff0000">(</font><font color="#000080">sPassword</font> <font color="#ff0000">=</font> <font color="#008000">''</font><font color="#ff0000">)</font> <font color="#0000ff"><b>then</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font>
      <font color="#008000">'&lt;html&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;head&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'        &lt;title&gt;Log On Error&lt;/title&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;/head&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;body&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'Either the UserID or Password was blank.'</font> <font color="#ff0000"> </font>
      <font color="#008000">'Please make sure your user information is entered correctly'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;/body&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;/html&gt;'</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font>
  <font color="#0000ff"><b>else</b></font>
  <font color="#0000ff"><b>begin</b></font>
    <font color="#808080">{ At this point you could verify the userid and password with</font>
<font color="#808080">      data in a database or any other way. Assuming the userid</font>
<font color="#808080">      and password are valid. You can then send back an HTML page</font>
<font color="#808080">      indicating that to the user.</font>
<font color="#808080">    }</font>
    <font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font>
      <font color="#008000">'&lt;html&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;head&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'        &lt;title&gt;User is Valid&lt;/title&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;/head&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;body&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'Welcome. Your profile has been recognized.'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;/body&gt;'</font> <font color="#ff0000"> </font>
      <font color="#008000">'&lt;/html&gt;'</font><font color="#ff0000">;</font>
  <font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font>
<font color="#0000ff"><b>end</b></font><font color="#ff0000">;</font></font>
</pre></code></div></div>
<p>Remember, you need to use the Request object in this case and not the Response object. The Request Object is used to GET information about the request. The Response Object is used to send information back to the requestor.</p>
<p>Once we have this information, we can determine the validity of the user using standard Delphi methods. </p>
<p><b>Testing MyISAPI</b> 
<ol>
<li>We are now ready to compile and test MyISAPI DLL. If you changed the Output directory to the scripts folder of your web server then you should see the file MyISAPI.DLL in this folder once you've compiled your application. 
<li>Open up your browser and type in the following URL. Remember to substitute "MyPC" with the name of your PC. The URL is http://MyPC/scripts/MyISAPI.DLL/Logon 
<li>This should show you a page similar to this. </li></li></li></ol>
<p><img alt="FirstISAPI4.png" src="http://www.matlus.com/images/FirstISAPI4.png" border="0"> 
<p>Fill in the Fields and hit the submit button. Unless you've left any of the fields blank, you should see an HTML page like this: 
<p><img alt="FirstISAPI5.png" src="http://www.matlus.com/images/FirstISAPI5.png" border="0"> 
<p>
<hr>

<p><b>Developing Web applications: ISAPI or CGI?</b> 
<p>Those using PWS should choose CGI instead of ISAPI when creating the web application. The reason is that PWS does not have the option to stop the HTTP service. Due to this. DLLs once loaded can't be released by the web server easily, and you will not be able to compile your ISAPI DLL more than once without re-booting. The down side of this is that you can't debug CGI applications like you can an ISAPI application.</p>
<p>If you are using IIS and you wish to recompile your project, stop the HTTP service, recompile and then start the service again before attempting to refresh the browser. You could also set IIS such that it does not cache ISAPI Applications. But remember to turn on caching on your production web server. 
<p>From a development perspective there is no difference between ISAPI and CGI. You may find it convenient to develop your applications as CGI through the development and de-bugging stages, and then when done, convert the CGI to an ISAPI. To do this a few minor changes are required in the Project source file: 
<ol>
<li>Change the word "program" to "library" in the main project file. 
<li>Add an "export" clause for ISAPI. 
<li>Change the "CGIApp" unit to "ISAPIApp" in the uses clause. </li></li></li></ol>
<p>You can use compiler directives to account for these differences, so it becomes simple to change from CGI to ISAPI and back. There will be absolutely no change required to your code, except for the consideration that an ISAPI app loads only once so the OnCreate event of the web data module is called only once. Database access needs to be multi-threaded which is easily accomplished by using a TSession component with its AutoSessionName property set to True. Any initialization code needs to be considered. </p><b>
<p>Using Compiler Directives to Accommodate use of either ISAPI or CGI</p></b>
<p>Add the following compiler directives to your project file:</p><pre><font color="gray">{$IFDEF ISAPI}</font>
<b>library</b> Project1;
<font color="gray">{$ELSE}</font>
<b>program</b> Project1;
  <font color="gray">{$APPTYPE CONSOLE}</font>
<font color="gray">{$ENDIF}</font>
<b>uses</b>
  WebBroker,
  <font color="gray">{$IFDEF ISAPI}</font>
  ISAPIApp,
  <font color="gray">{$ELSE}</font>
  CGIApp,
  <font color="gray">{$ENDIF}</font>
  Unit1 <b>in</b> 'Unit1.pas'  <font color="gray">{WebModule1: TWebModule}</font>;
<font color="gray">{$R *.RES}</font>
<font color="gray">{$IFDEF ISAPI}</font>
<b>exports</b>
  GetExtensionVersion,
  HttpExtensionProc,
  TerminateExtension;
<font color="gray">{$ENDIF}</font>
<b>begin</b>
  Application.Initialize;
  Application.CreateForm(TWebModule1, WebModule1);
  Application.Run;
<b>end</b>.
</pre>
<p><b>Note</b>: The <kbd>WebBroker</kbd> unit found in the uses clause was the<kbd>HTTPApp</kbd> unit in Delphi 3 and 4. 
<p><b>Using Code Templates to Make HTML'ing Faster and Easier</b> 
<p>One can make good use of the code template features of Delphi's code editor, which will speed up your HTML typing. Some examples are. <pre>'&lt;INPUT TYPE="TEXT" NAME="txt|"&gt;'
'&lt;FORM METHOD="POST" ACTION="'   Response.ScriptName   '/|"&gt;'   crlf  
'&lt;/FORM&gt;'
</pre>
<p>Even a simple thing like typing "Response.Content := " can be painful since the code completion wizard will show you "Response.ContentEncoding". So set up a short cut such as "res" that generates <br><pre>Response.Content :=  | 
</pre>]]></description><category>Programming</category><category>Delphi</category><category>Html</category><category>Http</category><category>ISAPI</category></item><item><title>ISAPI Data Entry and Database Access</title><pubDate>Thu, 17 Jan 2008 11:14:42 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/7/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/7/</guid><description><![CDATA[<P>In the first article dealing with ISAPI applications, we talked about web applications as ISAPI or CGI applications, and built our first ISAPI application.</P>
<P>This time we will build an application that:</P>
<OL>
<LI>Generates an HTML form, allowing users to enter some data. 
<LI>Validates and posts this information to a database. 
<LI>Displays the information stored in the database in a dynamically generated HTML page. </LI></OL>
<P>The application that we will build is a simple application that allows other web site owners to add a link to their web site to be accessed from our web site. Rather than having them send us an email and then we manually make the change in our database, we will build an application that will automate the process for us.</P><B>
<P>Section 1 - Creating the HTML Form for data entry.</P></B>
<P>To create a data entry form, we could create an HTML file and place it in the web server's root folder. To display it, you would enter the URL to the HTML form, such as:</P>
<P><a rel="nofollow" href="http://servername/DataEntry.htm" target="_blank">http://ServerName/DataEntry.htm</A> 
<P>ServerName is the Computer Name of your PC or web server. DataEntry.htm is the physical name of the HTML file that resides in the root folder of your web server (C:\inetpub\wwwroot). 
<P>The other approach, the one we will use here, is to generate the HTML form from our application. Here, we will: 
<OL>
<LI>Create a web server application called AddLink, and add an "action" to it called "AddLinkPage". The URL to this would be - <a rel="nofollow" href="http://servername/AddLink.Dll/AddLinkPage" target="_blank">http://servername/AddLink.Dll/AddLinkPage</A> 
<P>Notice the "scripts" word. If you remember, all ISAPI and CGI applications need to be in the scripts folder of the web server (C:\Inetpub\scripts). Or any folder with access rights similar to that of the scripts folder. </P>
<LI>Write some code in the OnAction event of this action that will send back the HTML required for the browser to show the form. </LI></OL>
<P>Let's start a new ISAPI application using the Wizard. </P>
<UL>
<LI>From Delphi's main menu, choose File | New and in the dialog box presented, select - Web Server Application. 
<LI>Click OK in the next dialog box shown (ISAPI application option is selected) </LI></UL>
<P>You should now see a Web Data Module as a blank white form.</P>
<P>To ensure that your applications will reside in the scripts folder, you will want to compile directly to that folder. To do this, choose Project | Options from Delphi's main menu. In the dialog box presented, switch to the - Directories/Conditionals page, and in the "output directory" field, enter the path to the scripts folder, for example, C:\Inetpub\scripts. Then click the OK button. We do this so that our ISAPI DLL is generated in this folder rather than copy it over to this folder each time we re-compile.</P>
<P>To create an Action item, select the Web Data Module, and then from the object inspector's properties page, select "Actions" and click on the ellipses (or double click on the data module (not in the TreeView partition of the Datamodule (D5)) to active the Actions editor).</P>
<P>You will be presented with the Actions Editor. Click on the "Add new" button.</P>
<P>In the object inspector, fill in the PathInfo property as "/AddLinkPage". Set the "Name" property to "waAddLinkPage".</P>
<P>The object inspector and actions editor should look like that shown in <B>Figure 1.<BR><BR><IMG alt=SecondISAPI1.png src="http://www.matlus.com/images/SecondISAPI1.png" border=0><BR>Figure1: Showing the Object Inspector and Actions Editor with the /AddLinkPage action item.</P></B>
<P>Now, choose the Events page of the object inspector and generate the OnAction event handler for this action item. In the event handler, type in the following code:</P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebMod1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebMod1waAddLinkPageAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT>
    <FONT color=#008000>'&lt;html&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;head&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'	&lt;title&gt;Add a Link to your Web Site&lt;/title&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;/head&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;body&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;h2&gt;Please Enter the Required information to be able to link your Site from here.&lt;/h2&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;form action="'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>'/PostLinkInfo" method="post"'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  title="Enter the information required to Add a link to your Web Site."&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;table&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;URL to your Web Site&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;&lt;input type="text" name="txtLinkURL"'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  style="height: 22px; width: 274px" value="http://"&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;Title to be Shown&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;&lt;input type="text" name="txtTitle"'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  style="height: 22px; width: 274px"&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;Description to be shown&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;textarea name="txtDescription" style="height: 80px; width: 274px"&gt;&lt;/textarea&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;Owner'</FONT><FONT color=#008000>'s First Name&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;&lt;input type="text" name="txtOwnerFirstName"'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  style="height: 22px; width: 274px"&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
     <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;Owner'</FONT><FONT color=#008000>'s Last Name&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;&lt;input type="text" name="txtOwnerLastName"'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  style="height: 22px; width: 274px"&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;Email Address&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font face="Tahoma"&gt;&lt;input type="text" name="txtEmailAddress"'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  style="height: 22px; width: 274px"&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  face="Tahoma"&gt;&lt;input type="submit" name="btnSubmit" value="Submit"&gt;&lt;/font&gt;&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;td&gt;&lt;font'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'  face="Tahoma"&gt;&lt;input type="reset" value="Reset"&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;/table&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;/form&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;P&gt;&lt;h4&gt;The server will attempt to validate the URL you are attempting to submit. If you get an error'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' due to an invalid URL. Please refresh the page before attempting to re-sumbit.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' if everything goes fine, you should be re-directed to the Links Page.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' You should be able to see the link you just added.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;P&gt;Thank you for taking the time to link your web site from here.&lt;/h4&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;/body&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;/html&gt;'</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>Note: You may want to use the variable "NewLine" in your web applications to make the generated HTML more readable. You may declare it as a constant in the interface section of the unit, as:</P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>const</B></FONT>
  <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>Instead of NewLine, you may prefer crlf (easier to type). Also, remember that we don't need to have a new line per se. We do this only to format the generated HTML. The browser will render the page in exactly the same way, with or without the new line. But if one was to see the source of the HTML, then it would all be in one line. This would make it awfully difficult to debug (the HTML) if things were to go wrong. I personally like to see well formatted HTML when I look at the source of an HTML page.</P>
<P>Now let's have a closer look at the Form's "Action":</P><PRE>&lt;FORM action='   Request.ScriptName   '/PostLinkInfo method=post'   NewLine   ' title="Enter the information required to Add a link to your Web Site."&gt;
</PRE>
<P>The Action tells the browser what to do when the "submit" button is pressed. In this case, we tell the browser to execute the action item with the PathInfo property set as /PostLinkInfo in our ISAPI. The Action evaluates to: 
<P>/scripts/AddLink.dll/PostLinInfo.</P>
<P>The <PRE>Method</PRE>attribute generally can be either POST or GET. We'll explore the difference between the two later. The <PRE>Title</PRE>attribute produces the hint or tool tip for the form in the browser. 
<P></P>
<P>Since we have told the web server to direct the form's data to the /PostLinkInfo action of our application (AddLink.dll), we will need to create an action item with a PathInfo of "/PostLinkInfo". We'll do that later.</P>
<P>For now, let's see what is happening in the OnAction event created above. What we're doing, is sending back (using the "Response" object's "Contents" property) the HTML required for a data entry HTML form. The Contents property is a string that is sent back via the web server to the requesting browser.</P>
<P>For this example, the fields we need our user (who is interested in adding a link to her site from our web site) to enter, are:</P>
<OL>
<LI>The URL to the site (for example - <a rel="nofollow" href="http://www.matlus.com" target="_blank">http://www.matlus.com</A>) 
<LI>The Title to be shown on your web site (for example - The Delphi Stop) 
<LI>The description of the web site. 
<LI>The web site owner's First Name. 
<LI>The web site owner's Last Name. 
<LI>The web site owner's email address. </LI></OL>
<P>When you see this form, you will notice that the URL field already has the text - "http://". This is done at the time of generating the form, by entering "http://" in the "value" attribute as follows:</P><PRE><P>'&lt;TD&gt;&lt;FONT face=Tahoma&gt;&lt;INPUT name=txtLinkURL'   NewLine  </P>
<P>' style="HEIGHT: 22px; WIDTH: 274px" value="http://"&gt;&lt;/FONT&gt;&lt;/TD&gt;</P>
</PRE>
<P>Notice also that each field on the HTML Form (recognized by the &lt;INPUT&gt; tag) has a unique name such as txtLinkURL. Later, we will use these names to extract the values for each of the required fields in order to post this information to a database.</P>
<P>So we have an action item in our ISAPI DLL that will generate a data entry form. To call this action, you will enter the following URL in the web browser's address field:</P>
<P><a rel="nofollow" href="http://servername/scripts/AddLink.dll/AddLinkPage" target="_blank">http://ServerName/scripts/AddLink.dll/AddLinkPage</A></P>
<P>Before you can use this URL in your browser, you must:</P>
<OL>
<LI>Make sure that your web server is running and the HTTP service has been started. 
<LI>Compile your application and make sure that a DLL by the name AddLink.dll exists in your web servers "scripts" folder. 
<LI>Substitute the ServerName with your PC's name or IP address. </LI></OL>
<P>Note that if you need to recompile your project for any reason as an ISAPI (DLL), you must stop and restart the WWW service, and then recompile your application. (This is not necessary for a CGI (EXE)). If you are using IIS, you could turn off - Cache ISAPI Applications checkbox in the Internet service manager options. Be sure to turn it on, on your production web server machine. </P>
<P>In order to release the lock on a DLL, PWS must be manually stopped using the command prompt. By default, Pws.exe resides in the folder C:\Windows\System\Inetsrv.</P>
<P>To stop PWS, type the following command:</P><B>
<P>windows\system\inetsrv\pws.exe /stop</P></B>
<P>You can then restart PWS manually restarted from the Command Prompt by using the following command:</P><B>
<P>windows\system\inetsrv\pws.exe /start</P></B>
<P>Once PWS is stopped, this will release the ISAPI DLL. Recompile the DLL, if necessary. Once PWS restarts, it will again lock the DLL when it gets instantiated by your browser.</P><B>
<P>For IIS</P></B>
<P>At the run line, type: <B>net stop iisadmin /y</B> and then press <B>Enter</B>. This will stop all services while running the make on the DLL.<BR><BR>After recompiling your DLL, type: <B>net start w3svc</B> from the run line. Your services will be up again. </P>
<P>After you have compiled the ISAPI DLL, make sure it is present in your scripts folder. Type in the URL and you should see the form as shown in <B>Figure 2</B>.<BR><BR><IMG alt=SecondISAPI2.png src="http://www.matlus.com/images/SecondISAPI2.png" border=0><BR><B>Figure 2: Showing the dynamically generated Data Entry Screen in a browser.</P></B>
<P>If we set the Default property of this action to True, we could simply type in the URL</P>
<P><a rel="nofollow" href="http://servername/scripts/AddLink.dll/AddLinkPage" target="_blank">http://ServerName/scripts/AddLink.dll/AddLinkPage</A></P>
<P>http://ServerName/scripts/AddLink.dll and we would get the same form.</P><B>
<P>Section 2 - Validating and posting the HTML Form's information to a database.</P></B>
<P>Now that we have an HTML form that will allow us to capture data, we need to "receive" this data, validate it and post it to our database.</P>
<P>We need to create an Action item that corresponds to the Form's action. The form's action is: </P><PRE><P>&lt;FORM action='   Request.ScriptName   '/PostLinkInfo method=post&gt;</P>
</PRE>
<P>This evaluates to - /scripts/AddLink.dll/PostLinkInfo.</P>
<P>To do this, we need to create a new action item. Set the pathinfo property to - /PostLinkInfo and the Name property to waPostLinkInfo. Then we need to write an event handler for the OnAction event of this action item. But before that, we need our database in place.</P>
<P>For this example, we'll use an Access database. Access is fine for small ISAPI/CGI applications. But ideally you should use an RDBMS. The name of the table in the Access mdb is LINKS and the structure of the table is as shown in <B>Figure 3</B>. 
<TABLE cellSpacing=0 cellPadding=7 width=271 border=0>
<TBODY>
<TR>
<TD vAlign=top width="16%"><B><FONT face=Tahoma size=2>
<P>Key</B></FONT></P></TD>
<TD vAlign=top width="58%"><B><FONT face=Tahoma size=2>
<P>FieldName</B></FONT></P></TD>
<TD vAlign=top width="27%"><B><FONT face=Tahoma size=2>
<P>Type</B></FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%"><FONT face=Tahoma size=2>
<P>Yes</FONT></P></TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>LinkURL</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%">&nbsp;</TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>Title</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%">&nbsp;</TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>Description</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%">&nbsp;</TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>DateAdded</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%">&nbsp;</TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>OwnerFirstName</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%">&nbsp;</TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>OwnerLastName</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR>
<TR>
<TD vAlign=top width="16%">&nbsp;</TD>
<TD vAlign=top width="58%"><FONT face=Tahoma size=2>
<P>EmailAddress</FONT></P></TD>
<TD vAlign=top width="27%"><FONT face=Tahoma size=2>
<P>Text</FONT></P></TD></TR></TBODY></TABLE>
<P><B>Figure 3: The structure of the LINKS table in the Access mdb.</B> 
<P>Create an ODBC alias for this mdb file called WEBSITE_ODBC using the ODBC Manager. The ODBC DSN should be a System DSN since it will be used by the Webserver(IIS) and not by a logged-on user. This point is very important to note. On Windows NT, IIS uses IUSER_<MACHINENAME> as the user. This user has limited access to the system. Also, I suggest creating a folder called <KBD>Database</KBD> under the scripts folder and keeping all databases in this folder.</P>
<P>Lets add some data access component and set of few properties.</P>
<OL>
<LI>Drop a TDatabase component, a TQuery and a TSession component. 
<LI>Set the AliasName property of the database component to WEBSITE_ODBC. 
<LI>Set the DatabaseName of the database component to DELPHILINKS. 
<LI>Set the DatabaseName of Query1 to DELPHILINKS. 
<LI>Set the Login property of the TDatabase component to False. 
<LI>Set the params property to</LI></OL><B>
<P>user name=admin</P>
<P>password=</P>
<DIR></DIR></B>
<P>We can't have a login dialog box popping up in our ISAPI/CGI applications. We will never see this dialog box and therefore we'll never be able to log in to the database. When that happens, the application will seem to hang. It's not really hanging, but since you didn't login, you won't be able to use the application either. Setting the LogInPrompt property to False and setting the parameters as shown above, will allow our ISAPI/CGI application to log in to the database non-interactively.</P>
<P>Set the AutoSessionName of the TSession component to True.</P>
<P>Remember that an ISAPI DLL runs in the process space of the web server. Each time a request is made to the ISAPI DLL, a new thread is spawned (An instance of the web data module is created in this thread). To be able to connect to a database multiple times (like in a multi-threaded application) using the same instance we need to provide a unique session name for each connection. The TSession component handles that for us when we set the AutoSessionName property to true. Do not use a TSession component in your CGI applications. The web server creates a new instance of your CGI application for each request and so a unique session name is not required. Your data module should look like that shown in <B>Figure 4.<BR><BR><IMG alt=SecondISAPI3.png src="http://www.matlus.com/images/SecondISAPI3.png" border=0><BR>Figure 4 shows the web data module with the data access components thus far.</P></B>
<P>Every action's event (OnAction) makes 2 objects available to you -- the Request object and the Response object. You can see above that we've used the Request object's ScriptName property.</P>
<P>The Request.ScriptName property evaluates to - /scripts/AddLink.DLL. It is good practice to not hard- code the script's name, but instead use the ScriptName property. Later if you change the name of the script or the scripts folder, you won't have to modify your code.</P>
<P>Since we used the POST method of the form above, the data of that form will be made available in the ContentFields property of the Request object - "Request" since it comes to this event as a Request made by the browser via the web server. If we use the GET method in the HTML form, then the same information would be made available to us in the QueryFields property of the Request object.</P>
<P>To make our data validation easier, we will first create two custom Exception objects that can be raised if any part of the data is invalid, by putting the following code in the Type section:</P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>type</B></FONT>
  <FONT color=#000080>EInsufficientInfo</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#0000ff><B>class</B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Exception</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>EInvalidURL</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#0000ff><B>class</B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Exception</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>The ContentFields and QueryFields properties are TStrings derivatives. The Form's data is made available to us in the form of name=value pairs. So the data entered in the URL field will look like 
<P>txtLinkURL=http://www.matlus.com</P>
<P>We can therefore use the Values method of the ContentFields object to get the Value for a given (Field) Name. The code in this action item's OnAction event will look like this:</P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebMod1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebMod1waPostLinkInfoAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#808080>{ I've create a custom Exception object called - EInsufficientInfo that will</FONT>
<FONT color=#808080>    be rasied if any part of the data is invalid. In this case invalid = null.</FONT>
<FONT color=#808080>  }</FONT>
  <FONT color=#0000ff><B>try</B></FONT>
    <FONT color=#808080>{ Validate Data Entered by the User }</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtLinkURL'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>''</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT>  <FONT color=#000080>EInsufficientInfo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Please Enter the URL of your Web Site'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtTitle'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>''</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT>  <FONT color=#000080>EInsufficientInfo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Please Enter the Title you want Displayed for your Web Site'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtDescription'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>''</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT>  <FONT color=#000080>EInsufficientInfo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Please Enter the Description you want Displayed for your Web Site'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtOwnerFirstName'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>''</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT>  <FONT color=#000080>EInsufficientInfo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Please Enter Your First Name.'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtOwnerLastName'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>''</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT>  <FONT color=#000080>EInsufficientInfo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Please Enter Your Last Name'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtEmailAddress'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#008000>''</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT>  <FONT color=#000080>EInsufficientInfo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Please Enter your contact Email Address'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>

    <FONT color=#808080>{ In this particular case, we'd like to validate the URL that the user has</FONT>
<FONT color=#808080>      entered as well. To do that, we'll use an HTTP component in the URLIsValid</FONT>
<FONT color=#808080>      function. Warn the user if the URL is found to be invalid.</FONT>
<FONT color=#808080>    }</FONT>
    <FONT color=#0000ff><B>if</B></FONT> <FONT color=#0000ff><B>not</B></FONT> <FONT color=#000080>URLIsValid</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtLinkURL'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
      <FONT color=#0000ff><B>raise</B></FONT> <FONT color=#000080>EInvalidURL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'The URL you submitted is not a valid URL.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#008000>'Please make sure you type a valid URL before submitting'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>

    <FONT color=#808080>{ If data is Valid and URL is Valid, post it to the database }</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Clear</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'INSERT INTO LINKS'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'(LinkURL, Title, Description, DateAdded, OwnerFirstName, OwnerLastName, EmailAddress)'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Values(:LinkURL, :Title, :Description, :DateAdded, :OwnerFirstName, :OwnerLastName, :EmailAddress)'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'LinkURL'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtLinkURL'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Title'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtTitle'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Description'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtDescription'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'DateAdded'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsDateTime</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Now</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'OwnerFirstName'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtOwnerFirstName'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'OwnerLastName'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtOwnerLastName'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ParamByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'EmailAddress'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'txtEmailAddress'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Query1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ExecSQL</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#808080>{ If every thing went fine, we want to show the user the links page, so he</FONT>
<FONT color=#808080>      can see the link he just added</FONT>
<FONT color=#808080>    }</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SendRedirect</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>'/ShowDelphiLinks'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>except</B></FONT>
    <FONT color=#000080>on</FONT> <FONT color=#000080>E</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Exception</FONT> <FONT color=#0000ff><B>do</B></FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;html&gt;&lt;head&gt;&lt;title&gt;Error Posting Inforamtion&lt;/title&gt;'</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#008000>'&lt;/head&gt;&lt;body&gt;&lt;H1&gt;%s&lt;/H1&gt;&lt;/body&gt;&lt;/html&gt;'</FONT><FONT color=#ff0000>,</FONT>
        <FONT color=#ff0000>[</FONT><FONT color=#000080>E</FONT><FONT color=#ff0000>.</FONT><FONT color=#0000ff><B>Message</B></FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>If the data was posted successfully to the table then we want to show a list of links in our database. This line will redirect the browser to the action in our ISAPI DLL that can do that. We have yet to create that action and the code for it. We'll do that soon.</P>
<P>The Code for the URLIsValid function looks like:</P><PRE><B>function</B> TWebMod1.URLIsValid(URL : <B>string</B>) : Boolean;
<B>begin</B>
  <B>try</B>
    URLValid := True;
    NMHTTP1.Get(URL);
    Result := URLValid;
  <B>except</B>
    Result := False;
  <B>end</B>;
<B>end</B>;
</PRE>
<P>NMHTTP1 is a NetMaster's HTTP component. We use this component to try and retrieve the web site the user gave us. If the HTTP component can not find the URL it fires the OnInvalidHost event. In this event we set the URLValid variable to false, indicating that the URL was not found. If we find the URL, we set this variable to true. 
<P>Those using Indy (Indy aka Winshoes 8 can be downloaded from the <a rel="nofollow" href="http://www.nevrona.com/Indy/" target="_new">Indy Web Site</A>) can use the IdHTTP component for this function like this: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>function</B></FONT> <FONT color=#000080>TWebMod1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>URLIsValid</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>URL</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>)</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
 <FONT color=#0000ff><B>try</B></FONT>
   <FONT color=#808080>{ If the URL is not found an exception will be rasied }</FONT>
   <FONT color=#000080>IdHTTP1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Get</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>URL</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
   <FONT color=#000080>Result</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>True</FONT><FONT color=#ff0000>;</FONT>
 <FONT color=#0000ff><B>except</B></FONT>
  <FONT color=#000080>Result</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>False</FONT><FONT color=#ff0000>;</FONT>
 <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>Before we go onto create the waShowDelphiLinks action item let's briefly discuss the difference between the GET method and the POST method. We have used the POST method here. If instead we used the GET method, the URL would change when you hit the submit button. The browser will add (to the path information) the information as parameters to send back to the server.</P>
<P>In this case the URL would look like:</P>
<P>http://ServerName/scripts/AddLink.dll/PostLinkInfo?txtLinkURL=http://mywebsite.com&amp;txtTitle=My%20Site%20Title&amp;txtDescription=My%20Sites%20description 
<P>Your application accesses the data from the Request object's "QueryFields" property rather than its "ContentFields" property, extracting the values from Request.QueryFields in the same manner as Request.ContentFields since both properties are TStrings derivatives.</P>
<P>The advantage of the GET method is that it does not require a form to send information back to your application. You can simply append the value you need to send, to the end of the URL. In the POST method, the information is captured from the form and sent as a separate stream. Of course you may find that the POST method is advantageous because the information does not appear in the address box of the browser. Additionally, the POST method can handle much greater volumes of information.</P>
<P>So what have we done so far?</P>
<OL>
<LI>We have an action item that will generate an HTML data entry form. To see this form in the browser, the URL we need to use is </FONT><a rel="nofollow" href="http://servername/scripts/AddLink.DLL/AddLinkPage" target="_blank">http://ServerName/scripts/AddLink.DLL/AddLinkPage</A> 
<LI>We have another action item whose path info is set to /PostLinkInfo. This is the action item that will be called (it's OnAction event) when the user hits the submit button of the form. The reason this action item's OnAction event is fired when the submit button is hit, is that the Form's Action property is set to the above action item's path info. 
<LI>The /PostLinkInfo's OnAction event will validate the data entered and will either send back the appropriate information if the data is not valid or post the information to a database table if everything is working fine. Before the data is actually posted in the tables, we also check to see if we have been given a valid URL for the site to link to. </LI></OL><B>
<P>Section 3 - Displaying the information in the database on the web.</P></B>
<P>We can do this in two ways. The simpler way is to use the TQueryTableProducer component that comes with Delphi. The second way is to do the work manually. For now, we'll take the manual approach</P>
<P>To display the information, which in our example is links to other sites, we will create a new Action item and call it waShowDelphiLinks and set its PathInfo property to /ShowDelphiLinks. </P>
<P>Drop another TQuery component on the web data module. Set its DatabaseName property to DELPHILINKS and its SQL property to:</P><B>
<P>SELECT * FROM LINKS<BR>ORDER BY Title</P></B>
<P>In the OnAction event of this action we have the following Code:</P></FONT>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebMod1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebMod1waShowDelphiLinksAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>Query2</FONT> <FONT color=#0000ff><B>do</B></FONT>
  <FONT color=#0000ff><B>begin</B></FONT>
    <FONT color=#000080>Open</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT>
      <FONT color=#008000>'&lt;html&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'  &lt;head&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'    &lt;title&gt;Delphi Links People have added&lt;/title&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'  &lt;/head&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;body&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#808080>{ The Image is in a sub folder of your web server's root folder called "Images"</FONT>
<FONT color=#808080>        for exmaple C:\inetpub\wwwroot\images\ }</FONT>
      <FONT color=#008000>'&lt;img src="/Images/DelphiLinksHead.gif"&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;a href="'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#008000>'/AddLinkPage"&gt;&lt;img alt="Add a link to your web site from here" border="0" src="'</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#008000>'/Images/AddLink.gif"&gt;&lt;/a&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;p/&gt;&lt;hr/&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;table&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT><FONT color=#ff0000>;</FONT>

    <FONT color=#0000ff><B>while</B></FONT> <FONT color=#0000ff><B>not</B></FONT> <FONT color=#000080>Eof</FONT> <FONT color=#0000ff><B>do</B></FONT>
    <FONT color=#0000ff><B>begin</B></FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;tr&gt;%s&lt;td&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="%s"&gt;&lt;b&gt;%s&lt;/b&gt;&lt;/A&gt;&lt;/td&gt;%s'</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;td&gt;&lt;b&gt;Posted By:&lt;/b&gt;%s&lt;/td&gt;'</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'%s&lt;td&gt;&lt;b&gt;Date Posted:&lt;/b&gt;%s&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;%s&lt;b&gt;Description:&lt;/b&gt;&lt;br&gt;%s%s&lt;/td&gt;%s&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;hr/&gt;&lt;/td&gt;&lt;/tr&gt;'</FONT><FONT color=#ff0000>,</FONT>
        <FONT color=#ff0000>[</FONT><FONT color=#000080>NewLine</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'LinkURL'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Title'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>NewLine</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'OwnerFirstName'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>' '</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'OwnerLastName'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>NewLine</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'DateAdded'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>NewLine</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Description'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>NewLine</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>NewLine</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Next</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT> <FONT color=#808080>{ while not Eof }</FONT>
    <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;/table&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;/body&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;/html&gt;'</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>Notice the line 
<P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New">      <FONT color=#008000>'&lt;img src="/Images/DelphiLinksHead.gif"&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;a href="'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#008000>'/AddLinkPage"&gt;&lt;img alt="Add a link to your web site from here" border="0" src="'</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#008000>'/Images/AddLink.gif"&gt;&lt;/a&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>NewLine</FONT> <FONT color=#ff0000> </FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>We've referenced 2 images here. These images should be in a sub folder of your web server's root folder. The name of the sub folder should be Images. You can call this folder anything you like but be sure to change the code above to match your folder's name. </P>
<P>It is a good idea to keep images in a separate folder, rather than in the root folder. It's easier to manage your web sites that way. The second image is hyper-linked. This link will direct the user to our Data Entry screen.</P>
<P>Also notice the line with the Format procedure. This line of code generates a string that looks something like this:</P><PRE><P>&lt;A href="http://www.matlus.com"&gt;&lt;B&gt;The Delphi Stop&lt;/B&gt;&lt;/A&gt;</P></PRE>
<P>In the browser this will be rendered as words - The Delphi Stop, in bold typeface as hyper-linked text. When one clicks on the hyperlink, the browser will direct you to the URL specified in the HREF attribute of the anchor &lt;A&gt; tag.</P>
<P>To see this page, the URL will be http://ServerName/scripts/AddLink.dll/ShowDelphiLinks.</P>
<P>Since we'd like our users to hit this page by default we'll set the Default property of this action item to True. This will automatically set all other action item's Default property to False. There can be one and only one default action in an ISAPI/CGI application.</P>
<P>If you have data in your table, then the generated HTML page should look like that shown in <B>Figure 5</B>. 
<P><IMG alt=SecondISAPI4.png src="http://www.matlus.com/images/SecondISAPI4.png" border=0><BR><B>Figure 5: Showing the default page of our ISAPI.</B> 
<P>There you have it -- an ISAPI/CGI that allows data entry into a database and then displays that information in an HTML page. </P>]]></description><category>Programming</category><category>Database</category><category>Delphi</category><category>ISAPI</category></item><item><title>Showing Images in a Browser from a Database</title><pubDate>Wed, 16 Jan 2008 11:18:10 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/8/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/8/</guid><description><![CDATA[<P>For this article we will use the Biolife table that can be found in the DBDEMOS Alias that comes standard with Delphi. 
<P>Starting the Project 
<OL>
<LI>Start a new Web Server Application using the Delphi wizard. 
<LI>Choose CGI in the dialog box (you can choose ISAPI also. There will be no change in the code) 
<LI>Choose the Project menu from the IDE. 
<LI>Choose Options from the Project menu. 
<LI>In the Project Options dialog, click on the Directories/Conditionals page. 
<LI>Set the Output directory to - C:\inetpub\scripts (or your scripts folder of you web server). 
<LI>Create 2 action items by double clicking on the Web Data Module. 
<LI>Set the PathInfo property of the first action item to /Fish, the Name to waFish and the defalt property to True. 
<LI>Set the PathInfo of the second action item to /SendImage and the Name to waSendImage. 
<LI>Drop a TQuery component onto the Web Data Module and set its DatabaseName property to DBDEMOS. </LI></OL>
<P>In the OnAction event of the waFish action item, type the following code:<BR>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1waFishAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#0000ff><B>try</B></FONT>
    <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>Query1</FONT> <FONT color=#0000ff><B>do</B></FONT>
    <FONT color=#0000ff><B>begin</B></FONT>
      <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Clear</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'SELECT BIOLIFE."Species No", Common_Name FROM BIOLIFE'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Open</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'&lt;h2&gt;The various species of Fish&lt;/h2&gt;&lt;br&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
      <FONT color=#008000>'Click on the hyperlinks below to see the picture of the given species&lt;P&gt;'</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#0000ff><B>while</B></FONT> <FONT color=#0000ff><B>not</B></FONT> <FONT color=#000080>Eof</FONT> <FONT color=#0000ff><B>do</B></FONT>
      <FONT color=#0000ff><B>begin</B></FONT>
        <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000> </FONT>
          <FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;a href="%s/%s?No=%s"&gt;%s&lt;/a&gt;&lt;br&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT><FONT color=#ff0000>,</FONT>
                <FONT color=#ff0000>[</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,</FONT>
                 <FONT color=#008000>'SendImage'</FONT><FONT color=#ff0000>,</FONT>
                 <FONT color=#000080>Fields</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
                 <FONT color=#000080>Fields</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>1</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Next</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT> <FONT color=#808080>{ while not Eof }</FONT>
      <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT> <FONT color=#808080>{ with Query1 do }</FONT>
  <FONT color=#0000ff><B>except</B></FONT>
    <FONT color=#000080>on</FONT> <FONT color=#000080>E</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Exception</FONT> <FONT color=#0000ff><B>do</B></FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'&lt;b&gt;ERROR&lt;/b&gt;&lt;br&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#000080>E</FONT><FONT color=#ff0000>.</FONT><FONT color=#0000ff><B>Message</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>In this event we query the Biolife table. We use only two fields in this case. The "species no" field and the Common Name field. The common name field is what we display in the browser while the Species no field is used to send back as a "parameter" to the /SendImage action of our application. I use the Format function here to construct the HTML string to be returned to the web browser. Each record of the table will generate a string that looks like : 
<P><PRE>&lt;A HREF="/scripts/Fish.exe/SendImage?No=90030"&gt;Red Emperor&lt;/A&gt;&lt;BR&gt;</PRE>
<P>This is standard HTML. Notice here that the /SendImage action is called sending it a parameter -"No=90030". We will "extract" the value of "No" from this to use in the next query that we will build dynamically in the /SendImage action's OnAction event.</P>
<P>The /SendImage action's OnAction event looks like this :</P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1waSendImageAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT>
  <FONT color=#000080>JPEG</FONT>   <FONT color=#ff0000>:</FONT> <FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Bitmap</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#808080>{ In this action event, I "extract" the Species No parameter from the QueryFields</FONT>
<FONT color=#808080>    property of the Request object and use that to get the image from the</FONT>
<FONT color=#808080>    table.</FONT>
<FONT color=#808080>    Then I stream out the image as a Jpeg image</FONT>
<FONT color=#808080>  }</FONT>
  <FONT color=#0000ff><B>try</B></FONT>
    <FONT color=#000080>JPEG</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>MemStrm</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Bitmap</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>try</B></FONT>
      <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>Query1</FONT> <FONT color=#0000ff><B>do</B></FONT>
      <FONT color=#0000ff><B>begin</B></FONT>
        <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Clear</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'SELECT Graphic FROM BIOLIFE'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>SQL</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'WHERE BIOLIFE."Species No" = :LastName'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Params</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsInteger</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>StrToInt</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'No'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Open</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#808080>{ Assign the image from the database to a Bitmap object since the</FONT>
<FONT color=#808080>          field type is a TGraphicField.}</FONT>
        <FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'GRAPHIC'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SaveToStream</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Position</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#808080>{ The content type needs to be set !! }</FONT>
        <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentType</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'image/jpeg'</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentStream</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>finally</B></FONT>
      <FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#808080>{ Do not Free MemStrm. The Web server will take care of it. }</FONT>
      <FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>except</B></FONT>
    <FONT color=#000080>on</FONT> <FONT color=#000080>E</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Exception</FONT> <FONT color=#0000ff><B>do</B></FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'&lt;b&gt;ERROR&lt;/b&gt;&lt;br&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
        <FONT color=#000080>E</FONT><FONT color=#ff0000>.</FONT><FONT color=#0000ff><B>Message</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>The code above is commented to explain what is going on. If one had instantiated the fields of the Query object than one could have assigned the field object (for the image field) directly to the bitmap. The code for that would look like Bitmap.Assign(Query1Graphic). In this particular example, you shouldn't/can't instantiate the field object explicitly since we use the same Query object for different SQL queries that return different sets of fields.</P>
<P>The ContentType property of the Response object can be set to 'image/gif' if you want to send gif images. The various ContentType values can be found in the HTTP specifications. 
<P>Another interesting Project is the next project where we reduce the image size just before we send the image. This technique is very useful and effective is real world ISAPI application development. Check it out. </P>]]></description><category>Programming</category><category>Database</category><category>Delphi</category><category>ISAPI</category></item><item><title>Reducing Image Size on-the-fly (thumbnails)</title><pubDate>Tue, 15 Jan 2008 11:18:10 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/9/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/9/</guid><description><![CDATA[<P>On to more fun things! In this article, we're going to send images (from within a database) to a web browser. But we won't just stream out images straight out of the database. We'll stream out a thumbnail version of each image that we'll create on-the-fly.We will also explore using the TQueryTableProducer component that comes as part of Delphi's web broker technology.</P>
<P><B>Sending Data</B> 
<P>This part is really simple. Actually, Delphi makes it really simple. We won't need to write any code for this so let's start building the project. 
<OL>
<LI>Start a new ISAPI Web server (extension) application. 
<LI>Drop down a TQuery component and change its name to qryData. 
<LI>Set the Database property of qryData to DBDEMOS. 
<LI>Set the Active property to True. 
<LI>Set the SQL property to SELECT * FROM BIOLIFE. 
<LI>Drop down a TQueryTableProducer component on the Web Data Module. 
<LI>Drop down its Query property and set it to qryData. 
<LI>Double click on the Web Data Module (or right click on it and choose "Action Editor...") and create a new action item. 
<LI>Set the PathInfo property of this action item to <PRE>/data</PRE>. 
<LI>Change the Name property of the action item to <PRE>waData</PRE>
<LI>Set the Default property to <PRE>True</PRE>
<LI>Drop down the Producer property of the action item and set it to <PRE>QueryTableProducer1</PRE>. 
<LI>Drop down a TSession component and set its AutoSessionName property to <PRE>True</PRE>. 
<LI>From the Project | Options menu, set the output directory to C:\inetpub\scripts (or the scripts folder of your web server. This step is followed in all ISAPI/CGI projects. </LI></OL>
<P>Your Object inspector and Web Data Module should look like that shown in <B>Figure 1.</B> 
<P><IMG alt=ISAPI3F1.png src="http://www.matlus.com/images/ISAPI3F1.png" border=0> 
<P><B>Figure1: Showing the Object inspector and Web Data Module thus far.</B> 
<P><B>Explanation</B> 
<P>There can be only one action item per application with its default property set to True. What this really does is, it allows you to call your ISAPI/CGI application from a browser without the need to specify an action. So the URLs http://www.mydomain.com/scripts/myserverextension.dll/data and http://www.mydomain.com/scripts/myserverextension.dll will return the same page. In other words, the same action is executed in this case since the action item with the pathinfo - /data has been set as the default action.</P>
<P>Setting the Producer property of the action item to the QueryTableProducer1 causes the Response.Content property of the web module to be automatically set to QueryTableProducer1.Content in the OnAction event of the action item. One could create an OnAction event for this action item and write the line</P>
<P><PRE>Response.Content := QueryTableProducer1.Content;
</PRE>
<P>to achieve the same end result without setting the Producer property. In this case we'll use the property and so we won't write any code in the OnAction event. 
<P>Every request from the web server causes your ISAPI application to spawn a new thread within which a new instance of the web data module is created. To allow for multiple simultaneous access to a we use a TSession component and set its AutoSessionName property to True so it generates a new session name for every session (thread). For CGI applications this is not required (and should not be done) since every request from the web server creates a new instance of your CGI application (simulating multiple simultaneous users, each using an instance of your application) thereby allowing for multiple simultaneous access to your database.</P>
<P><B>Seeing the output</B> 
<P>Save your project as Biolife.dpr and compile your application. This should create a DLL by the name of Biolife.dll in the scripts folder of your web server. In your browser, type in the URL 
<P>http://mypcname/scripts/biolife.dll (replace mypcname with the IP address or machine name of the machine running the web server). You should see a page like the one shown in <B>Figure 2</B>. 
<P><IMG alt=ISAPI3F2.png src="http://www.matlus.com/images/ISAPI3F2.png" border=0> <BR><B>Figure 2: Showing the output generated by the QueryTableProducer component.</B> 
<P>Notice how the Notes Field has the word (MEMO) in it instead of the actual memo text. Notice also that the Graphic field shows the word (GRAPHIC) instead of the actual graphic. In the remainder of this article, we will attempt to correct this. 
<P>Before we get the memo and graphic fields to show, we'll remove some of the unnecessary fields so we see only the fields we want in our browser. This process will also demonstrate to you, how you can re-order the fields in the output if you need to do that using the TxxxTableProducer components that come with Delphi. <B>
<P>Using the TQueryTableProducer</B> 
<P>The TQueryTableProducer component has a response editor that can be invoked by double clicking on it or right clicking on it and choosing the "Response editor" pop up menu option. Before you do this, you need to set the TQuery, qryData's Active property to True. The Response Editor should like that that shown in <B>Figure 3</B> after you've set the Active property of qryData to True and double click on the QueryTableProducer1 component.<BR><BR><IMG alt=ISAPI3F3.png src="http://www.matlus.com/images/ISAPI3F3.png" border=0><BR><B>Figure 3: The QueryTableProducer's Response Editor</P></B>
<P>You will notice here that you see all the fields of the dataset, since our SQL statement does not explicitly specify fields. You could change the SQL statement such that you see only the fields you are interested in. This will speed up your application as well, but for now we'll see how we can accomplish field ordering and selection using the table producer component's response editor. Before we can start manipulating fields, you need to first add all fields (kind of like instantiating fields of a dataset). To do this, click on the "Add All Fields" tool bar button in the response editor. Once you've done that, you can:</P>
<OL>
<LI>Drag-drop fields to re-order them or use the toolbar buttons with up-down arrows. 
<LI>Select each field in turn and set its properties listed in the object inspector. </LI></OL>
<P>You can also set the table properties (HTML table) using the response editor. Lets delete the fields, Length(cm), Length_in and Common_Name. This should give us some extra space to show the notes field and graphic field in the browser, instead of the words (MEMO) and (GRAPHIC). We'll also set the Border property of the HTML table (in the response editor) to 1. You should see the effect of doing this in the response editor.</P>
<P><B>Getting the Notes Field to show in the browser</B> 
<P>To be able to see the Notes field in the browser we need to write some code in the OnFormatCell event of the QueryTableProducer component. This event is fired automatically before rendering each cell in the HTML table. At this point, you have the ability to change the content of the cell, the background color and the horizontal and vertical alignments of the content of the cell etc. 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryTableProducer1FormatCell</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>CellRow</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>CellColumn</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Integer</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>BgColor</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLBgColor</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Align</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>VAlign</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLVAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>CustomAttrs</FONT><FONT color=#ff0000>,</FONT>
<FONT color=#000080>CellData</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV><BR>You will notice, that there are a number of parameters passed in this event. For the purpose of showing the contents of the Notes field, we need to change the value of the CellData variable to the contents of the memo field. Write the following code in this event. Before writing any code, lets go ahead and create the field objects (instantiate) for the qryData dataset. Instantiating field objects is not required for things to work, but in this case we will. We will create field objects only for the fields we are interested in. <B>Figure 4</B> shows the field objects that we need to instantiate. 
<P><IMG alt=ISAPI3F4.png src="http://www.matlus.com/images/ISAPI3F4.png" border=0><BR><BR><B>Figure 4: Showing the Fields instantiated in qryData's fields editor.</B> 
<P>Now in the OnFormatCell event, write the following code: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryTableProducer1FormatCell</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#000080>CellRow</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>CellColumn</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Integer</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>BgColor</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLBgColor</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Align</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>VAlign</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLVAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>CustomAttrs</FONT><FONT color=#ff0000>,</FONT>
<FONT color=#000080>CellData</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#808080>{ Row 0 is the Column Header, so check for CellRow &gt; 0 }</FONT>
  <FONT color=#0000ff><B>if</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellRow</FONT> <FONT color=#ff0000>&gt;</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>and</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellColumn</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>4</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
    <FONT color=#000080>CellData</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>qryDataNotes</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Value</FONT><FONT color=#ff0000>;</FONT><FONT color=#808080>//Memo Field data</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>If you recompile your project and refresh your browser, you should see a result similar to that shown in <B>Figure 5.</B> 
<P><IMG alt=ISAPI3F5.png src="http://www.matlus.com/images/ISAPI3F5.png" border=0> <BR><B>Figure 5: The output in the browser showing the contents of the Memo field.</B> 
<P>Notice that the Notes field now shows the contents rather than the word (NOTES). The graphic field still shows the word (GRAPHIC) since we haven't yet done anything to change that.</P>
<P><B>Showing the Graphics Field in the browser</B> 
<P>Getting the browser to show the graphic along with the data is a bit trickier than what we had to do to get the Notes field's contents to show. Trickier, not harder. Nothing in Delphi is hard.</P>
<P>Lets see what the concept is before we attempt to do this in code. The CellData (in the OnFormatCell event) for the graphics field is being set to (GRAPHIC) by the QueryTableProducer. That's why we see (GRAPHIC) in the browser instead of the graphic itself. If we change the CellData variable for the Graphic column to an HTML &lt;IMG&gt; tag then we should see an image instead. The problem, however is that we need to extract the image from the table and show that image. If we wanted to show an image that resided on the hard drive, we could have simply given the correct URL in the SRC attribute of the &lt;IMG&gt; tag and the browsers would have loaded the required image and shown it.</P>
<P>The concept is similar however. The change is that the image needs to come from the table and not the hard drive. We can write a procedure in our ISAPI to extract the image from the table for the given record. This image then needs to be streamed out to the browser. To get the browser to load the image, we simply give the SRC attribute of the &lt;IMG&gt; tag as an action item in our ISAPI. The action will then have the responsibility of sending back the corresponding image. All this may seem complicated at this point, but it really isn't. We'll work this out step by step to simplify the process.</P>
<P>First we need to change the CellData to an HTML &lt;IMG&gt; tag. Add code such that your OnFormatCell event looks like the following: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryTableProducer1FormatCell</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#000080>CellRow</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>CellColumn</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Integer</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>BgColor</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLBgColor</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Align</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>VAlign</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLVAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>CustomAttrs</FONT><FONT color=#ff0000>,</FONT>
<FONT color=#000080>CellData</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#808080>{ Row 0 is the Column Header, so check for CellRow &gt; 0 }</FONT>
  <FONT color=#0000ff><B>if</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellRow</FONT> <FONT color=#ff0000>&gt;</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>and</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellColumn</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>4</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
    <FONT color=#000080>CellData</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>qryDataNotes</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Value</FONT><FONT color=#ff0000>;</FONT><FONT color=#808080>//Memo Field data</FONT>
  <FONT color=#808080>{ Change the CellData from (GRAPHIC) to an HTML &lt;IMAGE&gt; TAG }</FONT>
  <FONT color=#0000ff><B>if</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellRow</FONT> <FONT color=#ff0000>&gt;</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>and</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellColumn</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>5</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
    <FONT color=#000080>CellData</FONT> <FONT color=#ff0000>:=</FONT>
      <FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;IMG SRC="%s/image?No=%s"&gt;'</FONT><FONT color=#ff0000>,</FONT>
        <FONT color=#ff0000>[</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,</FONT>
         <FONT color=#000080>qryDataSpeciesNo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>The result of the Format procedure and therefore the value of the CellData variable will be something like this: <PRE>&lt;IMG SRC="/biolife.dll/image?No=90020"&gt;
</PRE>
<P>Notice that there is a reference to a /image action item in our ISAPI. We don't have this action item as yet, but we will create one soon. A parameter that we send in the form of a Name=Value pair, to this action item is No=90020. 90020 being the Species No value for the first record in the biolife table. This will change to correspond with each record's Species No value. 
<P>In our /image action item's OnAction event, we can extract this parameter using the Request object's QueryFields property. Using the Species No value, we can zero in on the required record, extract the image from the field and send it back to the browser as a response. 
<P>Let's first create a new action item and set the pathinfo property to /image and call it waImage as shown in <B>Figure 6</B>. 
<P><IMG alt=ISAPI3F6.png src="http://www.matlus.com/images/ISAPI3F6.png" border=0><BR><B>Figure 6: Showing the Actions Editor with the waImage Action item created.</B> </B>
<P>If you compile your ISAPI and refresh your browser, you should see an output like that shown in <B>Figure 7</B>. 
<P><IMG alt=ISAPI3F7.png src="http://www.matlus.com/images/ISAPI3F7.png" border=0><BR><B>Figure 7: Showing the place holders for images in our database. </B>
<P>Notice how the actual image is not shown, since we have yet to do something about that, but the word (GRAPHIC) has now been replaced with what the browser shows for an image it has not been able to find. Since we have yet to write code in the waImage action item's OnAction event, this is expected. </P>
<OL>
<LI>Add the Graphics and JPEG unit to the uses clause of the interface section of the Web data module. 
<LI>Then drop down another TQuery component on the web data module 
<LI>Set the Name property to qryImage 
<LI>Set the DatabaseName property to DBDEMOS. 
<LI>Set the SQL property to </LI></OL>
<P><B>SELECT Graphic FROM BIOLIFE<BR>WHERE BIOLIFE."Species No" = :SpeciesNo</B> 
<P>We'll be streaming the image out as a jpeg image and we'll use another query componet, qryImage to "zero in" on the record with the species no given to us. The code in the OnAction event of the waImage action item should look like this:</P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1waImageAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT>
  <FONT color=#000080>JPEG</FONT>    <FONT color=#ff0000>:</FONT> <FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>MemStrm</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Bitmap</FONT>  <FONT color=#ff0000>:</FONT> <FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
<FONT color=#808080>{ In this action event, we "extract" the Species No parameter from the QueryFields</FONT>
<FONT color=#808080>property of the Request object and use that to get the image from the</FONT>
<FONT color=#808080>table.Then we stream out the image as a Jpeg image</FONT>
<FONT color=#808080>}</FONT>
  <FONT color=#0000ff><B>try</B></FONT>
    <FONT color=#000080>JPEG</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>MemStrm</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Bitmap</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>try</B></FONT>
      <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>qryImage</FONT> <FONT color=#0000ff><B>do</B></FONT>
      <FONT color=#0000ff><B>begin</B></FONT>
        <FONT color=#808080>{ Assign the :SpeciesNo paramter the value received in the Request</FONT>
<FONT color=#808080>          object's QueryFields property. Remember that it comes as eg. No=90020</FONT>
<FONT color=#808080>        }</FONT>
        <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Params</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsInteger</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>StrToInt</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'No'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Prepare</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Open</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#808080>{ Assign the image from the database to a Bitmap object since the</FONT>
<FONT color=#808080>          field type is a TGraphicField.}</FONT>
        <FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'GRAPHIC'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#808080>{ Save the JPEG image to the memory stream object}</FONT>
        <FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SaveToStream</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#808080>{ Set the position to the start }</FONT>
        <FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Position</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#808080>{ The content type needs to be set to image/jpeg. Default is 'text/html' }</FONT>
        <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentType</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'image/jpeg'</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentStream</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Unprepare</FONT><FONT color=#ff0000>;</FONT>
        <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>finally</B></FONT>
      <FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#808080>{ We don't need to  free MemStrm since the WebServer will do that }</FONT>
      <FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT> <FONT color=#808080>{ try - finally }</FONT>
  <FONT color=#0000ff><B>except</B></FONT>
    <FONT color=#000080>on</FONT> <FONT color=#000080>E</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Exception</FONT> <FONT color=#0000ff><B>do</B></FONT>
    <FONT color=#0000ff><B>begin</B></FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentType</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'text/html'</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'&lt;B&gt;ERROR&lt;/B&gt;&lt;BR&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>E</FONT><FONT color=#ff0000>.</FONT><FONT color=#0000ff><B>Message</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT> <FONT color=#808080>{ try - except }</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>What we do in here is extract the Species No from the QueryFields property of the Request object and assign that to the :SpeciesNo parameter of the SQL statement used to "zero in" on the correct record. Next we extract the graphic from this record and assign it to a TBitmap object. The graphic in the table happens to be a bitmap in this case. To convert the bitmap to a jpeg image, we simply assign the Bitmap to the JPEG image. To be able to stream the image we save the JPEG image to a memory stream object. 
<P>Before we can actually send back the stream, we need to let the browser know what kind of data to expect. We do this by setting the response object's ContentType to 'image/jpeg'. Once we've done this, we send the response using the SendResponse method of the Response object. 
<P>If you now recompile the ISAPI and refresh the browser you should see an output like that shown in <B>Figure 8</B>.</P></FONT>
<P><IMG alt=ISAPI3F8.png src="http://www.matlus.com/images/ISAPI3F8.png" border=0><BR><B>Figure 8: Showing the contents of the Notes field and Graphic field in the browser.</B> 
<P>There we have it. The Notes field and the Graphic field shown in the browser along with the other fields. On a slow network, this kind of thing could take a long time to process, since there are a number of images involved. We could change this application to first show hyper linked names of each of the species. When one clicks on these links, one is shown the Notes field and the Graphics field either is a separate browser window or using HTML frames in the same window but in the bottom half. We could also show the notes and graphic fields in another page (so you will need to hit the "BACK" button on your browser to see the list of Species names once again). 
<P>All of this is made simple enough with the QueryTableProducer component. Your knowledge of HTML comes into play here, since we now know how to extract the image and memo fields and show it in the browser. 
<P>Rather than change this application's behavior, we'll add to it. What we'll do is create additional action items that will produce a different output. What we want to do now is show a page that contains only the Common Name column of the table with hyperlinks. When one clicks on the hyperlink, one should be shown the Notes Field and the Graphic field for the record in question.</P>
<P>1. Drop another TQueryTableProducer component on the form.<BR>2. Set its Query property to qryData.<BR>3. Double click on it to invoke the Response Editor.<BR>4. Add All Fields.<BR>5. Then delete all fields except for the Common_Name field.<BR>6. Select the Common_Name field in the Response Editor.<BR>7. Set its Title's align property to haLeft.</P>
<P>The Response Editor should look like that shown in <B>Figure 9</B>.</P>
<P><IMG alt=ISAPI3F9.png src="http://www.matlus.com/images/ISAPI3F9.png" border=0><BR><B>Figure 9: Showing the Response Editor for our second QueryTableProducer component.</B> </B>
<P>In the Web Data Module, create a new action item.</P>
<P>1. Set its Name property to waNames.<BR>2. Set its PathInfo property to /names.<BR>3. Set its Producer property to QueryTableProducer2.</P>
<P>Your web data module should look like that shown in <B>Figure 10</B></P>
<P><IMG alt=ISAPI3F10.png src="http://www.matlus.com/images/ISAPI3F10.png" border=0><BR><B>Figure 10: Showing the updated Web Data Module.</B> 
<P>What we've done so far is linked a second QueryTableProducer component to our qryData query component. We've made sure that only the Common_Name field is produced in the output. We then created a new action item with the pathinfo of /names. Next we linked the Producer property of this action item to QueryTableProducer2. 
<P>If we re-compile our ISAPI and change the URL in our browser to http://myservername/scripts/biolife.dll/names, we should see an HTML page similar to that shown in <B>Figure 11</B>.</P>
<P><IMG alt=ISAPI3F11.png src="http://www.matlus.com/images/ISAPI3F11.png" border=0><BR><B>Figure 11: Showing the Result of the /names action of our ISAPI DLL.</B> 
<P>The names are not yet hyper linked. To do this, we generate the OnFormatCell event of QueryTableProducer2 and write the following code in there: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryTableProducer2FormatCell</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#000080>CellRow</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>CellColumn</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Integer</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>BgColor</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLBgColor</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Align</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>VAlign</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLVAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>CustomAttrs</FONT><FONT color=#ff0000>,</FONT>
<FONT color=#000080>CellData</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#0000ff><B>if</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellRow</FONT> <FONT color=#ff0000>&gt;</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>and</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellColumn</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
    <FONT color=#000080>CellData</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;A HREF="%s/Details?No=%s"&gt;%s&lt;/A&gt;'</FONT><FONT color=#ff0000>,</FONT>
      <FONT color=#ff0000>[</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,</FONT>
       <FONT color=#000080>qryDataSpeciesNo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
       <FONT color=#000080>qryDataSpeciesName</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>The result of the Format function will look like this: <PRE>&lt;A HREF="/scripts/biolife.dll/Details?No=90020"&gt;Clown Triggerfish&lt;/A&gt;
</PRE>
<P>We reference an action item with a pathinfo of /details that expects to see a parameter called No. We don't have an action item with a PathInfo of /details yet. But we will soon. 
<P>If you re-compile the ISAPI and refresh the browser, you should see an output similar to that shown in <B>Figure 12</B>. 
<P><IMG alt=ISAPI3F12.png src="http://www.matlus.com/images/ISAPI3F12.png" border=0><BR><B>Figure 12: Showing the Names hyper-linked in the browser.</B> 
<P>If you move your mouse over each of these hyperlinks, you should see in the status bar of the browser (as shown in <B>Figure 12</B> above) that each species has its associated species no.<BR><BR>If you click on any of the hyperlinks now, you'll get an error since we have not created an action item with a pathinfo of /details. So lets go ahead and create it now.</P>
<P>Create a new action item.</P>
<P>1. Set its PathInfo property to /details.<BR>2. Set its Name property to waDetails.</P>
<P>Your Actions Editor should look like that shown in <B>Figure 13</B>.</P>
<P><IMG alt=ISAPI3F13.png src="http://www.matlus.com/images/ISAPI3F13.png" border=0><BR><B>Figure 13: Showing the Action Editor with the new action items&nbsp;</B> 
<P>To keep things simple, we'll drop another TQuery component on the web data module</P>
<OL>
<LI>Set its Name property to qryNotes. 
<LI>Set its DatabaseName property to DBDEMOS. 
<LI>Set its SQL property to:</LI></OL>
<P><B>SELECT Notes FROM BIOLIFE<BR>WHERE BIOLIFE."Species No" = :SpeciesNo</B> 
<P>We'll use this query component to zero in on the required record and get the value of the Notes field to be displayed in the browser. 
<P>In the OnAction event of the waDetails action item, write the following code: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1waDetailsAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
<FONT color=#808080>{ Manually create an HTML table with two columns. Populate the first</FONT>
<FONT color=#808080>one with the contents of the Notes field. The second column will contain</FONT>
<FONT color=#808080>the graphic from the table. Here we'll only put an HTML &lt;IMG&gt; tag</FONT>
<FONT color=#808080>with the correct URL to extract the required image from the table using</FONT>
<FONT color=#808080>the species no parameter sent to us here in the QueryFields property</FONT>
<FONT color=#808080>of the Request object</FONT>
<FONT color=#808080>}</FONT>
  <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'&lt;H3&gt;Notes&lt;/H3&gt;&lt;BR&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
  <FONT color=#008000>'&lt;TABLE&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
  <FONT color=#008000>' &lt;TR&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
  <FONT color=#008000>' &lt;TD&gt;'</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#808080>{ Zero in on the correct record in the table }</FONT>
  <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>qryNotes</FONT> <FONT color=#0000ff><B>do</B></FONT>
  <FONT color=#0000ff><B>begin</B></FONT>
    <FONT color=#808080>{ Assign the :SpeciesNo paramter the value received in the Request</FONT>
<FONT color=#808080>      object's QueryFields property. Remember that it comes as eg. No=90020</FONT>
<FONT color=#808080>    }</FONT>
    <FONT color=#000080>Close</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Params</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsInteger</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>StrToInt</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'No'</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Prepare</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Open</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#808080>{ Put the value of the Notes field in the First cell }</FONT>
    <FONT color=#000080>qryNotes</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Notes'</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>'&lt;/TD&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#808080>{ Put an &lt;IMG&gt; tag in the second cell and set its SRC parameter's value</FONT>
<FONT color=#808080>     to the waImage action item, sending it the species no received in the</FONT>
<FONT color=#808080>     Request object's QueryFields property.</FONT>
<FONT color=#808080>    }</FONT>
    <FONT color=#008000>' &lt;TD&gt;&lt;IMAGE SRC="'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>'/image?No='</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'No'</FONT><FONT color=#ff0000>]</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>'"&gt;&lt;/TD&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' &lt;/TR&gt;'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'&lt;/TABLE&gt;'</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>You will find the explanation of the code in the comments above. I'll explain the part with the &lt;IMAGE&gt; HTML tag some more. Just like we did the first time, all we're doing is setting the SRC parameter of the &lt;IMAGE&gt; tag to our waImage action item (pathInfo of /image). This action item can extract the graphic and stream it out to the browser given the species no of the record for which we require an image. 
<P>If you re-compile the ISAPI and refresh your browser and then click on a hyperlink, you should see an as showin in <B>Figure 14</B>:</P></FONT>
<P><IMG alt=ISAPI3F14.png src="http://www.matlus.com/images/ISAPI3F14.png" border=0><BR><B>Figure 14: Showing the notes and Graphic field</B><BR>
<P>I have noticed that if an ISAPI/CGI is attempting to send a number of images in this fashion, things tend to get a bit funny. If you play with this application a bit, you may see that at times the browser won't show the right image for the Common Name that you clicked on, or that you won't see an image at all, or you may even get access violation errors. 
<P>To get around this problem, the solution I found was to use Response.SendStream(MemStrm) instead of the earlier, Response.ContentStream := MemStrm;. 
<P>I suggest you make this change to the code in the OnAction event of the waImage action item. 
<P>This brings us to the end of this project. We've learned how to use the TQueryTableProducer component. How to use the OnFormatCell event to change the resulting output. Then we learned how we can extract an image from a database table and stream it out to the browser. As an excersize for the reader, I suggest trying to showing the Notes and Graphic in the same page in the bottom half of the browser using HTML Frames.</P>
<P>Your output should look like that shown in <B>Figure 15</B>:</P>
<P><IMG alt=ISAPI3F15.png src="http://www.matlus.com/images/ISAPI3F15.png" border=0><BR><B>Figure 15: Showing the output using HTML Frames</B> 
<P>You don't really have to make too much of a change to the existing project if you don't want to. However, you will need to create an HTML file with the following HTML in it. Note however, that you could change the project to generate this HTML file in question. The HTML should look like this: <PRE>&lt;!-- frames --&gt;
&lt;frameset rows="50%,50%" border="0"&gt;
&lt;frame name="Data" src="http://YourPCName/scripts/biolife.dll/names" marginwidth="10" marginheight="5" scrolling="auto" frameborder="no"&gt;
&lt;frame name="Detail" src="" marginwidth="10" marginheight="10" scrolling="auto" frameborder="no"&gt; 
&lt;/frameset&gt;
</PRE>
<P>In the project, change the format string in the OnFormatCell event of TQueryTableProducer2 from <PRE>&lt;A HREF="%s/Details?No=%s"&gt;%s&lt;/A&gt;'
</PRE>
<P>to <PRE>&lt;A HREF="%s/Details?No=%s" <B><I>TARGET="Detail"</I></B>&gt;%s&lt;/A&gt;'
</PRE>
<P>This will instruct the browser to show the Notes field and Graphic field in the frame called "Detail". Which is the frame at the bottom half of the HTML file you created. Note that the Name of the frame is case sensitive. 
<P><B>Creating Image Thumbnails</B> 
<P>Generally, due to speed considerations, we'd like to be able to create thumbnail images of the images we're sending to the browser, giving the user the option of seeing the image in actual size if s/he so desires. 
<P>Delphi makes it really simple to create thumbnail images on the fly. The procedure listed below does exactly that. 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ReduceBitmap</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>smBitmap</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>orgBitmap</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Reduction</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Integer</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>1</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT>
  <FONT color=#000080>Rect</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TRect</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Width</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>orgBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Width</FONT> <FONT color=#0000ff><B>div</B></FONT> <FONT color=#000080>Reduction</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Height</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>orgBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Height</FONT> <FONT color=#0000ff><B>div</B></FONT> <FONT color=#000080>Reduction</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Rect</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Top</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Rect</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Left</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Rect</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Right</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Width</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Rect</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Bottom</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Height</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Canvas</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>StretchDraw</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Rect</FONT><FONT color=#ff0000>,</FONT><FONT color=#000080>orgBitmap</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>Two bitmap objects are sent to this procedure. smBitmap is the bitmap that contains the reduced bitmap while orgBitmap is the bitmap that contain the bitmap to be reduced. Reduction is the factor by which to reduce the bitmap. 
<P>To implement thumbnails in our project we'll have to make a few following changes. Note however that we'll implement thumbnail images only for the waData action item. This is out default action item. We'd also like to be able to click on the images seen in output created by this action to see the image in its normal size. 
<P>First let us make the changes required in the waImage action item's OnAction event. The following is the code listing of this event: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><PRE><CODE><FONT color=#0000ff><B>procedure </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1waImageAction</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TObject</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>; </FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>; </FONT><FONT color=#0000ff><B>var </B></FONT><FONT color=#000080>Handled</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>Boolean</FONT><FONT color=#ff0000>);
</FONT><FONT color=#0000ff><B>var
  </B></FONT><FONT color=#000080>JPEG    </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>MemStrm </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Bitmap  </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080><B><I>smBitmap</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TBitmap</I></B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>begin

</B></FONT><FONT color=#808080>{ In this action event, we "extract" the Species No parameter from the QueryFields
property of the Request object and use that to get the image from the
table.Then we stream out the image as a Jpeg image
} </FONT><FONT color=#0000ff><B>try
    </B></FONT><FONT color=#000080>JPEG </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>MemStrm </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>Bitmap </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080><B><I>smBitmap </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</I></B></FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>try
      with </B></FONT><FONT color=#000080>qryImage </FONT><FONT color=#0000ff><B>do
      begin
        </B></FONT><FONT color=#808080>{ Assign the :SpeciesNo paramter the value received in the Request
          object's QueryFields property. Remember that it comes as eg. No=90020
        }
        </FONT><FONT color=#000080>Close</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>Params</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>].</FONT><FONT color=#000080>AsInteger </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>StrToInt</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'No'</FONT><FONT color=#ff0000>]);
        </FONT><FONT color=#000080>Prepare</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>Open</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#808080>{ Assign the image from the database to a Bitmap object since the
        field type is a TGraphicField.}
        </FONT><FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'GRAPHIC'</FONT><FONT color=#ff0000>));
        </FONT><FONT color=#000080><B><I>ReduceBitmap</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>, </FONT><FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>,</FONT><FONT color=#000080>StrToIntDef</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'Size'</FONT><FONT color=#ff0000>],</FONT><FONT color=#800080>1</FONT><FONT color=#ff0000>));</I></B>
        </FONT><FONT color=#000080><B><I>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>smBitmap</FONT><FONT color=#ff0000>);</I></B>
        </FONT><FONT color=#808080>{ Save the JPEG image to the memory stream object}
        </FONT><FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SaveToStream</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>);
        </FONT><FONT color=#808080>{ Set the position to the start }
        </FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Position </FONT><FONT color=#ff0000>:= </FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#808080>{ The content type needs to be set to image/jpeg. Default is 'text/html' }
        </FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentType </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'image/jpeg'</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>CotentStream </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>Unprepare</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>Close</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>finally
      </B></FONT><FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#808080>{ We don't need to free MemStrm since the WebServer will do that }
      </FONT><FONT color=#000080>Bitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#000080><B><I>smBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</I></B>
    </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>except
    on </B></FONT><FONT color=#000080>E </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>Exception </FONT><FONT color=#0000ff><B>do
    begin
      </B></FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentType </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'text/html'</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'&lt;b&gt;ERROR&lt;/b&gt;&lt;br&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>#13#10 </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>E</FONT><FONT color=#ff0000>.</FONT><FONT color=#0000ff><B>Message</B></FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>
<P>The lines of code that have either been added or changed are marked in bold-italic. Notice that the line <PRE>ReduceBitmap(smBitmap,Bitmap,StrToIntDef(Request.QueryFields.Values['Size'],1));
</PRE>
<P>Is expecting to see a parameter called "Size" in the QueryFields property of the Request object. There is no problem if this parameter doe not exist. But if we want the images to be reduced then we need to specify this parameter. To do that we need to modify the QueryTableProducer1's OnFormatCell event as shown below:</P>
<P>
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryTableProducer1FormatCell</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>CellRow</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>CellColumn</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Integer</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>BgColor</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLBgColor</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Align</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>VAlign</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>THTMLVAlign</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>CustomAttrs</FONT><FONT color=#ff0000>,</FONT>
  <FONT color=#000080>CellData</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
<FONT color=#808080>{ Row 0 is the Column Header, so check for CellRow &gt; 0 }</FONT>
  <FONT color=#0000ff><B>if</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellRow</FONT> <FONT color=#ff0000>&gt;</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>and</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellColumn</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>4</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
    <FONT color=#000080>CellData</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>qryDataNotes</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Value</FONT><FONT color=#ff0000>;</FONT><FONT color=#808080>//Memo Field data</FONT>
<FONT color=#808080>{ Change the CellData from (GRAPHIC) to an HTML &lt;IMG&gt; TAG }</FONT>
<FONT color=#0000ff><B>if</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellRow</FONT> <FONT color=#ff0000>&gt;</FONT> <FONT color=#800080>0</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>and</B></FONT> <FONT color=#ff0000>(</FONT><FONT color=#000080>CellColumn</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#800080>5</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>then</B></FONT>
    <B><I><FONT color=#000080>CellData</FONT> <FONT color=#ff0000>:=</FONT>
      <FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;A HREF="%s/image?No=%s&amp;Size=1"&gt;&lt;IMG SRC="%s/image?No=%s&amp;Size=2" BORDER="0"&gt;&lt;/A&gt;'</FONT><FONT color=#ff0000>,</FONT>
       <FONT color=#ff0000>[</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,</FONT>
        <FONT color=#000080>qryDataSpeciesNo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>,</FONT>
        <FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,</FONT>
        <FONT color=#000080>qryDataSpeciesNo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT></I></B>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>
<P>Once again, the lines of code that have been modified or added are marked in bold-italic. The result of the Format function above will look like this: <PRE>&lt;A HREF="/scripts/biolife.dll/image?No=90020&amp;Size=1"&gt;&lt;IMG SRC="/scripts/biolife.dll/image?No=90020&amp;Size=2" BORDER="0"&gt;&lt;/A&gt;
</PRE>
<P>This is standard HTML but you will notice that the URL for the image source specifies the size parameter of 2 (half size), while the link's HREF parameter's URL specifies the size to be 1 (full size.</P>
<P>Make sure you add the <PRE>ReduceBitmap</PRE>procedure to your project and then recompile your project. Change the URL in your browser such that it invokes the default action of our ISAPI. The resulting page of the default action should now look similar to that shown in <B>Figure 16</B>: 
<P></P>
<P><IMG alt=ISAPI3F16.png src="http://www.matlus.com/images/ISAPI3F16.png" border=0><BR><B>Figure 16: Showing the final result of the ISAPI application we've built thus far.</B> 
<P>Notice that the images are now half the size. We have effectively reduced the response time of this page by half. Also, you should notice that each image is hyper linked (the BORDER=0 parameter of the IMG tag has been used to remove the border). Clicking on any of the images will show you a page containing the full sized version of that image as shown in <B>Figure 17</B>.<BR><BR><IMG alt=ISAPI3F17.png src="http://www.matlus.com/images/ISAPI3F17.png" border=0><BR><B>Figure 17: Showing the full size image after clicking on the thumbnail version</B> 
<P>Creating thumbnails in this fashion comes extremely handy since one doesn't need to maintain two or more versions of each image being used in ones web applications. In cases where the images being used reside on the hard disk as jpeg files, Delphi's TJPEGImage class makes it a breeze to create thumbnails. Simply setting the scale property does the trick. Well, almost. Also keep in mind that one can create grayscale versions of the images if required by setting the grayscale property (both the TBimap and TJPEGImage class have this property) to True.</P>]]></description><category>Programming</category><category>Delphi</category><category>ISAPI</category></item><item><title>Maintaining State - Using Fat URLs</title><pubDate>Mon, 14 Jan 2008 11:21:33 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/10/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/10/</guid><description><![CDATA[<P>Sometimes, we'd like to be able to show only one record from a database in a web page with the ability to navigate to the previous and next records. In this tutorial this is what we'll set out to achieve. If you're new to ISAPI programming, please take a look at the tutorials prior to this. In this tutorial, I don't give you the step by step instructions on how to start with ISAPI projects but rather assume, you've gone through and understood the previous tutorials. . You can take a look at a demo of the project we're about to create, here <a rel="nofollow" href="http://www.matlus.com/scripts/biolifesingle.dll" target="_blank">http://www.matlus.com/scripts/biolifesingle.dll</A><BR><a rel="nofollow" href="http://matlus.com/scripts/biolifesingle.dll"><IMG alt=BiolifeSingle.png src="http://www.matlus.com/images/BiolifeSingle.png" border=0></A> 
<P>Since the http protocol is a stateless protocol (after every response the connection to the client is dropped) we need to know what the "next" and "prior" records are for any given client. When a client requests the next record, we need to know either what the current record is, or what the next record is, in order for us to respond with the next record. In this tutorial, we'll use a technique known as <B><I>"fat URLs"</B></I> for passing on the <B><I>state information</B></I> to our ISAPI application.</P>
<P>What we really do is pass on the ID of the next record when the user clicks on the Next button. Or the ID of the Prior record if the user clicked on the Prior button. Since this information needs to be given to us in each request, we need to have sent this information in the earlier response. A kind of "thinking ahead". You'll find you frequently need to "think ahead" when you're building browser based (ISAPI/CGI) applications. So when we return the current requested record, we also need to know the prior and next records at that time for us to be able to create hyper-links for the prior and next buttons. 
<P>For example, if the user requested the first record, we need to know the ID of the next record and create a hyper-link for the next button, that requests that next record. For simplicity sake, lets assume the Ids of our records were 1,2,3 ...for the corresponding records. Lets also suppose we have an action in out ISAPI application with the path info of /ShowRecord, that expected to see a parameter called No that indicated the record we need to respond with. So for the first record the anchor tag for the Next button should be 
<P>/ShowRecord?No=2 (Note that we're ignoring the full URL here). In this case, since the current record is the first record the anchor tag for the Prior button should not exist (since there is no record prior to the first). Now if the user clicks on the Next button, we need to respond with the 2nd record (extracted from QueryFields property of the Request object - /ShowRecord?No=2). But we also need to know the IDs of the Prior record and Next record. The anchor tag for the Prior Button should be /ShowRecord?No=1 and that for the Next Button should be /ShowRecord?No=3. Now if the users clicks on either of the buttons, we know which record to respond with. 
<P>The function ShowSingleRecord in our ISAPI does this job as shown below: 
<DIV class=codeblockouter>The function ShowSingleRecord 
<DIV class=codeblockInner><PRE><CODE><FONT color=#0000ff><B>function </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ShowSingleRecord</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>SpeciesNo </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>) : </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>var
  </B></FONT><FONT color=#000080>GotRequiredRecord </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>Boolean</FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>begin
  with </B></FONT><FONT color=#000080>qryData </FONT><FONT color=#0000ff><B>do
  begin
    </B></FONT><FONT color=#000080>Open</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#808080>{ When a Query is opened it is set to the BOF Crack }
    </FONT><FONT color=#000080>FFirstRecordID </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Species_No'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>Last</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#808080>{ Move it to the Last Record and assign the property its values }
    </FONT><FONT color=#000080>FLastRecordID </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Species_No'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#808080>{ Move it back to first }
    </FONT><FONT color=#000080>First</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>GotRequiredRecord </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>False</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>FPreviousID </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>''</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>FNextID </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>''</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>while not </B></FONT><FONT color=#000080>Eof </FONT><FONT color=#0000ff><B>do
    begin
      </B></FONT><FONT color=#808080>{ If the Required SpeciesNo has been found then assign the NextCode variable and exit the loop }
      </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>GotRequiredRecord </FONT><FONT color=#0000ff><B>then
      begin
        </B></FONT><FONT color=#000080>FNextID </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Species_No'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>Break</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
      </FONT><FONT color=#808080>{ If this is the Requested SpeciesNo, then assign values to variables for later use }
      { SpeciesNo will be blank for the first and last records }
      </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Species_No'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString </FONT><FONT color=#ff0000>= </FONT><FONT color=#000080>SpeciesNo</FONT><FONT color=#ff0000>) </FONT><FONT color=#0000ff><B>or
         </B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>SpeciesNo </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>''</FONT><FONT color=#ff0000>)  </FONT><FONT color=#0000ff><B>then
      begin
        </B></FONT><FONT color=#000080>GotRequiredRecord </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>True</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#808080>{ Assign the Current Records Field values to the corresponding properties of the web module }
        </FONT><FONT color=#000080>FSpeciesNo </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Species_No'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>FCategory </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Category'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>FCommonName </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Common_Name'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
        </FONT><FONT color=#000080>FNotes </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Notes'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
      </FONT><FONT color=#0000ff><B>if not </B></FONT><FONT color=#000080>GotRequiredRecord </FONT><FONT color=#0000ff><B>then
        </B></FONT><FONT color=#000080>FPreviousID </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Species_No'</FONT><FONT color=#ff0000>).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#000080>Next</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>Close</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>; </FONT><FONT color=#808080>{ with Query1 do }

  { Construct the HTML now }
  </FONT><FONT color=#000080>PageProducer1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>HTMLDoc</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Text </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>GetDisplayTemplate</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>GetHeader</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Biolife Species No:' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>SpeciesNo</FONT><FONT color=#ff0000>);
  </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>PageProducer1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#808080>{ Add the Previous and Next Button Images with the required hyper links }
  </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>GetNavigationButtons</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#808080>{ Add the HTML footer }
  </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>GetFooter</FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>
<P>The Web Module has properties declared for placeholders of the information we need to store across methods. Such as: 
<DIV class=codeblockouter>Properties of the WebModule 
<DIV class=codeblockInner><PRE><CODE><FONT color=#000000>    </FONT><FONT color=#0000ff><B>constructor </B></FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>AOwner</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TComponent</FONT><FONT color=#ff0000>) ;</FONT><FONT color=#0000ff><B>override</B></FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>FirstRecordID </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FFirstRecordID</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>LastRecordID </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FLastRecordID</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>PreviousID </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FPreviousID</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>NextID </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FNextID</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>SpeciesNo </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FSpeciesNo</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>Category </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FCategory</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>CommonName </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FCommonName</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>property </B></FONT><FONT color=#000080>Notes </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string read </B></FONT><FONT color=#000080>FNotes</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#808080>{ Public declarations }
</FONT>
</CODE></PRE></DIV></DIV>
<P>The purpose of the function GetNavigationButtons is to construct the required HTML to show the navigation buttons with the appropriate anchor tags for each of the buttons. That is, with respect to the current requested record, the anchor tags for the prior and next buttons should contain the Ids of the prior and next records. Also, if there is no prior record (the current record is the first record), we should use the disabled version of the image and have no anchor tag for the prior button. Similarly, if there is no next record (current record is the last record) we need to use the disabled version of the next button's image and have no anchor tag for it. Since we also have to contend with a First Button and Last Button, the enabled/disabled states of these buttons need to be as we would expect as well. 
<DIV class=codeblockouter>The function GetNavigationButtons 
<DIV class=codeblockInner><PRE><CODE><FONT color=#0000ff><B>function </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>GetNavigationButtons </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>var
  </B></FONT><FONT color=#000080>PreviousImage </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>NextImage     </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>FirstImage    </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>LastImage     </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>begin
  </B></FONT><FONT color=#808080>{ If the Requested Record is the First Record, use the disabled images }
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>PreviousID </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'' </FONT><FONT color=#0000ff><B>then
  begin
    </B></FONT><FONT color=#000080>PreviousImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'PriorDis.jpg'</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>FirstImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'FirstDis.jpg'</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end
  else
  begin
    </B></FONT><FONT color=#000080>PreviousImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'Prior.jpg'</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>FirstImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'First.jpg'</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;

  </FONT><FONT color=#808080>{ If the Requested Record is the Last Record, use the disabled image }
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>NextID </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'' </FONT><FONT color=#0000ff><B>then
  begin
    </B></FONT><FONT color=#000080>NextImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'NextDis.jpg'</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>LastImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'LastDis.jpg'</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end
  else
  begin
    </B></FONT><FONT color=#000080>NextImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'Next.jpg'</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>LastImage </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'Last.jpg'</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;

  </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:=
    </FONT><FONT color=#008000>'&lt;TABLE&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;TR&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;

  </FONT><FONT color=#808080>{ If the Requested Record is the First Record, use the diabled image and don't
    create an hyper-link for the Button }

  { The Property SpeciesNo holds the current record's values }
  </FONT><FONT color=#0000ff><B>if  </B></FONT><FONT color=#000080>SpeciesNo </FONT><FONT color=#ff0000>= </FONT><FONT color=#000080>FirstRecordID </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>FirstImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="First Record"&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf
  </FONT><FONT color=#0000ff><B>else
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;A HREF="' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'/ShowRecord?No=' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>FirstRecordID </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'"&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>FirstImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="First Record"&gt;&lt;/A&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;

  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>PreviousID </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>PreviousImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="Previous Record"&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf
  </FONT><FONT color=#0000ff><B>else
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;A HREF="' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'/ShowRecord?No=' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>PreviousID </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'"&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>PreviousImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="Previous Record"&gt;&lt;/A&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;

  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>NextID </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>NextImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="Next Record"&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf
  </FONT><FONT color=#0000ff><B>else
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;A HREF="' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'/ShowRecord?No=' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>NextID </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'"&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>NextImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="Next Record"&gt;&lt;/A&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;

  </FONT><FONT color=#0000ff><B>if  </B></FONT><FONT color=#000080>SpeciesNo </FONT><FONT color=#ff0000>= </FONT><FONT color=#000080>LastRecordID </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>LastImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="Last Record"&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf
  </FONT><FONT color=#0000ff><B>else
    </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;A HREF="' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'/ShowRecord?No=' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>LastRecordID </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'"&gt;&lt;IMG SRC="/Images/' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>LastImage </FONT><FONT color=#ff0000>  </FONT><FONT color=#008000>'" BORDER="0" ALT="Last Record"&gt;&lt;/A&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;

  </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;/TR&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'&lt;/TABLE&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>
<P><B>The TPageProducer</B><BR>This is by no means a really good example of the capability of the TPageProducer component, but we do use it here in one of many ways it can be used. This component allows you to use an HTML template (either a physical file or a TStrings property). In the template, we have placeholders for the various fields of our dataset. These place holders are denoted with the # sign. When we read the Content property of the PageProducer (either directly or by assigning it to another variable etc.), the OnHTMLTag event is fired for every placeholder we have in our template. 
<P>In this particular example, we'll use a function in our ISAPI that basically returns an HTML "template" . The result of this function is then fed to the TPageProducer component. Lets look at this function before we proceed. 
<DIV class=codeblockouter>The function GetDisplayTemplate that returns our HTML Template 
<DIV class=codeblockinner><PRE><CODE><FONT color=#0000ff><B>function </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>GetDisplayTemplate </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>begin
  </B></FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:=
    </FONT><FONT color=#008000>'&lt;A HREF="http://www.matlus.com/scripts/website.dll/Tutorials?DelphiISAPI&amp;DelphiISAPIPreviouNext&amp;7"&gt;' </FONT><FONT color=#ff0000> 
      </FONT><FONT color=#008000>'&lt;FONT FACE="Arial"&gt;Back to The Tutorial Page&lt;/FONT&gt;&lt;/A&gt;&lt;P&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'&lt;TABLE WIDTH=80% BGCOLOR="BLACK" BORDER="1" BORDERCOLOR="BLACK" CELLSPACING="2" CELLPADDING="2"&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;TH COLSPAN="6"&gt;&lt;FONT FACE="Arial" COLOR="#9999cc" SIZE="4"&gt;Biolife Data with Navigation Capability&lt;/FONT&gt;&lt;/TH&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;TR BGCOLOR="#ffffcc"&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;B&gt;&lt;FONT FACE="Arial"&gt;No&lt;/FONT&gt;&lt;/B&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;FONT FACE="Arial"&gt;&lt;#SpeciesNo&gt;&lt;/FONT&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;B&gt;&lt;FONT FACE="Arial"&gt;Category&lt;/FONT&gt;&lt;/B&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;FONT FACE="Arial"&gt;&lt;#Category&gt;&lt;/FONT&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;B&gt;&lt;FONT FACE="Arial"&gt;Common Name&lt;/FONT&gt;&lt;/B&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;FONT FACE="Arial"&gt;&lt;#Common_Name&gt;&lt;/FONT&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;/TR&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;TR BGCOLOR="#9999cc"&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;B&gt;&lt;FONT FACE="Arial"&gt;Notes&lt;/FONT&gt;&lt;/B&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD COLSPAN="5"&gt;&lt;FONT FACE="Arial"&gt;&lt;#Notes&gt;&lt;/FONT&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;/TR&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;TR BGCOLOR="#ffffcc"&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD&gt;&lt;B&gt;&lt;FONT FACE="Arial"&gt;Image&lt;/FONT&gt;&lt;/B&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'    &lt;TD COLSPAN="5" ALIGN="CENTER"&gt;&lt;#Graphic&gt;&lt;/TD&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'  &lt;/TR&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf </FONT><FONT color=#ff0000> 
    </FONT><FONT color=#008000>'&lt;/TABLE&gt;' </FONT><FONT color=#ff0000>  </FONT><FONT color=#000080>crlf</FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>All we're really doing here is defining the display format of our data in HTML terms. I personally prefer keeping such information inside my applications for such uses, but it may be advantageous to have this as an HTML (.htm file) template. This will give you, or your client the ability to change the format of data presentation simply by modifying the physical HTML file using Homesite or any other such tool. The effects of the change in the template will be seen without the need to recompile the ISAPI application. 
<DIV class=opinion><IMG alt=Suggestion.gif src="http://www.matlus.com/images/Suggestion.gif" border=0> With regard to the <CODE>TPageProducer</CODE> and the special tags we've used in this template. 
<P></P>
<P>I personally prefer using tags with attribues. This not only allows me to define a "tag language" of sorts, but also streamlines the code that processes these tags (since there are fewer tags). For example the tags in the above template would be something like this: </P><CODE><PRE>&lt;#fieldvalue name="Species_No"&gt;
&lt;#fieldvalue name="Category"&gt;
&lt;#fieldvalue name="Common_Name"&gt;
&lt;#fieldvalue name="Graphic"&gt;
</PRE></CODE>
<P>The code that will process these tags in the <CODE>OnHTMLTag</CODE> event would look like this: </P>
<DIV class=codeblockouter>
<DIV class=codeblockinner><PRE><CODE><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'fieldvalue' </FONT><FONT color=#0000ff><B>then
  </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>qryData</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>TagParams</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'name'</FONT><FONT color=#ff0000>]).</FONT><FONT color=#000080>AsString</FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>
<P>This is not to say that this code is a replacement for what we have here, but this is the kind of technique I prefer to use (that is use of attributes in special tags) since it reduces the number of tags you need to process and therefore streamlines the use of special tags in your code/templates. In time, you'll find you have developed a kind of "language" of your own. Thus maintaining/debugging code becomes a lot simpler. </P></DIV>
<P>The TPageProducer component has two properties that are used most often. The <KBD>HTMLDoc</KBD> and <KBD>HTMLFile</KBD> properties. If you used physical HTML files as templates, then you'd assign the <KBD>HTMLFile</KBD> property the path and name of the .htm file. In this case, we need to use the <KBD>HTMLDoc</KBD> property. This is a TStrings type property. Since a TStrings object has a property called <KBD>Text</KBD>, we can easily assign the result of our <KBD>GetDisplayTemplate</KBD> function to the <KBD>HTMLDoc</KBD> property like so - <BR><KBD>PageProducer1.HTMLDoc.Text := GetDisplayTemplate;</KBD>. 
<P>This is exactly what we do in our <KBD>ShowSingleRecord</KBD> function above. 
<P>The TPageProducer component has a property called <KBD>Content</KBD>. The moment we assign this property to the <KBD>Response</KBD> object's <KBD>Content</KBD> property (that is, when ever the Content property is accessed) the component starts to parse the <KBD>HTMLDoc or HTMLFile</KBD> property. Each time it encounters a token/place holder (), it fires the OnHTMLTag event giving use the following information: <PRE><B>procedure</B> TWebModule1.PageProducer1HTMLTag(Sender: TObject; Tag: TTag;
  <B>const</B> TagString: <B>String</B>; TagParams: TStrings; <B>var</B> ReplaceText: <B>String</B>);
</PRE>In our template, we have tokens such as: <KBD>&lt;#SpeciesNo&gt;, &lt;#Category&gt;, &lt;#Common_Name&gt;</KBD> etc. The TagString parameter passed to us in the OnHTMLTag event will contain these values. So the first time the event is fired, the TagString parameter will contain the value - <KBD>SpeciesNo</KBD> minus the <KBD></KBD>parts. We then have the option to change this text to whatever we want. Notice that the <KBD>ReplaceText</KBD> parameter is a <KBD>var</KBD> parameter. If we set this parameter to the actual value of the field (Species No in this case) then we'll see this value in the generated HTML file in a browser. In this way, we can have "place holders" in our HTML template for values that will be determine at run time. 
<P></P>
<DIV class=codeblockouter>The OnHTMLTag event in this example looks like this: 
<DIV class=codeblockinner><PRE><CODE><FONT color=#0000ff><B>procedure </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>PageProducer1HTMLTag</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TObject</FONT><FONT color=#ff0000>; </FONT><FONT color=#000080>Tag</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TTag</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>const </B></FONT><FONT color=#000080>TagString</FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>; </FONT><FONT color=#000080>TagParams</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TStrings</FONT><FONT color=#ff0000>; </FONT><FONT color=#0000ff><B>var </B></FONT><FONT color=#000080>ReplaceText</FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>String</B></FONT><FONT color=#ff0000>);
</FONT><FONT color=#0000ff><B>begin
</B></FONT><FONT color=#808080>{ Since this event will be fired during the same session (thread) that
  called the ShowRecord Action, it is safe to use properties and assign
  the values here. Beware of using global variables. They are not thread safe.
  Properties are thread safe. In this case since we don't need to maintain these
  values across instances, properties will work just fine. }
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'SpeciesNo' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>SpeciesNo</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'Category' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Category</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'Common_Name' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>CommonName</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'Notes' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Notes</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#808080>{ For the Image, create an &lt;IMG&gt; tag }
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'Graphic' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;IMG SRC="%s%s?SpeciesNo=%s" BORDER="0" ALT="%s"&gt;'</FONT><FONT color=#ff0000>,
                     [</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,
                      </FONT><FONT color=#008000>'/GetImage'</FONT><FONT color=#ff0000>,
                      </FONT><FONT color=#000080>SpeciesNo</FONT><FONT color=#ff0000>,
                      </FONT><FONT color=#000080>CommonName</FONT><FONT color=#ff0000>]);
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>
<P>The only TagString condition that may need some explanation, is </P>
<DIV class=codeblockouter>One condition that may need some explnation 
<DIV class=codeblockinner><PRE><CODE><FONT color=#000000>  </FONT><FONT color=#808080>{ For the Image, create an &lt;IMG&gt; tag }
  </FONT><FONT color=#0000ff><B>if </B></FONT><FONT color=#000080>TagString </FONT><FONT color=#ff0000>= </FONT><FONT color=#008000>'Graphic' </FONT><FONT color=#0000ff><B>then
    </B></FONT><FONT color=#000080>ReplaceText </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'&lt;IMG SRC="%s%s?SpeciesNo=%s" BORDER="0" ALT="%s"&gt;'</FONT><FONT color=#ff0000>,
                     [</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ScriptName</FONT><FONT color=#ff0000>,
                      </FONT><FONT color=#008000>'/GetImage'</FONT><FONT color=#ff0000>,
                      </FONT><FONT color=#000080>SpeciesNo</FONT><FONT color=#ff0000>,
                      </FONT><FONT color=#000080>CommonName</FONT><FONT color=#ff0000>]);
</FONT>
</CODE></PRE></DIV></DIV>
<P></P>Our graphic place holder/token, needs to be replace with an image. But can't really replace it with an image at this moment, since the web browser is expecting the content as type <KBD>Text</KBD>. This is because, by default, the <KBD>Response.ContentType</KBD> property is set to <KBD>text/html</KBD>. So what we do instead, is replace the TagString with an HTML &lt;IMG&gt; tag using the ReplaceText <KBD>var</KBD> parameter. This image tag should contain the information required by the browser to get the right image. Since the image needs to be extracted from a specific record in our database, we need to give the browser enough information to come back to our ISAPI with the required information to enable us to extract the correct image from our database table. One other improtant thing to know/notice is that the our tokens can not contain spaces. That is, the token<KBD>&lt;#Common Name&gt;</KBD> would not be the same as<KBD>&lt;#Common_Name&gt;</KBD>. The TagString parameter for this token would result in <KBD>Common</KBD> and not <KBD>Common_Name</KBD> as we would want it. The reason is that the token can contain <KBD>Parameters</KBD>. Parameters are delimited with spaces! This is important to know. In this example, we've not used the <KBD>Parameters</KBD> capability of this component. To give you a short example: 
<P>We could have a token such as <KBD>&lt;#FirstName Type=Text Length=15&gt;</KBD>, then in the OnTag event, we could do something like: <PRE>  <B>if</B> TagString='FirstName' <B>then</B>
    ReplaceText := '&lt;INPUT TYPE='   TagParams.Values['Type']   ' MAXLENGTH='   TagParams.Values['Length']   '&gt;';
</PRE>This would generate an Edit box in the browser that would allow a maximum of <KBD>Length</KBD> characters.....but let's not get too confused at this time. Let us continue on with our project. 
<P>The <KBD>ReplaceText</KBD> parameter would evaluate to something like this: <PRE>ReplaceText := '&lt;IMG SRC="/scripts/BiolifeSingle.dll/GetImage?SpeciesNo=90012 BORDER="0" ALT="Clown Triggerfish"&gt;';
</PRE>Which means we need to have an action in our ISAPI with a <KBD>PathInfo</KBD> property of <KBD>GetImage</KBD> which expects to see a <KBD>Request.QueryString</KBD> parameter <KBD>SpeciesNo=90012</KBD>. In this action, we'll do what it takes for us to extract the correct image from the database table and send it back to the browser using the <KBD>Response</KBD> object. This time, we'll set the <KBD>Response.ContentType</KBD> property to <KBD>image/jpeg</KBD> so the browser knows to expect an image and not text. The OnAction event for this action looks like this: 
<P>
<DIV class=codeblockouter>The <CODE>OnAction</CODE> event of the action with the <CODE>/GetImage</CODE> PathInfo 
<DIV class=codeblockinner><PRE><CODE><FONT color=#0000ff><B>procedure </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1WebActionItem1Action</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TObject</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>; </FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>; </FONT><FONT color=#0000ff><B>var </B></FONT><FONT color=#000080>Handled</FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>Boolean</FONT><FONT color=#ff0000>);
</FONT><FONT color=#0000ff><B>begin
  </B></FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentType </FONT><FONT color=#ff0000>:= </FONT><FONT color=#008000>'image/jpeg'</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ContentStream </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>GetImageStream</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Request</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>QueryFields</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Values</FONT><FONT color=#ff0000>[</FONT><FONT color=#008000>'SpeciesNo'</FONT><FONT color=#ff0000>]);
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT>
</CODE></PRE></DIV></DIV>
<P></P>and the <KBD>GetImageStream</KBD> function looks like this: 
<P></P>
<DIV class=codeblockouter>The function GetImageStream 
<DIV class=codeblockinner><PRE><CODE><FONT color=#0000ff><B>function </B></FONT><FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>GetImageStream</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>SpeciesNo </FONT><FONT color=#ff0000>: </FONT><FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>) : </FONT><FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>var
  </B></FONT><FONT color=#000080>MemStrm </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>JPEG    </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Bmp     </FONT><FONT color=#ff0000>: </FONT><FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>begin
  </B></FONT><FONT color=#000080>MemStrm </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TMemoryStream</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>JPEG </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TJPEGImage</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#000080>Bmp </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>TBitmap</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>try
    with </B></FONT><FONT color=#000080>qryImage </FONT><FONT color=#0000ff><B>do
    begin
      </B></FONT><FONT color=#808080>{ The SQL Statement is assigned at designed time in the SQL Property }
      </FONT><FONT color=#000080>Params</FONT><FONT color=#ff0000>[</FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>].</FONT><FONT color=#000080>AsInteger </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>StrToInt</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>SpeciesNo</FONT><FONT color=#ff0000>);
      </FONT><FONT color=#000080>Open</FONT><FONT color=#ff0000>;
      </FONT><FONT color=#000080>Bmp</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>FieldByName</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Graphic'</FONT><FONT color=#ff0000>));
      </FONT><FONT color=#000080>Close</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
   </FONT><FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Bmp</FONT><FONT color=#ff0000>);
   </FONT><FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SaveToStream</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>);
   </FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Position </FONT><FONT color=#ff0000>:= </FONT><FONT color=#800080>0</FONT><FONT color=#ff0000>;
   </FONT><FONT color=#000080>Result </FONT><FONT color=#ff0000>:= </FONT><FONT color=#000080>MemStrm</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>finally
    </B></FONT><FONT color=#808080>{ Do not Free the Memory Stream ! }
    </FONT><FONT color=#000080>JPEG</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;
    </FONT><FONT color=#000080>Bmp</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;
  </FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT><FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;
</FONT></CODE></PRE></DIV></DIV>]]></description><category>Programming</category><category>Database</category><category>Delphi</category><category>ISAPI</category></item><item><title>Sending an Email from an ISAPI application (Threaded)</title><pubDate>Sun, 13 Jan 2008 11:24:47 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/11/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/11/</guid><description><![CDATA[The process of sending an email in Delphi is very simple. One can use any STMP components for this purpose. In this example, we'll use the Indy (Winshoes) SMTP component but one can easily alter the <KBD>execute</KBD> method to be used with any SMTP component. 
<P>It is not advisable to send an Email directly from within your ISAPI/CGI application as this may slow down the ISAPI application while it waits for the SMTP component to connect with your SMTP server. What we'll do instead is create a thread and send the email from within the thread. This will allow the ISAPI application to continue on without having to wait for the email to be sent. 
<DIV class=note><IMG alt=exclamation.gif src="http://www.matlus.com/images/exclamation.gif" border=0> If you plan to send bulk emails from your ISAPI, I reccomend you build a separate ISAPI Application or WebService to do this job specifically. Take a look at the Tutorial <a rel="nofollow" href="http://www.matlus.com/scripts/website.dll/Tutorials?DelphiISAPI&amp;ISAPIAndWebServices&amp;19" target="_blank">Using WebServices from a Delphi 5/6 ISAPI</A> for an example of how to do this. This is the preferred method in my opinion. </DIV>To keep things manageable/simple, we'll create our thread class in a separate unit. The code in this unit will look like the following: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>unit</B></FONT> <FONT color=#000080>SndMailThrd</FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>interface</B></FONT>

<FONT color=#0000ff><B>uses</B></FONT>
  <FONT color=#000080>Windows</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Messages</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>SysUtils</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Classes</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IdBaseComponent</FONT><FONT color=#ff0000>,</FONT>
  <FONT color=#000080>IdComponent</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IdTCPConnection</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IdTCPClient</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IdMessageClient</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IdSMTP</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>IdMessage</FONT><FONT color=#ff0000>,</FONT>
  <FONT color=#000080>IdEMailAddress</FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>type</B></FONT>
  <FONT color=#000080>TEmailThread</FONT> <FONT color=#ff0000>=</FONT> <FONT color=#0000ff><B>class</B></FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>TThread</FONT><FONT color=#ff0000>)</FONT>
  <FONT color=#0000ff><B>private</B></FONT>
    <FONT color=#000080>FSubject</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FReplyTo</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FHost</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FFromAddress</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FUserID</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FToAddress</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FBody</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FFromName</FONT><FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>SetBody</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>const</B></FONT> <FONT color=#000080>Value</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>SetToAddress</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>const</B></FONT> <FONT color=#000080>Value</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#808080>{ Private declarations }</FONT>
  <FONT color=#0000ff><B>protected</B></FONT>
    <FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>OnThreadTerminate</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>public</B></FONT>
    <FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>Execute</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>override</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>constructor</B></FONT> <FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>CreateSuspended</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>ThreadPriority</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TThreadPriority</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>destructor</B></FONT> <FONT color=#000080>Destroy</FONT><FONT color=#ff0000>;</FONT><FONT color=#0000ff><B>override</B></FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>Host</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FHost</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>FHost</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>UserID</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FUserID</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>FUserID</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>Body</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FBody</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>SetBody</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>ToAddress</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FToAddress</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>SetToAddress</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>Subject</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FSubject</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>FSubject</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>FromAddress</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FFromAddress</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>FFromAddress</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>FromName</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FFromName</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>FFromName</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>property</B></FONT> <FONT color=#000080>ReplyTo</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#0000ff><B>string</B></FONT> <FONT color=#0000ff><B>read</B></FONT> <FONT color=#000080>FReplyTo</FONT> <FONT color=#0000ff><B>write</B></FONT> <FONT color=#000080>FReplyTo</FONT><FONT color=#ff0000>;</FONT>
 <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>implementation</B></FONT>
 <FONT color=#808080>{ Example of usage }</FONT>
 <FONT color=#808080>{with TEmailThread.Create(True, tpHigher) do</FONT>
<FONT color=#808080>  begin</FONT>
<FONT color=#808080>    Host := 'smtp-server';</FONT>
<FONT color=#808080>    UserID := 'skumar';</FONT>
<FONT color=#808080>    ToAddress.Add('shiv@matlus.com');</FONT>
<FONT color=#808080>    Subject := 'Threaded Email';</FONT>
<FONT color=#808080>    FromAddress := 'shiv@matlus.com';</FONT>
<FONT color=#808080>    ReplyTo := 'shiv@matlus.com';</FONT>
<FONT color=#808080>    Body.Add('This is a test email !!');</FONT>
<FONT color=#808080>    Resume;</FONT>
<FONT color=#808080>  end;}</FONT>

<FONT color=#808080>{ TEmailThread }</FONT>

<FONT color=#0000ff><B>constructor</B></FONT> <FONT color=#000080>TEmailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>CreateSuspended</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>ThreadPriority</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TThreadPriority</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>Priority</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>ThreadPriority</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>FToAddress</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TStringList</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>FBody</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TStringList</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>inherited</B></FONT> <FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>CreateSuspended</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>FreeOnTerminate</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>True</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>destructor</B></FONT> <FONT color=#000080>TEmailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Destroy</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>FToAddress</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>FBody</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>inherited</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TEmailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SetBody</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>const</B></FONT> <FONT color=#000080>Value</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>FBody</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Value</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TEmailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>SetToAddress</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>const</B></FONT> <FONT color=#000080>Value</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TStrings</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>FToAddress</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Value</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TEmailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Execute</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>var</B></FONT>
  <FONT color=#000080>IdMsg</FONT> <FONT color=#ff0000>:</FONT> <FONT color=#000080>TIdMessage</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
  <FONT color=#000080>IdMsg</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>TIdMessage</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>nil</B></FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>try</B></FONT>
    <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>TIdSMTP</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#0000ff><B>nil</B></FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>do</B></FONT>
    <FONT color=#0000ff><B>begin</B></FONT>
      <FONT color=#000080>UserID</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>FUserID</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Host</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>FHost</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Body</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Assign</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Body</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Recipients</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>EMailAddresses</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>ToAddress</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Text</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Subject</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>Subject</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>From</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Address</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>FromAddress</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>From</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Name</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>FromName</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>ReplyTo</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Address</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>ReplyTo</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Connect</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Send</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Disconnect</FONT><FONT color=#ff0000>;</FONT>
      <FONT color=#000080>Free</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>finally</B></FONT>
    <FONT color=#000080>FreeAndNil</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>IdMsg</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Terminate</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TEmailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>OnThreadTerminate</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>

<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>

<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>.</FONT></FONT>
</PRE></CODE></DIV></DIV>Now all we need to do is include this unit is the <KBD>uses</KBD> clause of our ISAPI/CGI application and create the thread when required. Notice that the <KBD>TEmailThread</KBD> has properties similar to that of an SMTP component. This makes the process of sending an email using a thread very simple. 
<P>Lets look at an example of how we can use this thread class. In a function or procedure in your ISAPI application in which you want to send an email, you need a have the following lines of code. 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New">  <FONT color=#0000ff><B>with</B></FONT> <FONT color=#000080>TEMailThread</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Create</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>True</FONT><FONT color=#ff0000>,</FONT><FONT color=#000080>tpHigher</FONT><FONT color=#ff0000>)</FONT> <FONT color=#0000ff><B>do</B></FONT>
  <FONT color=#0000ff><B>begin</B></FONT>
    <FONT color=#000080>FromName</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'Shiv Kumar'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Subject</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'Thankyou for the Visit on '</FONT> <FONT color=#ff0000> </FONT> <FONT color=#000080>FormatDateTime</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'mmmm dd yyyy at hh:nn:ss'</FONT><FONT color=#ff0000>,</FONT> <FONT color=#000080>Now</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>ReplyTo</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'shiv@matlus.com'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Host</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'smtp-server'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>UserID</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'shivk'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>FromAddress</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'shiv@matlus.com'</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>ToAddress</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>sEMail</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Body</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Add</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Format</FONT><FONT color=#ff0000>(</FONT><FONT color=#008000>'Dear %s %s,'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Thank you for taking the time to fill my guest book. I hope you enjoyed what you saw on my web site.'</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' I am constantly making changes to my site, so please come back often.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'I take special care of the Tutorials section of my web site. I hope you found them useful and encouraging.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'SITE INFORMATION:'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Web Site: http://www.matlus.com'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Web Server: Windows 2000 Advanced Server'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Database: Interbase 6.0'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Generators: Dynamically generated by a number of Delphi built ISAPI DLLs'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' If you need more information on the tools I'</FONT><FONT color=#008000>'ve used to develop this site,'</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>' please feel free to contact me.'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Regards,'</FONT> <FONT color=#ff0000> </FONT> <FONT color=#008000>#13</FONT><FONT color=#008000>#10</FONT> <FONT color=#ff0000> </FONT>
    <FONT color=#008000>'Shiv.'</FONT><FONT color=#ff0000>,</FONT><FONT color=#ff0000>[</FONT><FONT color=#000080>sFirstName</FONT><FONT color=#ff0000>,</FONT><FONT color=#000080>sLastName</FONT><FONT color=#ff0000>]</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Resume</FONT><FONT color=#ff0000>;</FONT>
   <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>This code snippet is straight out of, one of the ISAPI applications that drives my web site. If you've signed my guest book, you will notice that the automatic email you received soon after you hit the submit button was produced by this code. The thread is created here, but is freed in the thread's <KBD>Execute</KBD> method. Notice, that in the <KBD>OnCreate</KBD> method of the thread, we've set <KBD>FreeOnTerminate := True</KBD> and then in the last line of the <KBD>Execute</KBD> method, we terminate the thread. You can substitute any SMTP component of your choice in this code. ]]></description><category>Programming</category><category>Database</category><category>Delphi</category><category>ISAPI</category></item><item><title>Using Cookies, Hidden Fields and the TPageProducer</title><pubDate>Sat, 12 Jan 2008 11:46:42 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/12/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/12/</guid><description><![CDATA[In this tutorial, we'll explore using cookies, hidden fields and the TPageProducer component. For a detailed explanation of what cookies are, have a look at the article - <a href="http://exposureroom.com/members/skumar.aspx/articles/post/7" rel="nofollow" target="_blank">What are cookies?</a>.
<h2>Use of Cookies</h2>
In this example, we will use cookies to store information about a user to be able to use this information when the user returns to the site at a later date. In this way, the user won't have to enter this information each time s/he comes to this part of the web site. In other words, the use of cookies in this example is not so much to "maintain state" as it is to retain information. But we would set cookies and read values in exactly the same way if we wanted to use cookies to maintain state during a session. So the concept will still work.
<h2>Use of Hidden Fields</h2>
Hidden fields in this case are used by way of maintaining session information. A very simple use, but none the less the way hidden fields will be used in most cases. Information about the project is passed on to an action using fat ULRs. In this action, we need to generate an HTML Data Entry form. When the form's submit button is clicked, we need to save this information along with the form's fields to a database. This information (Project Information) is required two steps later:
<ol>
    <li>First the Project information is sent to the action that generates the HTML Form.</li>
    <li>When the submit button of the form is clicked, this information is saved to a database table </li>
</ol>
Since we don't need to show the user this information, we use hidden fields in the generated HTML Form to store this information so we can use it later, at the time of posting this information.
<p>We could have used cookies for this job as well. But remember that cookies are a limited resource (a certain number and size restriction) and also, that the user may have disabled cookies in his/her browser. Since this information is critical to the proper functioning of our application, we don't want to rely on cookies for this job.
<h2>The use of the TPageProducer component</h2>
The Data Entry HTML form we have will either be presented to the first time visitor as a blank form, with no values entered or, for repeat visitors whose information we already have, the form will be presented to the visitor pre populated. Rather than have two templates that will allow us to do this, we'll use the capabilities of the TPageProducer component to populate the fields with information extracted from cookies or leave them blank as the case may be. This example of the usage of the TPageProducer component should give you a good idea of its usage.
<h2>The Project</h2>
The project is a download registration form. This is the form you see each time you download a project from my web site (probably not implemented at this time). There are two fields of information in this HTML form:
<ol>
    <li>User Name</li>
    <li>Email Address </li>
</ol>
<strong>Figure 1</strong> shows what the HTML form will look like for the first time visitor
<p><img alt="" src="http://www.matlus.com/images/ISAPICookiesHF1.jpg"> <br>
<strong>Figure 1 Showing the HTML Form as a first time Visitor will see it</strong>
<p>Once the user enters this information and clicks on the <kbd>Download</kbd> button, we save his/her information as cookies and then present him/her with the standard download screen to be able to download the project files. The next time this visitor downloads a project file, either in the same session or on another day, s/he will be presented with the same form. Only this time the information will be filled out automatically by our ISAPI application as shown in <strong>Figure 2</strong>.
<p><img alt="" src="http://www.matlus.com/images/ISAPICookiesHF2.jpg"> <br>
<strong>Figure 2 Showing a pre populated HTML Form using Cookie information</strong>
<p>Since the Download registration form is common for all downloads, we need to have information about the project that the user is interested in, so as to present him with the correct files to download. We do this by calling our ISAPI's action with information in the URL. We can extract this information using the <kbd>Response</kbd> object's <kbd>QueryFields</kbd> property. This information is later used to get the name of the file that needs to be sent as well as to put the Project title in the Download registration form.
<h2>Getting Started</h2>
In this tutorial, I assume you've read the earlier tutorials, so I'm not going into the details of how to start an ISAPI project etc. From now on, I'll just list of the steps that need to be taken. I assume, when I say, "Change the output directory of the project to your web server's scripts folder", you know what I mean by that, why we need to do it, and how to do it.
<ol>
    <li>Start with an ISAPI project</li>
    <li>Create two action items and name them:
    <ul>
        <li><kbd>waDownLoadReg</kbd> with a PathInfo of <kbd>/DownloadReg</kbd></li>
        <li><kbd>waRegister</kbd> with a PathInfo of <kbd>/Register</kbd> </li>
    </ul>
    </li>
    <li>Place a TPageProducer component on the Web DataModule.</li>
    <li>Change the output directory of the project to your web server's scripts folder<kbd>(C:\inetpub\scripts)</kbd></li>
    <li>Save the project as <kbd>Download.dpr</kbd> </li>
</ol>
The Web DataModule should look like that shown in <strong>Figure 3</strong>.
<p><img alt="" src="http://www.matlus.com/images/ISAPICookiesHF3.jpg"><br>
<strong>Figure 3 showing the Web DataModule as it should look like up to now</strong>
<p>In the OnAction event of our first action item - <kbd>waDownloadReg</kbd>, we need to send back the HTML form shown in <strong>Figure 1</strong> above. But we also need to know the Tutorial details so we know which tutorial the user is interested in and show the <kbd>Tutorial Title</kbd> in the form. In the Tutorials section of my web site, you will have noticed that at the end of each project, there is a link to download the project files. It is this link that will call this action. The way my data model is structured, we need to know the <kbd>TutorialType</kbd> and <kbd>TutorialCode</kbd> field values. These are the key fields (composite key) of the table that contains the information for each Tutorial, such as:
<ol>
    <li>Tutorial Title</li>
    <li>Content (the text of the whole tutorial)</li>
    <li>ProjectFile (the name of the zip file for this project </li>
</ol>
And other information that is relevant to the tutorial. For this tutorial the:
<pre>  TutorialType = DelphiISAPI
TutorialCode = ISAPICookiesHiddenFields
</pre>
These two fields will uniquely identify each Tutorial in my database. The HTML of the link you see at the end of each project looks like this:
<pre>  &lt;A HREF="/scripts/website.dll/DownloadReg?TutorialType=DelphiISAPI&amp;TutorialCode= ISAPICookiesHiddenFields"&gt;Download Project&lt;/A&gt;
</pre>
<kbd>Website.dll</kbd> is the main ISAPI that runs my web site. The Action - <kbd>waDownloadReg</kbd> gets two parameters sent to it. These two parameters will tell us what tutorial the user is interested in. This information was generated when you first clicked on the link to this project from the main Tutorials section to be used later in an other action, we've "maintained the state" using fat URLs. The OnAction event of the action <kbd>waDownloadReg</kbd> looks like this:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>procedure</strong></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">WebModule1waDownLoadRegAction</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">;</font>
<font color="#000080">Request</font><font color="#ff0000">:</font> <font color="#000080">TWebRequest</font><font color="#ff0000">;</font> <font color="#000080">Response</font><font color="#ff0000">:</font> <font color="#000080">TWebResponse</font><font color="#ff0000">;</font> <font color="#0000ff"><strong>var</strong></font> <font color="#000080">Handled</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#808080">{ This action expects to see the Project Key as Query Fields }</font>
<font color="#000080">PageProducer1</font><font color="#ff0000">.</font><font color="#000080">HTMLDoc</font><font color="#ff0000">.</font><font color="#000080">Text</font> <font color="#ff0000">:=</font> <font color="#000080">GetDownloadRegistrationForm</font><font color="#ff0000">;</font>
<font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font> <font color="#000080">PageProducer1</font><font color="#ff0000">.</font><font color="#000080">Content</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
The function <kbd>GetDownloadRegistrationForm</kbd> is our "template" for the form shown in <strong>Figure 1</strong>. We could have used the physical .htm file for this purpose if we wanted. The advantage to doing that is that you could change the look and feel of the form without having to recompile the project since the file resides physically on the hard drive. I personally prefer to have my projects less dependent on external files. But say you wanted to give your client the option to modify the look and feel, you'd be better off using an external .htm file making sure, the client understands the special "transparent" tags that we use for the TPageProducer.
<p>So first we assign the result of the function <kbd>GetDownloadRegistrationForm</kbd> to the <kbd>HTMLDoc</kbd> property of the <kbd>TPageProducer</kbd> component and then assign the <kbd>Content</kbd> property of the <kbd>TPageProducer</kbd> component to the <kbd>Response</kbd> object's <kbd>Content</kbd> property. This will in turn send back the HTML form shown in <strong>Figure 1</strong>.
<p>The function <kbd>GetDownloadRegistrationForm</kbd> looks like this.
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>function</strong></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">GetDownloadRegistrationForm</font> <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#808080">{ Template for the Download Registration Form }</font>
<font color="#000080">Result</font> <font color="#ff0000">:=</font>
<font color="#008000">'&lt;HTML&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;HEAD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;#METATAGS&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TITLE&gt;Download Registration Form&lt;/TITLE&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;/HEAD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;BODY&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;#Form&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;#Tutorial Field=TutorialType&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;#Tutorial Field=TutorialCode&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;TABLE BORDER="1" BORDERCOLOR="#66ccff" BGCOLOR="#6699cc" CELLPADDING="2"&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;TH BGCOLOR= "#ccccff" COLSPAN="2"&gt;&lt;CENTER&gt;Download Registration Form&lt;/CENTER&gt;&lt;/TH&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;TR BGCOLOR= "#6699cc"&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD COLSPAN="2"&gt;&lt;CENTER&gt;&lt;H3&gt;&lt;#ProjectName&gt;&lt;/H3&gt;&lt;/CENTER&gt;&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;/TR&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;TR BGCOLOR= "#6699cc"&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD COLSPAN="2"&gt;&lt;#FileName&gt;&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;/TR&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;TR BGCOLOR="#ccccff"&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD&gt;Name&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD&gt;&lt;#DataEntry Field=Name FieldName=UserName&gt;&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;/TR&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;TR BGCOLOR="#ffffcc"&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD&gt;Email Address&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD&gt;&lt;#DataEntry Field=Email FieldName=UserEmail&gt;&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;/TR&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;TR&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD&gt;&lt;INPUT TYPE="SUBMIT" VALUE="Download"&gt;&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'    &lt;TD&gt;&lt;INPUT TYPE="RESET" VALUE="Reset"&gt;&lt;/TD&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'  &lt;/TR&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;/TABLE&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;/FORM&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;/BODY&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font> <font color="#ff0000"> </font>
<font color="#008000">'&lt;/HTML&gt;'</font> <font color="#ff0000"> </font> <font color="#000080">crlf</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
This function returns standard HTML that will generate the download registration form. There are some special tags however, that need some explanation. These are tags that start with <kbd>&lt;#..&gt;</kbd>. These are called <kbd><strong>Transparent Tags</strong></kbd>. Browsers are supposed to ignore these tags. But the TPageProducer component generates an <kbd><strong>OnHTMLTag</strong></kbd> event for each transparent tag it encounters while parsing the HTML when the <kbd>Content</kbd> property is accessed (assigned).
<p>The <kbd>OnHTMLTag</kbd> event looks like this:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>procedure</strong></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">PageProducer1HTMLTag</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">;</font> <font color="#000080">Tag</font><font color="#ff0000">:</font> <font color="#000080">TTag</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>const</strong></font> <font color="#000080">TagString</font><font color="#ff0000">:</font> <font color="#0000ff"><strong>String</strong></font><font color="#ff0000">;</font> <font color="#000080">TagParams</font><font color="#ff0000">:</font> <font color="#000080">TStrings</font><font color="#ff0000">;</font> <font color="#0000ff"><strong>var</strong></font> <font color="#000080">ReplaceText</font><font color="#ff0000">:</font> <font color="#0000ff"><strong>String</strong></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'METATAGS'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#008000">'  &lt;LINK REL=STYLESHEET TYPE="text/css" href="http://www.matlus.com/home-styles.css"&gt;'</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'ProjectName'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">GetProjectTitle</font><font color="#ff0000">(</font><font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">QueryFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'TutorialType'</font><font color="#ff0000">]</font><font color="#ff0000">,</font>
<font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">QueryFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'TutorialCode'</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'FileName'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="HIDDEN" NAME="txtFileName" VALUE="%s"&gt;'</font><font color="#ff0000">,</font><font color="#ff0000">[</font><font color="#000080">ProjectFileName</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'Form'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;FORM ACTION=%s/Register METHOD="POST"&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ScriptName</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'Tutorial'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="HIDDEN" NAME="txt%s" VALUE="%s"&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">,</font>
<font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">QueryFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">]</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'DataEntry'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="TEXT" NAME="txt%s" VALUE="%s"&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">,</font> <font color="#000080">GetCookie</font><font color="#ff0000">(</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'FieldName'</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
Notice the parameters that are passed to us in this event. Notice also, that the parameter <kbd>ReplaceText</kbd> is a <strong>var</strong> parameter.
<h2>The TPageProducer component</h2>
Each time the <kbd>Content</kbd> property of the TPageProducer component is accessed (assigned) the OnHTMLTag event is fired for every Transparent tag found. The <kbd><strong>TagString</strong></kbd> parameter gives us the HTML Tag name of the transparent tag. For instance, our first transparent tag in our template is <kbd>&lt;#METATAGS&gt;</kbd>. The <kbd>TagString</kbd> parameter will contain the value <kbd><strong>METATAGS</strong></kbd>.
<p>In the OnHTML event handler you will notice that we check for every Tag name using code like:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New">  <font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'METATAGS'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#008000">'  &lt;LINK REL=STYLESHEET TYPE="text/css" href="http://www.matlus.com/home-styles.css"&gt;'</font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
In this case we <strong>replace</strong> the transparent tag (&lt;#METATAGS&gt;) with the string literal
<pre>'  &lt;LINK REL=STYLESHEET TYPE="text/css" href="http://www.matlus.com/home-styles.css"&gt;';
</pre>
in other words, the string <kbd>&lt;#METATAGS&gt;</kbd> is replaced with the string <kbd>' &lt;LINK REL=STYLESHEET TYPE="text/css" href="http://www.matlus.com/home-styles.css"&gt;';</kbd>, including the "#" and the "&lt;" and "&gt;". The tags "&lt;.&gt;" are just placeholders. So even though we check for just the tag name (METATAGS), we replace the whole tag.
<p>You will have noticed that some of the transparent tags don't have just names. For instance, the transparent tag <kbd>&lt;#Tutorial Field=TutorialType&gt;</kbd> has more than just the name. The tag name in this case is <kbd>Tutorial</kbd>.
<p>Each transparent tag can have parameters. Parameters are in the form <kbd>Name=Value</kbd>. It is important to know that the delimiter for parameters is a space. So you can't have a parameter whose <kbd>name</kbd> part or <kbd>value</kbd> part contains a space. This makes the usage of parameters in transparent tags a bit tricky. But none the less, it's the parameters that make using the transparent tags in conjunction with the TPageProducer extremely useful. The parameters of an HTML Transparent tag are surfaced to us in the OnHTMLTag event as <kbd>TStrings</kbd>, namely the <kbd>TagParams</kbd> parameter.
<p>Using the <kbd>Values</kbd> property of the TStrings object we can extract the value of any parameter for a given transparent tag. Based on the value of certain TagParams, we can process the result differently. This capability can prove to be extremely powerful and useful. In this tutorial, I've tried to show how we can make good use of this particular capability of the TPageProducer.
<p>Let us now examine this more closely. Below, is a snippet of code from the OnHTMLTag event that processes the <kbd>Tutorial</kbd> tag:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New">  <font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'Tutorial'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="HIDDEN" NAME="txt%s" VALUE="%s"&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">,</font>
<font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">QueryFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">]</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
To start with, you will notice that it is this tag that is responsible for creating the <strong>Hidden</strong> fields of our HTML Form. These hidden fields contain the <strong>TutorialType</strong> and <strong>TutorialCode</strong> values that were passed to us via the <kbd>QueryString</kbd> property of the <kbd>Request</kbd> object. Remember the example of a URL that will call our ISAPI?
<pre>&lt;A HREF="/scripts/website.dll/DownloadReg?TutorialType=DelphiISAPI&amp;TutorialCode= ISAPICookiesHiddenFields"&gt;Download Project&lt;/A&gt;
</pre>
Notice the
<pre>TutorialType=DelphiISAPI
TutorialCode=ISAPICookiesHiddenFields
</pre>
The values for these two parameters need to be passed on to the action that will submit our HTML form. We're using <strong>Fat URLs</strong> here to maintain state or rather persist information. But since this information is required two actions later, we need to persist this information over two actions. The first action generates the HTML form, so we persist this information in hidden fields of the HTML form to be used when the form is later submitted. I hope this is clear. It can be a bit confusing at first. <strong>Figure 4</strong> shows the various steps involved in this process.
<p><img alt="" src="http://www.matlus.com/images/ISAPICookiesHF4.jpg"> <br>
<strong>Figure 4 showing the persistence of information across multiple actions</strong>
<p>Getting back to the hidden fields and transparent tags .
<p>There are 2 tags named <strong>Tutorial</strong> in our template. Both have a parameter called <kbd><strong>Field</strong></kbd>. The first tag's <kbd>Field</kbd> parameter's value is <kbd><strong>TutorialType</strong></kbd> and the second tag's <kbd>Field</kbd> parameter's value is <kbd><strong>TutorialCode</strong></kbd>.
<p>The resulting HTML string in the OnHTMLTag event for the first tag will be:
<pre>  &lt;INPUT TYPE="HIDDEN" NAME="txtTutorialType" VALUE="DelphiISAPI"&gt;
</pre>
The resulting HTML string for the second tag will be:
<pre>  &lt;INPUT TYPE="HIDDEN" NAME="txtTutorialCode" VALUE="ISAPICookiesHiddenFields"&gt;
</pre>
Similarly, you will have noticed that the <kbd><strong>DataEntry</strong></kbd> tag appears twice in our template. The code that will process these tags in the OnHTMLTag event looks like this:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New">  <font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'DataEntry'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="TEXT" NAME="txt%s" VALUE="%s"&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">,</font> <font color="#000080">GetCookie</font><font color="#ff0000">(</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'FieldName'</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
The <kbd>GetCookie</kbd> function returns the value of a cookie given a name (name=value pair). We'll examine cookies later, but for now just understand that this function returns the value of a given cookie.
<p>Before I go on to explain the processing of this tag, imagine if you will, that we have an HTML data entry form. Imagine also, that we'd like to use this form not only for data entry, but also to edit/modify existing data. We can have one template such as the one we have, that generates the HTML form the way we want it. Using the TPageProducer component and transparent tags in this way we could present a blank form for data entry or a pre-populated form for data edits. This comes real handy when doing data intensive ISAPI work. Of course, we'd need to know if we wanted to construct the HTML form with blank fields or with pre-populated fields.
<p>For example:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New">  <font color="#0000ff"><strong>if</strong></font> <font color="#000080">TagString</font> <font color="#ff0000">=</font> <font color="#008000">'DataEntry'</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">InEditMode</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="TEXT" NAME="txt%s" VALUE="%s"&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">,</font> <font color="#000080">Table1</font><font color="#ff0000">.</font><font color="#000080">FieldByName</font><font color="#ff0000">(</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'FieldName'</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">]</font><font color="#ff0000">)</font>
<font color="#0000ff"><strong>else</strong></font>
<font color="#000080">ReplaceText</font> <font color="#ff0000">:=</font> <font color="#000080">Format</font><font color="#ff0000">(</font><font color="#008000">'&lt;INPUT TYPE="TEXT" NAME="txt%s" VALUE=""&gt;'</font><font color="#ff0000">,</font>
<font color="#ff0000">[</font><font color="#000080">TagParams</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'Field'</font><font color="#ff0000">]</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
Where <kbd>InEditMode</kbd> is a Boolean variable that will switch states to indicate the operation. But the key point here is the parameter <kbd><strong>FieldName</strong></kbd> that can be used for all fields of our database table! One transparent HTML tag with a parameter whose value indicates the field we're trying to construct.
<p>This is exactly how we use the <kbd>DataEntry</kbd> tag here. If we find a cookie for the given name, we populate the HTML field with its value. If not, we leave it blank. So if the visitor is a first time visitor, s/he gets a blank form, if not s/he gets a pre-populated form.
<h2>Setting Cookies</h2>
Setting Cookies in Delphi using the WebBroker technology is really easy. There are a few things that one needs to be careful of, but once you've made a note of them, things should be really simple.
<p>The <kbd>Response</kbd> object has a method called <kbd>SetCookieFields</kbd> that looks like this:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>procedure</strong></font> <font color="#000080">TWebResponse</font><font color="#ff0000">.</font><font color="#000080">SetCookieField</font><font color="#ff0000">(</font><font color="#000080">Values</font><font color="#ff0000">:</font> <font color="#000080">TStrings</font><font color="#ff0000">;</font> <font color="#0000ff"><strong>const</strong></font> <font color="#000080">ADomain</font><font color="#ff0000">,</font>
<font color="#000080">APath</font><font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font> <font color="#000080">AExpires</font><font color="#ff0000">:</font> <font color="#000080">TDateTime</font><font color="#ff0000">;</font> <font color="#000080">ASecure</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">)</font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
It is recommended that you read the article - <a href="http://www.matlus.com/scripts/website.dll/Tutorials?DelphiISAPI&amp;ISAPIWhatAreCookies" rel="nofollow" target="_blank">What are Cookies</a> for an explanation of the various parameters of this method. We'll continue on from the end of that article here in our discussion of cookies and how they can be implemented in Delphi. The <kbd>SetCookies</kbd> procedure in our project looks like this:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>procedure</strong></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">SetCookies</font><font color="#ff0000">(</font><font color="#000080">CookieValues</font> <font color="#ff0000">:</font> <font color="#0000ff"><strong>array</strong></font> <font color="#0000ff"><strong>of</strong></font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>var</strong></font>
<font color="#000080">CookieVals</font> <font color="#ff0000">:</font> <font color="#000080">TStringList</font><font color="#ff0000">;</font>
<font color="#000080">i</font>          <font color="#ff0000">:</font> <font color="#000080">Integer</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#000080">CookieVals</font> <font color="#ff0000">:=</font> <font color="#000080">TStringList</font><font color="#ff0000">.</font><font color="#000080">Create</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>try</strong></font>
<font color="#0000ff"><strong>for</strong></font> <font color="#000080">i</font> <font color="#ff0000">:=</font> <font color="#800080">0</font> <font color="#0000ff"><strong>to</strong></font> <font color="#000080">High</font><font color="#ff0000">(</font><font color="#000080">CookieValues</font><font color="#ff0000">)</font> <font color="#0000ff"><strong>do</strong></font>
<font color="#000080">CookieVals</font><font color="#ff0000">.</font><font color="#000080">Add</font><font color="#ff0000">(</font><font color="#000080">CookieValues</font><font color="#ff0000">[</font><font color="#000080">i</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">SetCookieField</font><font color="#ff0000">(</font><font color="#000080">CookieVals</font><font color="#ff0000">,</font><font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">Host</font><font color="#ff0000">,</font><font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ScriptName</font><font color="#ff0000">,</font><font color="#000080">Now</font> <font color="#ff0000"> </font> <font color="#800080">30</font><font color="#ff0000">,</font><font color="#000080">False</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>finally</strong></font>
<font color="#000080">CookieVals</font><font color="#ff0000">.</font><font color="#000080">Free</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
Using a method such as this simplifies the process of setting cookies. The <kbd>GetCookie</kbd> method uses the <kbd>Request</kbd> object instead of the <kbd>Response</kbd> object. This method is a one liner and looks like this:
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>function</strong></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">GetCookie</font><font color="#ff0000">(</font><font color="#000080">sName</font> <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">)</font> <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#000080">Result</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">CookieFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#000080">sName</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
Now lets look at the <kbd>/Register</kbd> action of our project. This is the action that the HTML Form will call when the Submit button is clicked.
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#0000ff"><strong>procedure</strong></font> <font color="#000080">TWebModule1</font><font color="#ff0000">.</font><font color="#000080">WebModule1waRegisterAction</font><font color="#ff0000">(</font><font color="#000080">Sender</font><font color="#ff0000">:</font> <font color="#000080">TObject</font><font color="#ff0000">;</font>
<font color="#000080">Request</font><font color="#ff0000">:</font> <font color="#000080">TWebRequest</font><font color="#ff0000">;</font> <font color="#000080">Response</font><font color="#ff0000">:</font> <font color="#000080">TWebResponse</font><font color="#ff0000">;</font> <font color="#0000ff"><strong>var</strong></font> <font color="#000080">Handled</font><font color="#ff0000">:</font> <font color="#000080">Boolean</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>var</strong></font>
<font color="#000080">ErrMSg</font>       <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#000080">UserName</font>     <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#000080">UserEmail</font>    <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#000080">TutorialType</font> <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#000080">TutorialCode</font> <font color="#ff0000">:</font> <font color="#0000ff"><strong>string</strong></font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>begin</strong></font>
<font color="#808080">{ Extract Values from the HTML Form's Fields }</font>
<font color="#000080">UserName</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ContentFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'txtName'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
<font color="#000080">UserEmail</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ContentFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'txtEmail'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
<font color="#000080">TutorialType</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ContentFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'txtTutorialType'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
<font color="#000080">TutorialCode</font> <font color="#ff0000">:=</font> <font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ContentFields</font><font color="#ff0000">.</font><font color="#000080">Values</font><font color="#ff0000">[</font><font color="#008000">'txtTutorialCode'</font><font color="#ff0000">]</font><font color="#ff0000">;</font>
<font color="#808080">{ Set the Cookies now }</font>
<font color="#000080">SetCookies</font><font color="#ff0000">(</font><font color="#ff0000">[</font><font color="#008000">'UserName='</font> <font color="#ff0000"> </font> <font color="#000080">UserName</font><font color="#ff0000">,</font><font color="#008000">'UserEmail='</font> <font color="#ff0000"> </font> <font color="#000080">UserEmail</font><font color="#ff0000">]</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#808080">{ Log the infomration to the database table }</font>
<font color="#0000ff"><strong>if</strong></font> <font color="#000080">PostDataToDatabase</font><font color="#ff0000">(</font><font color="#000080">ErrMsg</font><font color="#ff0000">,</font> <font color="#000080">UserEmail</font><font color="#ff0000">,</font> <font color="#000080">TutorialType</font><font color="#ff0000">,</font> <font color="#000080">TutorialCode</font><font color="#ff0000">,</font> <font color="#000080">UserName</font><font color="#ff0000">)</font> <font color="#0000ff"><strong>then</strong></font>
<font color="#808080">{ Everything went OK. Let the user download the Project Files }</font>
<font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font> <font color="#000080">SendFTPDialog</font>
<font color="#0000ff"><strong>else</strong></font>
<font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">Content</font> <font color="#ff0000">:=</font> <font color="#000080">SendErrorPage</font><font color="#ff0000">(</font><font color="#000080">ErrMsg</font><font color="#ff0000">)</font><font color="#ff0000">;</font>
<font color="#0000ff"><strong>end</strong></font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
First we extract the Form's field values into local variables so we can work with them directly. Once we have this information stored in variables, we <strong>Set the Cookies</strong>. In this project, we're interested in setting only 2 cookies.
<pre>  UserName=Value
UserEmail=Value
</pre>
In large applications, where a lot of cookies are being set, we might resort to shorter cookies (ue to size limitation) or better yet, just a unique identifier (sessionID) that we can use to then lookup our database to find associated information. But in this project, we should be fine with the above cookies.
<p>Once we've set the cookies, we need to log this rest of the Form's information and show our visitor the next screen. From here on out, the process it specific to this project. Those interested in this part of the project should look at the source code. We'll continue on to learn more about cookie in this article.
<h2>Session Cookies</h2>
In the above example, we set the cookies to expire in about 30 days.
<div class="codeblockouter">
<div class="codeblockInner"><code>
<pre><font face="Courier New"><font color="#000080">Response</font><font color="#ff0000">.</font><font color="#000080">SetCookieField</font><font color="#ff0000">(</font><font color="#000080">CookieVals</font><font color="#ff0000">,</font><font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">Host</font><font color="#ff0000">,</font><font color="#000080">Request</font><font color="#ff0000">.</font><font color="#000080">ScriptName</font><font color="#ff0000">,</font><font color="#000080"><strong>Now</strong></font> <font color="#ff0000"> </font> <font color="#800080">30</font><font color="#ff0000">,</font><font color="#000080">False</font><font color="#ff0000">)</font><font color="#ff0000">;</font></font>
</pre>
</code></div>
</div>
Session cookies are cookies that expire as soon as the visitor closes his browser. Sometimes, we'd like to set session cookies in our ISAPI applications and the way we can do this is by setting the variable <kbd>AExpires</kbd> to <strong>-1</strong>.
<h2>Cookies and Domains</h2>
Over and above what was explained in the article - What are Cookies, lets see some of the things we need to be careful of while developing/debugging our ISAPI applications. We've used the <kbd>Request.Host</kbd> variable as the value to be fed for the <kbd>ADomain</kbd> parameter of the <kbd>SetCookieFields</kbd> method of the <kbd>Request</kbd> object. This will evaluate to the host header value of the HTTP request. In other words, this will be the host part of the URL you specified while you called your ISAPI using the browser. What you need to be careful of here while testing is that you can't switch between using the IP address in the URL and the host name /machine name. For example, using localhost instead of 127.0.0.1 (loop back IP) is not the same. All of this can get quite confusing during testing. I strongly recommend getting into the habit of using the IP address of your machine in the URL for all you ISAPI work. Use either 127.0.0.1 or the actual IP address of your machine if you work in a LAN environment (where the IP address most probably will not change).
<p>The Machine I develop on has a domain name registered to it. It also has an IP address allocated by my ISP and the loop back IP address and of course <kbd>localhost</kbd>. Because we are using the <kbd>Request.Host</kbd> property this property Indicates the value of the Host header of the HTTP request message. That is it extracts the Host header from the HTTP request. The cookie, therefore will be set for that particular "domain". The URL http://127.0.0.1/scripts/download.dll... will save a cookie for the ADomain - 127.0.0.1. This cookie will not be available for matlus.matlus.com, which is the domain name of my development machine. Nor will it be available for 24.28.203.177, which is the IP address of the same machine. You could spend hours if not days, if you're not careful with the way you define the URL in your browser. Stick to one and use only that for all your ISAPI work. There will be 3 different cookie files created if you use all three URLs for testing. The results can throw you in a loop! </p>
]]></description><category>Programming</category><category>Delphi</category><category>ISAPI</category></item><item><title>Upload Files From a Browser using an ISAPI</title><pubDate>Fri, 11 Jan 2008 11:46:42 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/13/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/13/</guid><description><![CDATA[<p>I have searched long and hard, high and low, for code that would allow me to do this in Delphi. Many people sent me to various web sites but never gave me a solution. No code, just the how-to. From the Microsoft site it was easy to find out the how-to, but obviously there was no code sample for the Delphi programmer. </p>
<p>&nbsp;</p>
<p>It took me 2 full days to get this going. An extremely long time to be able to something so simple in Delphi. Well, simple, once you've figured it out and got it to work!</p>
<p>&nbsp;</p>
<p>The code presented works and has no limitation on file size that can be uploaded. One could however optimize the code and clean it up a bit. I'd personally be interested in suggestions to improve the code from a resource/performance standpoint. Please <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#104;&#105;&#118;&#64;&#109;&#97;&#116;&#108;&#117;&#115;&#46;&#99;&#111;&#109;" rel="nofollow">email me</a> with your tried and tested code.</p>
<p>&nbsp;</p>
<h2>Using the ISAPI application.</h2>
To be able to upload a file from a browser (client) to the web server, the HTML form needs to have the <kbd>enctype</kbd> set the <kbd>multipart/form-data</kbd>.
<p>&nbsp;</p>
<p>&nbsp;</p>
You can download the project file below to check out the code. The default action of the ISAPI will generate the HTML form suitable for file uploads. Once you compiled the project, you should see the file FileUpload.dll in C:\inetpub\scripts folder (set in the project options).
<p>&nbsp;</p>
<p>In your web browser, type in the URL http://mydomain/scripts/fileupload.dll</p>
<p>&nbsp;</p>
<p>This should present you with the File Upload HTML Form. Browse to the required file and then click on the Send Button.</p>
<p>The file will be saved with the same name but in the C:\inetpub\scripts folder (set in the application).</p>
<p>&nbsp;</p>
<h2>Known Issues</h2>
I have noticed that files larger than 48K (this is when you have to use the Request.ReadClient method) the Request.ReadClient method takes one hell of a long time to return (I'm using D5 Win2000 and IIS 5.0). It does return eventually and everything works fine after that. I'd be interested in a "fix" for this or even a good explanation.
<p>&nbsp;</p>
<p>Wayne Niddery, sent me an email with the explanation for the delay. The reason is that in the code I was reading past the actual file size. The ReadClient method is supposed to return a -1 when there is nothing more to read. It does, but after a very long time. Wyne suggested I read only the actual file size. So I implemented the change and it worked perfectly. Thank you Wyne ! </p>
<p>The modified project is <a href="http://www.matlus.com/scripts/download.dll?TutorialType=DelphiISAPI&amp;TutorialCode=ISAPIMultiFileUpload">available for download</a>.</p>
]]></description><category>Programming</category><category>Delphi</category><category>ISAPI</category></item><item><title>Using Basic Authentication</title><pubDate>Thu, 10 Jan 2008 12:05:04 GMT</pubDate><link>http://exposureroom.com/members/skumar/tutorials/post/14/</link><guid isPermaLink="true">http://exposureroom.com/members/skumar/tutorials/post/14/</guid><description><![CDATA[Before we begin, let me say, that I expect, you've read the earlier article <a rel="nofollow" href="http://www.matlus.com/scripts/website.dll/Tutorials?DelphiISAPI&amp;ISAPIAuthentication&amp;12" target="_blank">Authentication And Security in IIS</A>. This article deals purely with the <B>Basic Authentication Scheme</B>. There is a demo you can play with before you begin. Please note a few important points before you try the demo. These points apply to the project as well. 
<OL>
<LI>The username and password are shiv and matlus respectively 
<LI>If you go past 3 tries, please close you browser and start over. This is normal/expected due to reasons explained in the tutorial below. 
<LI><a rel="nofollow" href="http://www.matlus.com/scripts/basicauth.dll">You can find the demo here</A> </LI></OL>
<H2>Getting the Browser to Pop Up the Dialog Box</H2>First lets see how we can get the browser to pop up the log in dialog box. Once we know how to do this, it's a matter of retrieving/extracting the user name and password and verifying the user. 
<P>We need to do two things: 
<OL>
<LI>Set the Status Code to <KBD>401</KBD> 
<LI>Set the <KBD>WWWAuthenticate</KBD> HTTP header to <KBD>Basic realm=Secured Site</KBD> </LI></OL>This may sound complicated for the first timer, but is simply achieved in Delphi. The <KBD>Response</KBD> object has a property called <KBD>StatusCode</KBD> as well as <KBD>WWWAuthenticate</KBD>, so we can set these easily as shown below 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New">    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>StatusCode</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>401</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WWWAuthenticate</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>AuthenticationString</FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>The moment we do this, the browser pops up a dialog box similar to that shown in <B>Figure 1</B> 
<P><IMG src="http://www.matlus.com/images/BasicAuthLoging.jpg"> <BR><B>Figure 1 showing the Log in Screen (I.E) for Basic Authentication</B> 
<P>When the user clicks on the <KBD>OK</KBD> or <KBD>Cancel</KBD> buttons, the request returns to the same action that initially responded with the 401 status code and the WWWAuthenticate header. So we get a second chance at confirming the users validity in our action in the ISAPI. 
<P>In I.E, if the user name and password combination is incorrect I.E will automatically respond with the dialog once again. But it will do this only 3 times. Netscape on the other hand will continue to show this dialog until the user hits the cancel button or quits the session. 
<H2>Getting Started</H2>
<OL>
<LI>Start with a new ISAPI Project 
<LI>Save the project as <KBD>BasicAuth</KBD> 
<LI>Create an Action item and set the <KBD>Default</KBD> property to <KBD>True</KBD> </LI></OL>In the <KBDONACTION< KBD>event of this action item write the following code: 
<DIV class=codeblockouter>
<DIV class=codeblockInner><CODE><PRE><FONT face="Courier New"><FONT color=#0000ff><B>procedure</B></FONT> <FONT color=#000080>TWebModule1</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WebModule1WebActionItem1Action</FONT><FONT color=#ff0000>(</FONT><FONT color=#000080>Sender</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TObject</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#000080>Request</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebRequest</FONT><FONT color=#ff0000>;</FONT> <FONT color=#000080>Response</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>TWebResponse</FONT><FONT color=#ff0000>;</FONT> <FONT color=#0000ff><B>var</B></FONT> <FONT color=#000080>Handled</FONT><FONT color=#ff0000>:</FONT> <FONT color=#000080>Boolean</FONT><FONT color=#ff0000>)</FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>begin</B></FONT>
<FONT color=#808080>{ Entry point into the application }</FONT>
  <FONT color=#0000ff><B>if</B></FONT> <FONT color=#000080>UserIsAuthorized</FONT> <FONT color=#0000ff><B>then</B></FONT>
  <FONT color=#0000ff><B>begin</B></FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>StatusCode</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>200</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'You are Welcome Here'</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT>
  <FONT color=#0000ff><B>else</B></FONT>
  <FONT color=#0000ff><B>begin</B></FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>StatusCode</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#800080>401</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>WWWAuthenticate</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#000080>AuthenticationString</FONT><FONT color=#ff0000>;</FONT>
    <FONT color=#000080>Response</FONT><FONT color=#ff0000>.</FONT><FONT color=#000080>Content</FONT> <FONT color=#ff0000>:=</FONT> <FONT color=#008000>'&lt;H1&gt;Access Denied&lt;/H1&gt;'</FONT><FONT color=#ff0000>;</FONT>
  <FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT>
<FONT color=#0000ff><B>end</B></FONT><FONT color=#ff0000>;</FONT></FONT>
</PRE></CODE></DIV></DIV>Before we go on, we need to understand a key point here. The browser treats the user name and password just like a cookie in that, it sends the user name and password with every request from the time the WWWAuthenticate header was set. This functionality makes it really simple to validate a user in any action of our ISAPI application. What we need to do is check the validity of the user in every action that needs the proper access rights. If the user is not valid, we simply send back an <B>Access denied</B> message or, set the status code to 401 and set the WWWAuthenticate header to give the user the opti
