📄 009.htm
字号:
<br>
exports <br>
GetExtensionVersion, <br>
HttpExtensionProc; <br>
<br>
begin <br>
end. <br>
<br>
为了运行这个DLL程序,您应该把它复制到您的NT服务器下的脚本目录中去。在我的NT4.0
机器中,它就像这样: <br>
<br>
c:\winnt\system32\inetsrv\scripts\mystuff\isapi1.dll <br>
<br>
在这个例子中,我已经创建了我的名为“mystuff”的目录,它只不过是用来存储我创建的
<br>
ISAPI DLLs。您的目录,当然和我的机器上的不完全一样,取决于您的“inetsrv”目录位置和其它因素。
<br>
为成功调用这个DLL,您应该在您的HTML页上增添这个超链接:
<br>
<br>
<A HREF="/scripts/mystuff/isapi1.dll" >ISAPI One</A><BR> <br>
<br>
当用户点击这个超链接时,ISAPI1 Dll会被呼叫,然后字符串“Hello
from ISAPI”会显 <br>
示在用户的浏览器上。如果您并不是把 ISAPI.DLL放在 mystuff
目录下,那么您应该修改上面的HTML代码来使之与您的情况适应。注意,您的目录必须与目录
inetsrv 有关,不应,也不能包含您的整个DLL所在的目录。 <br>
<br>
下面是呼叫的完整的HTML脚本: <br>
<br>
<HTML> <br>
<HEAD> <br>
<TITLE>CharlieC Home Page</TITLE> <br>
</HEAD> <br>
<BODY> <br>
<H1>My Home Page </H1> <br>
<P> <br>
This is the home page for my home computer. <br>
<P> <br>
<A HREF="/scripts/mystuff/isapi1.dll" >ISAPI One</A><BR> <br>
</BODY> <br>
</HTML> <br>
<br>
注意,如果您多次把程序ISAPI1.DLL复制到 mystuff
目录下,在每一次复制之前您应该 <br>
关掉网络服务器的万维网端口。这是因为,在第一次复制这个DLL时,您可以不受限制,但在此之后,它就属于服务器了。因此,在您复制第一次拷贝的更新版本时,因当关掉万维网服务。您可以使用网络管理程序来关掉万维网服务。这个程序应该在微软网络管理程序组(Microsoft
Internet Server group)下面,在安装网络信息服务时被安装到程序管理器(Explorer/Program
Manager)下。 <br>
<br>
与 TExtensionControlBlock 一起工作 <br>
通过本文中的这一要点,您能够建立您的第一个ISAPI
DLL,并且能在第二台机器上的网 <br>
页浏览器调用它。 <br>
在本文中接下来的ISAPI的其余部分将会更加深入。 <br>
这里是HttpExtensionProc参数中比较复杂的部分<br>
<br>
PExtensionControlBlock = ^TExtensionControlBlock; <br>
TExtensionControlBlock = packed record <br>
cbSize: DWORD; // = sizeof(TExtensionControlBlock) <br>
dwVersion: DWORD; // version info of this spec <br>
ConnID: HCONN; // Context Do not modify! <br>
dwHttpStatusCode: DWORD; // HTTP Status code <br>
// null terminated log info specific to this Extension DLL <br>
lpszLogData: array [0..HSE_LOG_BUFFER_LEN-1] of Char; <br>
lpszMethod: PChar; // REQUEST_METHOD <br>
lpszQueryString: PChar; // QUERY_STRING <br>
lpszPathInfo: PChar; // PATH_INFO <br>
lpszPathTranslated: PChar; // PATH_TRANSLATED <br>
cbTotalBytes: DWORD; // Total bytes from client <br>
cbAvailable: DWORD; // Available number of bytes <br>
lpbData: Pointer; // pointer to cbAvailable bytes <br>
lpszContentType: PChar; // Content type of client data <br>
<br>
GetServerVariable: TGetServerVariableProc; <br>
WriteClient: TWriteClientProc; <br>
ReadClient: TReadClientProc; <br>
ServerSupportFunction: TServerSupportFunctionProc; <br>
end; <br>
<br>
注意到这个纪录中包含了上面提到过的ConnID字段,并且向
WriteClient 传送第一个参数。 <br>
这个纪录中的第一个参数是为版本控制而设的。它应该是TExtensionControlBlock的大小的规定。如果微软公司改变了它的结构,那么它们能够通过检查纪录的大小来判断它们正在处理的结构版本。
您永远也不要这个纪录中的前三个字段,它们早已被ISAPI填充,在您的程序中,它们只能被访问,而不能被改变。
<br>
这个纪录中最重要的字段可能就是lpszQueryString了,它包含了从服务器上传来的请求
<br>
的信息。例如,假设您已经创建了一个名叫 ISAPI1.Dll。为了调用这个DLL,您就要在您的浏览器的一页上创建一个像这样的HREF
[注:HTML语言中的一种格式(译者)] : <br>
<br>
<A HREF="/scripts/mystuff/test1.dll">Test One</A> <br>
<br>
如果您希望响应这个DLL,您就要对上面那行做这样的改动:
<br>
<br>
<A HREF="/scripts/mystuff/test1.dll?MyQuery">Test One</A> <br>
<br>
假如HTML代码段中有像上面两行中的第二行,那么,您的DLL就会在lpszQueryString参数
<br>
中得到“MyQuery”
的字符串,特别要注意跟在请求字符串后的请求标志的使用。 <br>
当然,您可以随心所欲地改变请求字符串。例如,您可以这样写: <br>
<br>
<A HREF="/scripts/mystuff/test1.dll?ServerName">Test One</A> <br>
<br>
在这个请求中,这个DLL会回答服务器的名称。您在传递这个参数时,不受任何限制。您
<br>
可以传递任何您想要的东西,而且,如何分析DLL中的信息也由您的喜好决定。
<br>
当您从服务器返回信息至浏览器时,您使用到了这个纪录中的“WriteClient”函数指针
<br>
。在初始化这个指针时您不需做任何事;它已经自动地有网络信息服务器传递给您了。
<br>
CGI应用程序的作者会注意到传送请求字符串的语法十分熟悉。事实上,ISAPI跟随了CGI
<br>
的大多数习惯,在TExtensionControlBlock中的多数字段可以简单地被CGI技术借用。
<br>
在TExtensionControlBlock中的另一个关键字段是 lpbData
,它包含了从浏览起上传给您的附加信息。 <br>
例如,您有一个伴随几个字段的HTML窗体,这些自断中包含的信息就会被一个叫做“
<br>
lpData”的指针传递。本文中的下一个主题,“从‘确认’按钮中获得信息”,将会着重讲述怎样处理这种情况。
<br>
<br>
到现在为止我已经介绍了TExtensionControlBlock中的四个关键字段:
<br>
<br>
WriteClient: 一个能够让您传递格式化的HTML数据到浏览器上的指针。这个函数用到了
<br>
TExtensionControlBlock的ConnID字段。 <br>
lpszQueryString: 从浏览骑上传来的请求。<br>
lpbData: 从浏览器上传给你的人一的附加数据。通常是一个HTML窗体的任意字段的内容
<br>
。我将在“确认 按钮”这部分进一步讨论。 <br>
<br>
要获得其他TExtensionControlBlock中的字段是如何工作的感觉,最好的办法就是亲自在
<br>
浏览其中将他们做对照。换句话说,您会希望创建一个HTML页,使得用能够调用客户端的ISAPI
DLL。这个ISAPI DLL的目的仅仅是在HTML中格式话TExtensionControlBlock中的每一个字段,然后把它们传回浏览器。这样就把您的浏览器变成了一个有点可怕的调试器,来显示TExtensionControlBlock中的所有字段。<br>
<br>
这里有一个程序,由Borland公司的 Danny Thorpe
编写,他会执行这个任务: <br>
<br>
library test1; <br>
<br>
uses <br>
Windows, <br>
SysUtils, <br>
HTTPExt; <br>
<br>
function GetExtensionVersion( var Ver: THSE_VERSION_INFO ): BOOL; stdcall; <br>
begin <br>
Ver.dwExtensionVersion := $00010000; // 1.0 support <br>
Ver.lpszExtensionDesc := 'A test DLL written in Delphi 2.0'; <br>
Result := True; <br>
end; <br>
<br>
function HttpExtensionProc( var ECB: TEXTENSION_CONTROL_BLOCK ): <br>
DWORD; stdcall; <br>
var <br>
ResStr: string; <br>
StrLen: Integer; <br>
Buf: array [0..1024] of Char; <br>
begin <br>
ECB.lpszLogData := 'Delphi DLL Log'; <br>
ECB.dwHTTPStatusCode := 200; <br>
ResStr := Format( <br>
'<HTML><TITLE>Test server result</TITLE>' + <br>
'<H1>Test server results</H1>' + <br>
'Size = %d<BR>'+ <br>
'Version = %.8x<BR>'+ <br>
'ConnID = %.8x<BR>'+ <br>
'Method = %s<BR>' + <br>
'Query = %s<BR>' + <br>
'PathInfo = %s<BR>'+ <br>
'PathTranslated = %s<BR>'+ <br>
'TotalBytes = %d<BR>'+ <br>
'AvailableBytes = %d<BR>'+ <br>
'ContentType = %s<BR><BR>'+ <br>
'<H1>Some Server Variables</H1>', <br>
[ECB.cbSize, ECB.dwVersion, ECB.ConnID, <br>
ECB.lpszMethod, ECB.lpszQueryString, <br>
ECB.lpszPathInfo, ECB.lpszPathTranslated, <br>
ECB.cbTotalBytes, ECB.cbAvailable, <br>
ECB.lpszContentType]); <br>
with ECB do <br>
begin <br>
StrLen := Sizeof(Buf); <br>
GetServerVariable(ConnID, 'REMOTE_ADDR', @Buf, StrLen); <br>
ResStr := ResStr + 'REMOTE_ADDR = '+Buf+'<BR>'; <br>
StrLen := SizeOf(Buf); <br>
GetServerVariable(ConnID, 'REMOTE_HOST', @Buf, StrLen); <br>
ResStr := ResStr + 'Remote_Host = '+Buf+'<BR>'; <br>
StrLen := SizeOf(Buf); <br>
GetServerVariable(ConnID, 'REMOTE_USER', @Buf, StrLen); <br>
ResStr := ResStr + 'Remote_User = '+Buf+'<BR>'; <br>
StrLen := SizeOf(Buf); <br>
GetServerVariable(ConnID, 'SERVER_NAME', @Buf, StrLen); <br>
ResStr := ResStr + 'SERVER_NAME = '+Buf+'<BR>'; <br>
StrLen := SizeOf(Buf); <br>
GetServerVariable(ConnID, 'SERVER_PORT', @Buf, StrLen); <br>
ResStr := ResStr + 'SERVER_PORT = '+Buf+'<BR>'; <br>
StrLen := SizeOf(Buf); <br>
GetServerVariable(ConnID, 'SERVER_PROTOCOL', @Buf, StrLen); <br>
ResStr := ResStr + 'SERVER_PROTOCOL = '+Buf+'<BR>'; <br>
StrLen := SizeOf(Buf); <br>
GetServerVariable(ConnID, 'SERVER_SOFTWARE', @Buf, StrLen); <br>
ResStr := Format('%sSERVER_SOFTWARE = %s<BR>'+ <br>
'ThreadID = %.8x<BR>',[ResStr, Buf, GetCurrentThreadID]); <br>
end; <br>
ResStr := ResStr + '</HTML>'; <br>
ResStr := Format( <br>
'HTTP/1.0 200 OK'#13#10+ <br>
'Content-Type: text/html'#13#10+ <br>
'Content-Length: %d'#13#10+ <br>
'Content:'#13#10#13#10'%s', [Length(ResStr), ResStr]); <br>
StrLen := Length(ResStr); <br>
ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0); <br>
Result := HSE_STATUS_SUCCESS; <br>
end; <br>
<br>
xports <br>
GetExtensionVersion, <br>
HttpExtensionProc; <br>
<br>
<br>
egin <br>
end. <br>
<br>
为了调用这个DLL,您应该建立一个包括下面这行的 HRML 脚本 <br>
<br>
<A HREF="/scripts/mystuff/test1.dll">Test One</A> <BR> <br>
<br>
从“确认”按钮获得信息 <br>
通常向您发送信息的HTML窗体中都有一个确认按钮。只要信息量小于49KB,您就可以
<br>
认为TExetensionControlBlock中的 lpbData
字段是可用的。这里显示了您可以如何在大 <br>
多数情况下获得由这个字段的指针发来的信息: <br>
<br>
var <br>
S: string; <br>
begin <br>
… <br>
S := PChar(ECB.lpbData); <br>
… <br>
end; <br>
<br>
如果从这个字段传来的信息大于48KB,那么您必须呼叫
ReadClient 来获得其余的信息。 <br>
如果您想要确切地知道在 lpbData
字段中哪些信息是可用的,您可以使用下面两个函数把数据传回到您的网页浏览器中:
<br>
<br>
function SetUpResString: string; <br>
begin <br>
Result := '<HTML>' + <br>
'<TITLE>Test server result</TITLE>' + <br>
'<H1>Test server results</H1>' + <br>
'<BODY>lpbData = %s </BODY>' + <br>
'</HTML>'; <br>
end; <br>
<br>
function HttpExtensionProc(var ECB: TExtensionControlBlock): <br>
DWORD; stdcall; <br>
var <br>
ResStr: string; <br>
StrLen: Integer; <br>
S, S1: string; <br>
begin <br>
ECB.lpszLogData := 'Delphi DLL Log'; <br>
ECB.dwHTTPStatusCode := 200; <br>
ResStr := SetUpResString; <br>
S := PChar(ECB.lpbData); <br>
ResStr := Format(ResStr, [S]); <br>
StrLen := Length(ResStr); <br>
ECB.WriteClient(ECB.ConnID, Pointer(ResStr), StrLen, 0); <br>
Result := HSE_STATUS_SUCCESS; <br>
end; <br>
<br>
假设您已经有了附有下面代码的HTML窗体: <br>
<br>
<FORM ACTION="/scripts/mystuff/isapi2.dll" METHOD="POST" <br>
ENCTYPE="application/x-www-form-urlencoded"> <br>
<br>
<P> <br>
Enter Number to Square: <INPUT NAME="GetSquare" VALUE="" <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -