📄 ch26.htm
字号:
<P>Most of the body of the function is taken up with simple HTML code
that provides
basic information to the user:</P>
<PRE><FONT COLOR="#0066FF">char *HtmlInfo =
"<HTML>"
"<HEAD><TITLE>C++ Builder ISAPI DLL </TITLE></HEAD>"
"<H1>ISAPI1 Test
Results</H1>"
"<BODY bgcolor=\"#0000FF\" text=\"#00FFFF\">"
"Hello from a C++ Builder ISAPI DLL!<BR></BODY>"
"</HTML>";
</FONT></PRE>
<P>You also need
to fill in a few fields of the <TT>EXTENSION_CONTROL_BLOCK</TT>:</P>
<PRE><FONT COLOR="#0066FF">char *IsapiLogText = "ISAPI1 - Simple ISAPI Extension DLL";
strcpy(pECB->lpszLogData, IsapiLogText);
pECB->dwHttpStatusCode = 200;
</FONT></PRE>
<P>The <TT>lpszLogData</TT> field contains the string that will be written to the
log on your server. With the Personal Web Server, this log is kept by default in
the <TT>Windows</TT> directory, though you can change this in the
Administration
section of the server applet found in the Control Panel.</P>
<P>The status code in this example is set to <TT>200</TT>, which means "OK."
Other possible values include the following:</P>
<PRE><FONT
COLOR="#0066FF">HTTP_STATUS_BAD_REQUEST
HTTP_STATUS_AUTH_REQUIRED
HTTP_STATUS_FORBIDDEN
HTTP_STATUS_NOT_FOUND
HTTP_STATUS_SERVER_ERROR
HTTP_STATUS_NOT_IMPLEMENTED
</FONT></PRE>
<P>More information on the <TT>EXTENSION_CONTROL_BLOCK</TT> is
provided in the section
called "Working with the <TT>EXTENSION_CONTROL_BLOCK</TT>."</P>
<P>Notice the function pointer called <TT>WriteClient</TT> in the struct. You can
call this function to send information back to the browser. When
calling this function,
you use the value in the <TT>ConnID</TT> field of the <TT>EXTENSION_CONTROL_BLOCK</TT>
struct. <TT>ConnID</TT> is filled in for you automatically when the <TT>HttpExtensionProc</TT>
function is called.</P>
<P>Before you look at
the <TT>EXTENSION_CONTROL_BLOCK</TT> struct, let me show you
a complete ISAPI DLL that uses the <TT>HttpExtensionProc</TT> function shown in this
section.
<H3><A NAME="Heading10"></A><FONT COLOR="#000077">A Stripped-Down ISAPI Example</FONT></H3>
<P>The source code in Listing 26.1 shows how to create the simplest possible ISAPI
DLL. The goal is to remove all the complications from the code, and just include
enough information to make sure everything is working correctly.<BR>
<BR>
<A
NAME="Heading11"></A><FONT COLOR="#000077"><B>Listing 26.1. The ISAPI1 example.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">///////////////////////////////////////
// FILE: ISAPI1.CPP
// PROJECT: ISAPI1.DLL
// copyright (3) 1996 by Charlie Calvert
//
// This example shows how to use ISAPI, which is similar to creating a
// CGI application. The code should return a simple string to an HTML
// browser such as the Internet Explorer.
//
// Here is the HTML you output in a browser to call this
ISAPI DLL:
//
// <HTML>
// <HEAD>
// <TITLE>CharlieC Home Page</TITLE>
// </HEAD>
// <BODY>
// <H1>My Home Page </H1>
// <P>
// This is the home page for my home computer.
// <P>
// <A HREF="/scripts/isapi1.dll" >ISAPI One</A><BR>
// </BODY>
// </HTML>
#include <vcl\vcl.h>
#include <string.h>
#include <stdio.h>
#pragma hdrstop
#include
"..\..\utils\Httpext.h"
USERES("Isapi1.res");
FILE *out;
// GetExtensionVersion callback definition
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
fputs("Version", out);
pVer->dwExtensionVersion =
MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
strcpy(pVer->lpszExtensionDesc, "C++ Builder ISAPI DLL");
return (TRUE);
};
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
AnsiString ResultString;
DWORD
resultLen;
AnsiString IsapiLogText = "ISAPI1 - Simple ISAPI Extension DLL";
strcpy(pECB->lpszLogData, IsapiLogText.c_str());
AnsiString HtmlInfo =
"<HTML>"
"<HEAD><TITLE>C++ Builder
ISAPI DLL </TITLE></HEAD>"
"<H1>ISAPI1 Test Results</H1>"
"<BODY bgcolor=\"#0000FF\" text=\"#00FFFF\">"
"You are talking to a C++Builder ISAPI DLL."
"<BR></BODY>"
"</HTML>";
pECB->dwHttpStatusCode = 200;
ResultString = Format(
"HTTP/1.0 200 OK\nContent-Type: text/html\n"
"Content-Length: %d\nContent:\n\n %s",
OPENARRAY(TVarRec, (HtmlInfo.Length(), HtmlInfo)));
resultLen = ResultString.Length();
fprintf(out, ResultString.c_str());
pECB->WriteClient(pECB->ConnID, ResultString.c_str(), &resultLen, 0);
return (HSE_STATUS_SUCCESS);
}
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
out = fopen("c:\\test.txt", "w+");
fprintf(out,"hello");
break;
case DLL_PROCESS_DETACH:
fprintf(out,"goodbye");
fclose(out);
break;
default:
break;
}
return (TRUE);
}
</FONT></PRE>
<P>To use this DLL, you should copy it into a subdirectory of the
<TT>scripts</TT>
directory beneath the root for your Web. On my NT 4.0 machine, the subdirectory looks
like this:</P>
<PRE><FONT COLOR="#0066FF">c:\winnt\system32\inetsrv\scripts\mystuff\isapi1.dll
</FONT></PRE>
<P>In this case, I have created the
directory called <TT>MYSTUFF</TT>, and it is
used solely for storing ISAPI DLLs I have created. Your mileage may, of course, differ
on your machine, depending on where you put the <TT>InetSrv</TT> directory and various
other factors.</P>
<P>To call
this DLL, you should add the following hyperlink to one of your HTML pages:</P>
<PRE><FONT COLOR="#0066FF"><A HREF="/scripts/mystuff/isapi1.dll" >ISAPI One</A><BR>
</FONT></PRE>
<P>For example, here is a complete sample
page:</P>
<PRE><FONT COLOR="#0066FF"><HTML>
<HEAD><TITLE>An ISAPI Page</TITLE></HEAD>
<BODY>
<H1>My ISAPI Page</H1>
<P>This is the home page for ISAPI on my computer.<P>
<A
HREF="/scripts/mystuff/isapi1.dll" >ISAPI One</A><BR>
</BODY>
</HTML>
</FONT></PRE>
<P>When the user clicks the hyperlink, the ISAPI1 DLL will be called and the string
<TT>"Hello from C++ Builder"</TT>
will appear in the user's browser. If
you did not put the <TT>ISAPI1.DLL</TT> in the <TT>MYSTUFF</TT> directory, then you
should change the preceding HTML code to reflect that fact. Notice that the path
you assign is relative to the <TT>InetSrv</TT>
directory and does not, and should
not, contain the entire path to your DLL.</P>
<P>Note that if you copy the <TT>ISAPI1.DLL</TT> into the <TT>MYSTUFF</TT> directory
multiple times, you will need to shut down the WWW portion of the Internet server
before each copy. The rule is that you can copy the DLL the first time for free,
but after you have used it, it belongs to the server, and you need to shut down the
WWW services on the server before you can copy an updated version of the file over
the
first copy. You can use the Internet Service Manager application to shut down
the WWW services on the NT Server. This application should be in the Microsoft Internet
Server group created in Windows Explorer or Program Manager (NT 3.51) at the time
of
the installation of the Internet Information Server. You can use the PWS applet
in the Control Panel if you're using the Personal Web Server on Windows 95 or on
the Windows NT Workstation.
<H3><A NAME="Heading12"></A><FONT COLOR="#000077">Working with
the EXTENSION_CONTROL_BLOCK</FONT></H3>
<P>By this point in the chapter, you should be able to create your first ISAPI DLL
and call it from a Web browser on a second machine. The rest of this chapter explores
ISAPI in more depth.</P>
<P>The following
fairly complex record is passed as the sole parameter to <TT>HttpExtensionProc</TT>:</P>
<PRE><FONT COLOR="#0066FF">typedef struct _EXTENSION_CONTROL_BLOCK {
DWORD cbSize; // size of this struct.
DWORD dwVersion;
// version info of this spec
HCONN ConnID; // Context number not to be modified!
DWORD dwHttpStatusCode; // HTTP Status code
CHAR lpszLogData[HSE_LOG_BUFFER_LEN];// log info
LPSTR lpszMethod;
// REQUEST_METHOD
LPSTR lpszQueryString; // QUERY_STRING
LPSTR lpszPathInfo; // PATH_INFO
LPSTR lpszPathTranslated; // PATH_TRANSLATED
DWORD cbTotalBytes; // Total bytes indicated from client
DWORD cbAvailable; // Available number of bytes
LPBYTE lpbData; // pointer to cbAvailable bytes
LPSTR lpszContentType; // Content type of client data
BOOL (WINAPI * GetServerVariable) ( HCONN
hConn,
LPSTR lpszVariableName,
LPVOID lpvBuffer,
LPDWORD lpdwSize );
BOOL (WINAPI * WriteClient) ( HCONN
ConnID,
LPVOID Buffer,
LPDWORD lpdwBytes,
DWORD dwReserved );
BOOL (WINAPI * ReadClient) ( HCONN ConnID,
LPVOID lpvBuffer,
LPDWORD lpdwSize );
BOOL (WINAPI * ServerSupportFunction)( HCONN hConn,
DWORD dwHSERRequest,
LPVOID lpvBuffer,
LPDWORD lpdwSize,
LPDWORD lpdwDataType );
} EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;
</FONT></PRE>
<P>Notice that this record
contains the <TT>ConnID</TT> field referenced previously
and passed as the first parameter to <TT>WriteClient</TT>.</P>
<P>The first parameter of this record is used for version control. It should be set
to the size of the
<TT>EXTENSION_CONTROL_BLOCK</TT>. If Microsoft changes this structure,
then they can tell which version of the structure they are dealing with by checking
the size of the record as recorded in this field. You should never change any of
the first three
fields of this record; these fields are filled out ahead of time
by ISAPI and can only be referenced, not changed, by your program.</P>
<P>The most important field of this record is probably the <TT>lpszQueryString</TT>,
which contains information
about the query passed in from the server. For example,
suppose you have created a DLL called <TT>ISAPI1.DLL</TT>. To call this DLL, you
would create an <TT>HREF</TT> that looks like this in one of your browser pages:</P>
<PRE><FONT
COLOR="#0066FF"><A HREF="/scripts/mystuff/test1.dll">Test One</A>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -