⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 009.htm

📁 Delphi书籍--Delphi网上教程
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<br> 
exports <br> 
GetExtensionVersion, <br> 
HttpExtensionProc; <br> 
<br> 
begin <br> 
end. <br> 
<br> 
&nbsp;&nbsp;&nbsp; 为了运行这个DLL程序,您应该把它复制到您的NT服务器下的脚本目录中去。在我的NT4.0 
机器中,它就像这样: <br> 
<br> 
&nbsp;&nbsp;&nbsp; c:\winnt\system32\inetsrv\scripts\mystuff\isapi1.dll <br> 
<br> 
&nbsp;&nbsp;&nbsp; 在这个例子中,我已经创建了我的名为“mystuff”的目录,它只不过是用来存储我创建的 
<br> 
ISAPI DLLs。您的目录,当然和我的机器上的不完全一样,取决于您的“inetsrv”目录位置和其它因素。 
<br> 
&nbsp;&nbsp;&nbsp; 为成功调用这个DLL,您应该在您的HTML页上增添这个超链接: 
<br> 
<br> 
&lt;A HREF=&quot;/scripts/mystuff/isapi1.dll&quot; &gt;ISAPI One&lt;/A&gt;&lt;BR&gt; <br> 
<br> 
&nbsp;&nbsp;&nbsp; 当用户点击这个超链接时,ISAPI1 Dll会被呼叫,然后字符串“Hello 
from ISAPI”会显 <br> 
示在用户的浏览器上。如果您并不是把 ISAPI.DLL放在 mystuff 
目录下,那么您应该修改上面的HTML代码来使之与您的情况适应。注意,您的目录必须与目录 
inetsrv 有关,不应,也不能包含您的整个DLL所在的目录。 <br> 
<br> 
下面是呼叫的完整的HTML脚本: <br> 
<br> 
&lt;HTML&gt; <br> 
&lt;HEAD&gt; <br> 
&lt;TITLE&gt;CharlieC Home Page&lt;/TITLE&gt; <br> 
&lt;/HEAD&gt; <br> 
&lt;BODY&gt; <br> 
&lt;H1&gt;My Home Page &lt;/H1&gt; <br> 
&lt;P&gt; <br> 
This is the home page for my home computer. <br> 
&lt;P&gt; <br> 
&lt;A HREF=&quot;/scripts/mystuff/isapi1.dll&quot; &gt;ISAPI One&lt;/A&gt;&lt;BR&gt; <br> 
&lt;/BODY&gt; <br> 
&lt;/HTML&gt; <br> 
<br> 
&nbsp;&nbsp;&nbsp; 注意,如果您多次把程序ISAPI1.DLL复制到 mystuff 
目录下,在每一次复制之前您应该 <br> 
关掉网络服务器的万维网端口。这是因为,在第一次复制这个DLL时,您可以不受限制,但在此之后,它就属于服务器了。因此,在您复制第一次拷贝的更新版本时,因当关掉万维网服务。您可以使用网络管理程序来关掉万维网服务。这个程序应该在微软网络管理程序组(Microsoft 
Internet Server group)下面,在安装网络信息服务时被安装到程序管理器(Explorer/Program 
Manager)下。 <br> 
<br> 
与 TExtensionControlBlock 一起工作 <br> 
&nbsp;&nbsp;&nbsp; 通过本文中的这一要点,您能够建立您的第一个ISAPI 
DLL,并且能在第二台机器上的网 <br> 
页浏览器调用它。 <br> 
&nbsp;&nbsp;&nbsp; 在本文中接下来的ISAPI的其余部分将会更加深入。 <br> 
&nbsp;&nbsp;&nbsp; 这里是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> 
&nbsp;&nbsp;&nbsp; 注意到这个纪录中包含了上面提到过的ConnID字段,并且向 
WriteClient 传送第一个参数。 <br> 
&nbsp;&nbsp;&nbsp; 
这个纪录中的第一个参数是为版本控制而设的。它应该是TExtensionControlBlock的大小的规定。如果微软公司改变了它的结构,那么它们能够通过检查纪录的大小来判断它们正在处理的结构版本。 
您永远也不要这个纪录中的前三个字段,它们早已被ISAPI填充,在您的程序中,它们只能被访问,而不能被改变。 
<br> 
&nbsp;&nbsp;&nbsp; 这个纪录中最重要的字段可能就是lpszQueryString了,它包含了从服务器上传来的请求 
<br> 
的信息。例如,假设您已经创建了一个名叫 ISAPI1.Dll。为了调用这个DLL,您就要在您的浏览器的一页上创建一个像这样的HREF 
[注:HTML语言中的一种格式(译者)] : <br> 
<br> 
&lt;A HREF=&quot;/scripts/mystuff/test1.dll&quot;&gt;Test One&lt;/A&gt; <br> 
<br> 
&nbsp;&nbsp;&nbsp; 如果您希望响应这个DLL,您就要对上面那行做这样的改动: 
<br> 
<br> 
&lt;A HREF=&quot;/scripts/mystuff/test1.dll?MyQuery&quot;&gt;Test One&lt;/A&gt; <br> 
<br> 
&nbsp;&nbsp;&nbsp; 假如HTML代码段中有像上面两行中的第二行,那么,您的DLL就会在lpszQueryString参数 
<br> 
中得到“MyQuery” 
的字符串,特别要注意跟在请求字符串后的请求标志的使用。 <br> 
&nbsp;&nbsp;&nbsp; 
当然,您可以随心所欲地改变请求字符串。例如,您可以这样写: <br> 
<br> 
&lt;A HREF=&quot;/scripts/mystuff/test1.dll?ServerName&quot;&gt;Test One&lt;/A&gt; <br> 
<br> 
&nbsp;&nbsp;&nbsp; 在这个请求中,这个DLL会回答服务器的名称。您在传递这个参数时,不受任何限制。您 
<br> 
可以传递任何您想要的东西,而且,如何分析DLL中的信息也由您的喜好决定。 
<br> 
&nbsp;&nbsp;&nbsp; 
当您从服务器返回信息至浏览器时,您使用到了这个纪录中的“WriteClient”函数指针 
<br> 
。在初始化这个指针时您不需做任何事;它已经自动地有网络信息服务器传递给您了。 
<br> 
&nbsp;&nbsp;&nbsp; CGI应用程序的作者会注意到传送请求字符串的语法十分熟悉。事实上,ISAPI跟随了CGI 
<br> 
的大多数习惯,在TExtensionControlBlock中的多数字段可以简单地被CGI技术借用。 
<br> 
在TExtensionControlBlock中的另一个关键字段是 lpbData 
,它包含了从浏览起上传给您的附加信息。 <br> 
&nbsp;&nbsp;&nbsp; 例如,您有一个伴随几个字段的HTML窗体,这些自断中包含的信息就会被一个叫做“ 
<br> 
lpData”的指针传递。本文中的下一个主题,“从‘确认’按钮中获得信息”,将会着重讲述怎样处理这种情况。 
<br> 
<br> 
&nbsp;&nbsp;&nbsp; 到现在为止我已经介绍了TExtensionControlBlock中的四个关键字段: 
<br> 
<br> 
WriteClient: 一个能够让您传递格式化的HTML数据到浏览器上的指针。这个函数用到了 
<br> 
TExtensionControlBlock的ConnID字段。 <br> 
lpszQueryString: 从浏览骑上传来的请求。<br> 
lpbData: 从浏览器上传给你的人一的附加数据。通常是一个HTML窗体的任意字段的内容 
<br> 
。我将在“确认 按钮”这部分进一步讨论。 <br> 
<br> 
&nbsp;&nbsp;&nbsp; 要获得其他TExtensionControlBlock中的字段是如何工作的感觉,最好的办法就是亲自在 
<br> 
浏览其中将他们做对照。换句话说,您会希望创建一个HTML页,使得用能够调用客户端的ISAPI 
DLL。这个ISAPI DLL的目的仅仅是在HTML中格式话TExtensionControlBlock中的每一个字段,然后把它们传回浏览器。这样就把您的浏览器变成了一个有点可怕的调试器,来显示TExtensionControlBlock中的所有字段。<br> 
<br> 
&nbsp;&nbsp;&nbsp; 这里有一个程序,由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> 
'&lt;HTML&gt;&lt;TITLE&gt;Test server result&lt;/TITLE&gt;' + <br> 
'&lt;H1&gt;Test server results&lt;/H1&gt;' + <br> 
'Size = %d&lt;BR&gt;'+ <br> 
'Version = %.8x&lt;BR&gt;'+ <br> 
'ConnID = %.8x&lt;BR&gt;'+ <br> 
'Method = %s&lt;BR&gt;' + <br> 
'Query = %s&lt;BR&gt;' + <br> 
'PathInfo = %s&lt;BR&gt;'+ <br> 
'PathTranslated = %s&lt;BR&gt;'+ <br> 
'TotalBytes = %d&lt;BR&gt;'+ <br> 
'AvailableBytes = %d&lt;BR&gt;'+ <br> 
'ContentType = %s&lt;BR&gt;&lt;BR&gt;'+ <br> 
'&lt;H1&gt;Some Server Variables&lt;/H1&gt;', <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+'&lt;BR&gt;'; <br> 
StrLen := SizeOf(Buf); <br> 
GetServerVariable(ConnID, 'REMOTE_HOST', @Buf, StrLen); <br> 
ResStr := ResStr + 'Remote_Host = '+Buf+'&lt;BR&gt;'; <br> 
StrLen := SizeOf(Buf); <br> 
GetServerVariable(ConnID, 'REMOTE_USER', @Buf, StrLen); <br> 
ResStr := ResStr + 'Remote_User = '+Buf+'&lt;BR&gt;'; <br> 
StrLen := SizeOf(Buf); <br> 
GetServerVariable(ConnID, 'SERVER_NAME', @Buf, StrLen); <br> 
ResStr := ResStr + 'SERVER_NAME = '+Buf+'&lt;BR&gt;'; <br> 
StrLen := SizeOf(Buf); <br> 
GetServerVariable(ConnID, 'SERVER_PORT', @Buf, StrLen); <br> 
ResStr := ResStr + 'SERVER_PORT = '+Buf+'&lt;BR&gt;'; <br> 
StrLen := SizeOf(Buf); <br> 
GetServerVariable(ConnID, 'SERVER_PROTOCOL', @Buf, StrLen); <br> 
ResStr := ResStr + 'SERVER_PROTOCOL = '+Buf+'&lt;BR&gt;'; <br> 
StrLen := SizeOf(Buf); <br> 
GetServerVariable(ConnID, 'SERVER_SOFTWARE', @Buf, StrLen); <br> 
ResStr := Format('%sSERVER_SOFTWARE = %s&lt;BR&gt;'+ <br> 
'ThreadID = %.8x&lt;BR&gt;',[ResStr, Buf, GetCurrentThreadID]); <br> 
end; <br> 
ResStr := ResStr + '&lt;/HTML&gt;'; <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> 
&lt;A HREF=&quot;/scripts/mystuff/test1.dll&quot;&gt;Test One&lt;/A&gt; &lt;BR&gt; <br> 
<br> 
从“确认”按钮获得信息 <br> 
&nbsp;&nbsp;&nbsp; 通常向您发送信息的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> 
&nbsp;&nbsp;&nbsp; 如果从这个字段传来的信息大于48KB,那么您必须呼叫 
ReadClient 来获得其余的信息。 <br> 
&nbsp;&nbsp;&nbsp; 如果您想要确切地知道在 lpbData 
字段中哪些信息是可用的,您可以使用下面两个函数把数据传回到您的网页浏览器中: 
<br> 
<br> 
function SetUpResString: string; <br> 
begin <br> 
Result := '&lt;HTML&gt;' + <br> 
'&lt;TITLE&gt;Test server result&lt;/TITLE&gt;' + <br> 
'&lt;H1&gt;Test server results&lt;/H1&gt;' + <br> 
'&lt;BODY&gt;lpbData = %s &lt;/BODY&gt;' + <br> 
'&lt;/HTML&gt;'; <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> 
&lt;FORM ACTION=&quot;/scripts/mystuff/isapi2.dll&quot; METHOD=&quot;POST&quot; <br> 
ENCTYPE=&quot;application/x-www-form-urlencoded&quot;&gt; <br> 
<br> 
&lt;P&gt; <br> 
Enter Number to Square: &lt;INPUT NAME=&quot;GetSquare&quot; VALUE=&quot;&quot; <br> 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -