| Tenouk C & C++ | MFC Home | IIS & ISAPI Programming 2 | IIS & ISAPI Programming 4 | Download | Site Index |


 

 

 

 

 

 

Programming the Microsoft Internet Information Server

ISAPI Extension Part 3

 

 

 

 

 

 

 

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. The Simplest Idea...Continue

  2. The MFC ISAPI Server Extension Classes

  3. CHttpServer

  4. CHttpServerContext

  5. CHtmlStream

  6. A Practical ISAPI Server Extension: myex34a.dll

  7. MYEX34A From Scratch

 

 

Next, create HTML page named weathermap.html with the following simple content.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>

 

<HEAD>

<TITLE>Weathermap HTML Form</TITLE>

</HEAD>

 

<BODY>

 

<H1></H1>

<CENTER><B><FONT color="#FF0000" face="Verdana">Welcome to the Satellite Weathermap Service</FONT></B></CENTER>

<H1></H1>

<FORM action="scripts/mymaps.dll?GetMap" method="POST">

  <P>Select your state: <SELECT name="State">

  <OPTION>Alabama</OPTION>

  <OPTION>Alaska</OPTION>

  <OPTION>Idaho</OPTION>

  <OPTION>Washington</OPTION>

  </SELECT> </P>

  <P><INPUT type="submit"><INPUT type="reset"> </P>

</FORM>

 

</BODY>

 

</HTML>

 

Listing 4.

 

Put this file under the c:\Inetpub\wwwroot. Launch browser and type the local address as shown below.

 

http://localhost/weathermap.html

 

The following web page will be displayed. When you select a state and click the Submit Query button, mymaps.dll will be executed.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 39: The Weathermap page in action.

 

Figure 30: The Weathermap page in action.

 

Select a state and click the Submit Query button.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 40: Invoking and executing GetMap() in mymaps.dll.

 

Figure 31: Invoking and executing GetMap() in mymaps.dll.

 

Hopefully you got the idea now.

 

The MFC ISAPI Server Extension Classes

 

Now is a good time to review the three MFC classes that are used to create an MFC ISAPI server extension. Remember that these classes are for ISAPI server extensions only. Don't even think of using them in ordinary Winsock or WinInet applications.

 

CHttpServer

 

With the help of the ISAPI Extension Wizard, you derive a class from CHttpServer for each ISAPI server extension DLL that you create. You need one member function for each extension function (including the default function), and you need an overridden GetTitle() function. The framework calls your extension functions in response to client requests, using the connections established in the parse map. The ISAPI Extension Wizard provides an overridden GetExtensionVersion() function, which you seldom edit unless you need initialization code to be executed when the DLL is loaded. One of the CHttpServer member functions that you're likely to call is AddHeader(), which adds special response headers, such as Set-Cookie, before the response is sent to the server.

 

CHttpServerContext

 

There's one CHttpServer object per DLL, but there is one CHttpServerContext object for each server transaction request. Your extension functions each provide a pointer to one of these objects. You don't derive from CHttpServerContext, so you can't easily have variables for individual transactions. Because different IIS threads can manage transactions, you have to be careful to perform synchronization for any data members of your CHttpServer class or global variables. You've already seen the use of the StartContent(), EndContent(), and WriteTitle() functions of the CHttpServer class plus the overloaded >> operator. You might also need to call the CHttpServerContext::GetServerVariable function to read information sent by the client in the request headers.

 

CHtmlStream

 

Most of the time, you don't use the CHtmlStream class directly. The CHttpServerContext class has a CHtmlStream data member, m_pStream, that's hooked up to the >> operator and serves as the output for HTML data. You could access the CHtmlStream object and call its Write member function if you needed to send binary data to the client. Because objects of the CHtmlStream class accumulate bytes in memory before sending them to the client, you need an alternative approach if your DLL relays large files directly from disk.

 

A Practical ISAPI Server Extension: myex34a.dll

 

The weather map server isn't interesting enough to make into a real project. You'll probably find the MYEX34A example more to your taste. It's a real Internet commerce application, a pizza-ordering program. Imagine a computer-controlled pizza oven and a robot arm that selects frozen pizzas.

 

MYEX34A From Scratch

 

Use the previous module’s DEFAULT.HTM file, rename it to index.html and put it under the c:\Inetpub\wwwroot. You also can create it by using the following code. Also make sure the backgrd.gif and bullet.gif files are also in the same sub directory.

 

<!-- This is DEFAULT.HTM file (myex33a) renamed to index.html -->

<HTML>

 

<HEAD>

<TITLE>Inside Visual C++ Home Page</TITLE>

</HEAD>

 

<BODY background="backgrd.gif">

 

<FONT color="#0000ff">

<H1></H1>

<CENTER><B><FONT face="Verdana">Welcome to the Nothing test page</FONT></B></CENTER>

<H1></H1>

<P></FONT></P>

<UL>

  <UL>

    <BR>

    <IMG src="bullet.GIF" align="MIDDLE" border="0"><A href="PizzaForm.html"> Pizza

    form </A>

  </UL>

</UL>

 

</BODY>

 

</HTML>

 

Listing 5.

 

You can test the page using http://localhost/ address provided that your IIS/web server was properly configured.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 41: MYEX34A main web page in action.

 

Figure 32: MYEX34A main web page in action.

 

Create another HTML page named PizzaForm.html and use the following code. Put this file under the c:\Inetpub\wwwroot directory.

 

<HTML>

 

<HEAD>

<TITLE>Inside Visual C++ HTML Form 1</TITLE>

</HEAD>

 

<BODY>

 

<H1></H1>

<CENTER><B><FONT color="#0000FF" face="Verdana" size="4">Welcome to CyberPizza</FONT></B></CENTER>

<H1></H1>

<P><FONT color="#FF0000" face="Tahoma">Enter your order.</FONT> </P>

<FORM action="scripts/myex34a.dll?ProcessPizzaForm" method="POST">

  <P>Your Name: <INPUT type="text" name="name" value> </P>

  <P>Your Address: <INPUT type="text" name="address" value> </P>

  <P>Number of Pies: <INPUT type="text" name="quantity" value="1"> </P>

  <P>Pizza Size: </P>

  <MENU>

    <LI><INPUT type="radio" name="size" value="8">8-inch </LI>

    <LI><INPUT type="radio" name="size" value="10">10-inch </LI>

    <LI><INPUT type="radio" name="size" value="12" checked>12-inch </LI>

    <LI><INPUT type="radio" name="size" value="14">14-inch </LI>

  </MENU>

  <P>Toppings: </P>

  <P><INPUT type="checkbox" name="top1" value="Pepperoni" checked> Pepperoni

  <INPUT type="checkbox" name="top2" value="Onions"> Onions

  <INPUT type="checkbox" name="top3" value="Mushrooms"> Mushrooms

  <INPUT type="checkbox" name="top4" value="Sausage"> Sausage </P>

  <P><EM>(you can select multiple toppings)</EM> </P>

  <P><INPUT type="submit" value="Submit Order Now"><INPUT type="reset"> </P>

</FORM>

 

</BODY>

 

</HTML>

 

Listing 6.

 

Test the page by clicking the Pizza form link in the previous main page.

 

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 42: PizzaForm.html in action.

 

Figure 33: PizzaForm.html in action.

 

Next, let build the MYEX34A DLL program. Follow the shown steps.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 43: MYEX34A – ISAPI Extension new project dialog.

 

Figure 34: MYEX34A – ISAPI Extension new project dialog.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 44: MYEX34A – ISAPI Extension Wizard Step 1 of 1.

 

Figure 35: MYEX34A – ISAPI Extension Wizard Step 1 of 1.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 45: MYEX34A project summary.

 

Figure 36: MYEX34A project summary.

 

Use ClassView or manually add the following member variables to CMyex34aExtension class (myex34a.h).

 

private:

      CCriticalSection m_cs;

      int m_nTotalPizzaOrders;

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 46: Adding private member variable to CMyex34aExtension class.

 

Figure 37: Adding private member variable to CMyex34aExtension class.

 

Listing 7 - C++ source code and MFC for ISAPI and IIS

 

Listing 7.

 

Then, add GetTitle() message handler function for the page title.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 47: Adding GetTitle() message handler function to CMyex34aExtension class.

 

Figure 38: Adding GetTitle() message handler function to CMyex34aExtension class.

 

Add handlers for the commands.

 

void ConfirmOrder(CHttpServerContext* pCtxt, LPCTSTR pstrName);

void ProcessPizzaForm(CHttpServerContext* pCtxt, LPCTSTR pstrName, LPCTSTR pstrAddr, int nQuantity, LPCTSTR pstrSize, LPCTSTR pstrTop1, LPCTSTR pstrTop2, LPCTSTR pstrTop3, LPCTSTR pstrTop4);

void ProcessTimesheet(CHttpServerContext* pCtxt, int nPeriod, LPCTSTR pstrEmployee, double dHours, int nJob);

 

Listing 8 - C++ source code and MFC for ISAPI and IIS

 

Listing 8.

 

Delete the TerminateExtension(), here, been commented out.

 

Listing 9 - C++ source code and MFC for ISAPI and IIS

 

Listing 9.

 

The CPP file. Manually, add command passing maps in myex34a.cpp.

 

ON_PARSE_COMMAND(ConfirmOrder, CMyex34aExtension, ITS_PSTR)

ON_PARSE_COMMAND_PARAMS("name")

ON_PARSE_COMMAND(ProcessPizzaForm, CMyex34aExtension, ITS_PSTR ITS_PSTR ITS_I4 ITS_PSTR ITS_PSTR ITS_PSTR ITS_PSTR ITS_PSTR)

ON_PARSE_COMMAND_PARAMS("name address quantity size top1=~ top2=~ top3=~ top4=~")

ON_PARSE_COMMAND(ProcessTimesheet, CMyex34aExtension, ITS_I4 ITS_PSTR ITS_R8 ITS_I4)

ON_PARSE_COMMAND_PARAMS("Period Employee Hours Job")

 

Listing 10 - C++ source code and MFC for ISAPI and IIS

 

Listing 10.

 

Initialize the m_nTotalPizzaOrders in the constructor as shown below.

 

CMyex34aExtension::CMyex34aExtension()

{

      m_nTotalPizzaOrders = 0;

}

 

Listing 11 - C++ source code and MFC for ISAPI and IIS

 

Listing 11.

 

Finally, add the implementation part as shown below just after the Default() and don’t forget to delete the TerminateExtension() implementation.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

...

...

 

// BOOL CMyex34aExtension::TerminateExtension(DWORD dwFlags)

// {

//     // extension is being terminated

//     //TODO: Clean up any per-instance resources

//     return TRUE;

// }

 

///////////////////////////////////////////////////////////////////////

// CMyex34aExtension command handlers

 

void CMyex34aExtension::Default(CHttpServerContext* pCtxt)

{

       StartContent(pCtxt);

       WriteTitle(pCtxt);

 

       *pCtxt << _T("This default message was produced by the Internet");

       *pCtxt << _T(" Server DLL Wizard. Edit your CMyex34aExtension::Default()");

       *pCtxt << _T(" implementation to change it.\r\n");

 

       EndContent(pCtxt);

}

 

// This must be defined first, coz we will use it in ProcessPizzaForm

void CMyex34aExtension::ConfirmOrder(CHttpServerContext* pCtxt, LPCTSTR pstrName)

{

       StartContent(pCtxt);

       WriteTitle(pCtxt);

       *pCtxt << "<p>Our courteous delivery person will arrive within 30 minutes.";

       *pCtxt << "<p>Thank you, " << pstrName << ", for using CyberPizza.";

       // now retrieve the order from disk by name, then make the pizza

       // be prepared to delete the order after a while if the customer doesn't confirm

       m_cs.Lock(); // gotta be threadsafe

         long int nTotal = ++m_nTotalPizzaOrders;

       m_cs.Unlock();

       *pCtxt << "<p>Total pizza orders = " << nTotal;

       EndContent(pCtxt);

}

 

void CMyex34aExtension::ProcessPizzaForm(CHttpServerContext* pCtxt, LPCTSTR pstrName,

                           LPCTSTR pstrAddr, int nQuantity, LPCTSTR pstrSize,

                           LPCTSTR pstrTop1, LPCTSTR pstrTop2, LPCTSTR pstrTop3, LPCTSTR pstrTop4)

{

       StartContent(pCtxt);

       WriteTitle(pCtxt);

       if((strlen(pstrName) > 0) && (strlen(pstrAddr) > 0))

       {

              *pCtxt << " Your pizza order is as follows:";

              *pCtxt << "<p>Name: " << pstrName;

              *pCtxt << "<p>Address: " << pstrAddr;

              *pCtxt << "<p>Number of pies: " << (long int) nQuantity;

              *pCtxt << "<p>Size: " << pstrSize;

              *pCtxt << "<p>Toppings: " << pstrTop1 << " " << pstrTop2 << " " << pstrTop3 << " " << pstrTop4;

               // Just fix the price...hahahaha...should has another routine lol!

              *pCtxt << "<p>The total cost is $23.49, including delivery.";

              *pCtxt << "<form action=\"myex34a.dll?ConfirmOrder\" method=POST>";

              *pCtxt << "<p><input type=\"hidden\" name=\"name\" value=\"" << pstrName << "\">"; // xref to original order

              *pCtxt << "<p><input type=\"submit\" value=\"Confirm and charge my credit card\">";

              *pCtxt << "</form>";

              // store this order in a disk file or database, referenced by name

       }

       else {

              *pCtxt << " You forgot to enter your name or address. Back up and try again.";

       }

       EndContent(pCtxt);

}

 

void CMyex34aExtension::ProcessTimesheet(CHttpServerContext* pCtxt, int nPeriod, LPCTSTR pstrEmployee, double dHours, int nJob)

{

       StartContent(pCtxt);

       WriteTitle(pCtxt);

       *pCtxt << " Employee timesheet:";

       *pCtxt << "<p>Period: " << (long int) nPeriod;

       *pCtxt << "<p>Employee: " << pstrEmployee;

       *pCtxt << "<p>Hours: " << dHours;

       *pCtxt << "<p>Job: " << (long int) nJob;

       // store this transaction in a disk file or database

       EndContent(pCtxt);

}

// Do not edit the following lines, which are needed by ClassWizard.

#if 0

BEGIN_MESSAGE_MAP(CMyex34aExtension, CHttpServer)

       //{{AFX_MSG_MAP(CMyex34aExtension)

       //}}AFX_MSG_MAP

END_MESSAGE_MAP()

#endif // 0

 

///////////////////////////////////////////////////////////////////////

// If your extension will not use MFC, you'll need this code to make

// sure the extension objects can find the resource handle for the

// module.  If you convert your extension to not be dependent on MFC,

// remove the comments around the following AfxGetResourceHandle()

// and DllMain() functions, as well as the g_hInstance global.

 

/****

static HINSTANCE g_hInstance;

 

HINSTANCE AFXISAPI AfxGetResourceHandle()

{

       return g_hInstance;

}

 

BOOL WINAPI DllMain(HINSTANCE hInst, ULONG ulReason,

                                  LPVOID lpReserved)

{

       if (ulReason == DLL_PROCESS_ATTACH)

       {

              g_hInstance = hInst;

       }

       return TRUE;

}

****/

 

LPCTSTR CMyex34aExtension::GetTitle() const

{

       // TODO: Add your specialized code here and/or call the base class

       return "MyEx34a Pizza Extension";

}

 

 

Listing 12.

 

Build the program, generating myex34a.dll. Copy the DLL file to c:\Inetpub\scripts sub directory. We put all the DLL in one place for easier management. You can create other directory/sub directory or put directly under the default wwwroot directory, make sure the path is matched with the code in your HTML and create virtual directory if needed.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 48: The DLL copied to scripts sub directory on Windows XP Pro.

 

Figure 39: The DLL copied to scripts sub directory on Windows XP Pro.

 

Restart/start the World Wide Web publishing if required. Go to the browser address bar and type http://localhost/ and press Enter or click the Go button. The following page should be launched.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 49: Pizza order web site in action.

 

Figure 40: Pizza order web site in action.

 

 

When the Pizza form link is clicked, the following form will be displayed.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 50: CyberPizza’s Pizza form, ready for the order.

 

Figure 41: CyberPizza’s Pizza form, ready for the order.

 

Fill up the data and click the Submit Order Now button.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 51: Buying pizza by filling up the Pizza form.

 

Figure 42: Buying pizza by filling up the Pizza form.

 

Here, we have the confirmation page for the data filled, processed by ProcessPizzaForm().

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 52: Confirmation page for the ordered pizza.

 

Figure 43 Confirmation page for the ordered pizza.

 

Click the Confirm and charge my credit card button. The following page displayed, processed by ConfirmOrder().

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 53: Confirmed page of the ordered pizza and the payment, ready to be delivered.

 

Figure 44: Confirmed page of the ordered pizza and the payment, ready to be delivered.

 

Try reorder the pizzas, the Total pizza orders will increase. If the required fields not filled and customer just clicks the Submit Order Now, the following message will be displayed.

 

IIS, ISAPI, Winsock, C++ and MFC - Figure 54: Form information validation message.

 

Figure 45 Form information validation message.

 

For all the web pages shown, take note that the DLL functions executed were displayed in the browser address bar.

 

 

Continue on next Module...

 

 

 

 

 

 

 

 

 

 

 

 

 

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 2 | IIS & ISAPI Programming 4 | Download | Site Index |