delphi_internet 使DELPHI和因特网配合工作.docx
首页=>学习教程=DE1.PHIANDTHEINTERNETbyCharlieCalvert由Boen翻译,转载请注明:TranslatebyBoen.中文译稿版权属Boen所有,使用权归CXM编程版第一部分第二部分第一这篇文章主要讲述如何使DE1.PHl和因特网配合工作。本文中将详述两个专门技术:WININET:构建FTP,HTTP和Gopher用户端程序ISAPI:扩充因特网信息服务,例如,获得服务器上的信息并把它们显示在浏览器上。现今的计算机世界中,由于微软公司的因特网战略而掀起了一个巨大发展潮流。那些制作CGl(公共网关接口)和第三方工具(即使是最基本的因特网工具)的日子将最终一去不复返了。对复杂的第三方工具的需求总是存在的,但现在程序员将会发现他们所需的大量的嵌入操作系统的因特网工具,简言之,并不需要进一步的投资,你就能够使用免费的DE1.PHl资源来:* 开发WEB浏览器* 运行FTP,HTTP和Gopher,在两个DE1.PHl应用软件之间或DE1.PHl应用软件和基于TCP(传输控制协议)的服务器之间操作TCP因为DE1.PHl能够轻松地调用WindoWSAPI,并且它支持OCX/ActiveX,因此微软的新战略和我们的计划配合的恰到好处。微软生产工具,而DE1.PHl程序员获得收成!在本篇中有些什么?这篇文章中包含了三个大部分和一些小部分,有三个大主题:* 寻找资料:那里能搞到本文中提及的技术资料,而且包含了关于您所需的运行文中代码的软硬件的简短说明。* TSAPI:怎样使用ISAPI*WININET:怎样使用WININET在大多数情况下,本文中的ISAPl和WlNNET部分是完全独立的,您可以自由地选择阅读时的顺序。查找资料,硬件和软件的要求您需要一份UiCrOSOftWindOWSNT3.51Server或NT4.0Server的拷贝,其中应附有因特网信息服务文档,因为您需要甬道其中所提到的技术。这份文档应随NTServer4.0附送,NT3.51的用户可从微软的网址上下载。运行WindoWSNT,您的机器的最低配置应为486兼容,20兆以上内存。您必须有另一台计算机装有网页浏览器。为使本文中的ISAPl部分能够顺利运行,第二台机器必须能够运行所有支持网页浏览器的软件。如果在您的机器上运行的是WindoWS95或WindowsNT,那么本文中的WlNINET代码片就能运行的最好。任何符合条件的网页浏览器在这种技术环境下都能够使用。在1996年六月以后发布的Delphi2.0以上的版本中,有您所需的把Delphi连接到因特网上的几乎全部资源。如果您没有最新的DelPhi版本注:此处作者指的是2.0版本(译者),那么您需要本文档中提到的特殊文件,所有这些几乎都可以从万维网上免费获得注:如果您正在使用DelPhi2.0以上版本,则不许考虑(译者)Io所有本文中提到的技术在DeIPhi2.0环境下都能顺利工作,但在16位DeIPhi环境下则不一定能顺利工作。如果您需要从万维网上下载信息,链接为:htlp:WWTechInfodelphiindex,html注:现在已经不存在了!:-(译者)DeIPhi2.0的新版本中附有WININET.PAS文档,如果你的拷贝中不包含它,那么上面那个万维网节点可以为您提供。町NINET.PAS包括为扩展微软视窗因特网所设计的变量清单、函数、类型和属性。这意味着您能够轻而易举地为您的应用程序增添FTP、HnP和GOPher支持。微软公司的WINlNET.D1.1.是免费发布的,如果它不在您的WindoWS/System或WindowsSystem32目录下的话,您可以从微软公司那里得到它。下面是可获得WININET.H这个视窗帮助文件的万维网节点:http术能使您“写入服务器端的原本和过滤本,从而扩充微软因特网信息服务和其他ISAPI万维网服务”。如果您需要找到关于ISAPI的描述,可以去:httpr%在本文最后,附加了一个名为HTTPEXT.PAS的关键的ISAPl文档的拷贝。微软公司免费发布的因特网控制包(ICP)是一个OCX/ActiveX控制集,您可以在DeIPhi中把它们拖放到应用程序上(DeIPhi2.0中包含这些控件)。他们提供了创建DeIPhi应用程序的即时支持,他们知道如何浏览网页、如何应用FTP、WINSOCK和其他因特网技术。如果您的DeIPhi拷贝中没有包含这些控件,那么您在使用它们之前您应该把这些文档添加进DelPhi所在的目录中的1.ib目录下。这些文档位于上面提及的链接中的Borland的IM)EX.HTM1.站点下。在本文中我没有提到ICP控件,但是任何对这项技术有兴趣的人应该明确确认他拥有这些控件的拷贝。您可以从我的站点下载我的PaSCal应用文件,他们的名字是STRBOX.PAS和MATHBOX.PASo经常察看一下这个站点上的关于本文提到的信息的更新情况是很有好处的。在这里我假设读者对于DeIPhi和ObjeetPaSCaI都很熟悉,并且读者对于因特网,HTM1.,浏览器和万维网服务器有基本的了解。ISAPIISAPI是一项很容易使用然而功能强大的技术,它能够让您扩充因特网信息服务的功能。这项技术随WindowsNT4.0附送,让您在您的服务器上建立WEB、FTP和GOPHER站点。同时这项技术与WindowsNTs.51SerVer注:指服务器版本,另一个版本是工作站版本(译者)兼容。在过去,扩充网页服务器的最佳办法是建立CGl应用程序。它们是强有力的工具,但是也被他们的执行格式所限制注:如PER1.是解释执行的(译者)。当您从浏览其上发出一个基于CGl的请求到服务器上时,这个CGl应用程序将极有可能先被强制装入内存中,这会消耗很多时间。而且,在某些环境下,CGT技术显得稍微难用了一点。ISAPl是一种通过写入D1.1.S注:动态链结程序(译者)从而替代CGl应用的方法。您也可以通过ISAPl来写过滤文本,但这项技术我不会在本篇中提及。同CGl相比,ISAPl更容易使用,而且它更快,同时能更好地利用系统资源。在下面几点中,我将详细地介绍为什么ISAPlD1.1.S比CGl应用要更为出色:ISAPID1.1.S与HTTP服务位于相同的地址,因此他们能够从服务器上直接存取HTTP服务。与CGl应用相比,它们能更快地装入内存;当他们在服务器上发出请求时,所需的停悬的时间注:指发出请求到接受服务器应答的时间(译者)要少的多。这点当服务器的负荷很重时更加重要。您可以控制D1.1.S何时被装载和卸载。例如:您可以在第一次尝试请求时预先装载D1.1.s;当它们不被使用时卸载这个ISAPl应用D1.1.s以便释放系统资源。正如前文所述,您可以利用ISAPl写过滤文本注:一般指C/S结构中的脚木(译者),更具微软的文档,您可以通过ISAPl过滤文本做下面这些事情:用户授权方案压缩加密登入通信分析或其他请求分析(例如,寻找.etcpasswordz,中的请求)在本文中,我会着重介绍如何编写返回数据集的D1.1.s,或者是如何与运行浏览器的用户进行简单的联系。ISAPI基础HTTPEXT.PAS文件包含了使用ISAPl的关键声明。这个文件应随1996年6月以后发表的Delphi版本分发。它也可以在BorIand的站点上找到,在本文的ISAPl部分附有这份文档。因为这是基于NT的技术,您必须使用DCIPhi2.0以上的版本来应用这项技术。您不可能在16位的编辑器上应用它。HTTPEXT.PAS包含了微软公司创立的ISAPl技术的接口注:指Delphi接口,ISAPl由C+编写(译者)o在编写Delphi的时候并没有提供ISAPI的用户接口,我会仅仅就如何使用微软公司的现有技术进行描述。不过,ISAPl太容易使用了,而且对大多数用户来说,用户的DeIPhi对象的版本并不是必须的。有三个函数可作为ISAPlD1.1.S的入口,前两个是必须的,第三个时可选的。GetExtensionVersion:进对最低版本做检查HttpExtensionProc:这是D1.1.的入口,就象是DeIPhi应用程序中的begin.end块TerminateExtension:这是个可选的程序,它可以用作清除其他内存分配的线程。当您在创建ISAPlD1.1.的时候,您必须引用上面列出的三个函数中的头两个函数,执行这两个函数是所有ISAPI编程的关键。这三个语句都包含了“字输出”,使用这项术语是因为ISAPlD1.1.S扩充了因特网信息服务器。(记住,因特网信息服务器指的是微软服务器。如果您要把一台NT服务器作为体格网页服务器的话,那么,这正是您所需的工具。ISAPlD1.1.S随NT4.O分发,在安装操作系统是自动安装。)ISAPl提供了一个制作服务器可遵循的标准。例如,它可以把网景公司的复杂的NSAPl接口压缩至相关的简练而优美的ISAPl来对NSAPI接口进行操作。下面是这两个重要函数的声明functionGetExtensionVersion(varVer:THSEVERSIONINFO):BOO1.;Stdcall;functionHttpExtensionProc(varECB:TExtensionControlBlock):DWORD;Stdcall;您只要把GetEXtenSionVerSion粘贴到您的D1.1.s救行了.当ISAPl向公众发布新版本时您只需要做轻微的改动。functionGetExtensionVersion(varVer:THSEVERSlONNFo):BOO1.;Stdcall;beginVer.dwExtensiOnVersion:=$00010000;/1.0supportVer.IpszExtensionDesc:=,Delphi2.0ISAPID1.1.*;/DescriptionResult:=True;end;TheparameterpassedtothisfunctionisdeclaredinHTTPEXT.PASasfollows:有关的参数在HTTPEXT.PAS中声明如下:PHSE_VERSION_INFO="THSE_VERSION_INFO;THSE_VERSION_INFO=packedrecorddwExtensionVersion:DWORD;IpszExtensionDesc:array0.HseMaxExtD1.1.Name1.en-IofChar;end;常量HseMaxExtDllName1.en在声明中的值为256。纪录中的这两个变量是“自声明”的,前一个包含了ISAPl的版本号注:即变量ChvExtensionVersion(译者),后一个则表示用户定义的一个用来描述D1.1.s的字符串。在您引用GetExtensionVersion语句的同时,您必须在您的D1.1.程序的DPR文件部分增添输出部分。在您写这段语句时您还应该写下:exportsGetExtensionVersion,HttpExtensionProc;这就是您在建立这两个重要ISAPlD1.1.的函数时所要做的。下一步,使用HttpExtensionProc,稍微复杂一点,因此我将把它作为一个独立的部分。与HttpExtensionProc一起工作HttPEXtenSiOnProC语句是D1.1.的入口。它的作用就好比C语言中的main()语句,或者Delphi中的begin.end部分这里有一个简单的使用GetExtensionVersion语句的例子functionHttpExtensionProc(varECB:TExtensionControlBlock):DWORD;stdcall;varResStr:string;Str1.en:Integer;beginECB.Ipsz1.ogData:=,DelphiD1.1.1.og,;ECB.dwHTTPStatusCode:=200;ResStr:=><HTM1.><TIT1.E>Testserverresult<T!T1.E>>+,<Hl>Testserverresults<Hl>,+,<BODY>HellofromISAPI<BR><BODY>>+,<HTM1.>>ResStr:=Format(,HTTP1.02000K'#13#10+,Content-Type:texthtml,#13#10+,Content-1.ength:%d'#13#10+,Content/ttl3ttlftl3ttl,%s,1.ength(ResStr),ResStr);Str1.en:=1.ength(ResStr);ECB.WriteClient(ECB.ConnID,Pointer(ResStr),Str1.en,0);Result:=HSE_STATUS_SUCCESS;end;如果您在浏览其中向这个D1.1.发出请求,那么您会得到一页这样的回应:TestServerResultsHellofromISAPI函数体内的大部分域提供基本信息的简单的HTM1.代码密切相关。您还需要填写TExtensioncontrolBlock中的一些域,如下所示。注意到在这个纪录里有一个叫做WriteCIient的函数指针,您可以引用这个函数把信息传送回浏览器。当呼叫这个函数时,您使用到了下面提到的TExtensionControl块中的ConnID字段。当函数被呼叫时,COnnID为您自动填充。在察看函数的代码之前,请让我为您演示所有用到的上文提及的HttpExtensionProc函数的ISAPID1.1.的完整程序1ibraryTsapil;libraryIsapil;usesWindows,SysUtils,HTTPExt;functionGetExtensionVersion(varVer:THSEVERSI0N_INFO):BOO1.;Stdcall;beginVer.ClwExtensionVersion:=$00010000;/We'reexpectingversion1.0supportVer.IpszExtensionDesc:=,WritteninDelphi2.0,;Result:=True;end;functionHttpExtensionProc(varECB:TEXTENSIONCONTRO1._B1.OCK):DWORD;stdcall;varResStr:string;Str1.en:Integer;beginECB.Ipsz1.ogData:=,DelphiD1.1.1.og,;ECB.dwHTTPStatusCode:=200;ResStr:='Testserverresults,+>IsapisayshellotoDevRelResStr:=Format(,HTTP/1.02000K'#13#10+,Content-Type:texthtml,#13#10+,Content-1.ength:%d'#13#10+,Content:,ttl310ttl3ttl0,%s,1.ength(ResStr),ResStr);Str1.en:=1.ength(ResStr);ECB.WriteClient(ECB.ConnID,Pointer(ResStr),Str1.en,O);Result:=HSE_STATUS.SUCCESS;end;exportsGetExtensionVersion,HttpExtensionProc;beginend.为了运行这个D1.1.程序,您应该把它复制到您的NT服务器下的脚本目录中去。在我的NT4.0机器中,它就像这样:c:winntsystem32inetsrvscriptsmystuffisapi1.dl1在这个例子中,我已经创建了我的名为“mystuff”的目录,它只不过是用来存储我创建的ISAPID1.1.s0您的目录,当然和我的机器上的不完全一样,取决于您的“inetsrv”目录位置和其它因素。为成功调用这个D1.1.,您应该在您的HTM1.页上增添这个超链接:<HREF="/scripts/InyStUffisapi1.dll”>ISPIOne<A><BR>当用户点击这个超链接时,ISAPnDII会被呼叫,然后字符串aHellofromTSAP,会显示在用户的浏览器上。如果您并不是把ISAP1.D1.1.放在mystuff目录下,那么您应该修改上面的HTM1.代码来使之与您的情况适应。注意,您的目录必须与目录inetsrv有关,不应,也不能包含您的整个D1.1.所在的目录。下面是呼叫的完整的HTM1.脚本:<HTM1.><HEAD><TIT1.E>CharlieCHomePage<TIT1.E><HEAD><BODY><Hl>MyHomePage<H1><P>Thisisthehomepageformyhomecomputer.<P><AHREF="/scripts/InyStUff7isapil.dll”>ISAPIOne<A><BR><BODY><HTM1.>注意,如果您多次把程序ISAPl1.D1.1.复制到mystuff目录下,在每一次复制之前您应该关掉网络服务器的万维网端口。这是因为,在第一次复制这个D1.1.时,您可以不受限制,但在此之后,它就属于服务器了。因此,在您®制第一次拷贝的更新版本时,因当关掉万维网服务。您可以使用网络管理程序来关掉万维网服务。这个程序应该在微软网络管理程序组(MiCroSoftInternetServergroup)下面,在安装网络信息服务时被安装到程序管理器(ExplorcrProgra11Manager)下。与TEXtenSiOneontrOlBloCk一起工作通过本文中的这一要点,您能够建立您的第一个ISAPlD1.1.,并且能在第二台机器上的网页浏览器调用它。在本文中接下来的ISAPl的其余部分将会更加深入。这里是HttpExtensionProc参数中比较复杂的部分PEXtenSiOnContrOlBloCk=TExtensionControlBlock;TExtensioncontrolBlock=packedrecordcbSize:DWORD;/=sizeof(TExtensioncontrolBlock)dwVersion:DWORD;/versioninfoofthisspecConnID:HCONN;/ContextDonotmodify!dwHttpStatusCode:DWORD;/HTTPStatuscode/nullterminatedloginfospecifictothisExtensionD1.1.Ipsz1.ogData:array0.HSE_1.OG_BUFFER_1.EN-1ofChar;IpszMethod:PChar;/REQUEST_METHODIpszQueryString:PChar;/QUERY_STRINGIpszPathlnfo:PChar;/PATHINFOIpszPathTranslated:PChar;/PATH.TRANS1.ATEDCbTotalBytes:DWORD;/TotalbytesfromclientCbAvailable:DWORD;/AvailablenumberofbytesIpbData:Pointer;/pointertoCbAvailablebytesIpszContentType:PChar;/ContenttypeofclientdataGetServerVariable:TGetserverVariableProc;WriteClient:TWriteClientProc;ReadClient:TReadClientProc;ServerSupportFunction:TServerSupportFunctionProc;end;注意到这个纪录中包含了上面提到过的ConnID字段,并且向WriteClient传送第一个参数。这个纪录中的第一个参数是为版本控制而设的。它应该是TEXtenSiOnCOntrOIBIOCk的大小的规定。如果微软公司改变了它的结构,那么它们能够通过检查纪录的大小来判断它们正在处理的结构版本。您永远也不要这个纪录中的前三个字段,它们早已被ISAPl填充,在您的程序中,它们只能被访问,而不能被改变。这个纪录中最重要的字段可能就是IpszQueryString了,它包含了从服务器上传来的请求的信息。例如,假设您已经创建了一个名叫ISAPi1.D11。为了调用这个D1.1.,您就要在您的浏览器的一页上创建一个像这样的HREF注:HTM1.语言中的一种格式(译者):<AHREF=,zscriptsmystufftestl.dllz,>TestOne<A>如果您希望响应这个D1.1.,您就要对上面那行做这样的改动:<AHREF="/scripts/InyStUff/test1.dll?MyQUery”>TestOne<A>假如HTU1.代码段中有像上面两行中的第二行,那么,您的D1.1.就会在IPSZQUerString参数中得到"MyQuery”的字符串,特别要注意跟在请求字符串后的请求标志的使用。当然,您可以随心所欲地改变请求字符串。例如,您可以这样写:<HREF=VscriptsZmystuffZtestl.dll?ServerName*>TestOne<A>在这个请求中,这个D1.1.会回答服务器的名称。您在传递这个参数时,不受任何限制。您可以传递任何您想要的东西,而且,如何分析D1.1.中的信息也由您的喜好决定。当您从服务器返回信息至浏览器时,您使用到了这个纪录中的“WriteClienl”函数指针。在初始化这个指针时您不需做任何事;它已经自动地有网络信息服务器传递给您了。CGl应用程序的作者会注意到传送请求字符串的语法十分熟悉。事实上,ISAPl跟随了CGl的大多数习惯,在TExtensioncontrolBlock中的多数字段可以简单地被CGT技术信用。在TEXtenSiOnControIBloCk中的另一个关键字段是1pbData,它包含了从浏览起上传给您的附加信息。例如,您有一个伴随几个字段的HTM1.窗体,这些自断中包含的信息就会被一个叫做“IpDala”的指针传递。本文中的下一个主题,“从'确认'按钮中获得信息”,将会着重讲述怎样处理这种情况。到现在为止我已经介绍了TEXtCnSionCOntrOIBIOCk中的四个关键字段:WriteClient:一个能够让您传递格式化的HTM1.数据到浏览器上的指针。这个函数用到了TExtensioncontrolBlock的ConnID字段。IpszQueryString:从浏览骑上传来的请求。IpbData:从浏览器上传给你的人一的附加数据。通常是一个HTM1.窗体的任意字段的内容。我将在“确认按钮”这部分进一步讨论。要获得其他TEXtenSionCOntroIBloCk中的字段是如何工作的感觉,最好的办法就是亲自在浏览其中将他们做对照。换句话说,您会希望创建一个HTM1.页,使得用能够调用客户端的ISAPlD1.1.。这个ISAPID1.1.的目的仅仅是在HTM1.中格式话TExtensioncontrolBlock中的每一个字段,然后把它们传回浏览器。这样就把您的浏览器变成了一个有点可怕的调试器,来显示TEXtenSionCOntroIBIoCk中的所有字段。这里有一个程序,由Borland公司的DannyThorpe编写,他会执行这个任务:librarytestl;usesWindows,SysUtils,HTTPExt;functionGetExtensionVersion(varVer:THSEVERS10N_INFO):BOO1.;Stdcall;beginVer.dwExtensionVersion:=$00010000;/1.0supportVer.IpszExtensionDesc:=,testD1.1.writteninDelphi2.0,;Result:=True;end;functionHttpExtensionProc(varECB:TEXTENSION_CONTRO1._B1.OCK):DWORD;stdcall;varResStr:string;Str1.en:Integer;Buf:array0.1024ofChar;beginECB.Ipsz1.ogData:=,DelphiD1.1.1.og,;ECB.dwIITTPStatusCode:=200;ResStr:=Format(,<HTM1.><TlT1.E>Testserverresult<TIT1.E>>+,<Hl>Testserverresults<Hl>,+,Size=%d<BR>>+,Version=%.8x<BR>>+,ConnID=%.8x<BR>>+,Method=%s<BR>,+'Query=%s<BR>>+,Pathlnfo=%s<BR>>+,PathTranslated=%s<BR>,+,TotalBytes=%d<BR>,+,AvailableBytes=%d<BR>>+'ContentType=%s<BR><BR>>+,<Hl>SomeServerVariables<Hl>>,ECB.cbSize,ECB.dwVersion,ECB.ConnlD,ECB.IpszMethod,ECB.IpszQueryString,ECB.IpszPathInfo,ECB.IpszPathTranslated,ECB.CbTotalBytes,ECB.cbvailable,ECB.IpszContentType);withECBdobeginStr1.en:=Sizeof(Buf);GetServerVariable(ConnID,REMOTEADDR,Buf,Str1.en);ResStr:=ResStr+,REMOTEADDR=,+Buf÷,<BR>>Str1.en:=SizeOf(Buf);GetServerVariable(ConnID,REMOTEHOST*,Buf,Str1.en);ResStr:=ResStr+,RemoteHost='+Buf+'<BR>'Str1.en:=SizeOf(Buf);GetServerVariable(ConnID,'REUOTEuSER',Buf,Str1.en);ResStr:=ResStr+,Remote_(Jser='+Buf+'<BR>'Str1.en:=SizeOf(Buf);GetServerVariable(ConnID,SERVERNAMEf,Buf,Str1.en);ResStr:=ResStr+,SERVER_NAME='+Buf+'<BR>'Str1.en:=SizeOf(Buf);GetServerVariable(ConnID,'SERVER_PORT',BUf,Str1.en);ResStr:=ResStr+'SERVER_PORT=,+Buf÷,<BR>>Str1.en:=SizeOf(Buf);GetServerVariable(ConnID,'SERVEI1.PRoTOCo1.',©Buf,Str1.en);ResStr:=ResStr+'SERVEi1.PROTOCO1.='+Buf+'<BR>'Str1.en:=SizeOf(Buf);GetServerVariable(ConnlD,SERVERSOETWARE,©Buf,Str1.en);ResStr:=Format(,%sSERVER_SOFTWARE=%s<BR>,+,ThreadID=%.8x<BR>,ResStr,Buf,GetCurrentThreadID);end;ResStr:=ResStr+,<HTM1.>>ResStr:=Format(,HTTP1.O2000K'#13#10+,Content-Type:texthtm#13#10+,Content-1.ength:%d,#13#10+,Content:,#13#10#13#10*%s*,1.ength(ResStr),ResStr);Str1.en:=1.ength(ResStr);ECB.WriteClient(ECB.ConnID,Pointer(ResStr),S,O);Result:=HSE_STATUS_SUCCESS;end;exportsGetExtensionVersion,HttpExtensionProc;beginend.为了调用这个D1.1.,您应该建立一个包括下面这行的HRM1.脚本<AHREF=VscriptsZmystuffZtestl.dll*>TestOne<A><BR>从“确认”按钮获得信息通常向您发送信息的HTM1.窗体中都有一个确认按钮。只要信息量小于49KB,您就可以认为TEXetCnSiOnControIBIOCk中的IPbData字段是可用的。这里显示了您可以如何在大多数情况下获得由这个字段的指针发来的信息:var5: string;beginS:=PChar(ECB.IpbData);end;如果从这个字段传来的信息大于48KB,那么您必须呼叫ReadClient来获得其余的信息。如果您想要确切地知道在IPbData字段中哪些信息是可用的,您可以使用下面两个函数把数据传回到您的网页浏览器中:functionSetUpResString:string;beginResult:=><HTM1.>>+,<TIT1.E>Testserverresult<TIT1.E>>+,<Hl>Testserverresults<Hl>>+,<BODY>IpbData=%s<BODY>>+,<HTM1.>>end;functionHttpExtensionProc(varECB:TExtensionControlBlock):DWORD;stdcall;varResStr:string;Str1.en:Integer;S,Sl:string;beginECB.Ipsz1.ogData:=,DelphiD1.1.1.og,;ECB.dwIITTPStatusCode:=200;ResStr:=SetUpResString;S:=PChar(ECB.IpbData);ResStr:=Format(ResStr,S);Str1.en:=1.ength(ResStr);ECB.WriteClient(ECB.ConnID,Pointer(ResStr),Str1.en,0);Result:=HSE_STATUS_SUCCESS;end;假设您已经有了附有下面代码的HTM1.窗体:<FORMACTT0N=,7scriptsmystuffisapi2.dllz,METUOD=,POST,ENCTYPE=*app1ication/X-WwW-form-ur1encoded”><P>EnterNumbertoSquare:<INPUTNAUE="GetSquare"VA1.UE="”MAX1.ENGTH="25"SIZE=25><P><INPUTTYPE=SUBMITVA1.UE="Submit"NAME="GetSquare”><FORM>这段代码会产生一个包含一个供您输入数字的文本区和一个叫做“submit”按钮的窗体,按钮的名字叫做“GetSquare"。如果有了这个窗体,接着您可以预计上面的两段程序会返回如下的字符串,假设用户在窗体中的文本区输入了数字23:IpbData=GetSquare=23feGetSquare=Submit为了理解这时究竟发生了什么,注意一下从上面函数中摘录HTM1.语句中的主体部分,这部分语句驻留在服务器上,反映如下:,<BODY>IpbData=%s<BODY>>+如果您研究过上面HttpExtensionProc函数中的代码,您会发现就在这句之前,它使用了Format语句中的%s参数来代替了ECB.IpbData中的值。(如果您不清楚语句Format是怎样工作的,请参阅有关的Delphi文档)注:在作者所著的Delphi2编程大全(Delphi2Unleashed)中的第三章字符串与文本文件中有详细说明(译者)假设上面所示的窗体中,当用户按下“确认”按钮时,IpbData传递给ISAPID1.1.的值是:GetSquare=23&GetSquare=Submit为了让您有清晰的概念,让我重复一下上面两个语句传回给浏览器的信息是下面的字符串,您已经看过了:IpbData=GetSquare=23&GetSquare=Submit观看这个过程的最好办法试运行下面列出的ISAPI2程序。ISAPI2和ISAPIl差不多,但他包含了上面显示的新的HttpExtensionProc函数,并且它还包含了SetlpResString这个实用函数。libraryIsapi2;usesWindows,SysUtils,HTTPExt;functionGetExtensionVersion(var