演练:使用本机代码创建Global-Level HTTP 模块
本演练演示如何使用 C++ 创建一个示例全局级别 HTTP 模块,该模块在 IIS 7 中实现新的请求处理体系结构。 当你使用早期 ASP.NET 版本的 HTTP 模块和 ISAPI 筛选器或扩展编写 IIS 应用程序时,此新体系结构扩展了本机代码编程的功能。 有关使用新的请求处理体系结构设计 HTTP 模块的详细信息,请参阅 设计Native-Code HTTP 模块。
在本演练中,你将为 HTTP 模块创建一个 C++ 项目,添加“Hello World”项目所需的代码,然后编译并测试该模块。
先决条件
需要以下软件才能完成示例中的步骤:
IIS 7。
Visual Studio 2005。
注意
也可以使用 Visual Studio .NET 2003 或更早版本,但演练步骤可能并不相同。
创建模块
在本部分演练中,你将为 HTTP 模块创建一个空的 C++ DLL 项目。
创建新的 C++ DLL 项目
启动 Visual Studio 2005。
验证全局选项是否具有 SDK 包含文件的所有正确路径:
在 “工具” 菜单上,单击 “选项” 。
在树视图中展开 “项目和解决方案 ”节点,然后单击“ VC++ 目录”。
在 “显示目录” 下拉框中,选择“ 包括文件”。
验证是否已列出 SDK 的安装路径(包括文件)。 如果未列出路径,请单击“ 新建行 ”图标,然后添加安装 SDK 包含文件的路径。
单击 “确定” 。
创建新的 C++ 项目:
在 “文件” 菜单上,指向 “新建” ,然后单击 “项目” 。
“新建项目” 对话框随即打开。
在“ 项目类型 ”窗格中,展开 “Visual C++ ”节点,然后单击“ Win32”。
在 “模板 ”窗格中,选择“ Win32 项目”。
在“ 名称 ”框中,键入 “HelloWorld”。
在“ 位置 ”框中,键入示例的路径。
单击 “确定” 。
Win32 应用程序向导随即打开。
单击“应用程序设置”。
在“ 应用程序类型”下,单击“ DLL”。
在“ 其他选项”下,单击“ 空项目”。
单击“完成”。
添加代码和源文件
下一步是将所需的 C++ 和模块定义文件添加到项目中。
将源文件添加到项目
创建模块定义文件以导出 RegisterModule 函数:
在“解决方案资源管理器”中,右键单击“源文件”,指向“添加”,然后单击“新建项”。
此时将打开“添加新项”对话框。
在“类别”窗格中展开“Visual C++”节点,然后单击“代码”。
在 “模板 ”窗格中,选择“ 模块定义文件 ”模板。
在“ 名称 ”框中,键入 “HelloWorld”,并在“ 位置 ”框中保留文件的默认路径。
单击“添加”。
添加以下代码:
LIBRARY HelloWorld EXPORTS RegisterModule
可以选择使用 /EXPORT:RegisterModule 开关导出 RegisterModule 函数:
在“ 项目 ”菜单上,单击“ HelloWorld 属性”。
在树视图中展开 “配置属性” 节点,展开“ 链接器 ”节点,然后单击“ 命令行”。
在 “配置” 下拉框中,选择“ 所有配置”。
在 “其他选项” 框中,键入 /EXPORT:RegisterModule。
单击 “确定” 。
创建 C++ 文件:
在“解决方案资源管理器”中,右键单击“源文件”,指向“添加”,然后单击“新建项”。
此时将打开“添加新项”对话框。
在“类别”窗格中展开“Visual C++”节点,然后单击“代码”。
在 “模板 ”窗格中,选择“ C++ 文件” 模板。
在“ 名称 ”框中,键入 “HelloWorld”,并在“ 位置 ”框中保留文件的默认路径。
单击“添加”。
添加以下代码:
#define _WINSOCKAPI_ #include <windows.h> #include <sal.h> #include <httpserv.h> // Create the module's global class. class MyGlobalModule : public CGlobalModule { public: // Process a GL_APPLICATION_START notification. GLOBAL_NOTIFICATION_STATUS OnGlobalPreBeginRequest( IN IPreBeginRequestProvider * pProvider ) { UNREFERENCED_PARAMETER( pProvider ); WriteEventViewerLog( "Hello World!" ); return GL_NOTIFICATION_CONTINUE; } VOID Terminate() { // Remove the class from memory. delete this; } MyGlobalModule() { // Open a handle to the Event Viewer. m_hEventLog = RegisterEventSource( NULL,"IISADMIN" ); } ~MyGlobalModule() { // Test whether the handle for the Event Viewer is open. if (NULL != m_hEventLog) { // Close the handle to the Event Viewer. DeregisterEventSource( m_hEventLog ); m_hEventLog = NULL; } } private: // Create a handle for the event viewer. HANDLE m_hEventLog; // Define a method that writes to the Event Viewer. BOOL WriteEventViewerLog(LPCSTR szNotification) { // Test whether the handle for the Event Viewer is open. if (NULL != m_hEventLog) { // Write any strings to the Event Viewer and return. return ReportEvent( m_hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, &szNotification, NULL ); } return FALSE; } }; // Create the module's exported registration function. HRESULT __stdcall RegisterModule( DWORD dwServerVersion, IHttpModuleRegistrationInfo * pModuleInfo, IHttpServer * pGlobalInfo ) { UNREFERENCED_PARAMETER( dwServerVersion ); UNREFERENCED_PARAMETER( pGlobalInfo ); // Create an instance of the global module class. MyGlobalModule * pGlobalModule = new MyGlobalModule; // Test for an error. if (NULL == pGlobalModule) { return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } // Set the global notifications and exit. return pModuleInfo->SetGlobalNotifications( pGlobalModule, GL_PRE_BEGIN_REQUEST ); }
可以选择使用
__stdcall (/Gz)
调用约定编译代码:在“ 项目 ”菜单上,单击“ HelloWorld 属性”。
在树视图中展开 “配置属性” 节点,展开 C/C++ 节点,然后单击“ 高级”。
在 “配置” 下拉框中,选择“ 所有配置”。
在 “调用约定 ”下拉框中,选择 __stdcall (/Gz) 。
单击 “确定” 。
编译和测试模块
HTTP 模块具有所需的一切。 只需编译并测试 HTTP 模块即可。
编译和测试项目
编译 HTTP 模块:
在 “生成” 菜单上,单击 “生成解决方案” 。
验证 Visual Studio 是否未返回任何错误或警告。 如果遇到任何错误或警告,则需要在测试项目之前解决这些问题。
将 HTTP 模块的 DLL 文件复制到 IIS 文件夹:
打开 Windows 资源管理器,找到创建 C++ 项目时指定的默认文件夹。
根据生成选项,应在项目的默认文件夹中看到名为 Debug 或 Release 的文件夹。
在“调试”或“发布”文件夹中,找到名为 HelloWorld.dll 的文件。
将 HelloWorld.dll 文件复制到 Inetsrv 文件夹,该文件夹默认位于 %WinDir%\System32\Inetsrv。
有关说明,请将HelloWorld.dll模块添加到模块列表 (,请参阅 设计Native-Code HTTP 模块) 。
使用 Internet Explorer 浏览到网站;应会看到正常的网站内容。
打开 Windows 事件查看器并切换到全局应用程序日志;应看到一个条目,其中列出了“IISADMIN”作为事件源。
右键单击事件,然后单击“ 属性 ”以查看事件详细信息。 应会在“说明”窗格中看到“Hello World!”消息。
设置疑难解答
如果模块未编译或不按预期工作,可以检查以下几个方面:
确保已为导出的函数指定
__stdcall
,或者已使用__stdcall (/Gz)
调用约定配置编译。确保已将正确的
RegisterModule
导出添加到定义文件。确保已将定义文件添加到项目设置。 若要将文件添加到项目设置,请完成以下步骤:
在 “项目” 菜单上,单击 “属性” 。
在树视图中展开 “配置属性” 节点,展开 “链接器 ”节点,然后单击“ 输入”。
对于 模块定义文件 设置,请确保已列出定义文件。