The information in this article applies to:
IMPORTANT: This article contains information about editing the registry. Before you edit the registry, make sure you understand how to restore it if a problem occurs. For information about how to do this, view the "Restoring the Registry" Help topic in Regedit.exe or the "Restoring a Registry Key" Help topic in Regedt32.exe. SUMMARY
Writing an ISAPI extension or filter is no more difficult than writing any
other DLL, but debugging the DLL can be a challenge. This article provides
a few ideas for debugging an ISAPI DLL.
The following approaches are discussed:
MORE INFORMATION
ISAPI is a subset of the Win32 API. It allows WWW servers, such as
Microsoft's IIS, to be extended in two ways: extensions and filters. In an
ISAPI extension, a browser typically sends information entered in a form,
and the extension returns a complete HTML page built programmatically. In
an ISAPI filter, all browser data, both inbound and outbound, can be
modified before or after the server processes it. Extension and filter DLLs
must conform to a specification; there are specific functions that must be
implemented in order for the DLL to work.
Tips for ISAPI DevelopmentIIS runs as a Windows NT service in the local system account, which is what makes debugging ISAPI DLLs difficult. Running as a service introduces issues that are new to many programmers:
Turning Off DLL CachingIt is often desirable during development to force your ISAPI DLL to unload after each request, allowing you to replace it with a new version. IIS, by default, will hold the DLL in memory, keeping the DLL file in use. To modify this default cache setting, use the registry editor to change the following key:
WARNING: Using Registry Editor incorrectly can cause serious problems that
may require you to reinstall your operating system. Microsoft cannot
guarantee that problems resulting from the incorrect use of Registry Editor
can be solved. Use Registry Editor at your own risk.
For information about how to edit the registry, view the "Changing Keys And Values" Help topic in Registry Editor (Regedit.exe) or the "Add and Delete Information in the Registry" and "Edit Registry Data" Help topics in Regedt32.exe. Note that you should back up the registry before you edit it. If you are running Windows NT, you should also update your Emergency Repair Disk (ERD). Set CacheExtensions to 0 to disable caching, or set it to 1 to enable caching. When caching is turned off, extra loading and unloading makes ISAPI extensions dramatically slower, so use this option only for development. Filter DLLs are always loaded when the IIS service is running, and there is no way to change filter loading behavior. You must stop the IIS service with the administration tool, copy your new version over the old, and then restart the WWW service. The administration tool can run on a remote development machine controlling the server over the network. OutputDebugStringAn easy technique to debug either an ISAPI filter or extension is to use OutputDebugString. This function is part of Win32 and it is a standard way to send a string to a debug monitor. Use DBMON, included as a sample in the Win32 SDK, to view debug strings. A fix is necessary to view ISAPI debug output with DBMON, because the DLL runs in the local system account while DBMON runs in the logged-in user account. Starting with the Win32 SDK for Windows NT 4 beta 2, DBMON creates a NULL DACL and passes the security attributes to both CreateEvent calls and the CreateFileMapping call. You can modify DBMON yourself if you do not have the current SDK. The code below shows how to make a NULL DACL:
MessageBoxThe Online Help for MessageBox in the Win32 SDK describes a number of rarely-used constants, including MB_SERVICE_NOTIFICATION and MB_TOPMOST. In the context of ISAPI, add both of these flags to your message boxes because without them, the message box call will fail. Your ISAPI DLL is running as a service so it does not have a desktop, and these flags tell the operating system to display the message on the logged-in user's desktop.Please note that the value of MB_SERVICE_NOTIFICATION has changed on Windows NT 4.0 because of a conflict with Windows 95. When you specify MB_SERVICE_NOTIFICATION|MB_TOPMOST, your message will display properly on all versions of Windows NT and Windows 95. Do not use MessageBox for anything but debugging. If you need to record error messages, use the Windows NT event log. See the Win32 sample "logging" for information on how to use the event log. Depending on the SDK version you have, the logging sample may be in the q_a subdirectory off the root of the SDK CD, or it may be with other samples in \mstools\samples. Output to a Log FileAn easy way to track the flow of an ISAPI extension or filter is to use a log file. You can use the normal Win32 file I/O functions such as CreateFile, ReadFile, WriteFile, and CloseHandle. Your DLL's current directory will be the system root (c:\winnt40\system32). Also, keep security in mind because the default security context for your DLL is the local system account. This applies even when impersonation is active. If you do not allow the local system to create files in the appropriate directory and do not specify a non-NULL security attribute, your CreateFile call will fail.The ISAPI homefilt sample in the SDK provides one example of a file-logging mechanism. Running IIS InteractivelyA popular debugging option is to run IIS as a console application and use Visual C++ or another debugger for full source debugging. Information to do this is given in the SDK readme. Prior to Win32 SDK version 4 beta 2, the readme was included in the ActiveX SDK from http://www.microsoft.com/intdev. As of version 4 beta 2, ISAPI became part of the Win32 SDK. Examine the Win32 SDK readme for the procedure to run IIS as a console application.Briefly, here are a few tips. IIS cannot run as a console application and a service at the same time. You will have to stop all three IIS services, WWW, FTP, and Gopher, before running IIS from a command prompt. Once IIS is running, you can use PVIEW (part of Visual C++) or TLIST (part of the NT resource kit) to get the process ID of INETINFO.EXE, and then use your debugger to attach to the running process. Another approach is to supply the full command line, inetinfo.exe -e W3SVC, as described in the SDK readme, within the debug settings. For Visual C++, choose the Build menu, select Settings, then select the Debug tab. Type the full path name of "inetinfo.exe" as the Executable for Debug Session, and type "-e W3SVC" in Program Arguments. See Visual C++ 4.1 tech note TN063: Debugging Internet Extension DLLs, for details on using the Visual C++ debugger. Running IIS as a console application still is not exactly the same as running it as a service. For instance, authentication filters do not function properly in the console version of IIS. Instead of debugging IIS as a console application, it is possible to debug IIS running as a service. Attach a debugger to the INETINFO.EXE process, then use a browser and interact with your web site. When a debugger is attached to IIS, any occurrence of DebugBreak() will stop the service and put the debugger in full-source debugging mode. Each time you modify your DLL code, detach and restart the service using the Microsoft Internet Service Manager tool. The main cost of running IIS interactively is the start-up time required. It takes a few seconds to start and stop your debugger and, during development, this may become unacceptable. Be sure to consider the other alternatives. Using an Alternate Heap for MemoryAn ISAPI DLL might share the process heap with the WWW service. ISAPI DLL memory overwrites may not show up until later, and they may appear to be a problem with IIS. When you suspect memory corruption problems, modify your DLL code to use an alternate heap by calling HeapCreate, then HeapAlloc and HeapFree for all memory allocations. If switching from the process heap to a new heap changes the behavior of a crash, you can conclude that your DLL is corrupting memory.See the ISAPI sample CGIWRAP to isolate your extension DLL from the server. CGIWRAP is an executable and will have its own address space so even when your DLL corrupts memory, IIS will remain safe. Also, the CGIWRAP process is terminated after each request is complete. This technique makes your extension very slow but is a helpful interim solution until the corruption bug is finally fixed. The Win32 family of VirtualAlloc functions allows you to allocate 64K blocks of memory and can modify the protection of a block of memory. It can be helpful to use the memory protection provided by these functions to diagnose memory overwrite bugs. Finally, before your DLL is deployed in a production environment, check for memory leaks. For example, cut and paste the following code to track the number of bytes allocated. Call DumpBytesInUse() within your code to track the number of bytes currently allocated:
Using CGIWRAP to Debug Without a ServerAn effective way to conduct basic testing on an ISAPI DLL is to use the CGIWRAP sample. CGIWRAP is an executable that calls an ISAPI DLL. Although it is intended to allow an ISAPI DLL run as a CGI executable, CGIWRAP can be modified for use with a debugger.There are two sources of input for an ISAPI DLL: HTTP header variables and HTTP data. An ISAPI DLL retrieves header variables from GetServerVariable and retrieves data from ReadClient. Similarly, a CGI executable gets its header variables from the environment (with getenv) and gets its data from standard input. This means you can simulate a WWW server from the Command Line. Set environment variables to match what is given to your ISAPI DLL and pipe a file into CGIWRAP to simulate the inbound form data given to your DLL. When CGIWRAP runs, it will translate environment variables and the piped input into an ISAPI interface. Because you have the source to CGIWRAP, you can set breakpoints on every line of code involved. You can also improve the utility of CGIWRAP by modifying the sample. Add your own Command Line options, including, perhaps, a "record" operation when no Command Line options are specified. A record operation automates the process of setting environment variables and piping standard input. The idea is to run CGIWRAP as a normal CGI application from your calling web page. CGIWRAP identifies that no Command Line parameters were sent, so it records the environment and saves it to a file. Then, from a debugger (on any machine), specify a Command Line option to CGIWRAP telling it to load its environment from the previously saved file. CGIWRAP doesn't do this now, but these changes are easy to make yourself. Keep in mind that CGIWRAP is not exactly like IIS. For example, CGIWRAP does not run in the context of a local system. This can make a tremendous difference in the way your ISAPI DLL behaves. Fortunately, when your DLL works with CGIWRAP but not with IIS, you'll know the problem is very likely related to security. Additional query words: iis isapi cgiwrap ismoke debug www cgi activex cache
Keywords : kbtshoot kbnokeyword iisapi |
Last Reviewed: August 26, 1999 © 2000 Microsoft Corporation. All rights reserved. Terms of Use. |