用VS2008开发ISAPI程序

因为ISAPI扩展和调用它的进程(IIS)在同一的进程地址空间中,这样它们就可以互相直接联系。这种方式一个最大的隐患就是会导致整个IIS当机,而且在有些时候是整个网站当掉。看一下下面的图:

你看到,如果ISAPI扩展程序遇到问题且处理不当,将会影响整个网站的服务进程。就像上图所示,ISAPI扩展和IIS的通讯是通过一个ECBExtension Control Block)结构的指针,其结构然如下:

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];// null terminated 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      dwHSERequest,

   LPVOID     lpvBuffer,

   LPDWORD    lpdwSize,

   LPDWORD    lpdwDataType );

 

}EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;

无论是调用进程还是ISAPI扩展,它们之间的任何信息都是通过EBC来要传递给对方的。我们已简单的看了一下ECB结构。现在,我们来看看IIS是如何通过与ISAPI扩展进行通讯,来为网站访问者服务的。

当一个ISAPI扩展被访问(比如:http://www.mydomain.com/script/example.dll? ID=p05874 & Tx=870250AZT6)时,IIS会检查example.dll是否已经被加载进内存中。如果没有加载,IIS会加载。一旦DLL被加载进内存,一个工作线程便开始运行我们的ISAPI扩展程序(example.dll)。先是DLL的入口函数DllMain被调用。调用完成后,IIS开始调用GetExtensionVersion函数,这个函数主要实现了下面两个功能:

  1. 报告ISAPI可以实现的扩展服务

  2. 取得一个简短的描述扩展的字符串。

然后IIS开始调用HttpExtensionProc函数。这个函数会传递一个ECB指针给ISAPI扩展以开始真正的调用。通过这个函数ISAPI可以向客户端(如浏览器)回写数据。过会儿我们会检查。

第三个也是最后一个ISAPI扩展的入口函数是TerminateExtension函数。它在当ISAPI扩展从内存中卸载的时候调用。所有的清除代码可以在这个函数中实现。

简言之,一个ISAPI扩展是一个导出三个函数的非常规范的DLL

  1. GetExtensionVersion

  2. HttpExtensionProc

  3. TerminateExtension (可选)

手头有了这些资料,我们开始DllMain的代码编写。它是所有的DLL的入口点函数。

DLLMain——入口点函数

就像微软说的,DllMain是每个DLL的入口函数,它是可选的。如DLL中定义了DllMain,在进程或线程初始化/中止时,或者当使用LoadLibrary加载和FreeLibrary卸载时调用这个入口点函数。这个如何函数原型如下:

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwCallReason, LPVOID lpReserved);

如果你的ISAPI扩展程序中提供这个过程,那么它将在初始化和结束时被被调用。dwCallReason参数可以是下面预定义值之一:

  • DLL_PROCESS_ATTACHED

  • DLL_THREAD_ATTACH

  • DLL_THREAD_DETACH

  • DLL_PROCESS_DETACH

对每个参数的详细描述超出了本文讨论范围,有兴趣的读者可以到MSDN上了解更多关于本函数的信息。

再有,我们可以保存hMoudle参数以便以后的使用。最后只是简单的返回一个TURE值。我们在开发扩展程序时,通常在这个函数中不做什么事。

GetExtensionVersion——真正的入口函数

这个函数是IIS调用的第一个入口函数,是ISAPI扩展用来向IIS提供信息用的。为了进一步的了解这个函数,我们来看一下这个函数的原型:

BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer);

在这个函数的调用时,我们假定使用pver参数来填写扩展信息,HSE_VERSION_INFO结构如下:

typedef struct _HSE_VERSION_INFO

{

   DWORD dwExtensionVersion;

   CHAR lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN];

}HSE_VERSION_INFO, *LPHSE_VERSION_INFO;

dwExtensionVersion是扩展的版本号,lpszExtensionDescription是扩展的描述。如果返回TRUE便表示我们告诉IIS我们的扩展程序准备好了,可以使用了;而返回FALSE则表示IIS不可以使用本扩展。

HttpExtensionProc——主要入口函数

一个ISAPI扩展的令人着迷部分是HttpExtensionProc。目前你所能想到的是这个函数可以用来向客户端回写数据。为了看明白这是怎么发生的,我们来一下这个函数原型:

DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB);

这里pECB是一个扩展控制块(ECB)的指针。这个结构用来解决IISISAPI扩展之间的通讯问题。在这个函数中,你可以决定你的网页中包含什么内容,如何返回给用户,怎样做?还想起来这个结构的成员了?ECB成员中包含了一个方法,原型如下:

BOOL WriteClient(HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync);

使用这个函数,你可以将数据放入缓冲区中,呈现给用ConnId标识的客户端。比如说,要想发送 “A BIG RED ROSE”这几个字给客户,你可以简单地进行下面的调用:

char szBigRedRos[] =

  "<font color='#FF0000' size='3'><b>A BIG RED ROSE</b></font>";

DWORD dwSize = strlen(szBigRedRos);

pECB->WriteClient(pECB->ConnID, szBigRedRose, dwSize, 0);

哈哈,到此为止。我想你已经拥有最基础的知识来开发你自己的第一个ISAPI扩展程序了。让我们开始吧。。。

项目需求

1.              一点点耐性

2.              一个MSVC++6编译器

3.              一个装有IISMS WINDOWS2000的操作系统

4.              一个网页浏览器

目标

我们决定不用MFC而用WIN32 API来开发开发一个ISAPI扩展程序。这个程序的功能是检查Master Card (万事达)卡号是否有效。我们给这个ISAPI扩展DLL命名为Validate.dll。在这个扩展程序中将简单地往客户端写一串字符以告诉客户:你所提供的卡号是否有效。当然,我们一定会检查,如果用户使用下面的URL地址:

http://mydomain/script/validate.dll?some%20string

http://mydomain/script/validate.dll?

或者相似的无效URL地址的情况(当然,所谓“无效”是从我们程序员的角度来看的,使用者可不这么想)。

当上面这种无效URL地址的情况发生时,我们将简单地回复下面一段文字到客户端:What you have entered is an invalid Master Card #.

上面就是我们的ISAPI扩展所能做的一切。

 

1、打开Visual Studio 2008

 

2、打开解决方案资源管理器视图->选择项目->添加新建项->C++文件(.cpp)

3、根据第二步,再添加一个模块定义文件(.def)

 

6、打开解决方案资源管理器视图->选择项目->属性->配置->所有配置->平台->所有平台

  • 常规->输出目录:$(SolutionDir)$(PlatformName)\$(ConfigurationName)
  • 常规->中间目录:$(PlatformName)\$(ConfigurationName)
  • 常规->配置类型:动态库(.dll)
  • 常规->MFC使用:使用标准 Windows 库
  • 常规->字符集:未设置
  • 常规->全程序优化:使用链接时间代码生成
  • C/C++->常规->调试信息格式:程序数据库(/Zi)
  • (如果需要编译64位的ISAPI)C/C++->常规->检测64位可移植性问题:是(/Wp64)

 

 

 

代码:

 1  #include  < windows.h >
 2  #include  < stdio.h >
 3  #include  < stdlib.h >
 4  // #include <httpfilt.h>
 5  #include  < httpext.h > //ISAPI扩展的头文件
 6 
 7  void  WriteContext(EXTENSION_CONTROL_BLOCK  * pECB,  char   * pszFormat,  );
 8  void  StartContext(EXTENSION_CONTROL_BLOCK  * pECB);
 9  void  EndContext(EXTENSION_CONTROL_BLOCK  * pECB);
10 
11  BOOL APIENTRY DLLMain(HANDLE hModule, DWORD dwCallReason, LPVOID lpReserved)
12  {
13       return  TRUE;
14  }
15 
16  BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO  * pVer)
17  {
18      pVer -> dwExtensionVersion  =  HSE_VERSION;
19      strncpy(pVer -> lpszExtensionDesc,  " My first ISAPI program " , HSE_MAX_EXT_DLL_NAME_LEN);
20       return  TRUE;
21  }
22 
23  DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK  * pECB)
24  {
25      StartContext(pECB);
26      WriteContext(pECB,  " <p>this is my first ISAPI program!!hello money!!</p> " );
27      EndContext(pECB);
28       return  HSE_STATUS_SUCCESS;
29  }
30 
31  BOOL WINAPI TerminateExtension(DWORD dwFlags)
32  {
33       return  TRUE;
34  }
35 
36  void  WriteContext(EXTENSION_CONTROL_BLOCK  * pECB,  char   * pszFormat,  )
37  {
38       char  szBuffer[ 1024 ];
39      va_list arg_ptr;
40      va_start(arg_ptr, pszFormat);
41      vsprintf(szBuffer, pszFormat, arg_ptr);
42      va_end(arg_ptr);
43 
44      DWORD dwSize  =  strlen(szBuffer);
45      pECB -> WriteClient(pECB -> ConnID, szBuffer,  & dwSize,  0 );
46  }
47 
48  void  StartContext(EXTENSION_CONTROL_BLOCK  * pECB)
49  {
50     WriteContext(pECB,  " <html>\r\n<body>\r\n " );
51  }
52   
53  void  EndContext(EXTENSION_CONTROL_BLOCK  * pECB)
54  {
55     WriteContext(pECB,  " </body>\r\n</html> " );

56 } 

 

其中EXTENSION_CONTROL_BLOCK结构用来和IIS通信

 

 

 

转载于:https://www.cnblogs.com/firefly_liu/archive/2009/11/11/1600738.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值