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

📄 ch26.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:

...

StrSize = sizeof(Buffer);

pECB->GetServerVariable(pECB->ConnID, "REMOTE_ADDR", &Buffer, &StrSize);

AnsiString 
VarString("REMOTE_ADDR = " + AnsiString(Buffer) + "<BR>");

</FONT></PRE>
<P>This function takes a connection ID in the first parameter, a constant in the
second parameter, a buffer in the third parameter, and the length of 
the buffer in
the fourth parameter:</P>
<PRE><FONT COLOR="#0066FF">BOOL WINAPI GetServerVariable(

 HCONN hConn,

 LPSTR lpszVariableName,

 LPVOID lpvBuffer,

 LPDWORD lpdwSizeofBuffer

);

</FONT></PRE>
<P>As a rule, you will have to reset the 
fourth parameter before each call to this
function because the function itself returns the length of the string found in the
<TT>lpvBuffer</TT> parameter in the <TT>lpdwSizeOfBuffer</TT> parameter. You definitely
don't want to raise any exceptions or 
cause any errors to occur in your DLL, so I
suggest playing it safe when calling this function.</P>
<P>The preceding code first sets the length of the buffer that will hold the information
retrieved from the server. It then calls the server and asks 
for information. In
this case, it asks for the content length of the information sent by the server.</P>
<P>You can pass the following strings in the second parameter of <TT>GetServerVariable</TT>:

<TABLE BORDER="1">
	<TR ALIGN="LEFT" rowspan="1">
		
<TD ALIGN="LEFT"><TT>AUTH_TYPE</TT></TD>
		<TD ALIGN="LEFT">Type of authentication used.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>CONTENT_LENGTH</TT></TD>
		<TD ALIGN="LEFT">Number of bytes you can expect to receive from the 
client.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>CONTENT_TYPE</TT></TD>
		<TD ALIGN="LEFT">Type of information in the body of a <TT>POST</TT> request.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD 
ALIGN="LEFT"><TT>PATH_INFO</TT></TD>
		<TD ALIGN="LEFT">Trailing part of the URL after the script name.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>PATH_TRANSLATED</TT></TD>
		<TD ALIGN="LEFT"><TT>PATH_INFO</TT> with any virtual 
pathname expanded.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>QUERY_STRING</TT></TD>
		<TD ALIGN="LEFT">Info following the <TT>&quot;?&quot;</TT> in the URL.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD 
ALIGN="LEFT"><TT>REMOTE_ADDR</TT></TD>
		<TD ALIGN="LEFT">IP address of the client (could be a gateway or firewall).</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>REMOTE_HOST</TT></TD>
		<TD ALIGN="LEFT">Hostname of the client or 
agent of the client.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>REMOTE_USER</TT></TD>
		<TD ALIGN="LEFT">Username supplied by the client and authenticated by the server.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD 
ALIGN="LEFT"><TT>UNMAPPED_REMOTE_USER</TT></TD>
		<TD ALIGN="LEFT">Username before ISAPI mapped to an NT user account.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>REQUEST_METHOD</TT></TD>
		<TD ALIGN="LEFT">The HTTP request 
method.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>SCRIPT_NAME</TT></TD>
		<TD ALIGN="LEFT">The name of the script program being executed.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>SERVER_NAME</TT></TD>
		
<TD ALIGN="LEFT">The server name.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>SERVER_PORT</TT></TD>
		<TD ALIGN="LEFT">The TCP/IP port on which the request was received.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD 
ALIGN="LEFT"><TT>SERVER_PORT_SECURE</TT></TD>
		<TD ALIGN="LEFT">If the request is on the secure port, then this will be <TT>1</TT>; otherwise, it
			is <TT>0</TT>.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD 
ALIGN="LEFT"><TT>SERVER_PROTOCOL</TT></TD>
		<TD ALIGN="LEFT">Usually HTTP/1.0.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>SERVER_SOFTWARE</TT></TD>
		<TD ALIGN="LEFT">The name of the server software.</TD>
	</TR>
	<TR 
ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>ALL_HTTP</TT></TD>
		<TD ALIGN="LEFT">All headers not already parsed into one of the previous variables.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>HTTP_ACCEPT</TT></TD>
		<TD 
ALIGN="LEFT">The special-case HTTP header.</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD ALIGN="LEFT"><TT>URL</TT></TD>
		<TD ALIGN="LEFT">New for version 2.0. The base portion of the URL.</TD>
	</TR>
</TABLE>
<BR>
<BR>
You can find additional 
information on these variable names in the Microsoft online
help.</P>
<P>You can see examples of the type of information returned by calling <TT>GetServerVariable</TT>
in Figure 26.2. Note that this screen shot simply shows the lower half of the 
window
shown in Figure 26.1.<BR>
<BR>
<A NAME="Heading17"></A><A HREF="26ebu02.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/26/26ebu02.jpg">FIGURE 26.2.</A><FONT COLOR="#000077">
</FONT><I>The results of making several repeated calls to <TT>GetServerVariable</TT>.</I></P>
<P>Note that many of the 
preceding pieces of information are automatically passed
in the <TT>EXTENSION_CONTROL_BLOCK</TT> record. Therefore, you usually do not need
to call <TT>GetServerVariable</TT>, but you can if you need to, particularly if you
want to retrieve 
information with <TT>ReadClient</TT> and need to know how much information
to read.</P>
<P>Most of the time, you don't need to call <TT>ReadClient</TT>. However, if the
amount of data being sent by the browser is larger than 48KB, you will need to 
call
<TT>ReadClient</TT> to get the rest of the data.
<H3><A NAME="Heading18"></A><FONT COLOR="#000077">The DLLEntryPoint</FONT></H3>
<P>Before completing the discussion of how this DLL works, I want to take a moment
to get some housekeeping chores 
out of the way. In particular, I want to mention
the <TT>DLLEntryPoint</TT> routine, which appears at the bottom of the DLL.</P>
<P>All DLLs have an entry point that is called automatically. You don't have to respond
to this entry point, but doing so 
is usually a good idea. In this case, I simply
open a text file for debugging purposes:</P>
<PRE><FONT COLOR="#0066FF">#pragma argsused

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)

{

  switch (reason)

  {

    case 
DLL_PROCESS_ATTACH:

      out = fopen(&quot;c:\\test.txt&quot;, &quot;w+&quot;);

      fprintf(out,&quot;hello&quot;);

      break;

    case DLL_PROCESS_DETACH:

      fprintf(out,&quot;goodbye&quot;);

      fclose(out);

      break;

    
default:

      break;

  }

  return (TRUE);

}

</FONT></PRE>
<P>Nothing about the code shown here is mandatory. You don't have to open a text
file and write to it; the code serves no other purpose than to give you a simple
means of debugging your 
DLL. In particular, it creates a text file on the server
to leave a record of your DLL's behavior. This file is helpful, particularly if you're
learning ISAPI and have problems simply creating a valid DLL that exports the key
functions.

<DL>
	
<DT></DT>
</DL>



<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>You can debug an ISAPI DLL by using
	several different means. One rather fancy method is to load the entire server into
	the stand-alone debugger, load your 
ISAPI DLL, and then set a break point inside
	it. <BR>
	<BR>
	Although effective, the technique described in the preceding paragraph can be overkill.
	My suggestion is not to be too proud about resorting to the old-fashioned technique
	of creating a 
text file and writing to it. You can produce very detailed reports
	in this fashion, and they can show you exactly what is going on in your DLL. The
	only flaw in this system is that entering all those <TT>fprintf</TT> statements takes
	a bit of time. 

<HR>


</BLOCKQUOTE>

<P>The example shown here has a more valuable purpose then merely showing one rather
simple-minded way to debug an ISAPI DLL. In particular, it reminds you of the proper
way to handle the entry point of a DLL. In addition to the 
<TT>DLL_PROCESS_ATTACH</TT>
and <TT>DLL_PROCESS_DETACH</TT> notifications are two others called <TT>DLL_THREAD_ATTACH</TT>
and <TT>DLL_THREAD_DETACH</TT>. Because multiple clients could be using your DLL
at the same time, <TT>DLL_THREAD_ATTACH</TT> 
can be a very important entry point
to use when you're debugging or constructing your DLL.
<H3><A NAME="Heading20"></A><FONT COLOR="#000077">Getting Information from a Submit
Button</FONT></H3>
<P>Often you get information sent to you from an HTML 
form that has a Submit button
on it. As long as this information is shorter than 49KB, you can assume that it will
be available in the <TT>lpbData</TT> field of <TT>TExtensionControlBlock</TT>. Otherwise,
you will need to call <TT>ReadClient</TT>. 
Here is how you would typically read the
information from the pointer passed in this field:</P>
<PRE><FONT COLOR="#0066FF">AnsiString S;

  if (pECB-&gt;lpbData != NULL)

  {

    S = (char *)pECB-&gt;lpbData;

    S = Parse(S);

  }

  else

    S = 
