说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

DELPHI与INTERNET(一)

HTML文档下载 WORD文档下载 PDF文档下载
DELPHI与INTERNET(一)

这篇文章主要讲述如何使DELPHI和因特网配合工作。本文中将详述两个专门技术:

WININET:构建 FTP,HTTP 和 Gopher 用户端程序 ISAPI:扩充因特网信息服务,例如,获得服务器上的信息并把它们显示在浏览器上。

现今的计算机世界中,由于微软公司的因特网战略而掀起了一个巨大发展潮流。那些制作

CGI(公共网关接口)和第三方工具(即使是最基本的因特网工具)的日子将最终一去不复返了。对复杂的第三方工具的需求总是存在的,但现在程序员将会发现他们所需的大量的嵌入操作系统的因特网工具,简言之,并不需要进一步的投资,你就能够使用免费的DELPHI资源来:

*开发 WEB 浏览器

*运行 FTP,HTTP 和 Gopher ,在两个DELPHI应用软件之间或DELPHI应用软件和基于TCP

(传输控制协议)的服务器之间操作TCP

因为DELPHI能够轻松地调用Windows API,并且它支持OCX/ActiveX,因此微软的新战

略和我们的计划配合的恰到好处。微软生产工具,而DELPHI程序员获得收成!

在本篇中有些什么?

这篇文章中包含了三个大部分和一些小部分,有三个大主题:

*寻找资料:那里能搞到本文中提及的技术资料,而且包含了关于您所需的运行文中代码 的软硬件的简短说明。

*ISAPI:怎样使用ISAPI

*WININET:怎样使用WININET

在大多数情况下,本文中的ISAPI和WININET部分是完全独立的,您可以自由地选择阅读时的顺序。

查找资料,硬件和软件的要求

您需要一份Microsoft Windows NT 3.51 Server 或 NT 4.0 Server 的拷贝,其中应附有因特网信息服务文档,因为您需要甬道其中所提到的技术。这份文档应随NT Server4.0 附送,NT 3.51的用户可从微软的网址上下载。运行Windows NT,您的机器的最低配置应为486兼容,20兆以上内存。

您必须有另一台计算机装有网页浏览器。为使本文中的ISAPI部分能够顺利运行,第二台

机器必须能够运行所有支持网页浏览器的软件。如果在您的机器上运行的是Windows 95 或 Windows NT

那么本文中的WININET 代码片就能运行的最好。任何符合条件的网页浏览器在这种技术环境下都能够使用。

在1996年六月以后发布的Delphi2.0以上的版本中,有您所需的把Delphi连接到因特网上

的几乎全部资源。

如果您没有最新的Delphi版本[注:此处作者指的是2.0版本(译者)],那么您需要本文

档中提到的特殊文件,所有这些几乎都可以从万维网上免费获得[注:如果您正在使用Delphi2.0以上版本,则不许考虑(译者)]。所有本文中提到的技术在Delphi2.0环境下都能顺利工作,但在16位Delphi环境下则不一定能顺利工作。

如果您需要从万维网上下载信息,链接为:http://www.borland.com/TechInfo/delphi/i

ndex.html

[注:现在已经不存在了!:-(( (译者)]

Delphi2.0的新版本中附有 WININET.PAS 文档,如果你的拷贝中不包含它,那么上面那个

万维网节点可以为您提供。WININET.PAS包括为扩展微软视窗因特网所设计的变量清单、函数、类型和属性。这意味着您能够轻而易举地为您的应用程序增添FTP、HTTP和Gopher支持。微软公司的WININET.DLL是免费发布的,如果它不在您的Windows/System 或Windows/System32 目录下的话,您可以从微软公司那里得到它。下面是可获得WININET.H这个视窗帮助文件的万维网节点:

http://www.microsoft.com/intdev/sdk/docs/wininet/default.htm [注:好象也没了!: -( (译者)]

一般来说,微软因特网开发者的网上之家是微软节点的 INTDEV 部分。

除了WININET和ICP之外,另一个为Delphi支持的关键技术就是ISAP。正如微软公司文档中

所描述的,这项技术能使您“‘写入’服务器端的原本和过滤本,从而扩充微软因特网信息服务和其他ISAPI万维网服务”。

如果您需要找到关于ISAPI的描述,可以去:

http://www.microsoft.com/intdev/sdk/servapi.htm [注:上帝保佑您!;-) (译者)]

在本文最后,附加了一个名为HTTPEXT.PAS的关键的ISAPI文档的拷贝。

微软公司免费发布的因特网控制包(ICP)是一个OCX/ActiveX控制集,您可以在Delphi中

把它们拖放到应用程序上(Delphi2.0中包含这些控件)。他们提供了创建Delphi应用程序的即时支持,他们知道如何浏览网页、 如何应用FTP、WINSOCK和其他因特网技术。如果您的Delphi拷贝中没有包含这些控件,那么您在使用它们之前您应该把这些文档添加进Delphi所在的目录中的Lib目录下。这些文档位于上面提及的链接中的Borland的INDEX.HTML站点下。在本文中我没有提到ICP控件,但是任何对这项技术有兴趣的人应该明确确认他拥有这些

控件的拷贝。

您可以从我的站点下载我的Pascal应用文件,他们的名字是STRBOX.PAS 和 MATHBOX.PAS 。

经常察看一下这个站点上的关于本文提到的信息的更新情况是很有好处的。

在这里我假设读者对于Delphi和Object Pascal都很熟悉,并且读者对于因特网,HTML,

浏览器和万维网服务器有基本的了解。

ISAPI

ISAPI是一项很容易使用然而功能强大的技术,它能够让您扩充因特网信息服务的功能。

这项技术随WindowsNT 4.0附送,让您在您的服务器上建立WEB、FTP和GOPHER站点。同时这项技术与WindowsNT3.51 Server[注:指服务器版本,另一个版本是工作站版本(译者)]兼容。

在过去,扩充网页服务器的最佳办法是建立CGI应用程序。它们是强有力的工具,但是也

被他们的执行格式所限制[注:如PERL是解释执行的(译者)]。当您从浏览其上发出一个基于CGI的请求到服务器上时,这个CGI 应用程序将极有可能先被强制装入内存中,这会消耗很多时间。而且,在某些环境下, CGI技术显得稍微难用了一点。

ISAPI是一种通过写入DLLs[注:动态链结程序(译者)]从而替代CGI应用的方法。您也可

以通过ISAPI来写过滤文本,但这项技术我不会在本篇中提及。同CGI相比,ISAPI更容易使用,而且它更快,同时能更好地利用系统资源。在下面几点中,我将详细地介绍为什么ISAPI DLLs比CGI应用要更为出色:

ISAPI DLLs与HTTP服务位于相同的地址,因此他们能够从服务器上直接存取HTTP服务。与CGI应用相比,它们 能更快地装入内存;当他们在服务器上发出请求时,所需的停悬的时间[注:指发出请求到接受服务器应答的时间(译者)]要少的多。这点当服务器的负荷很重时更加重要。

您可以控制DLLs何时被装载和卸载。例如:您可以在第一次尝试请求时预先装载DLLs;当

它们不被使用时卸载 这个ISAPI应用DLLs以便释放系统资源。

正如前文所述,您可以利用ISAPI写过滤文本[注:一般指C/S结构中的脚本(译者)],更

具微软的文档,您可以通过ISAPI过滤文本做下面这些事情:

用户授权方案

压缩

加密

登入

通信分析或其他请求分析(例如,寻找 "..\..\etc\password" 中的请求)

在本文中,我会着重介绍如何编写返回数据集的DLLs,或者是如何与运行浏览器的用户进

行简单的联系。

ISAPI 基础

HTTPEXT.PAS文件包含了使用ISAPI的关键声明。这个文件应随1996年6月以后发表的

Delphi版本分发。它也可以在Borland的站点上找到,在本文的ISAPI部分附有这份文档。因为这是基于NT的技术, 您必须使用Delphi2.0以上的版本来应用这项技术。您不可能在16位的编辑器上应用它。

HTTPEXT.PAS包含了微软公司创立的ISAPI技术的接口[注:指Delphi接口,ISAPI由C++编

写(译者)]。在编写Delphi的时候并没有提供ISAPI的用户接口,我会仅仅就如何使用微软公司的现有技术进行描述。不过,ISAPI 太容易使用了,而且对大多数用户来说,用户的Delphi对象的版本并不是必须的。

有三个函数可作为ISAPI DLLs的入口,前两个是必须的,第三个时可选的。

GetExtensionVersion: 进对最低版本做检查

HttpExtensionProc: 这是DLL的入口,就象是Delphi应用程序中的 begin...end 块

TerminateExtension: 这是个可选的程序,它可以用作清除其他内存分配的线程。

当您在创建ISAPI DLL的时候,您必须引用上面列出的三个函数中的头两个函数,执行这

两个函数是所有ISAPI编程的关键。

这三个语句都包含了“字输出”,使用这项术语是因为ISAPI DLLs扩充了因特网信息服务

器。(记住,因特网信息服务器指的是微软服务器。如果您要把一台NT服务器作为体格网页服务器的话,那么,这正是您所需的工具。ISAPI DLLs随NT4.0分发,在安装操作系统是自动安装。)

ISAPI提供了一个制作服务器可遵循的标准。例如,它可以把网景公司的复杂的NSAPI接口

压缩至相关的简练而优美的ISAPI来对NSAPI接口进行操作。

下面是这两个重要函数的声明

function GetExtensionVersion(var Ver: THSE_VERSION_INFO): BOOL; stdcall;

function HttpExtensionProc(var ECB: TExtensionControlBlock): DWORD; stdcall;

您只要把GetExtensionVersion粘贴到您的DLLs救行了.当ISAPI向公众发布新版本时您只需要做轻微的改动。

function GetExtensionVersion(var Ver: THSE_VERSION_INFO):

BOOL; stdcall;

begin

Ver.dwExtensionVersion := $00010000; // 1.0 support

Ver.lpszExtensionDesc := 'Delphi 2.0 ISAPI DLL'; // Description

Result := True;

end;

The parameter passed to this function is declared in HTTPEXT.PAS as follows:

有关的参数在HTTPEXT.PAS中声明如下:

PHSE_VERSION_INFO = ^THSE_VERSION_INFO;

THSE_VERSION_INFO = packed record

dwExtensionVersion: DWORD;

lpszExtensionDesc: array[0..HseMaxExtDLLNameLen-1] of Char;

end;

常量HseMaxExtDllNameLen 在声明中的值为256。纪录中的这两个变量是“自声明”的, 前一个包含了ISAPI的版本号[注:即变量dwExtensionVersion (译者)],后一个则表示用户定义的一个用来描述DLLs的字符串。

在您引用GetExtensionVersion语句的同时,您必须在您的DLL程序的DPR文件部分增添输

出部分。在您写这段语句时您还应该写下:

exports

GetExtensionVersion

HttpExtensionProc;

这就是您在建立这两个重要ISAPI DLL的函数时所要做的。下一步,使用 HttpExtensionProc,稍微复杂一点,因此我将把它作为一个独立的部分。

与 HttpExtensionProc 一起工作

HttpExtensionProc语句是DLL的入口。它的作用就好比C语言中的 main() 语句,或者

Delphi 中的begin...end 部分

这里有一个简单的使用GetExtensionVersion语句的例子

function HttpExtensionProc(var ECB: TExtensionControlBlock):

DWORD; stdcall;

var

ResStr: string;

StrLen: Integer;

begin

ECB.lpszLogData := 'Delphi DLL Log';

ECB.dwHTTPStatusCode := 200;

ResStr := 'Test server result' +

'

Test server results

' +

'Hello from ISAPI
' +

'';

ResStr := Format(

'HTTP/1.0 200 OK'#13#10+

'Content-Type: text/html'#13#10+

'Content-Length: %d'#13#10+

'Content:'#13#10#13#10'%s'

[Length(ResStr)

ResStr]);

StrLen := Length(ResStr);

ECB.WriteClient(ECB.ConnID

Pointer(ResStr)

StrLen

0);

Result := HSE_STATUS_SUCCESS;

end;

如果您在浏览其中向这个DLL发出请求,那么您会得到一页这样的回应:

Test Server Results

Hello from ISAPI

函数体内的大部分域提供基本信息的简单的HTML代码密切相关。您还需要填写TExtensionControlBlock中的一些域,如下所示。

注意到在这个纪录里有一个叫做WriteClient的函数指针,您可以引用这个函数把信息传

送回浏览器。当呼叫这个函数时,您使用到了下面提到的TExtensionControl块中的ConnID字段。当函数被呼叫时,ConnID为您自动填充。

在察看函数的代码之前,请让我为您演示所有用到的上文提及的HttpExtensionProc函数

的ISAPI DLL的完整程序

library Isapi1;

library Isapi1;

uses

Windows

SysUtils

HTTPExt;

function GetExtensionVersion( var Ver: THSE_VERSION_INFO ): BOOL; stdcall;

begin

Ver.dwExtensionVersion := $00010000; // We're expecting version 1.0 support

Ver.lpszExtensionDesc := 'Written in Delphi 2.0';

Result := True;

end;

function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ): DWORD;

stdcall;

var

ResStr: string;

StrLen: Integer;

begin

ECB.lpszLogData := 'Delphi DLL Log';

ECB.dwHTTPStatusCode := 200;

ResStr := '

' +

'

Test server results

' +

'

Isapi says hello to DevRel

';

ResStr := Format(

'HTTP/1.0 200 OK'#13#10+

'Content-Type: text/html'#13#10+

'Content-Length: %d'#13#10+

'Content:'#13#10#13#10'%s'

[Length(ResStr)

ResStr]);

StrLen := Length(ResStr);

ECB.WriteClient(ECB.ConnID

Pointer(ResStr)

StrLen

0);

Result := HSE_STATUS_SUCCESS;

end;

exports

GetExtensionVersion

HttpExtensionProc;

begin

end.

为了运行这个DLL程序,您应该把它复制到您的NT服务器下的脚本目录中去。在我的NT4.0 机器中

它就像这样:

c:\winnt\system32\inetsrv\scripts\mystuff\isapi1.dll

在这个例子中,我已经创建了我的名为“mystuff”的目录

它只不过是用来存储我创建的

ISAPI DLLs。您的目录,当然和我的机器上的不完全一样,取决于您的“inetsrv”目录位置和其它因素。

为成功调用这个DLL,您应该在您的HTML页上增添这个超链接:

ISAPI One

当用户点击这个超链接时,ISAPI1 Dll会被呼叫,然后字符串“Hello from ISAPI”会显

示在用户的浏览器上。如果您并不是把 ISAPI.DLL放在 mystuff 目录下,那么您应该修改上面的HTML代码来使之与您的情况适应。注意,您的目录必须与目录 inetsrv 有关,不应,也不能包含您的整个DLL所在的目录。

下面是呼叫的完整的HTML脚本:

CharlieC Home Page

My Home Page

This is the home page for my home computer.

ISAPI One

注意,如果您多次把程序ISAPI1.DLL复制到 mystuff 目录下,在每一次复制之前您应该

关掉网络服务器的万维网端口。这是因为,在第一次复制这个DLL时,您可以不受限制,但在此之后,它就属于服务器了。因此,在您复制第一次拷贝的更新版本时,因当关掉万维网服务。您可以使用网络管理程序来关掉万维网服务。这个程序应该在微软网络管理程序组(Microsoft Internet Server group)下面,在安装网络信息服务时被安装到程序管理器(Explorer/Program Manager)下。

与 TExtensionControlBlock 一起工作

通过本文中的这一要点,您能够建立您的第一个ISAPI DLL,并且能在第二台机器上的网

页浏览器调用它。

在本文中接下来的ISAPI的其余部分将会更加深入。

这里是HttpExtensionProc参数中比较复杂的部分

PExtensionControlBlock = ^TExtensionControlBlock;

TExtensionControlBlock = packed record

cbSize: DWORD; // = sizeof(TExtensionControlBlock)

dwVersion: DWORD; // version info of this spec

ConnID: HCONN; // Context Do not modify!

dwHttpStatusCode: DWORD; // HTTP Status code

// null terminated log info specific to this Extension DLL

lpszLogData: array [0..HSE_LOG_BUFFER_LEN-1] of Char;

lpszMethod: PChar; // REQUEST_METHOD

lpszQueryString: PChar; // QUERY_STRING

lpszPathInfo: PChar; // PATH_INFO

lpszPathTranslated: PChar; // PATH_TRANSLATED

cbTotalBytes: DWORD; // Total bytes from client

cbAvailable: DWORD; // Available number of bytes

lpbData: Pointer; // pointer to cbAvailable bytes

lpszContentType: PChar; // Content type of client data

GetServerVariable: TGetServerVariableProc;

WriteClient: TWriteClientProc;

ReadClient: TReadClientProc;

ServerSupportFunction: TServerSupportFunctionProc;

end;

注意到这个纪录中包含了上面提到过的ConnID字段,并且向 WriteClient 传送第一个参数。

这个纪录中的第一个参数是为版本控制而设的。它应该是TExtensionControlBlock的大小的规定。如果微软公司改变了它的结构,那么它们能够通过检查纪录的大小来判断它们正在处理的结构版本。 您永远也不要这个纪录中的前三个字段,它们早已被ISAPI填充,在您的程序中,它们只能被访问,而不能被改变。

这个纪录中最重要的字段可能就是lpszQueryString了,它包含了从服务器上传来的请求

的信息。例如,假设您已经创建了一个名叫 ISAPI1.Dll。为了调用这个DLL,您就要在您的浏览器的一页上创建一个像这样的HREF [注:HTML语言中的一种格式(译者)] :

Test One

如果您希望响应这个DLL,您就要对上面那行做这样的改动:

Test One

假如HTML代码段中有像上面两行中的第二行,那么,您的DLL就会在lpszQueryString参数

中得到“MyQuery” 的字符串,特别要注意跟在请求字符串后的请求标志的使用。

当然,您可以随心所欲地改变请求字符串。例如,您可以这样写:

Test One

在这个请求中,这个DLL会回答服务器的名称。您在传递这个参数时,不受任何限制。您

可以传递任何您想要的东西,而且,如何分析DLL中的信息也由您的喜好决定。

当您从服务器返回信息至浏览器时,您使用到了这个纪录中的“WriteClient”函数指针

。在初始化这个指针时您不需做任何事;它已经自动地有网络信息服务器传递给您了。

CGI应用程序的作者会注意到传送请求字符串的语法十分熟悉。事实上,ISAPI跟随了CGI

的大多数习惯,在TExtensionControlBlock中的多数字段可以简单地被CGI技术借用。

在TExtensionControlBlock中的另一个关键字段是 lpbData ,它包含了从浏览起上传给您的附加信息。

例如,您有一个伴随几个字段的HTML窗体,这些自断中包含的信息就会被一个叫做“

lpData”的指针传递。本文中的下一个主题,“从‘确认’按钮中获得信息”,将会着重讲述怎样处理这种情况。

到现在为止我已经介绍了TExtensionControlBlock中的四个关键字段:

WriteClient: 一个能够让您传递格式化的HTML数据到浏览器上的指针。这个函数用到了

TExtensionControlBlock的ConnID字段。

lpszQueryString: 从浏览骑上传来的请求。

lpbData: 从浏览器上传给你的人一的附加数据。通常是一个HTML窗体的任意字段的内容

。我将在“确认 按钮”这部分进一步讨论。

要获得其他TExtensionControlBlock中的字段是如何工作的感觉,最好的办法就是亲自在

浏览其中将他们做对照。换句话说,您会希望创建一个HTML页,使得用能够调用客户端的ISAPI DLL。这个ISAPI DLL的目的仅仅是在HTML中格式话TExtensionControlBlock中的每一个字段,然后把它们传回浏览器。这样就把您的浏览器变成了一个有点可怕的调试器,来显示TExtensionControlBlock中的所有字段。

这里有一个程序,由Borland公司的 Danny Thorpe 编写,他会执行这个任务:

library test1;

uses

Windows

SysUtils

HTTPExt;

function GetExtensionVersion( var Ver: THSE_VERSION_INFO ): BOOL; stdcall;

begin

Ver.dwExtensionVersion := $00010000; // 1.0 support

Ver.lpszExtensionDesc := 'A test DLL written in Delphi 2.0';

Result := True;

end;

function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ):

DWORD; stdcall;

var

ResStr: string;

StrLen: Integer;

Buf: array [0..1024] of Char;

begin

ECB.lpszLogData := 'Delphi DLL Log';

ECB.dwHTTPStatusCode := 200;

ResStr := Format(

'Test server result' +

'

Test server results

' +

'Size = %d
'+

'Version = %.8x
'+

'ConnID = %.8x
'+

'Method = %s
' +

'Query = %s
' +

'PathInfo = %s
'+

'PathTranslated = %s
'+

'TotalBytes = %d
'+

'AvailableBytes = %d
'+

'ContentType = %s

'+

'

Some Server Variables

'

[ECB.cbSize

ECB.dwVersion

ECB.ConnID

ECB.lpszMethod

ECB.lpszQueryString

ECB.lpszPathInfo

ECB.lpszPathTranslated

ECB.cbTotalBytes

ECB.cbAvailable

ECB.lpszContentType]);

with ECB do

begin

StrLen := Sizeof(Buf);

GetServerVariable(ConnID

'REMOTE_ADDR'

@Buf

StrLen);

ResStr := ResStr + 'REMOTE_ADDR = '+Buf+'
';

StrLen := SizeOf(Buf);

GetServerVariable(ConnID

'REMOTE_HOST'

@Buf

StrLen);

ResStr := ResStr + 'Remote_Host = '+Buf+'
';

StrLen := SizeOf(Buf);

GetServerVariable(ConnID

'REMOTE_USER'

@Buf

StrLen);

ResStr := ResStr + 'Remote_User = '+Buf+'
';

StrLen := SizeOf(Buf);

GetServerVariable(ConnID

'SERVER_NAME'

@Buf

StrLen);

ResStr := ResStr + 'SERVER_NAME = '+Buf+'
';

StrLen := SizeOf(Buf);

GetServerVariable(ConnID

'SERVER_PORT'

@Buf

StrLen);

ResStr := ResStr + 'SERVER_PORT = '+Buf+'
';

StrLen := SizeOf(Buf);

GetServerVariable(ConnID

'SERVER_PROTOCOL'

@Buf

StrLen);

ResStr := ResStr + 'SERVER_PROTOCOL = '+Buf+'
';

StrLen := SizeOf(Buf);

GetServerVariable(ConnID

'SERVER_SOFTWARE'

@Buf

StrLen);

ResStr := Format('%sSERVER_SOFTWARE = %s
'+

'ThreadID = %.8x
'

[ResStr

Buf

GetCurrentThreadID]);

end;

ResStr := ResStr + '';

ResStr := Format(

'HTTP/1.0 200 OK'#13#10+

'Content-Type: text/html'#13#10+

'Content-Length: %d'#13#10+

'Content:'#13#10#13#10'%s'

[Length(ResStr)

ResStr]);

StrLen := Length(ResStr);

ECB.WriteClient(ECB.ConnID

Pointer(ResStr)

StrLen

0);

Result := HSE_STATUS_SUCCESS;

end;

xports

GetExtensionVersion

HttpExtensionProc;

egin

end.

为了调用这个DLL,您应该建立一个包括下面这行的 HRML 脚本

Test One

从“确认”按钮获得信息

通常向您发送信息的HTML窗体中都有一个确认按钮。只要信息量小于49KB,您就可以

认为TExetensionControlBlock中的 lpbData 字段是可用的。这里显示了您可以如何在大

多数情况下获得由这个字段的指针发来的信息:

var

S: string;

begin

S := PChar(ECB.lpbData);

end;

如果从这个字段传来的信息大于48KB,那么您必须呼叫 ReadClient 来获得其余的信息。

如果您想要确切地知道在 lpbData 字段中哪些信息是可用的,您可以使用下面两个函数把数据传回到您的网页浏览器中:

function SetUpResString: string;

begin

Result := '' +

'Test server result' +

'

Test server results

' +

'lpbData = %s ' +

'';

end;

function HttpExtensionProc(var ECB: TExtensionControlBlock):

DWORD; stdcall;

var

ResStr: string;

StrLen: Integer;

S

S1: string;

begin

ECB.lpszLogData := 'Delphi DLL Log';

ECB.dwHTTPStatusCode := 200;

ResStr := SetUpResString;

S := PChar(ECB.lpbData);

ResStr := Format(ResStr

[S]);

StrLen := Length(ResStr);

ECB.WriteClient(ECB.ConnID

Pointer(ResStr)

StrLen

0);

Result := HSE_STATUS_SUCCESS;

end;

假设您已经有了附有下面代码的HTML窗体:

ENCTYPE="application/x-www-form-urlencoded">

Enter Number to Square:

MAXLENGTH="25" SIZE=25>

这段代码会产生一个包含一个供您输入数字的文本区和一个叫做“submit”按钮的窗体,按钮的名字叫做“GetSquare”。如果有了这个窗体,接着您可以预计上面的两段程序会返回如下的字符串,假设用户在窗体中的文本区输入了数字23:

lpbData = GetSquare=23&GetSquare=Submit

为了理解这时究竟发生了什么,注意一下从上面函数中摘录HTML语句中的主体部分, 这部分语句驻留在服务器上,反映如下:

'lpbData = %s ' +

如果您研究过上面 HttpExtensionProc 函数中的代码,您会发现就在这句之前,它使用了 Format 语句中的 %s 参数来代替了 ECB.lpbData 中的值。(如果您不清楚语句Format 是怎样工作的,请参阅有关的 Delphi 文档)[注:在作者所著的 Delphi2 编程大全(Delphi2

Unleashed)中的第三章《字符串与文本文件》中有详细说明(译者)]

假设上面所示的窗体中,当用户按下“确认”按钮时,lpbData 传递给ISAPI DLL的值是:

GetSquare=23&GetSquare=Submit

为了让您有清晰的概念,让我重复一下上面两个语句传回给浏览器的信息是下面的字符串,您已经看过了:

lpbData = GetSquare=23&GetSquare=Submit

观看这个过程的最好办法试运行下面列出的 ISAPI2 程序。 ISAPI2 和ISAPI1 差不多,但他包含了上面显示的新的 HttpExtensionProc 函数,并且它还包含了SetUpResString 这个实用函数。

library Isapi2;

uses

Windows

SysUtils

HTTPExt;

function GetExtensionVersion( var Ver: THSE_VERSION_INFO ):

BOOL; stdcall;

begin

Ver.dwExtensionVersion := $00010000; // 1.0 support

Ver.lpszExtensionDesc := 'DLL written in Delphi 2.0';

Result := True;

end;

function SetUpResString: string;

begin

Result := '' +

'Test server result' +

'

Test server results

' +

'lpbData = %s ' +

'';

end;

function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ):

DWORD; stdcall;

var

ResStr: string;

StrLen: Integer;

S

S1: string;

Len: Integer;

begin

ECB.lpszLogData := 'Delphi DLL Log';

ECB.dwHTTPStatusCode := 200;

ResStr := SetUpResString;

S := PChar(ECB.lpbData);

ResStr := Format(ResStr

[S]);

StrLen := Length(ResStr);

ECB.WriteClient(ECB.ConnID

Pointer(ResStr)

StrLen

0);

Result := HSE_STATUS_SUCCESS;

end;

exports

GetExtensionVersion

HttpExtensionProc;

begin

end.

一旦您从窗体中获得了由 lpbData 变量传来的信息,您就能分析这些信息或者把它们返回给用户。比如说,您可以从上面例子中把数字23抽出来,做平方后返回用户。通过这样做可以使您从用户中获得信息,在这里是数字,对数字进行一些数学运算,最后把结果返回给用户。这意味着您可以在电波中创建互动的网页,这可是现在因特网编程中最流行的哦!

以下是一个通过网络提交数字平方给浏览器的完整的程序代码:

library Isapi3;

{ This code shows how to take input from the user via a browser

parse that information

and then return an answer to the user. In particular

the user submits a number

this code squares it

and then sends the result back to user. Here is the form from the browser that submits the information for parsing:

ENCTYPE="application/x-www-form-urlencoded">

Enter Number to Square:

MAXLENGTH="25" SIZE=25>

}

uses

Windows

SysUtils

HTTPExt

StrBox;

function GetExtensionVersion( var Ver: THSE_VERSION_INFO ):

BOOL; stdcall;

begin

Ver.dwExtensionVersion := $00010000; // version 1.0 support

Ver.lpszExtensionDesc := 'ISAPI3.DLL';

Result := True;

end;

// Parse lpbData and retrieve the number the user passed to us.

function ParseData(S: string): Integer;

begin

S := StripLastToken(S

'&');

S := StripFirstToken(S

'=');

Result := StrToInt(S);

end;

function SetUpResString: string;

begin

Result := '' +

'Test server result' +

'

Test server results

' +

'Answer = %d ' +

'';

end;

function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ):

DWORD; stdcall;

var

ResStr: string;

StrLen: Integer;

S

S1: string;

Num: Integer;

begin

ECB.lpszLogData := 'Delphi DLL Log';

ECB.dwHTTPStatusCode := 200;

ResStr := SetUpResString;

S := PChar(ECB.lpbData);

Num := ParseData(S);

Num := Sqr(Num);

ResStr := Format(ResStr

[Num]);

StrLen := Length(ResStr);

ECB.WriteClient(ECB.ConnID

Pointer(ResStr)

StrLen

0);

Result := HSE_STATUS_SUCCESS;

end;

exports

GetExtensionVersion

HttpExtensionProc;

begin

end.

这段代码从按下确认按钮的用户那里接受下面的字符串,用户要求平方后的数字:

GetSquare=5&GetSquare=Submit

假设这样输入,这段代码会通过因特网返回用户下面的字符串:

Answer = 25

一句话,用户输入数字5,你返回用户数字25。如果用户提交数字10,那么您返回数字100。这看起来微不足道,但在这里重要的是因特网上发生的行为[注:指互动网页(译

者)]

分析用户传来的函数像这样:

// Parse lpbData and retrieve the number the user passed to us.

function ParseData(S: string): Integer;

begin

S := StripLastToken(S

'&');

S := StripFirstToken(S

'=');

Result := StrToInt(S);

end;

这两个语句在单元中,在本文开头提到过,也包含在我的站点上。[注:这个文件在网络上几乎到处可见

您也可以向译者索取(译者)][ 在本篇文章中

关于ISAPI我只想谈这么多了。这些内容对于启发您利用这项优越的技术并获得乐趣来说应该是够用的了。接下来我要谈一下 GetServerVariable 、 ReadClient 这两个语句,在这方面我只进行了极其有限的试验。在本文中,我附加了HTTPEXT.PAS 文件,因为除了这分关键文档,在其他地方您不会找到它。

GetServerVariable 和 ReadClient 语句

正如您的CGI应用程序中的请求信息一样,您可以使用语句来从服务器上获得信息。 下面是呼叫这个语句的例子:

Len := HseMaxExtDllNameLen;

SetLength(S1

Len);

Dec(Len);

ECB.GetServerVariable(ECB.ConnID

'CONTENT_LENGTH'

PChar(S1)

Len);

首先,这段代码设定了保留从服务器上取得的信息的缓冲区的长度。接着它呼叫服务 器并发出请求,在本例中,它要求获得服务器传来的信息的"CONTENT_LENGTH"。

微软公司的文献告诉我们,您可以通过 GetServerVariable 的第二个参数来传递跟 着的字符串:

AUTH_TYPE 它包含了使用授权的类型。比如,如果使用的是基本(basic)授权,那么

字符串就是"basic";如果是 NT challenge 回应,字符串就是"NTLM"。其他的授权属尤其对应的字符串。因为不断有新的授权类型被增添到服务器上,列出所有可能的字符串是不可行的。如果字符串为空,那么并没有使用任何授权。

CONTENT_LENGTH 脚本预计从客户端回收到的字节数。

CONTENT_TYPE 由请求布告的主体部分提供的信息的内容类型。[注:小弟才疏学浅,a

POST request 暂译作"请求布告",望方家指正(译者)]

PATH_INFO 附加的路由信息,由客户机提供。它包含了跟在脚本名字之后的URL的漫游路

由。如果有的话,它在请求字符串的前面。

PATH_TRANSLATED 它是 PATH_INFO 的值,但包含了扩充到一个路径标志的所有虚拟路由的名字。

QUERY_STRING 跟在参考这个脚本的URL中的"?"后面的信息。

REMOTE_ADDR 发出请求的客户机或其代理商(例如,网关或防火墙)的IP地址。

REMOTE_HOST 发出请求的客户机或其代理商(例如,网关或防火墙)的主机名。

REMOTE_USER 它包含了由客户机提供并且由服务器授权的用户名。如果返回空串那么用户

使你名的(但是经过授权)。

UNMAPPED_REMOTE_USER 它是有如下特征的用户的名称:该用户向NT用户帐目发出请求(这是他以身份出现),在此之前ISAPI应用程序过滤起映射了该用户。

REQUEST_METHOD 是 HTTP 请求方法。

SCRIPT_NAME 执行的脚本程序名称。

SERVER_NAME 当它以自参考URLs形式出现时的主机名或IP地址。

SERVER_PORT 接受请求的TCP/IP的端口。

SERVER_PORT_SECURE 一个非0即1的字符串。当请求由安全端口处理时,它是1;否则是0 。

SERVER_PROTOCOL 接受与这个请求相关的协议的信息的名称和版本。他通常是 HTTP/1.0 。

SERVER_SOFTWARE 是ISAPI应用DLL程序运行时所在的网页服务器的名称和版本。 ALL_HTTP 先前的变量并没有分析全部的HTTP字段头。这些变量从HTTP_<字段头名>中得出 。字段头(由行标分离)包含了各自的字符串,这些字符串并不会终止。

HTTP_ACCEPT HTTP字段头的特例。接受的值是:字段由逗号(,)分离。例如:如果下

面的几行是HTTP头的一部分:

接受:*/*,q=0.1

则URL(2.0新版本的特性)给出它的基础部分。

要注意的是,上面给出的信息片是由 TExtensionControlBlock 纪录自动传递的。因

此您不需要调用GetServerVariable。不过,如果您确有需要,特别是您要从ReadClient 中获得信息和需要知道要读入多少信息时,您可以调用它。

在很多时候,您不需要调用 ReadClient 。但是,您浏览器发出的信息量大于48KB

的时候,您需要调用 ReadClient 来获取其余的信息。

Windows 8.1重新推出的“开始按钮”毫无意义 手眼并用 代码泄露三种Google Glass手势操作 Google新论文 CPI²:基于Linux的世界级跨数据中心服务器CPU监控 20款非常实用的Web工具和资源列表 数据库界大事件 随机写性能巨好的TokuDB开源了 CMDN Club 26期:数字渠道营销主题沙龙 暴强:用iOS设备控制的HTML5“小蜜蜂”游戏 Leap Motion:500元体感,精确到0.01毫米 大事件:三大运营商将发布融合计费SDK 再培养一个扎克伯克:六款适合儿童上手编程的App 首届中国软件工程标准高峰论坛:软件开发的新机遇与挑战 Verizon研究显示:中国成为2012年度网络间谍攻击的主要来源 Clang宣布全面支持C++11标准 北大陈钟:SEMAT—中国软件工程发展的新机遇 超华尔街预期:苹果第二财季营收为436亿美元 跨平台游戏引擎Spaceport已被Facebook收购 文科生开发GPU数据库 性能超传统数据库70倍 开发者赚了90亿:从苹果Q2财报,看iOS生态 备受开发者青睐的13款热门开源项目 Netflix赌赢《纸牌屋》背后的秘密武器:大数据分析 为什么:Google Glass只能运行Web应用? 对话Rackspace高级副总裁Jim Curry:我们没有&quot;辜负&quot;营销炒作 7个大数据流言——避免错误的Hadoop和云分析决策 Facebook vs. Google:撇开搜索,数据中心产业上的又一竞技 苹果将于6月10日召开WWDC 新版OS X和iOS或将面世 传Amazon今年秋季发布电视机顶盒设备 够快:不会3种以上语言的程序员不是好程序员 Cloud Foundry、Greenplum获通用电气1亿美元注资 微软推超强Android应用Switch to Windows Phone Unity CEO宣布:放弃支持Flash平台 为交房租做App:我第一年赚了7万美金 怎样在程序运行时增加子菜单(要增加的数目是未知的) 关于Sprite动画 出售代码 ACCESS的FORMS DLL调用函数问题 VB在ACCESS中应用的一个小问题! ACCESS中的FORMS问题? 再普通不过的一个问题 delphi6中还有BDE和ADO吗?它们被淘汰了吗?现在还有必要用它们来学数据库的开发吗? 50分答谢!!!---这个css定义为什么会出现这样的效果??? 各位:怎么判断表里某个字段是否存在? 纯技术问题:精通“书签“与“层“的大虾请进!!!! 一个奇怪的现象,请教高手这是怎么回事? 哪里有破解清华五行卫士密码的软件? vc++7.0好用吗? 吃完晚饭了... 可不可以让 CppWebBrowser1的背景不是白色? 热热热!!!热疯了!!! 我的喇叭哪儿去了? 我的PB程序出了问题了!!! sql server中哪个函数是用于字符串与整型之间转换的? 我想限定文本输入框只能输入10个汉字或20个英文字符,但文件输入框却只能输入10个英文字符,如何解决? 当我将这样的字符串“dsdsdsdfsdffsdsdfsdfsfdsdfsdfsfsfdsdffs.....”放入我的表格中时,无论怎样设置也不折行,影响了部局,如何解决? MFC中视图(view)是怎样随着主窗口的大小改变而改变的。 急!请教!!猫猫连接,用数据管道同时访问两库,访问不到对方的网络库(sybase) 关于电影下载 我已经把一个exe文件加入到我自己的程序中了,请问在我的程序中应该样调用该exe文件呢? 哪位高手知道RTF格式的含义?或者更好,知道Rxlib中的RXRICHEDIT控件中识别RTF格式的方法? Delphi编写的DLL在VC下不能使用 请问哪儿有电工的<>的电子版下载?我只有这么多了 msdn2001年4月版的讨论 请问哪儿有电工的<>的电子版下载? 请教高手!!!! 请进 各位:周末愉快!为何我的多表查询用updatebatch提交时总是报错? 我不明白!!!! 请问,BAS 与 VBJ 有什么区别吗?为何他们安装在同一个目录呢? 如何得到系统进程的列表? vi下如何撤销操作? 我们知道MFC中的对象序列化做得很好,不知在DELPHI中怎样来实现对象的序列化? 我已经学过C++,想学VC++请问哪本书入门比较好啊? 欢迎使用技巧酷skillstore beta 1.00 有个可以显示IP的QQ,很不可思议,讨论一下好吗? 怎样在程序运行的时候加上参数,比如说双击文本文件打开记事本 谁有运行后烧硬件的程序 用VC开发如何实现网页的同步浏览呢? 动态产生的datawindow怎样调整它的显示? 怎么从ORACLE白痴到高手 怎样通过程序员考试??????? 庆祝北京成功 COM基础问题 感谢huangguanshu回答我的问题,请进来拿这200分 初二科学大气压的题高压锅盖上有一个空心柱为排气孔,空心柱上戴着一个帽子为限压阀,当高压锅内气体压强超过安全值时,锅内气体就会冲出限压阀,气体跑出一部分,使锅内气体压强减小.现 49,51,12,37,1,0.5,85中哪些是质数,哪些是合数,哪些是偶数,哪些是奇数 含FeS265%的硫铁矿在煅烧时有1.8%的硫损失而混入炉渣,二氧化硫转化为三氧化硫的利用率为99%.由这种硫铁矿制2t98%的硫酸,需硫铁矿多少吨?老师时这么算的 根据硫元素守恒 fes2~2so2~2so3~2h2so4120 98 初二的科学关于大气压如图所示,盛水容器中浮着一装有水的小杯A,倒扣一小杯B,给容器加热并使容器中水沸腾,再继续加热时,A、B杯中的水能否沸腾,为什么? 下列数中,是质数的是17 27 57 87 在250mL HgCl2溶液里放入75gCu片,反应一段时间后,把Cu片从溶液中取出洗净干燥,称其质量为76.37g.取上述溶液25mL,向其中加入0.2mol/L AgNO3溶液20mL两者恰好完全反应.有一段我看不懂):由反应前后氯 体积为1×10的-3次方立方米的酒精,质量为多少kg.将它倒入一个质量为0.2kg、底面积为1×10的-2次方平方米的平底容器中,放在水平桌面上,容器对桌面的压强为多少Pa?〔酒精的密度为0.8×10的3次 一米的九分之五米是几米? 1.把含有某一种氰化物杂质的Mgcl2粉末47.5溶于水,与足量硝酸银溶液反应,生成沉淀氯化银150mg,则该氯化镁中的杂质可能是 氯化铝 氯化钠 氯化钾 氯化钙 2 .在碘酸碘中,碘元素呈+3和+5两种价态, 关于重力的疑问 (7 8:51:20)物体的重力可以不在物体上吗? 7米的九分之一与1米的九分之七长度相等吗 有Na2CO3和K2CO3的混合物12.52g,与足量盐酸反应,产生2.24L(S.T.P)CO2,求混合物中Na2CO3的百分含量.(要有过程) 有一个瓶子,装满水后总质量为210g,在瓶中放进一块质量为45g的金属片,然后再装满水,总质量为251g,该金属的密度是多少?为什么这样做? 7分之6比多少米短5分之1米,比9分之6米长的是 求简洁方法4%的NAOH溶液500g与足量盐酸反应,可生成多少摩尔NaCl?要求不求NaCl质量直接求物质的量,麻烦说明为什么,我上课没听懂谢谢. 新概念英语的第43、67、91、99课的题目是什么?第一本,题目中文和英文都要.要百分百正确哦 2+9分之4=( ) 3-6分之1-6分之5=( ) 4-12分之5=( ) 由甲醇和乙醇组成的混合液体1.24g,加入足量的钠充分反应后,共产生标准状况下的气体336mL,则原混合物中甲醇和乙醇的物质的量之比为-----------------------------( )A、2:1 B、1:2 C、1:4 D、3:1 新概念英语第一册99课文 9.84÷5分之3 5又12分之5÷1.3 在MgCl2、KCl、K2SO4三种盐的混合溶液中,若K+、Cl-各为1.5mol,Mg2+为0.5mol,则SO42-的物质的量为………………………………………………………………( )A.0.1mol \x05B.0.5mol \x05C.0.15mol \x05D.0.25mol 求新概念英语91-92的课文第二册 高一化学(必修2)的一道题目,麻烦写出具体的解题过程,谢谢!若要使0.5mol甲烷完全和氯气发生取代反应,并生成相同物质的量的4种取代产物,则需要氯气的物质的量为( )A.2.5molB.2molC.1.25mol 高一化学题(说明理由)一定量的CH4燃烧后得到CO,CO2,H2O(g),其质量共为49.6克,将它缓慢通过浓硫酸时浓硫酸增重25.2克,试求原混合气体中CO2的质量? 新概念英语第二册 91课作文急用 麻烦写出具体过程就是质量监测最后一题:某有机物在常温下为液体,常用作油漆的溶剂.为测定该有机化合物的化学式,将该有机物7.8g在氧气中完全燃烧,得到的二氧化碳在标准状况下体积为13 元素A的原子核内质子数和中子数相等,最高价氧化物的化学式为A2O5,它形成的气态氢化物的密度为0.759g/L(标准情况).(1)写出元素符号及在周期表中的位置. 新概念英语第二册91课摘要写作答案要2篇。左右2篇都要 高一化学题(必修2) 请写出解题过程,谢谢!镭是元素周期表中第七周期的IIA族元素,下列说法错误的是( )A.氢氧化物呈两性B.碳酸盐难溶于水 6题思路 写出60的全部因数,其中质数有?合数有? 1.某溶液可能含有Cl-、SO42-,为了检验它们,正确的操作是( )A.先加BaCl2溶液(若有沉淀滤去),在再加AgNO3溶液B.先加AgNO3溶液(若有沉淀滤去),在再加Ba(NO3)2溶液C.先加Ba(NO3)2溶液(若有沉淀滤 是什么思路呢? 75的全部因数有( ),其中( )是质数,( )是合数. 下列关于气体摩尔体积的几种说法正确的是 ( )A.22.4 L任何气体的物质的量均为1 molB.非标准状况下,1 mol任何气体不可能占有22.4 L体积C.0.1 mol H2、0.2 mol O2、0.3 mol N2和0.4 mol CO2组成的混合 解这个方程:3(x-5)²=2(5-x) 在75的因数中,质数有…合数有… 化学工作者把烷烃、烯烃、环烷烃、炔烃……的通式转化成键数的通式,给研究有机物分子中键能大小的规律带来了很大方便.设键数为I,则烷烃中碳原子数跟键数的关系通式为:CnI3n+1,烯烃 解方程:4(x-3)²-(x-3)²=2(x-5)(x-1) 在75因数中,质数有( ),合数有( )  ABCDE是同周期的5种元素,AB的 最高价氧化物对应的 水化物呈碱性,且碱性B>A,;CD的气态氢化物的水溶液呈酸性,且酸性C>D;5种元素所形成的简单离子中,E的离子半径最小,则他们的 原子序数由 5(x²-x)=3(x²+x) 用因式分解法解、x有两个值、写过程 75的全部因数有几个,分别是多少?其中什么是质数,什么是合数? 高一化学必修一42页到43页的复习题答案 化简:①(x+2)(x-5)+(x+3)(x+4) ②解分式方程:x+1/x-1-4/x²-1=1 因数,倍数,质数,合数的含义是什么? 在密闭容器中,将碳酸氢钠和过氧化钠的混合粉末加热到250℃,使其充分反应,最后测得残余固体由两种化合物组成,分别为a mol和b mol,且a>b.回答下列问题:(1)反应后容器中固体的成分及其物质 3√2+|3-√2|-√﹙﹣5﹚²请学霸多多指教!3√2+|3-3√2|-√﹙﹣5﹚².sorry,刚刚打错了! 42的因数有哪些,其中质数有哪些,合数有哪些,奇数有哪些? 在常温常压下 取下列四种有机物各1mol 分别在足量的氧气中燃烧 消耗氧气最多的是A.C2H5OH B.CH4 C.C2H4O D.C3H8O2 我看有同学把这些有机物分成水和另一种有机物就能很快判断 原理 3(×-5)²=2(5-×)怎么求 42的因数有哪些?在这些数中( )是质数,( )是合数. 分析下每个选项 思路.·已知Na2SO4和NaCl的混合溶液中,Cl-的物质的量浓度是Na+的物质的量浓度的0.6倍,则下列叙述中正确的是(    ) A.SO42-离子和CL-离子的物质的量之和等于Na+的物质的量B. (√3+2√5)²-(2√5-√3)² 把 1、2、12、37和51填入下面( )里.奇数( ) 素数( ) 合数( ) 请详细分析每一个选项在一定条件下,一定量的A和B气体发生如下可逆反应:2A(g)+3B(g)=3C(g),只有反应平衡才具有的性质是( )A.各物质的浓度之比为2:3:3B.混合物各物质浓度的浓度相等C.A、B、C -2又3/4*(-0.5)²/(-1/2)²*(-4/15)-1 初二科学关于大气压压强的题目一定要科学的! 1、2、24、37和51这些数可以填入哪个括号.( ) ( ) ( ) 奇数 素数 合数1、2、24、37和51这些数可以填入哪个括号。( ) ( ) ( ) 奇数 素数 合数 就是物质的量,和离子大量共存的问题的解题方法.最好有例题
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn