Professional Documents
Culture Documents
Microsoft IS-API
Microsoft IS-API
The original article for this PDF can be found on DevCentral. http://devcentral.iticentral.com
by Kevin Webb
This is the first part in an introduction to the Internet Server API (ISAPI) used by some web servers for creating interactive web applications (Internet Server Applications, or ISAs). You need to have an understanding of Web/CGI development, MFC and Visual C++ v4.1 or later to fully understand this article.
Speed There is a considerable gain in performance. Features ISAPI allows for creation of server filters (for pre/post processing). And it's fully integrated with MFC.
Standardization Only a few servers currently support ISAPI. Ease of Development Documentation is very sparse, and debugging is somewhat tedious.
ISAPI DLLs are called by the client in the same manner as a CGI using ether GET or POST methods. For example, the following request is made: http://www.mysite.com/myisa.dll?name=bob&id=15248 The "name" and "id" fields and their associated data are passed into the ISA and the data must be placed in data structures before it can be used. To facilitate this, ISAPI uses a request mapping system. Each request that can be made has a parse map. The parse map directs the data to an appropriate data structure by defining the type and order in which the data will be received form the client. For example, with the "name=bob&id=15248" request, the map would show a string and an int, and "bob" and "15248" would be parsed out and placed in their respective data structures. The parse map system also has another function. ISAPI can direct requests to specific member functions within the ISA. The request string can contain a command that the parse map uses to direct the request to the proper member function (or Command Handler in ISAPI lingo) of the ISA.
Because ISAPI uses a command driven approach to handling requests, ISA development may seem a little awkward at first. But once learned, this can a very powerful way of handling requests.
1. 2. 3. 4. 5. 6.
Open the User Manager for Domains utility (found in Administrative Tools program group). Select the User Rights from the Policies menu. Check the Show Advanced User Rights box. Select Act as part of the operating system from the Right list. Click the Add button to get the Add Users and Groups dialog. Click the Show Users button, and select the account you will be using. Click Add. Do the same for the Generate security audits rights.
For these changes to take effect you must log out and log back in. IIS is a package of three Services: FTP Publishing Service, Gopher Publishing Service, and World Wide Web Publishing Service. Since the debugger will be running IIS from the command line, all three of these services must be stopped. This can be done from the Services Control Applet, or from the Internet Service Manager application. If you will be doing a lot of debugging, it is recommended that you turn the IIS service off using the Services Control Applet and disable the automatic restart feature (this will prevent you from having to turn the service off each time the computer is restarted). Once the service is off, the project workspace must be configured by doing the following:
1. 2. 3. 4. 5. 6.
Select Settings from the Build menu. Click on the Debug tab and select the "General Category". Type the location of the IIS executable (it would be c:\inetsrv\server\inetinfo.exe by default installation) in the "Executable for debug session" field. Type "-e w3svc" in the "Program arguments" field. Click on the Link tab. Type the path and filename to where you want the compiled DLL to be placed into the "Output filename" field. This path should be somewhere inside the website directory tree so it can be accessed by a URL. For example, if your website root directory is c:\www\ and you placed "helloweb.dll" in the root, it's URL would be: http://www.mysite.com/helloweb.dll
If you have not logged off since changing your privileges, do so now. Then log back on. The default source generated by ISAPI Extension Wizard contains everything necessary to compile a working ISA (it won't do anything, but it will compile). Now that you have finished configuring the debugging environment, you are ready to build and run the project. Press F5 to start the ISA and press yes when asked if you want to build the project. A few seconds after the debugger is up, IIS should be running in the background. Now that everything is ready, enter the URL of DLL into you favorite web browser, but add a question mark to the end. The URL should look similar to this: http://www.mysite.com/helloweb.dll? Connecting to the ISA for the first time should take several seconds. However, DLLs are cached after their first execution and that speeds things up considerably. After the DLL loads, the following message should appear:
This default message was produced by the Internet Server DLL Wizard. Edit your CHelloWebExtension::Default() implementation to change it.
BEGIN_PARSE_MAP(CHelloWebExtension, CHttpServer) // TODO: insert your ON_PARSE_COMMAND() and // ON_PARSE_COMMAND_PARAMS() here to hook up your commands. // For example: ON_PARSE_COMMAND(Default, CHelloWebExtension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CHelloWebExtension) END_PARSE_MAP(CHelloWebExtension)
The BEGIN_PARSE_MAP marks the beginning of the parse map. It takes the name of the ISA's CHttpServer and base class as parameters. The ON_PARSE_COMMAND macro maps a specific request format or command to a Command Handler function. It's parameters are the name of the function that the request should be directed to, the function's class, and the format of the request. The DEFAULT_PARSE_COMMAND specifies which function should be called if the request is empty or does not match any other parse map. It's parameters are the name of the function to be called and the function's class. The Command Handler functions are member functions of the main CHttpServer class that get called by the parse map. Below is the "Default" command handler for Hello Web:
void CHelloWebExtension::Default(CHttpServerContext* pCtxt) { StartContent(pCtxt); WriteTitle(pCtxt); *pCtxt << _T("This default message was produced by the Internet"); *pCtxt << _T("Server DLL Wizard. Edit your CHelloWebExtension::Default()"); *pCtxt << _T("implementation to change it.\r\n"); EndContent(pCtxt); }
When the request is empty or contains "Default", this fuction is called. On entry, it's passed the CHttpServerContext for the request (the first parameter of a command handler must be a CHttpServerContext). StartContent() places <HTML><BODY> in pCtxt, and WriteTitle() places the <TITLE> tags. The next three lines write the default message to pCtxt which points to a CHtmlStream. When the ISA is finished, the html stream buffer is sent to the client.
Hello Web
The first program will replace the default message string with "Hello Web!". Go the Default() member function of the CHelloWebExtension class and make the changes below:
void CHelloWebExtension::Default(CHttpServerContext* pCtxt) { StartContent(pCtxt); WriteTitle(pCtxt); *pCtxt << _T("Hello Web!"); EndContent(pCtxt); }
Build and run the DLL. Reload the DLL from the web browser and instead of:
This default message was produced by the InternetServer DLL Wizard. Edit your CHelloWebExtension::Default() implementation to change it.
Hello Web!
However, if you see "Server Error 500: Specified module not found.", your project is dynamically linked and the necessary DLLs are not available. To correct this, re-link the project statically with MFC (Go to Settings in the build menu and select the General tab and change the selection in the MFC list box to "Use MFC as a Static Library" and re-link the project). Developed Under: Windows NT 4.0 Visual C++ 4.1 IIS 3.0
2001 Interface Technologies, Inc. All Rights Reserved Questions or Comments? devcentral@iticentral.com PRIVACY POLICY
The original article for this PDF can be found on DevCentral. http://devcentral.iticentral.com
by Kevin Webb
This is the second part in an introduction to the Internet Server API (ISAPI) used by some web servers for creating interactive web applications (Internet Server Applications, or ISAs). You need to have an understanding of Web/CGI development, MFC and Visual C++ v4.1 or later to fully understand this article. Download the project files
G G
// // // // // //
Starts the definition of a parse map Parses the client's command Maps data from request to their respective data structures Defines the default command Ends the definition of a parse map
BEGIN_PARSE_MAP(CHelloWebExtension, CHttpServer) // TODO: insert your ON_PARSE_COMMAND()and // ON_PARSE_COMMAND_PARAMS() here to hook up your commands. // For example: ON_PARSE_COMMAND(Default, CHelloWebExtension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CHelloWebExtension) END_PARSE_MAP(CHelloWebExtension)
This map defines two commands: an empty request and the "Default" command. An empty request, handled by DEFAULT_PARSE_COMMAND, would look like:
// // // // // //
For the example above there would be an ITS_PSTR and an ITS_I4. The ON_PARSE_COMMAND would look like this:
This would not work, however, because ISAPI parses out everything between the ampersands as a field. So "name=bob" would be placed in the string, and "id=15248" would try to be placed in the int. This problem can be corrected by using the ON_PARSE_COMMAND_PARAMS macro. This is placed just after the ON_PARSE_COMMAND, and creates a map of the field names in the request. The parse map using ON_PARSE_COMMAND_PARAMS would look like this:
This specifies that the field titled "name" should be associated with the first data type in the parse map, and "id" with the second. When building HTML forms that interact with a parse map, make sure that the action of the form contains the command, and the form method is post. For example, the form for the parse map above would look like this:
<FORM ACTION="myisapi.dll?Add" METHOD=POST> <INPUT NAME="name"> <INPUT NAME="id"> <INPUT TYPE=SUBMIT> </FORM>
Writing: SimpleCalc
Create a new project titled "SimpleCalc", and follow the same steps as in lesson 1 to configure the debugger. SimpleCalc is a simple web driven calculator. It can add, subtract, multiply, and divide. By default, the SimpleCalc ISA will display a form containing two edit fields for number entry and a select box for choosing the appropriate mode. When the form is submitted, it will issue a "Calc" command, the answer will be calculated, and the result will be displayed. The first step of writing SimpleCalc is to set up the parse map. The map needs to handle a default and "Calc" command. With "Calc" the edit fields "num1" and "num2" must be mapped to doubles and the select box "mode" should be mapped to a string. The finished parse map should
BEGIN_PARSE_MAP(CSimpleCalcExtension, CHttpServer) //Handle "Calc" command. ON_PARSE_COMMAND(Calc, CSimpleCalcExtension, ITS_R8 ITS_R8 ITS_PSTR) //Maps "num1" and "num2" to the ITS_R8s, and "mode" to the ITS_PSTR. ON_PARSE_COMMAND_PARAMS("num1 num2 mode") //Display form if request is empty. ON_PARSE_COMMAND(Default, CSimpleCalcExtension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(Default, CSimpleCalcExtension) END_PARSE_MAP(CSimpleCalcExtension)
Next the default command handler needs to be changed so that it displays the calc form. The form contains two edit boxes named "num1" and "num2" and a select box with the basic math operators (+, -, *, /). Here is the Default command handler with the form:
void CSimpleCalcExtension::Default(CHttpServerContext* pCtxt) { //Print the <HTML> <BODY> tags. StartContent(pCtxt); //Print the title. WriteTitle(pCtxt); //The next six lines print the default calc form. //For this form to work correctly the action must contain the "Calc" //command, and the method must be POST. *pCtxt *pCtxt *pCtxt *pCtxt *pCtxt *pCtxt *pCtxt << << << << << << << _T("<H4>SimpleCalc</H4<BR><BR>"); _T("<FORM ACTION=\"simplecalc.dll?Calc\" METHOD=POST>"); _T("<INPUT NAME=\"num1\" SIZE=5> "); _T("<SELECT NAME=\"mode\"><OPTION>+<OPTION>"); _T("<OPTION>*<OPTION>/</SELECT>"); _T("<INPUT NAME=\"num2\" SIZE=5><BR><BR>"); _T("<INPUT TYPE=SUBMIT></FORM>");
Now the "Calc" command handler needs to be written. It must determine the operator chosen by the user and calculate "num1" and "num2" accordingly, then return the result. It will look similar to this:
void CSimpleCalcExtension::Calc(CHttpServerContext* pCtxt, double num1, double num2, LPTSTR mode) { double result; //Prints the <HTML><BODY> tags. StartContent(pCtxt); //Prints the title. WriteTitle(pCtxt); //Determine the operator. switch( mode[0] ) { //Add case '+' : result = num1 + num2; //Print result. *pCtxt << num1 << _T(" + ") << num2 << _T(" = ") << result; break; //Subtract case '-' :
Once the code has been modified, build and run the project. Upon loading the ISA in the browser, the form will be displayed. Enter two numbers, choose an operation, and press submit. The result displayed will look similar to this:
The Hello Web and SimpleCalc projects are available on this page for download. Make sure that all the directory paths are configured for your server before using. Developed Under: Windows NT 4.0 Visual C++ 4.1 IIS 3.0
2001 Interface Technologies, Inc. All Rights Reserved Questions or Comments? devcentral@iticentral.com PRIVACY POLICY