&quot;Error occurred on get from lpbData field&quot;;

</FONT></PRE>
<P>This code first checks to see if <TT>lpbData</TT> is non-<TT>NULL</TT>. This type
of conservative coding is a necessity in ISAPI, as you don't want errors to be occurring
way over 
on the server side, where it is hard to see what is going on. The fragment
shown here then typecasts <TT>lpbData</TT> so that you can place its contents in
a variable of type <TT>AnsiString</TT>. It then passes the string to a user-defined
function 
called <TT>Parse</TT> that handles the string passed by the server. If something
goes wrong, the string variable is set equal to an error message and then returned
to the user so he or she can view it in a browser.</P>
<P>If you want to see exactly 
what information is available in the <TT>lpbData</TT>
field, you can use the following two functions to echo the data back to your Web
browser:</P>
<PRE><FONT COLOR="#0066FF">AnsiString SetupHeader(AnsiString &amp;ResultString, AnsiString S, int 
&amp;Len)

{

  char *HeaderInfo = &quot;HTTP/1.0 200 OK\nContent-Type: text/html\n&quot;

                     &quot;Content-Length: %d\nContent:\n\n %s &lt;/HTML&gt;&quot;;



  ResultString.SetLength(S.Length() + strlen(HeaderInfo) + 1);

  Len = 
ResultString.Length();

  sprintf(ResultString.c_str(), HeaderInfo, Len, S);

  return ResultString;

}

//HttpExtensionProc callback definition

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)

{

  AnsiString ResultString;

  int 
ResultLen;

  char *IsapiLogText = &quot;Mirror lpbData&quot;;

  strcpy(pECB-&gt;lpszLogData,IsapiLogText);

  pECB-&gt;dwHttpStatusCode = 200;

  AnsiString S;

  if (pECB-&gt;lpbData != NULL)

  {

    S = (char *)pECB-&gt;lpbData;

  }

  else

    
S = &quot;Error occurred get lpbData field&quot;;

  SetupHeader(ResultString, S, ResultLen);

  pECB-&gt;WriteClient(pECB-&gt;ConnID, ResultString.c_str(), &amp;(DWORD)ResultLen, 0);

  return (HSE_STATUS_SUCCESS);

}

</FONT></PRE>
<P>The first 
function, called <TT>SetupHeader</TT>, is just a utility routine that
automates the process of setting up a header. It forces you to pass in the variable
that is sent in the third parameter of <TT>WriteClient</TT>. I do this simply to
help remind 
myself that I have to initialize this variable before passing it to the
server.</P>
<P>The second routine simply mirrors the <TT>lpbData</TT> field back to the user
of the DLL. On the CD that accompanies this book, you will find a DLL called 
<TT>MirrorData</TT>
and an HTML form called <TT>MirrorDataTest.htm</TT>, which looks like this:</P>
<PRE><FONT COLOR="#0066FF">&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;

&lt;html&gt;

&lt;head&gt;

&lt;meta 
http-equiv=&quot;Content-Type&quot;

content=&quot;text/html; charset=iso-8859-1&quot;&gt;

&lt;meta name=&quot;GENERATOR&quot; content=&quot;Microsoft FrontPage 2.0&quot;&gt;

&lt;title&gt;MirrorDataTest&lt;/title&gt;

&lt;/head&gt;

&lt;body 
bgcolor=&quot;#0000FF&quot; text=&quot;#00FFFF&quot;&gt;

&lt;h1&gt;View lpbData Test&lt;/h1&gt;

&lt;form action=&quot;/scripts/Books/BUnleash/MirrorData.dll&quot;

method=&quot;POST&quot;&gt;

    &lt;p&gt;Enter some information: &lt;/p&gt;

    

⌨️ 快捷键说明

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