HOWTO: Diagnose one cause of W3SVC failing to start with Win32 Error 193 on 64bit Windows

I recently came across an interesting new variation of "failure" related to enabling WOW64 that can happen on IIS6 on 64bit Windows... so I am going to explain what happened and how to fix it.

Question:

Hi,

I ran into an issue with IIS in wow64 mode. On this machine I consistently get an error trying to turn on wow64 mode.

I turn on wow64 mode in IIS, do IISReset, and then when I run “aspnet_regiis –I –enable” from the 32-bit directory, I get an error in the log file:

2005-12-14 12:37:39 Failure Waiting for service to start: WaitForServiceState failed with HRESULT 8007041d: 'The service did not respond to the start or control request in a timely fashion. '
2005-12-14 12:37:40 Failure Starting service: w3svc: StartServiceByName failed with HRESULT 8007041d: 'The service did not respond to the start or control request in a timely fashion. '
2005-12-14 12:37:40 Failure Restarting W3SVC: RestartW3svc failed with HRESULT 8007041d: 'The service did not respond to the start or control request in a timely fashion. '

If I check the w3svc service, it is stopped. If I try to start it, I get:

The World Wide Web Publishing Service service is starting.
The World Wide Web Publishing Service service could not be started.

A system error has occurred.

System error 193 has occurred.

*** is not a valid Win32 application.

If I check the EventVwr, I get:

Could not load all ISAPI filters for site/service. Therefore startup aborted.

ISAPI Filter 'd:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll' could not be loaded due to a configuration problem. The current configuration only supports loading images built for a AMD64 processor architecture. The data field contains the error number. To learn more about this issue, including how to troubleshooting this kind of processor architecture mismatch error, see https://go.microsoft.com/fwlink/?LinkId=29349.

This error makes no sense to me, because at this point IIS is in wow64 mode, so it should not have any problems loading the 32-bit aspnet_filter.dll.

I double-checked that wow64 mode is turned on:

 Enable32BitAppOnWin64           : (BOOLEAN) True

Do you know what could be causing this?

Answer:

Hmm... this issue is indeed interesting because all the rules for running IIS6 in WOW64 mode, as explained in this blog entry, were obeyed... except for one little detail that I did not mention earlier, though it is definitely there in MSDN documentation:

WOW64 mode is only valid when IIS6 is running in Worker Process Isolation Mode.

In particular, WOW64 mode is not valid when IIS6 is running in IIS5 Compatibility Mode. Now, we can argue over the philosophical oxymoron where "IIS5 never existed as 64bit" and "IIS6's IIS5 Compatibility Mode on 64bit Windows only runs as 64bit", but let's not sidetrack ourselves here... ;-)

The Problem...

What happened in this situation is that IIS6 is simultaneously configured to run in IIS5 Compatibility Mode (W3SVC/IIs5IsolationModeEnabled=1) AND WOW64 mode (W3SVC/AppPools/Enable32BitAppOnWin64=1). This is actually an invalid IIS configuration, but due to the sequence of configuration events, an interesting failure condition occurrs - W3SVC fails to start up due to Win32 Error 193 when it never loads the bitness-mismatched user binary. Here is what happens:

  1. IIS6 is configured to run in IIS5 Compatibility Mode (W3SVC/IIs5IsolationModeEnabled=1)
    • This means that ISAPI Filter DLLs will run inside of the inetinfo.exe process.
    • Now, inetinfo.exe is a 64bit process because it needs to read %SYSTEMROOT%\System32\inetsrv\metabase.xml for IIS configuration.
    • The reason that inetinfo.exe cannot be a 32bit process is because WOW64 FileSystemRedirection will be in effect for all non-excluded filepaths under %SYSTEMROOT%\System32 (this is an OS-level behavior). Having duplicate metabase.xml under both System32 and Syswow64 directories is simply bad design... for example, imagine change synchronization...
  2. IIS6 is then configured to run in WOW64 Mode (W3SVC/AppPools/Enable32BitAppOnWin64=1)
  3. ASPNET_REGIIS.EXE -I -Enable from the 32bit Framework directory is run, which changes W3SVC/Filters/ASP.Net_2.0.50727.42/FilterPath to load the 32bit ASP.Net ISAPI Filter DLL from %windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_filter.dll .
  4. IIS is then restarted to load the global ISAPI Filter.
  5. When W3SVC starts, it goes down two totally different initialization paths depending on whether IIS5 Compatibility Mode is enabled. In this case, it is enabled, so W3SVC communicates with the worker process core, now loaded in inetinfo.exe (instead of w3wp.exe - this is one major difference for IIS5 Compatibility Mode), to start up.
  6. Worker process core in inetinfo.exe, a 64bit process, tries to load global ISAPI Filters as a part of initialization (this is for IIS5 Compatibility Mode - global ISAPI Filters must load at service startup, unlike the demand-start of Worker Process Isolation Mode).
  7. From step #3, a 32bit aspnet_filter.dll is configured to load... into the 64bit inetinfo.exe process... which dutifully fails with Win32 error 193 (0x800700C1).
  8. Worker process core reports this error back to W3SVC and aborts startup because failure to load ISAPI Filter is a fatal failure on IIS6 (unlike on IIS5, where ISAPI Filters implementing security features can fail to load and IIS still continues).
  9. W3SVC also treats this failure as fatal and aborts. This eventually results in ExitProcess() being called, which causes SCM to report the failure to start the W3SVC service.

The Solution...

In this case, the fix is to resolve the invalid configuration of attempting to run IIS5 Isolation Mode and WOW64 simultaneously. Either choose to run in IIS5 Compatibility Mode and keep things 64bit, or run in IIS6 Worker Process Isolation Mode with WOW64. Due to the oxymoron stated earlier, I suspect that 99.9% of the time you will choose to run in IIS6 Worker Process Isolation Mode with WOW64. I mean, 64bit ISAPI Filter which requires ReadRawData is rare commodity, most likely generated by self-interest. :-)

This means that you should run the following:

 CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs SET W3SVC/IIs5IsolationModeEnabled 0
NET STOP HttpFilter /y
NET START W3SVC

To switch IIS6 back into Worker Process Isolation Mode, and since you already have WOW64 enabled and 32bit DLLs correctly configured, things should just work... assuming you covered all other bases regarding WOW64 and possible bitness mismatch mentioned in my prior blog entries.

//David