📄 ch25.htm
字号:
function. If the server calls out to that function, and nobody
answers, it knows that it's not a usable function. Therefore,
the attempt to load the DLL into memory will fail. If, on the
other hand, the function is there, then it will let the server
know what version of the API it conforms to. Microsoft's recommended
implementation of a <TT><FONT FACE="Courier">GetExtensionVersion()</FONT></TT>
definition is
<BLOCKQUOTE>
<TT><FONT FACE="Courier">BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *version
)<BR>
{<BR>
version->dwExtensionVersion = MAKELONG(HSE_VERSION_MAJOR,
HSE_VERSION_MINOR);<BR>
lstrcpyn( version->lpszExtensionDesc, "This
is a sample Extension",<BR>
HSE_MAX_EXT_DLL_NAME_LEN);<BR>
return TRUE;<BR>
}</FONT></TT>
</BLOCKQUOTE>
<P>
The <TT><FONT FACE="Courier">GetExtensionVersion()</FONT></TT>
entry point is really just a way for the server to ensure that
the DLL is conforming to the specification that the server itself
conforms to. It could be that the server or function is too old
(or too new), and so they wouldn't work well together. It's also
possible that future changes will need to know past versions to
accommodate for special changes, or use it for some other compatibility
purpose.
<P>
The actual startup of the function occurs at the <TT><FONT FACE="Courier">HttpExtensionProc()</FONT></TT>
entry point. Similar to the <TT><FONT FACE="Courier">main()</FONT></TT>
function declaration in a standard C program, it accepts data
inside an Extension Control Block. This block is made available
to the function to figure out what to do with the incoming data
before composing a response. Here is the declaration for the <TT><FONT FACE="Courier">HttpExtensionProc()</FONT></TT>
entry point:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK
*lpEcb);</FONT></TT>
</BLOCKQUOTE>
<P>
Whatever happens, you can't keep the client waiting; you have
to tell them something. In addition, it has to be something that
the server understands and can properly deal with. To properly
create a response, the ISA can call on either the <TT><FONT FACE="Courier">ServerSupportFunction()</FONT></TT>
or the <TT><FONT FACE="Courier">WriteClient()</FONT></TT> function
(These functions are defined and explained in "Callback Functions.").
Within that response, it will want to return one of the valid
return values shown in Table 25.1.<P>
<CENTER><B><FONT SIZE=2>Table 25.1. Acceptable return values for
an ISA application.</FONT></B></CENTER>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><I>Return Value</I></TD><TD WIDTH=348><I>Meaning</I>
</TD></TR>
<TR><TD WIDTH=229><TT><FONT FACE="Courier">HSE_STATUS_SUccESS</FONT></TT>
</TD><TD WIDTH=348>The ISA successfully completed its task, and the server can disconnect and clean up.
</TD></TR>
<TR><TD WIDTH=229><TT><FONT FACE="Courier">HSE_STATUS_SUccESS_<BR>AND_KEEP_CONN</FONT></TT>
</TD><TD WIDTH=348>The ISA successfully completed its task, but the server shouldn't disconnect just yet, if it supports persistent connections. The application hopes it will wait for another HTTP request.
</TD></TR>
<TR><TD WIDTH=229><TT><FONT FACE="Courier">HSE_STATUS_PENDING</FONT></TT>
</TD><TD WIDTH=348>The ISA is still working and will let the server know when it's done by sending an <TT><FONT FACE="Courier">HSE_REQ_DONE_WITH_SESSION</FONT></TT> message through the <TT><FONT FACE="Courier">ServerSupportFunction</FONT></TT> call.
</TD></TR>
<TR><TD WIDTH=229><TT><FONT FACE="Courier">HSE_STATUS_ERROR</FONT></TT>
</TD><TD WIDTH=348>Whoops, something has gone wrong in the ISA. The server should end the connection and free up space.
</TD></TR>
</TABLE></CENTER>
<P>
<P>
All of these extension processes have to interact with something
to get their data, and, as shown before, there's a group of intermediaries
called Extension Control Blocks (ECBs) that handle that particular
duty. They're nothing more than a C structure that is designed
to hold specific blocks of data and allow a few functions to make
use of that data. Here is the setup of an ECB:<BR>
<HR>
<BLOCKQUOTE>
<B>Listing 25.1. Extension Control Block structure.<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<TT><FONT FACE="Courier">// To be passed to extension procedure
on a new request<BR>
//<BR>
typedef struct _EXTENSION_CONTROL_BLOCK {<BR>
DWORD cbSize; //Size
of this struct<BR>
DWORD dwVersion; //Version
info for this spec<BR>
HCONN ConnID; //Connection
Handle/ContextNumber(don't modify!)<BR>
DWORD dwHttpStatusCode; //Http
Status code for request<BR>
chAR lpszLogData[HSE_LOG_BUFFER_LEN];
<BR>
//Log
info for this specific request (null terminated)<BR>
LPSTR lpszMethod; //
REQUEST_METHOD<BR>
LPSTR lpszQueryString; //
QUERY_STRING<BR>
LPSTR lpszPathInfo; //
PATH_INFO<BR>
LPSTR lpszPathTranslated; //
PATH_TRANSLATED<BR>
DWORD cbTotalBytes; //
Total Bytes from client<BR>
DWORD cbAvailable; //
Available Bytes<BR>
LPBYTE lpbData; //
Pointer to client Data (cbAvailable bytes worth)<BR>
LPSTR lpszContentType; //
Client Data Content Type<BR>
BOOL ( WINAPI
* GetServerVariable)<BR>
( HCONN ConnID,
<BR>
LPSTR lpszVariableName,
<BR>
LPVOID lpvBuffer,
<BR>
LPDWORD lpdwSize);
<BR>
BOOL ( WINAPI
* WriteClient)<BR>
( HCONN ConnID,
<BR>
LPVOID Buffer,
<BR>
LPDWORD lpdwBytes,
<BR>
DWORD dwReserved);
<BR>
BOOL ( WINAPI
* ReadClient)<BR>
( HCONN ConnID,
<BR>
LPVOID lpvBuffer,
<BR>
LPDWORD lpdwSize);
<BR>
BOOL ( WINAPI
* ServerSupportFunction)<BR>
( HCONN ConnID,
<BR>
DWORD dwHSERRequest,
<BR>
LPVOID lpvBuffer,
<BR>
LPDWORD lpdwSize,
<BR>
LPDWORD lpdwDataType);
<BR>
}</FONT></TT>
</BLOCKQUOTE>
<HR>
<P>
Table 25.2 goes into detail about each individual component of
an Extension Control Block.<P>
<CENTER><B><FONT SIZE=2>Table 25.2. Explanation of fields in the
Extension Control Block.</FONT></B></CENTER>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><I>Field</I></TD><TD WIDTH=115><CENTER><I>Data Direction</I>
</TD><TD WIDTH=279><I>Comments</I></TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">cbSize</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>The size of the structure itself (shouldn't be changed).
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">dwVersion</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Version information of this specification. The form for this information is <TT><FONT FACE="Courier">HIWORD</FONT></TT> for major version number, and <TT><FONT FACE="Courier">LOWORD</FONT></TT> for minor
version number.
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">ConnID</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>A connection handle uniquely assigned by the server (DO NOT chANGE).
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">dwHttpStatusCode</FONT></TT>
</TD><TD WIDTH=115><CENTER>OU </TD><TD WIDTH=279>The status of the current transaction once completed.
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpszLogData</FONT></TT>
</TD><TD WIDTH=115><CENTER>OU </TD><TD WIDTH=279>Contains a null-terminated string for log information of the size (<TT><FONT FACE="Courier">HSE_LOG_BUFFER_LEN</FONT></TT>).
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpszMethod</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Equivalent of the environment variable <TT><FONT FACE="Courier">REQUEST_METHOD.</FONT></TT>
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpszQueryString</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Equivalent of the environment variable <TT><FONT FACE="Courier">QUERY_STRING.</FONT></TT>
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpszPathInfo</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Equivalent of the environment variable <TT><FONT FACE="Courier">PATH_INFO.</FONT></TT>
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpszPathTranslated</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Equivalent of the environment variable <TT><FONT FACE="Courier">PATH_TRANSLATED</FONT></TT>.
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">cbTotalBytes</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Equivalent of the environment variable <TT><FONT FACE="Courier">CONTENT_LENGTH</FONT></TT>.
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">cbAvailable</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Available number of bytes (out of <TT><FONT FACE="Courier">cbTotalBytes</FONT></TT>) in the <TT><FONT FACE="Courier">lpbData</FONT></TT> buffer. See the explanation of the Data Buffer that follows this table.
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpbData</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Pointer to a buffer, of size <TT><FONT FACE="Courier">cbAvailable</FONT></TT>, which holds the client data.
</TD></TR>
<TR><TD WIDTH=196><TT><FONT FACE="Courier">lpszContentType</FONT></TT>
</TD><TD WIDTH=115><CENTER>IN</TD><TD WIDTH=279>Equivalent of the environment variable <TT><FONT FACE="Courier">CONTENT_TYPE</FONT></TT>.
</TD></TR>
</TABLE></CENTER>
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
For items that are referred to as "Equivalent of the environment variable...," a more detailed explanation of the particular environment variables can be found in this chapter in Table 25.6, "Variable Names and Purposes," and also in <A
HREF="ch3.htm" >Chapter 3</A>, "Crash Course in CGI."
</BLOCKQUOTE>
</TD></TR>
</TABLE></CENTER>
<P>
<H4>The Data Buffer</H4>
<P>
Sometimes there's a lot of information sent to a program, and
sometimes there's not. By default, <TT><FONT FACE="Courier">lpbData</FONT></TT>
will hold a 48K chunk of data from the client. If <TT><FONT FACE="Courier">cbTotalBytes</FONT></TT>
(the number of bytes sent by the client) is equal to <TT><FONT FACE="Courier">cbAvailable</FONT></TT>,
then the program is telling you that all the information that
was sent is available within the <TT><FONT FACE="Courier">lpbData</FONT></TT>
buffer. If <TT><FONT FACE="Courier">cbTotalBytes</FONT></TT> is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -