| Tenouk C & C++ | MFC Home | IIS & ISAPI Programming 4 | ActiveX Doc Servers & Internet Part 1 | Download | Site Index |


 

 

 

 

 

 

 

Programming the Microsoft Internet Information Server

ISAPI Filter Part 5

 

 

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 compiler on Windows XP Pro machine with Service Pack 2 and some Figure screen snapshots have been taken on Windows 2000 server. The Internet Information Services version is IIS 4.x/5.x/6.x on Windows 2000 Server SP 4 and Windows XP Pro SP 2. The Internet Explorer is 6.x. Topics and sub topics for this tutorial are listed below. A complete information about IIS installation, configuration and testing a Web site is dumped HERE and how to setup FTP server also included HERE. Both Web and FTP servers were done on Windows 2000 Server SP4. Don’t forget to read Tenouk’s small disclaimer.

  1. ISAPI Filters

  2. Writing an ISAPI Filter DLL

  3. The MFC ISAPI Filter Classes

  4. CHttpFilter

  5. CHttpFilterContext

  6. A Sample ISAPI Filter: myex34b.dll, myex34c.exe

  7. MYEX34B From Scratch: ISAPI Filter

  8. Choosing the Notification

  9. Sending Transaction Data to the Display Program

  10. MYEX34C From Scratch

  11. CMainFrame Class

  12. CMyex34cApp Class

  13. CMyex34cDoc Class

  14. CMyex34cView Class

  15. The Story of The Display Program

  16. Building and Testing the MYEX34B ISAPI Filter

 

 

ISAPI Filters

 

An ISAPI server extension DLL is loaded the first time a client references it in a GET or POST request. An ISAPI filter DLL is loaded (based on a Registry entry) when the WWW service is started. The filter is then in the loop for all HTTP requests, so you can read and/or change any data that enters or leaves the server.

 

 

Writing an ISAPI Filter DLL

 

The ISAPI Extension Wizard makes writing filters as easy as writing server extensions. Choose Generate A Filter Object, and Step 2 looks something like this.

 

ISAPI, IIS, MFC and C++ - Figure 64: ISAPI Extension Wizard Step 2 of 2.

 

Figure 55: ISAPI Extension Wizard Step 2 of 2.

 

The list of options under Which Notifications Will Your Filter Process? refers to seven places where your filter can get control during the processing of an HTTP request. You check the boxes, and the wizard generates the code.

 

The MFC ISAPI Filter Classes

 

There are two MFC classes for ISAPI filters, CHttpFilter and CHttpFilterContext.

 

CHttpFilter

 

With the help of the ISAPI Extension Wizard, you derive a class from CHttpFilter for each ISAPI filter you create. There's just one object of this class. The class has virtual functions for each of seven notifications. The list of filters in the order in which IIS calls them is below.

virtual DWORD OnReadRawData(CHttpFilterContext* pCtxt, PHTTP_FILTER_RAW_DATA pRawData);

virtual DWORD OnPreprocHeaders(CHttpFilterContext* pCtxt, PHTTP_FILTER_PREPROC_HEADERS pHeaderInfo);

virtual DWORD OnUrlMap(CHttpFilterContext* pCtxt, PHTTP_FILTER_URL_MAP pMapInfo);

virtual DWORD OnAuthentication(CHttpFilterContext* pCtxt, PHTTP_FILTER_AUTHENT pAuthent);

virtual DWORD OnSendRawData(CHttpFilterContext* pCtxt, PHTTP_FILTER_RAW_DATA pRawData);

virtual DWORD OnLog(CHttpFilterContext* pfc, PHTTP_FILTER_LOG pLog);

virtual DWORD OnEndOfNetSession(CHttpFilterContext* pCtxt);

If you override a function, you get control. It would be inefficient, however, if IIS made virtual function calls for every notification for each transaction. Another virtual function, GetFilterVersion(), is called once when the filter is loaded. The ISAPI Extension Wizard always overrides this function for you, and it sets flags in the function's pVer parameter, depending on which notifications you want. Here's a simplified sample with all the flags set:

BOOL CMyFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)

{

    CHttpFilter::GetFilterVersion(pVer);

    pVer->dwFlags |= SF_NOTIFY_ORDER_LOW | SF_NOTIFY_NONSECURE_PORT |

        SF_NOTIFY_LOG | SF_NOTIFY_AUTHENTICATION |

        SF_NOTIFY_PREPROC_HEADERS | SF_NOTIFY_READ_RAW_DATA |

        SF_NOTIFY_SEND_RAW_DATA | SF_NOTIFY_URL_MAP |

        SF_NOTIFY_END_OF_NET_SESSION;

    return TRUE;

}

If you had specified URL mapping requests only, the wizard would have set only the SF_NOTIFY_URL_MAP flag and it would have overridden only OnUrlMap(). IIS would not call the other virtual functions, even if they were overridden in your derived class.

 

CHttpFilterContext

 

An object of this second MFC class exists for each server transaction, and each of the notification functions gives you a pointer to that object. The CHttpFilterContext member functions you might call are GetServerVariable(), AddResponseHeaders(), and WriteClient().

 

A Sample ISAPI Filter: myex34b.dll, myex34c.exe

 

It was hard to come up with a cute application for ISAPI filters. The one we thought up, myex34b.dll, is a useful visual logging utility. IIS, of course, logs all transactions to a file (or database), but you must stop the server before you can see the log file entries. With this example, you have a real-time transaction viewer that you can customize.

 

MYEX34B From Scratch: ISAPI Filter

 

The following shows the steps to build MYEX34B, an ISAPI filter from scratch. Follow the shown steps.

 

ISAPI, IIS, MFC and C++ - Figure 65: MYEX34B – ISAPI Extension Wizard new project dialog.

 

Figure 56: MYEX34B – ISAPI Extension Wizard new project dialog.

 

ISAPI, IIS, MFC and C++ - Figure 66: MYEX34B – ISAPI Extension Wizard step 1 of 2, selecting Generate a Filter object option.

 

Figure 57: MYEX34B – ISAPI Extension Wizard step 1 of 2, selecting Generate a Filter object option.

 

ISAPI, IIS, MFC and C++ - Figure 67: MYEX34B – ISAPI Extension Wizard step 2 of 2, selecting the notification priority, connection type and notification type options.

 

Figure 58: MYEX34B – ISAPI Extension Wizard step 2 of 2, selecting the notification priority, connection type and notification type options.

 

ISAPI, IIS, MFC and C++ - Figure 68: MYEX34B project summary.

 

Figure 59: MYEX34B project summary.

 

Using ClassView, add the following two private member variables and a helper function.

 

HWND   m_hWndDest;

HANDLE m_hProcessDest;

void SendTextToWindow(char* pchData);

 

ISAPI, IIS, MFC and C++ - Figure 69: Adding m_hWndDest, a member variable through ClassView.

 

Figure 60: Adding m_hWndDest, a member variable through ClassView.

 

ISAPI, IIS, MFC and C++ - Figure 70: Adding m_hProcessDest member variable.

 

Figure 61: Adding m_hProcessDest member variable.

 

ISAPI, IIS, MFC and C++ - Figure 71: Adding SendToWindow() member function.

 

Figure 62: Adding SendToWindow() member function.

 

C++ source codes and MFC - ISAPI and IIS - Listing 14.

 

Listing 14.

 

In myex34b.cpp, define the following constant.

 

#define WM_SENDTEXT WM_USER + 5

 

C++ source codes and MFC - ISAPI and IIS - Listing 15.

 

Listing 15.

 

Add the following code at the end but before the return statement of the GetFilterVersion().

 

      ...

      ...

// m_hWndDest, m_hProcessDest used by SendTextToWindow

      m_hProcessDest = NULL;

      if((m_hWndDest = ::FindWindow(NULL, "myex34c")) != NULL)

      {

            DWORD dwProcessId;

            GetWindowThreadProcessId(m_hWndDest, &dwProcessId);

            m_hProcessDest = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);

            SendTextToWindow("MYEX34B filter started.\r\n");

      }

 

C++ source codes and MFC - ISAPI and IIS - Listing 16.

 

Listing 16.

 

Edit the OnReadRawData() as shown below.

DWORD CMyex34bFilter::OnReadRawData(CHttpFilterContext* pCtxt,

      PHTTP_FILTER_RAW_DATA pRawData)

{

      // TODO: React to this notification accordingly and

      // return the appropriate status code

      TRACE("CMyex34bFilter::OnReadRawData\n");

      // sends time/date, from IP, to IP, request data to a window

      char pchVar[50] = "";

      char pchOut[2000];

      DWORD dwSize = 50;

      BOOL bRet;

      CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%S GMT");

      strcpy(pchOut, strGmt);

      bRet = pCtxt->GetServerVariable("REMOTE_ADDR", pchVar, &dwSize);

      if(bRet && dwSize > 1) {

            strcat(pchOut, ", From ");

            strcat(pchOut, pchVar);

      }

      bRet = pCtxt->GetServerVariable("SERVER_NAME", pchVar, &dwSize);

      if(bRet && dwSize > 1) {

            strcat(pchOut, ", To ");

            strcat(pchOut, pchVar);

      }

      strcat(pchOut, "\r\n");

      int nLength = strlen(pchOut);

      // Raw data is not zero-terminated

      strncat(pchOut, (const char*) pRawData->pvInData, pRawData->cbInData);

      nLength += pRawData->cbInData;

      pchOut[nLength] = '\0';

      SendTextToWindow(pchOut);

      return SF_STATUS_REQ_NEXT_NOTIFICATION;

}

 

Edit the helper function, SendTextToWindow() as shown below.

void CMyex34bFilter::SendTextToWindow(char *pchData)

{

      if(m_hProcessDest != NULL) {

      int nSize = strlen(pchData) + 1;

      HANDLE hMMFReceiver;

      HANDLE hMMF = ::CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0, nSize, NULL);

      ASSERT(hMMF != NULL);

      LPVOID lpvFile = ::MapViewOfFile(hMMF, FILE_MAP_WRITE, 0, 0, nSize);

      ASSERT(lpvFile != NULL);

      memcpy((char*) lpvFile, pchData, nSize);

      ::DuplicateHandle(::GetCurrentProcess(), hMMF, m_hProcessDest, &hMMFReceiver, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

      ::PostMessage(m_hWndDest, WM_SENDTEXT, (WPARAM) 0, (LPARAM) hMMFReceiver);

      ::UnmapViewOfFile(lpvFile);

      }

}

Build MYEX34B, generating the myex34b.dll. We need another program, MYEX34C, to display the transaction data/messages. Before that let have some story about MYEX34B.

 

Choosing the Notification

 

Start by looking at the list of CHttpFilter virtual member functions. Observe the calling sequence and the parameters. For the MYEX34B logging application, we chose OnReadRawData() because it allowed full access to the incoming request and header text (from pRawData) and to the source and destination IP addresses (from pCtxt->GetServerVariable).

 

Sending Transaction Data to the Display Program

 

The ISAPI filter DLL can't display the transactions directly because it runs (as part of the IIS service process) on an invisible desktop. You need a separate program that displays text in a window, and you need a way to send data from the DLL to the display program. There are various ways to send the data across the process boundary. A conversation with Jeff Richter, the Windows guru who wrote Advanced Windows (Microsoft Press, 1997), led to the data being put in shared memory. Then a user-defined message, WM_SENDTEXT, is posted to the display program. These messages can queue up, so IIS can keep going independently of the display program.

We declared two handle data members in CMyex34bFilter::m_hProcessDest and CMyex34bFilter::m_hWndDest. We added code at the end of the GetFilterVersion() function to set these data members to the display program's process ID and main window handle. The code finds the display program's main window by its title (window’s title), myex34c, and then it gets the display program's process ID.

m_hProcessDest = NULL;

if((m_hWndDest = ::FindWindow(NULL, "myex34c")) != NULL)

{

    DWORD dwProcessId;

    GetWindowThreadProcessId(m_hWndDest, &dwProcessId);

    m_hProcessDest = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);

    SendTextToWindow("MYEX34B filter started\r\n");

}

Below is a helper function, SendTextToWindow(), which sends the WM_SENDTEXT message to the display program.

void CMyex34bFilter::SendTextToWindow(char* pchData)

{

    if(m_hProcessDest != NULL) {

        int nSize = strlen(pchData) + 1;

 

        HANDLE hMMFReceiver;

        HANDLE hMMF = ::CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL,

            PAGE_READWRITE, 0, nSize, NULL);

        ASSERT(hMMF != NULL);

        LPVOID lpvFile = ::MapViewOfFile(hMMF, FILE_MAP_WRITE, 0, 0, nSize);

        ASSERT(lpvFile != NULL);

        memcpy((char*) lpvFile, pchData, nSize);

        ::DuplicateHandle(::GetCurrentProcess(), hMMF, m_hProcessDest,

            &hMMFReceiver, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

        ::PostMessage(m_hWndDest, WM_SENDTEXT, (WPARAM) 0, (LPARAM) hMMFReceiver);

        ::UnmapViewOfFile(lpvFile);

    }

}

The DuplicateHandle() function makes a copy of MYEX34B's map handle, which it sends to the MYEX34C program in a message parameter. The MYEX34C process ID, determined in GetFilterVersion(), is necessary for the DuplicateHandle() call. Here is the filter's OnReadRawData() function, which calls SendTextToWindow():

DWORD CMyex34bFilter::OnReadRawData(CHttpFilterContext* pCtxt, PHTTP_FILTER_RAW_DATA pRawData)

{

    TRACE ("CMyex34bFilter::OnReadRawData\n");

    // sends time/date, from IP, to IP, request data to a window

    char pchVar[50] = "";

    char pchOut[2000];

    DWORD dwSize = 50;

    BOOL bRet;

    CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%SGMT");

    strcpy(pchOut, strGmt);

    bRet = pCtxt->GetServerVariable("REMOTE_ADDR", pchVar, &dwSize);

    if(bRet && dwSize > 1) {

        strcat(pchOut, ", From ");

        strcat(pchOut, pchVar);

    }

    bRet = pCtxt->GetServerVariable("SERVER_NAME", pchVar, &dwSize);

 

    if(bRet && dwSize > 1) {

        strcat(pchOut, ", To ");

        strcat(pchOut, pchVar);

    }

    strcat(pchOut, "\r\n");

    int nLength = strlen(pchOut);

    // Raw data is not zero-terminated

    strncat(pchOut, (const char*) pRawData->pvInData, pRawData->cbInData);

    nLength += pRawData->cbInData;

    pchOut[nLength] = '\0';

    SendTextToWindow(pchOut);

    return SF_STATUS_REQ_NEXT_NOTIFICATION;

}

 

MYEX34C From Scratch

 

The following are the steps to build MYEX34C. Follow the shown steps.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ISAPI, IIS, MFC and C++ - Figure 72: MYEX34C – new MFC AppWizard project dialog.

 

Figure 63: MYEX34C – new MFC AppWizard project dialog.

 

ISAPI, IIS, MFC and C++ - Figure 73: MYEX34C – Step 1 of 6, selecting SDI application.

 

Figure 64: MYEX34C – Step 1 of 6, selecting SDI application.

 

ISAPI, IIS, MFC and C++ - Figure 74: MYEX34C – Step 2 of 6.

 

Figure 65: MYEX34C – Step 2 of 6.

 

ISAPI, IIS, MFC and C++ - Figure 75: MYEX34C – Step 3 of 6, selecting Container in order to use CRichEditView class, deselect the Automation and ActiveX Controls.

 

Figure 66: MYEX34C – Step 3 of 6, selecting Container in order to use CRichEditView class, deselect the Automation and ActiveX Controls.

 

ISAPI, IIS, MFC and C++ - Figure 76: MYEX34C – Step 4 of 6, selecting SDI application, no Docking toolbar feature.

 

Figure 67: MYEX34C – Step 4 of 6, selecting SDI application, no Docking toolbar feature.

 

ISAPI, IIS, MFC and C++ - Figure 77: MYEX34C – Step 5 of 6.

 

Figure 68: MYEX34C – Step 5 of 6.

 

ISAPI, IIS, MFC and C++ - Figure 78: MYEX34C – Step 6 of 6, selecting CRichEditView for Doc and View as the base class.

 

Figure 69: MYEX34C – Step 6 of 6, selecting CRichEditView for Doc and View as the base class.

 

ISAPI, IIS, MFC and C++ - Figure 79: MYEX34C – project summary.

 

Figure 70: MYEX34C – project summary.

 

Add the following context menu.

 

ID

Caption

IDR_MENUCONTEXT

X

ID_EDIT_CLEAR_ALL

&Clear All

 

Table 1.

 

ISAPI, IIS, MFC and C++ - Figure 80: X menu property page.

 

Figure 71: X menu property page.

 

ISAPI, IIS, MFC and C++ - Figure 81: Clear All menu item property page.

 

Figure 72: Clear All menu item property page.

 

Just delete the View menu for the IDR_MAINFRAME, because we don’t need the Status bar.

 

ISAPI, IIS, MFC and C++ - Figure 82: Deleting the View menu.

 

Figure 73: Deleting the View menu.

 

 

CMainFrame Class

 

Define WM_SENDTEXT, a user define Windows message as shown below in MainFrm.h.

 

#define WM_SENDTEXT WM_USER + 5

 

C++ source codes and MFC - ISAPI and IIS - Listing 17.

 

Listing 17.

 

Delete the OnCreate(). Add OnSendText() message map function and OnUpdateFrameTitle() virtual function. Unfortunately the OnUpdateFrameTitle() function not available in ClassWizard of my Visual C++ 6.0, may be available in Visual Studio or VC++ with Service Pack. This function added manually.

 

virtual void OnUpdateFrameTitle(BOOL bAddToTitle);

 

C++ source codes and MFC - ISAPI and IIS - Listing 18.

 

Listing 18.

 

afx_msg LONG OnSendText(UINT wParam, LONG lParam);

 

C++ source codes and MFC - ISAPI and IIS - Listing 19.

 

Listing 19.

 

Add the following #include directive to MainFrm.cpp.

 

#include <afxpriv.h> // for AfxSetWindowText

 

C++ source codes and MFC - ISAPI and IIS - Listing 20.

 

Listing 20.

 

Add the message map manually.

 

ON_MESSAGE(WM_SENDTEXT, OnSendText)

 

C++ source codes and MFC - ISAPI and IIS - Listing 21.

 

Listing 21.

 

Just delete the OnCreate() and edit PreCreateWindow() as shown below.

 

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

      return CFrameWnd::PreCreateWindow(cs);

}

 

Add the following message handlers’ implementation.

void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)

{

      // the ISAPI filter needs to find this window by name

      // just display the app name without the file name

      TRACE("CFrameWnd::OnUpdateFrameTitle\n");

      AfxSetWindowText(m_hWnd, AfxGetApp()->m_pszAppName);

}

 

LONG CMainFrame::OnSendText(UINT wParam, LONG lParam)

{

      TRACE("CMainFrame::OnSendText\n");

      LPVOID lpvFile = ::MapViewOfFile((HANDLE) lParam, FILE_MAP_READ, 0, 0, 0);

      GetActiveView()->SendMessage(EM_SETSEL, (WPARAM) 999999, 1000000);

      GetActiveView()->SendMessage(EM_REPLACESEL, (WPARAM) 0, (LPARAM) lpvFile);

      ::UnmapViewOfFile(lpvFile);

      ::CloseHandle((HANDLE) lParam);

      return 0;

}

 

C++ source codes and MFC - ISAPI and IIS - Listing 22.

 

Listing 22.

 

CMyex34cApp Class

 

Add the following code after the InitInstance().

 

AfxEnableControlContainer();

 

C++ source codes and MFC - ISAPI and IIS - Listing 23.

 

Listing 23.

 

Add the following code just after the AddDocTemplate().

// Enable DDE Execute open

EnableShellOpen();

RegisterShellFileTypes(TRUE);

 

C++ source codes and MFC - ISAPI and IIS - Listing 24.

 

Listing 24.

 

CMyex34cDoc Class

 

Using ClassWizard or ClassView, add SaveModified() virtual function.

 

ISAPI, IIS, MFC and C++ - Figure 83: Adding SaveModified() virtual function.

 

Figure 74: Adding SaveModified() virtual function.

 

Then, edit the code as shown below.

BOOL CMyex34cDoc::SaveModified()

{

      return TRUE;

}

 

C++ source codes and MFC - ISAPI and IIS - Listing 25.

 

Listing 25.

 

Change the following message map:

 

ON_UPDATE_COMMAND_UI_RANGE(ID_OLE_VERB_FIRST, ID_OLE_VERB_LAST, CRichEditDoc::OnUpdateObjectVerbMenu)

 

to

 

ON_UPDATE_COMMAND_UI(ID_OLE_VERB_FIRST, CRichEditDoc::OnUpdateObjectVerbMenu)

 

C++ source codes and MFC - ISAPI and IIS - Listing 26.

 

Listing 26.

 

CMyex34cView Class

 

Using ClassWizard or ClassView, add WM_RBUTTONDOWN windows message handler, also, command and command update for ID_EDIT_CLEAR_ALL.

 

ISAPI, IIS, MFC and C++ - Figure 84: Adding Windows message, command and update commands.

 

Figure 75: Adding Windows message, command and update commands.

 

C++ source codes and MFC - ISAPI and IIS - Listing 27.

 

Listing 27.

 

Edit the code for the implementation part as shown below.

BOOL CMyex34cView::PreCreateWindow(CREATESTRUCT& cs)

{    

      BOOL bPreCreated = CRichEditView::PreCreateWindow(cs);

      cs.style |= ES_READONLY;

      return bPreCreated;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

C++ source codes and MFC - ISAPI and IIS - Listing 28.

 

Listing 28.

 

void CMyex34cView::OnRButtonDown(UINT nFlags, CPoint point)

{

      TRACE("CMyex34cView::OnRButtonDown\n");

      CMenu menu;

      menu.LoadMenu(IDR_MENUCONTEXT);

      ClientToScreen(&point);

      menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this);

}

 

void CMyex34cView::OnEditClearAll()

{

      CRichEditCtrl& re = GetRichEditCtrl();

      re.SetSel(0, -1);

      // won't let us clear unless we reset readonly flag

      re.SetOptions(ECOOP_XOR, ECO_READONLY);

      re.Clear();

      re.SetOptions(ECOOP_SET, ECO_READONLY);

}

 

void CMyex34cView::OnUpdateEditClearAll(CCmdUI* pCmdUI)

{

      pCmdUI->Enable(GetRichEditCtrl().GetTextLength() > 0);

}

 

C++ source codes and MFC - ISAPI and IIS - Listing 29.

 

Listing 29.

 

Build and run MYEX34C. The following is the output.

 

ISAPI, IIS, MFC and C++ - Figure 85: MYEX34C in action.

 

Figure 76: MYEX34C in action.

 

The Story of The Display Program

 

The display program, myex34c.exe, isn't very interesting. It's a standard AppWizard CRichEditView program with a WM_SENDTEXT handler in the main frame class:

LONG CMainFrame::OnSendText(UINT wParam, LONG lParam)

{

    TRACE("CMainFrame::OnSendText\n");

    LPVOID lpvFile = ::MapViewOfFile((HANDLE) lParam, FILE_MAP_READ, 0, 0, 0);

    GetActiveView()->SendMessage(EM_SETSEL, (WPARAM) 999999, 1000000);

    GetActiveView()->SendMessage(EM_REPLACESEL, (WPARAM) 0, (LPARAM) lpvFile);

    ::UnmapViewOfFile(lpvFile);

    ::CloseHandle((HANDLE) lParam);

    return 0;

}

This function just relays the text to the view. The MYEX34C CMainFrame class overrides OnUpdateFrameTitle() to eliminate the document name from the main window's title. This ensures that the DLL can find the MYEX34C window by name. The view class maps the WM_RBUTTONDOWN message to implement a context menu for erasing the view text. Apparently rich edit view windows don't support the WM_CONTEXTMENU message.

 

Building and Testing the MYEX34B ISAPI Filter

 

Build both the MYEX34B and MYEX34C projects, and then start the MYEX34C program. For IIS 1.0 – 3.0, to specify loading of your new filter DLL, you must manually update the Registry.

Run the Regedit/regedt32 application, and then double-click on Filter DLLs in \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\Parameters. Add the full pathname of the DLL separated from other DLL names if any, with a comma.

 

ISAPI, IIS, MFC and C++ - Figure 86:  Adding the full path of the DLL in registry – Windows XP Pro

 

Figure 77:  Adding the full path of the DLL in registry – Windows XP Pro

 

ISAPI, IIS, MFC and C++ - Figure 87:  Adding the full path of the DLL in registry – Windows 2000 Server.

 

Figure 78  Adding the full path of the DLL in registry – Windows 2000 Server.

 

To install an ISAPI filter for use with a Microsoft Internet Information Server version 4.0 - 6.0, 7.0 follow the following steps:

 

  1. Copy the filter DLL to an appropriate folder, such as the Scripts or Cgi-bin subdirectory.

  2. Open the Internet Service Manager (MMC).

  3. Select the appropriate level for the ISAPI filter:

    1. To use the ISAPI filter with all Web sites (global), select the ServerName icon. A global filter is installed for the entire IIS service and sees requests for all Web sites.

    2. To use the ISAPI filter with a specific Web site, select the icon for that Web site (for example, the default Web site). A site filter is installed at the site level and sees requests only for the site where it is installed.

  4. Right-click the level (icon) that you selected (for this example, we have to choose the global level).

 

ISAPI, IIS, MFC and C++ - Figure 88:  Invoking the Properties page of the Web site.

 

Figure 79:  Invoking the Properties page of the Web site.

 

  1. Click the ISAPI Filters tab. For Windows 2000 Server, to configure an ISAPI filter for all Web sites, first click the Edit button that is next to the Master Properties of the WWW Service.

  1. Click Add.

  2. Type a name for the ISAPI filter.

  3. Click Browse and select the ISAPI filter that you copied in step 1.

 

ISAPI, IIS, MFC and C++ - Figure 89:  Entering the filter properties.

 

Figure 80:  Entering the filter properties.

 

  1. Click OK.

  2. Stop the IISADMIN service. To do this, either type net stop iisadmin /y at a command prompt, or use the Services applet that is located in Control Panel (in Windows NT 4.0) or Administrative Tools (in Windows 2000) or .

  3. Start the World Wide Web Publishing Service by typing net start w3svc at a command prompt, or by using the Services applet that is located in Control Panel (in Windows NT 4.0) or Administrative Tools (in Windows 2000) or for steps 11 and 12, you can use the IIS context menu when the Server directory is selected and right clicked as shown below. All other dependencies (World Wide Web Publishing Service in this case) will also be restarted when you restart the IIS.

 

ISAPI, IIS, MFC and C++ - Figure 90:  Restarting the IIS.

 

Figure 81:  Restarting the IIS.

 

  1. Repeat the previous step for any other services that were stopped in step 11 if needed.

  2. Browse back to the ISAPI Filters tab (by following steps 1-5) and verify that the filter is loaded properly. You should see a green arrow that is pointing up under the Status column.

NOTE: The ISAPI Filters tab specifies a load order, with the filter at the top of the list loading first. Normally Sspifilt.dll, the ISAPI filter for SSL, is at the top of the list to allow any other filters to access data before IIS encrypts and transmits or decrypts and receives HTTPS traffic.

 

If your ISAPI filter failed to load, you may try removing the added filter and re-add the filter in the Debug directory of the project directly as shown below. This happens mostly because of the version of function (library) used in the source code not compatible with Windows operating system version.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

-------------------------------------------------------------------------------------------------------------------

ISAPI, IIS, MFC and C++ - Figure 91:  Using the debug version of the filter DLL.

 

Figure 82:  Using the debug version of the filter DLL.

 

The steps for adding an ISAPI filter to IIS 6.0 are the same as the steps for IIS 4.0 and IIS 5.0, but if you use an ISAPI filter that implements the SF_NOTIFY_READ_RAW_DATA event, you must change IIS 6.0 from its default configuration. Site filters cannot register for SF_NOTIFY_READ_RAW_DATA notifications. Global filters, however, can register for SF_NOTIFY_READ_RAW_DATA notifications. In this case, you must install the ISAPI filter at global level.

There's one more thing to do. You must change the IIS mode to allow the service to interact with the MYEX34C display program. To do this, click on the Services icon in the Control Panel/Administrative Tools, double-click on World Wide Web Publishing Service, and then check Allow Service To Interact With Desktop.

 

ISAPI, IIS, MFC and C++ - Figure 92: Enabling the Allow service to interact with desktop for World Wide Web Publishing service.

 

Figure 83: Enabling the Allow service to interact with desktop for World Wide Web Publishing service.

 

Finally, use Internet Service Manager to stop and restart the WWW service to load the filter DLL.

 

ISAPI, IIS, MFC and C++ - Figure 93: Restarting (start/stop) the World Wide Web service through the Services snap-in.

 

Figure 84: Restarting (start/stop) the World Wide Web service through the Services snap-in.

 

When you use the browser to retrieve pages from the server, you should see output something like this.

 

ISAPI, IIS, MFC and C++ - Figure 94: MYEX34C with user transaction data.

 

Figure 85: MYEX34C with user transaction data.

 

You can use the same steps for debugging an ISAPI filter that you used for an ISAPI server extension.

 

 

-----------End of the IIS/Web server programming--------

 

 

Further reading and digging:

  1. Apache web server for Windows ISAPI support.

  2. IIS 6.0 and CGI.

  3. DCOM at MSDN.

  4. COM+ at MSDN.

  5. COM at MSDN.

  6. Win32 process, thread and synchronization story can be found starting from Module R.

  7. MSDN MFC 7.0 class library online documentation.

  8. MSDN MFC 9.0 class library online documentation - latest version.

  9. MSDN Library

  10. Windows data type.

  11. Win32 programming Tutorial.

  12. The best of C/C++, MFC, Windows and other related books.

  13. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | IIS & ISAPI Programming 4 | ActiveX Doc Servers & Internet Part 1 | Download | Site Index |