用C++Builder开发ISAPI扩展应用程序
副标题#e#
一、ISAPI概述 Microsoft的WEB处事器提供了差异的ISAPI,应用ISAPI可以或许开拓出高机能的应用措施。
ISAPI具有两类组件:ISAPI扩展和ISAPI过滤器,本文着重先容ISAPI扩展的应用和开拓。
ISAPI应用措施通过DLL实现,DLL的特性使它可以或许作为WEB处事器自身的扩充来装载。在WEB处事器的地点空间运行, 并且只在第一次请求时装载一次,今后每一个后续请求通过建设一个线程(仅用一个简朴的函数挪用) 来完成,这比CGI建设一个历程要节省大量 的时间和空间等资源。
ISAPI扩展凡是取代传统Web应用措施中CGI剧本的位置,由客户触发,为其非凡请求处事。
——清单1————–
1.<html>
2. <img src="myGetGrp.dll">
3.</html>
如清单1所示代码,处事器将挪用myGetGrp.dll中提供的函数获得一GIF图像文件数据发 送给客户欣赏器,在这里,myGetGrp.dll就是一个ISAPI扩展。
假如处事器确定将执行一个ISAPI扩展, 他首先查抄此扩展是否已经装入高速缓存,若没有,则指定的DLL被装载;装入DLL后,处事器就挪用DLL中的HttpExtensionProc()函 数对请求提供处事, 这里是ISAPI措施员安排详细成果操纵的位置,处事器将所有须要 的信息通过一布局范例参数通报给这个函数,包罗请求自己的内容和措施员将用到的回 调函数等,用回调函数,可以将数据通报给用户以及执行其他的操纵。
留意:必需紧记处事器是启动多线程来处理惩罚同时吸收到的多个请求的,所以必需正确处理惩罚线程间的同步,不然将会导致数据粉碎甚至系统瓦解。
二、用C++ Builder开拓ISAPI扩展应用措施 C++ Builder是Inprise公司继Delphi之后开拓的又一个通用的客户/处事器布局的 开拓东西。 它利用了C++语言,可以发生更快速和更高效的代码。今朝已成为继Visual Basic、Delphi之后,在32位Windows情况下最具有吸引力的开拓东西之一。
#p#副标题#e#
启动C++ Builder后,用File→New菜单项打开New Items对话框,在New页面下选中 Web Server Application选项,单击<OK>按纽,弹出一New Web Server Application对 话框,选中ISAPI/NSAPI Dynamic将生成一ISAPI扩展应用措施框架,其主模块缺省名为 Project.cpp,个中主要实现了DLL的三个输出函数,说明如下:
1.1 GetExtensionVersion()函数 这是一个很是简朴的函数,它独一的目标是指定ISAPI版本,并给出扩展的描写。 当DLL第一次被装载时,由处事器挪用。这产生在HttpExtensionProc()函数第一次挪用 前, 在此函数中, 你所需做的全部就是用常量HSE_VERSION_MAJOR和HSE_VERSION_ MINOR(在Isapi2.hpp中界说)配置扩展版本域。而且返回一true值。
GetExtensionVersion()函数实现实例见清单2。
———清单2—————–
BOOL_export WINAPI GetextensionVersion(Isapi2::THSE_VERSION_INFO &Ver)
{ /*配置扩展版本域*/
Ver.dwExtensionVersion=MAKELONG(HSE_VERSION_MAJOR,HSE_VERSION_MINOR);
Ver.lpszExtensionDesc="Example ISAPI extension";//配置扩展描写域
return true; //返回true
}
在此函数中,措施员还可以插手初始化代码,如全局变量的初始化等。
1.2 HttpExtensionProc()函数
HttpExtensionProc() 函数是扩展的成果实现部门,每次发生对扩展的请求,处事器就挪用这个函数,同时通报一范例为TEXTENSION_CONTROL_BLOCK布局的参数(ECB) , 这个布局在Isapi2.hpp中界说:
struct TEXTENSION_CONTROL_BLOCK
{
unsigned cbSize; //布局巨细
unsigned dwVersion; //版本信息
unsigned ConnID; //正在被处事的毗连的ID;挪用回调函数时必需作为一参数通报
unsigned dwHttpStatusCode; //在HttpExtensionProc () 函数返回前,在此安排HTTP状态码,
//拜见HTTP1.0类型界说
char lpszLogData[80]; //吸收一记录信息字符串
char *lpszMethod; //定名请求方法的字符串的指针
char *lpszQueryString; //含一个GET请求查询的字符串指针
char *lpszPathInfo; //请求的字符串的指针
char *lpszPathTranslated; //把请求的字符串指针翻译为处事器的物理路径
unsigned cbTotalBytes; //请求中字节的全部数目
unsigned cbAvailable; //lpbData缓冲区长度
void *lpbData; //POST请求的数据缓冲区指针
char *lpszContentType; //识别请求的MIME内容范例的指针
TGetServerVariableProc GetServerVariable; /*检索处事器变量值的回调函数指针*/
TWriteClientProc WriteClient; //写数据给用户的回调函数的指针
TReadClientProc ReadClient; //检索用户数据的回调函数指针
TServerSupportFunctionProc ServerSupportFunction; /*支持其他操纵的回调函数指针*/
}
这种布局包括处事请求和回调函数指针所需得信息,你可以挪用它来获取信息或执 行操纵,下面临个中的回调函数作一说明:
(1)GetServerVariable函数
原型为:
typedef BOOL _stdcall (*TgetServerVarableProc) (int hConn,*VariableName, void *Buff,int &Size);
#p#分页标题#e#
挪用这个函数来获取处事器变量(如CONTEXT_TYPE)和同请求一起收到的头部。如通 过请求, 则获得HTTP_COOKIE来检索Cookies头部的内容。参数说明:hConn为传入参数 ECB的毗连句柄ConnID;VariableName为要检索的变量的名字(如HTTP_COOKIE);Buffer为 吸收变量的缓冲区指针;Size为缓冲区巨细,若由于缓冲区空间不足而失败,该值被改 变为须要的缓冲区巨细。
(2)WriteClient函数
原型为:
typedef BOOL _stdcall (*TWriteClientProc) (int ConnID,void *Buffer,int & Bytes,int dwReserver)
挪用这个函数来发送响应内容给用户, 参数说明:ConnID为传入参数ECB中的毗连 句柄ConnID; Buffer为包括写数据缓冲区的指针; Bytes为缓冲区数据的字节数; dwReserver保存。
(3)ReadClient函数
原型为:
typedef BOOL _stdcall (*TReadClientProc) (int ConnID, void *Buffer,int & Size)
挪用这个函数读取用户的附加数据,通过检讨ECB中cbAvailable和cbTotalBytes的 值来确定是否挪用此函数, 若cbTotalBytes大于cbAvailable;就表白有更多的数据需 要挪用该函数去读取。 参数说明:ConnID为传入参数ECB中的毗连句柄ConnID;Buffer 为读入数据存放的缓冲区;Size在挪用时,传入Buffer缓冲区的巨细,返回时,便是实 际读取的字节数。
(4)ServerSupportFunction函数
原型为:
typedef BOOL _stdcall (*TServerSupportFunctionProc) (int hConn, int HSERRequest,void buffer,int &Size,PDWORD DataType);
这个函数实现其他一些操纵,参数说明:hConn为传入参数ECB的毗连句柄ConnID, HSERRequest为要实现操纵的常量值。Size为Buffer缓冲区的巨细,Buffer缓冲区指针; DataType为数据范例指针;个中Buffer和DataType的寄义按照HSERRequest的值变革。
下面说明这个函数的几个主要操纵(也就是HSERRequest的可用值,在Isapi2.hpp中 界说),以及对应差异的操纵,参数Buffer,Size,DataType的差异寄义:
●HSE_REQ_SEND_URL_REDIRECT_RESP: 重定向客户欣赏器到另一个网址上的URL。 Buffer:指向一重定向方针URL字符串;DataType被忽略。
●HSE_REQ_SEND_URL: 重定向到本处事器上的一个URL,Buffer: 指向一重定向方针 URL字符串;DataType被忽略。
●HSE_REQ_SEND_RESPONSE_HEADER:发送响应头部给用户;Buffer: 指向包括头部的 字符串;DataType被忽略。
●HSE_REQ_DONE_WITH_SESSION: 通知处事器, 异步的请求处理惩罚已经完成。 Size, Buffer,DataType均被忽略。
●HSE_REQ_MAP_URL_TO_PATH: 映射一个逻辑路径到一个物理路径。Buffer:映射在 此缓冲区上完成;DataType被忽略。
HttpExtensionProc()函数的返回值必需使以下四个值(在Isapi2.hpp中界说)中的一个:
●HSE_STATUS_SUCCESS:所有历程已完成。
●HSE_STATUS_SUCCESS_AND_KEEP_CONN:所有历程已经完成,但但愿保持毗连以继 续进一步的交互。
●HSE_STATUS_PENDING: 历程未完成。 当扩展异步完成历程时, 将以参数 HSERRequest=HSE_REQ_DONE_WITH_SESSION挪用ServerSupportFunction(),以提醒处事 器历程已完成。
●HSE_STATUS_ERROR:历程由于错误已异常终止。
清单3包括了处理惩罚一个"Hello World"网页请求的简朴 但须要的逻辑。
———清单3————————
int _export WINAPI HttpExtensionProc(Isapi2::TEXTENSION_CONTROL_BLOCK &ECB)
{
char my_string[256];
int length;
strcpy(my_string,"200 OK/r/nContext-Type:text/html");
length=strlen(my_string);
ECB.dwHttpStatusCode=200;
ECB.ServerSupportFunction(ECB.ConnID, HSE_REQ_SEND_RESPONSE_HEADER, my_string,length,NULL);//发送头部 strcpy(my_string,"Hello World!");
length=strlen(my_string);
ECB.WriteClient(ECB.ConnID,my_string,length,0); //发送数据给客户欣赏器
return(HSE_STATUS_SUCCESS);
}
这是一个简朴的例子,实际应用的ISAPI扩展将需要做比这更多的事情。
与GetExtenVersion()函数和TerninateExtension()函数差异,HttpExtensionProc ()函数对用户的行为发生浸染。
1.3 TerminateExtension()函数
TerminateExtension() 函数在用户将卸载DLL时被挪用,它是可选择的。传入参数 为dwFlages,范例为int,是以下两个值(在Isapi2.hpp中界说)中的一个:
●请求同意卸载DLL的HSE_TERM_ADVISORY_UNLOAD值。 函数返回true将答允处事器 卸载该DLL。
●强迫DLL排除并筹备被卸载的HSE_TERM_MUST_UNLOAD值。 TerminateExtension()函数对处事器行为发生浸染。
编写完ISAPI扩展应用措施后,用C++ Builder的Project->菜单项成果,为ISAPI扩 展生成一个DLL,这个DLL就可以直接被作为ISAPI扩展利用。
2.竣事语
#p#分页标题#e#
本文先容的是一种在C++ Builder开拓情况下较为巨大的ISAPI扩展的实现要领,这 种要领对领略ISAPI扩展的事情方法有很大辅佐,除此以外,在C++ Builder中有更简朴 的要领来实现, 即通过利用WebModule, 以及TISAPIApplication、 TISAPIRequest、 TISAPIResponse等类。具体要领拜见C++ Builder文档。