Friday, April 27, 2007

Windows Forms Controls in IE Troubleshooting Guide

This post covers troubleshooting information for issues with loading .Net Windows Forms Usercontrols in Internet Explorer. IE in many cases does not provide clear error reporting when something goes wrong with loading a Windows Forms control embedded in a web page; the information here is presented to hopefully act as an aid in troubleshooting such issues.

For information on the general technique of embedding Windows Forms controls in web pages via <object> tags for viewing in Internet Explorer, take a look at these tutorials:

Tip: Viewing Fusion Bind errors from Internet Explorer

When a Windows Forms control fails to initially load properly, one or more "fusion bind errors" with information that may be helpful in diagnosing the problem may be logged.

Viewing fusion bind errors generated from errors loading .Net controls in Internet Explorer:

  • Open the Temporary Internet Files folder in an Explorer window. (One way to do this is from Internet Explorer, select Tools | Options; on the Internet Options dialog, on the General tab, next to "Browsing History", click Settings; on the Temporary Internet Files and History Settings dialog, click "View files".)
  • In the Temporary Internet Files explorer folder, sort by the Last Modified column to bring recent fusion bind error files to the top.
  • Look for files named "?FusionBindError ...". You can't double-click these files to view them; instead, open a new Internet Explorer window, and drag one of the Fusion Bind Error files to the new window to view the contents.

Setting up .Net framework trust to allow Windows Forms controls hosted in a web page on a remote web server to run

For .Net controls embedded in web pages that perform certain types of operations, .Net framework code access security trust must be set up to allow the control to load and run; if this is not done, the security policy of the .Net framework on the client machine will prevent the control from loading.

If a .Net control does fail to load due to load due to .Net trust not being set up properly, the symptom will be an empty rectangle with a "colorful icon" present in the top-left corner displayed on the web page in place of the control. (See the FAQ section below.)

In an internal corporate / LAN environment, trust can be granted to the web server hosting the web page that includes the .Net control. This can be done from the client machine by using the Microsoft .Net Framework Configuration tool (if it is installed), or from the command line by using the caspol.exe utility.

Granting .Net trust to a specific web server with the Microsoft .Net Framework Configuration tool

This tool is not installed on all machines. (I'm not sure when/how the tool does get installed on machines where it is present.) On machines where the tool is present, it can be found in the Administrative Tools folder as "Microsoft .NET 2.0 Configuration", where "2.0" is the actual installed version of the .Net framework.

Be sure to set up trust using the version of the tool that matches the .Net version which Internet Explorer will be using to load and run .Net controls. (In most cases, this will be newest version of the .Net framework installed on the machine.)

Setting up .Net framework trust on a single client machine for controls running on a particular web server:

  • Drill to .NET Framework Configuration | My Computer | Runtime Security Policy | Machine | Code Groups | All_Code.
  • Right-click All_Code and choose New from the context menu.
  • In the Create Code Group dialog that appears, enter a name for the new code group, then click Next. (The name can be anything, but I suggest using the name of the web server machine for which trust is to be established.)
  • In step 2 ("Choose a condition type"), select URL from the dropdown; in the URL field that appears, enter "http://mywebserver/*", where mywebserver is the actual name of the web server to trust. (If you use SSL to connect to the web server, enter "https" instead of "http".)
  • In step 3 ("Assign a Permission Set to the Code Group"), check the "Use existing permission set" radio button and select "FullTrust" from the dropdown. Click Next.
  • Click Finish on the final step of the Wizard.

Granting .Net trust to a specific web server with the caspol.exe command-line utility

Caspol.exe is a command-line code access security policy tool that is installed with the .Net framework. Caspol.exe is located at:

%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\caspol.exe

Where 2.0.50727 is the version number of the .Net framework installed on the client machine that IE is using to load the control. (2.0.50727 is the version number of the commercial release of the 2.0 .Net framework.)

Run the following command to establish .Net framework trust for a web server named serverName:

caspol -machine -addgroup 1 -url http://serverName/* FullTrust -name "http://serverName"

To view existing trust group settings set up on the local client machine, use:

caspol -lg

Regardless of which method is used to establish trust, after setting up trust for the web server, you'll need to close and re-open Internet Explorer to get it to pick up new trust setting.

The remainder of this document takes a FAQ format, with problems/issues in boldface and possible resolutions in plain type.

The "Colorful Icon" Issue

When attempting to load a Windows Forms control, the control does not appear; instead, a white box with a thin black outline appears in place of the control, with a colorful icon in the top-left corner.

A Windows Forms control that has failed to load, showing the "colorful icon"

Q: A Fusion Bind error is logged with this text: "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.VerificationException: Operation could destabilize the runtime."

A: The most common cause of this problem is that the control requires .Net Framework trust to run, but trust has not been granted to the server hosting the control, or to the control itself, by the client machine (the computer where Internet Explorer is running). See "Setting up .Net framework trust" above.

Other general things to check for a control failing to load with the "colorful icon" symptom:

A: The client machine might be configured to not trust unsigned .Net or ActiveX controls in IE | Tools menu | Internet Options | Security tab. (Not sure about the exact setting.) Adding the web server to "Trusted Sites" on the client will generally fix this. (This seems particularly common when the client is Windows 2003 Server.)

A: If the class constructor of the .Net control is throwing an uncaught exception, this behavior will occur. Try stepping through the constructor in a debugger (assuming the control is one you are developing).

A: Try clearing the Temporary Internet Files on the client machine (especially if some .Net components in the browser are working, but not others).

A: If the same browser window was previously used to bring up the same .Net control from a different virtual directory on the server machine, close the browser window and use a new one.

A: There could be something invalid or malformed in the client machine's machine.config file.

A: There could be an invalid or malformed iexplore.exe.config file present in the same folder as the Internet Explorer executable (typically C:\Program Files\Internet Explorer\). Try temporarily renaming the iexplore.exe.config file to something else.

More specific symptoms and resolutions for situations where IE is showing the "colorful icon" in place of the .Net control after the control has failed to load:

Q: Client is connecting to server using SSL (https://...). Connecting to the server using a normal (non-SSL, http://...) connection does load controls correctly (if the server permits non-SSL connections).

A: Ensure that .Net framework trust is set up on the client machine for the web server machine with both the "https://" and "http://" prefixes (2 separate trust entries).

A: In Internet Explorer | Tools | Options | Advanced tab, uncheck "Do not save encrypted pages to disk".

Q: On the server machine, the most recent event in the IIS log is a 401 error trying to load a config file linked from the web page where the .Net control is located using a <LINK REL='Configuration' HREF='/configFile.conf'> tag. No Fusion Bind error is logged on the client.

A: Check the Windows filesystem permissions on the .conf file. Try giving the "Everyone" group full permissions on the file to establish whether or not this is the problem. (If applying "Everyone" permissions does work to resolve the issue, you will probably then wish to remove "Everyone," and apply more fine-grained permissions, to allow IIS to serve the control, but without compromising security.)

A: On the server, in IIS Manager, under File Security for the config file (for that specific file, not the parent virtual directory security), if Anonymous access is checked, ensure that "Allow IIS to control password" is also checked.

Q: Server OS is Windows 2003 Server. Navigating in the browser directly to the config file referenced in the .Net control's web page results in a 404 error (even though the file really is there on the server).

A: In the Internet Information Services Manager utility, open the Properties dialog for the config file's parent virtual directory. In the HTTP Headers tab, click the Mime Types... button, and add the config file's extension (.conf).

Q: A new .Net framework version was recently installed on the client, after which the control started failing to load.

A: Set up trust for the web server machine under the new .Net framework version (as described above).

Q: A Fusion Bind error shows a FileLoadException and error message text that talks about a DLL file version incompatibility. The control may load properly from a different client machine, or when a different user is logged into the OS.

A: Clear the Shadow Cache for the user on the machine where the problem is occurring. (The Shadow Cache is typically located at "C:\Documents and Settings\username\Local Settings\Application Data\assembly\dl?", where ? is a numeral. Delete the entire directory tree under the "dl?" folder to clear the cache. It may be necessary to enable viewing of hidden files/folders to see the cache.)

Q: When using compressed .cab files referenced from a .conf file on the server to deliver the .dll file(s) for the Windows Forms control, a fusion bind error shows "System.IO.FileNotFoundException: File or assembly name ControlType, or one of its dependencies, was not found.

A: This may indicate some problem on the server or client with loading .cab files. One possible cause: The MIME type associated with cabinet files (.cab) is incorrectly set in IIS (HTTP Headers | File Types) to a content type of "application/x-compressed"; the MIME type associated with a .cab file must be "application/octet-stream" for .Net to load the controls from the cab file. In inetmgr, in the HTTP headers tab, click File Types... and fix the setting.

Q: The Fusion Bind Error shows something like "System.TypeLoadException: Could not load type 'Typename' from assembly 'TypeName'"

A: The class name specified in the object tag needs to have correct casing (uppercase/lowercase). In the example above, you would need to change "Typename" to "TypeName".

"Vertical Scrollbar" issues

Q: When attempting to load a Windows Forms control, the control does not appear; instead, a white box with a thin black outline appears in place of the control, with a colorful icon in the top-left corner.

A Windows Forms control that has failed to load, showing the "disabled vertical scrollbar"

A: Check the classid parameter of the control's <object> tag to be sure it is pointing at a valid virtual directory.

A: Make sure that the DLL file referenced in the classid is present in the virtual directory.

A: Rarely, I've seen this issue happen when in on the server, IIS settings (inetmgr), Execute Permissions for the virtual directory is set to "Scripts and Executables". Try setting Execute Permissions to "Scripts only".

A: When debugging an ASP.NET page through Visual Studio 2005, apparently the "ASP.NET Development Server" that Visual Studio 2005 provides for debugging ASP.NET 2.0 apps doesn't support display of Windows Forms controls in the browser. Use the real IIS server on the machine instead. (You can debug the ASP.NET page running in IIS by manually attaching the Visual Studio debugger to the aspnet_wp.exe process once the ASP.NET site has been initially opened in the browser.)

"X" Icon Issues

Q: When attempting to load a .Net control, the control does not appear; instead, a white box with a thin black outline appears in place of the control, with an "X" icon in the top-left corner.

A Windows Forms control that has failed to load, showing the "X" icon

A: Make sure that the .Net framework has been installed on the client machine.

A: Check that a classid parameter is present in the <object> tag in the HTML source of the web page where the control is located.

A: Check the primary DLL file of the assembly that the control is attempting to load. (I've seen this happen in a contrived case when a control was trying to use a .dll file with file size 0.)

Other Issues

Q: When attempting to load a .Net control, an error dialog appears: "Your current security settings prohibit running ActiveX controls on this page. As a result, the page may not display correctly." After the dialog is dismissed, the control does not appear on the page at all.

A: In Internet Explorer, go to Tools | Internet Options | Security tab. Running signed ActiveX controls needs to be allowed for the "zone" that the web server is in; the zone settings can be changed to "Medium", or the web server can be added to a more trusted zone ("Local intranet" or "Trusted sites").

Q: After a .Net control loads, it appears correctly, but the user needs to click the control before it can be interacted with. Before the control is "activated", a tooltip appears when the mouse is hovered over the control with text "Press SPACEBAR or ENTER to activate and use this control" or text "Click to activate and use this control".

A: This issue is caused by a change that Microsoft was forced to introduce in Internet Explorer due to patent litigation between Microsoft and Eolas. For details and workarounds, see the article Activating ActiveX Controls on MSDN.

Q: When attempting to load a .Net control, the control does not appear; instead, a solid gray box with no error message text appears.

A: Check the syntax of the <object> tag in the HTML source. IE is probably not recognizing it as an attempt to show a Windows Forms control.

Scripting Issues

Q: When calling a public API method on a .Net control from Javascript running on the web page, the Javascript error "Object doesn't support this property or method" occurs.

A: The .Net control probably didn't load successfully. (This may be non-obvious if the control is hidden on the page.)

Q: A script call to a .Net control fails with the Javascript error message "Unexpected call to method or property access."

A: Apparently IE doesn't support child windows directly calling methods in Windows Forms controls located in a browser parent window (using syntax like "window.opener.document.ControlID.Method()") . As a workaround, rewrite the script to call a Javascript function on the parent page, then have the new function make the actual call to the .Net control.

Q: A script call to a .Net control fails with the Javascript error message "Invalid procedure call or argument."

A: The script code may be calling the method with an incorrect number of method parameters.

Debugging Issues

Q: After making a code change to the .Net Usercontrol and rebuilding, the changes made are not reflected in the browser window, even after refreshing the page.

A: Close the current browser window, and reopen the web page in a new one.

Q: Can't hit breakpoints in the Visual Studio debugger when debugging a .NET Windows Forms object in the browser.

A: If launching the browser directly from Visual Studio, in Project Properties, on the Debug tab, make sure "Start external program" (pointing to iexplore.exe) is checked, not "Start browser with URL".

A: Make sure the DLL files used in the page being debugged are debug (not release) versions.

Q: When the Visual Studio 2003 .Net debugger is attached to an iexplore.exe instance, as soon as a .Net control starts loading, the browser closes and debugging ends. Both .Net 1.1 and 2.0 (or a later version) are installed on the machine. Q: Can't attach the VS.NET 2003 debugger to an iexplore.exe instance which is already running a .NET control.

A: Visual Studio 2003 can only debug .Net version 1.1 (not 2.0 or later versions), so you need to force IE to load controls using the 1.1 .Net framework. Create a new file named iexplore.exe.config in the Internet Explorer folder (the folder where iexplore.exe is located) with the following content:

<configuration>
 <startup>
   <requiredRuntime version="v1.1.4322"/>
   <supportedRuntime version="v1.1.4322"/>
 </startup>
</configuration>

This will force Internet Explorer to load any .Net controls that it encounters in web pages in the 1.1 version of the .Net framework, beginning with the next time a fresh instance of Internet Explorer is opened.

When finished debugging in Visual Studio .Net 2003, remove the iexplore.exe.config file to permit .Net controls (and possibly also Internet Explorer extensions) which require .Net 2.0 to run properly once again.

The information in this post is current as of Internet Explorer 7 and the .Net framework 2.0.

Please note that this is not a comprehensive guide to all possible issues that may occur with running .Net Usercontrols in Internet Explorer; also, the troubleshooting suggestions here may not work to resolve a given issue in all cases. Please use caution when making configuration changes to your system (particularly security-related changes)!

Thursday, April 26, 2007

Workaround: Foxit Reader Find feature not working

I was just using the basic Find feature of the lightweight .pdf document reader Foxit Reader to search for some text in a particular .pdf document. Inexplicably, the Find dialog kept reporting no results found, even though I was sure that the word I was searching on was present in the document.

I tried searching on other words in the document (even common words that I could see in the visible portion of the document on the screen right in front of me, such as "the"), but Foxit kept insisting on finding no results. Finally, out of frustration, I tried searching on a single letter ("a") -- and surprisingly, that did work correctly!

I subsequently figured out that the problem was that Foxit Reader was for whatever reason apparently rendering a tiny space between each pair of letters in each word of the document. So searching on "options" produced no results, but searching on "o p t i o n s" (with a space inserted between each letter) did successfully find each instance of the word "options" in the document.

I'm not sure why Foxit Reader (version 2.0 build 1606) was behaving this way, but at least using this workaround I was able to find what I was searching for. I did try opening the same .pdf document in Adobe Acrobat Reader 7, and I was able to successfully perform searches in the normal manner, without needing to insert spaces between each letter in the word I was searching on.

Friday, April 20, 2007

Strict mode IE6 bug with CSS "Bottom" style on img tags

While working on part of a new ASP.Net site at work recently, I came across a weird behavior when viewing the page in Internet Explorer 6 where a particular image on the page wasn't staying aligned with the surrounding elements on the page when the browser window was resized. I was able to boil the problem down to a very simple repro case on a basic html page. Here's the source code for the repro page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
  <img src="AnyKey.gif" style="position:absolute;bottom:20px">
</body>
</html>

It turns out that the problem is that for whatever reason, IE6 only recalculates the position of the image relative to the bottom of the browser window when the browser window is resized horizontally -- but not when the browser window is resized vertically! So on IE6, if you resize the browser window to be vertically, the image stays fixed in place, not moving to follow the bottom edge of the window. But when you resize the browser window horizontally, the image immediately pops back into its proper place relative to the bottom edge of the window.

I went ahead and put the repro page up on my website, here -- feel free to take a look if you happen to be using IE6.

Oddly enough, this issue only affects IE6 when in CSS standards-compliance mode; if the page is put into the IE6 quirks mode by deleting the !DOCTYPE tag from the top of the html source, the image does correctly move to follow the bottom edge of the browser window when the window is resized vertically in IE6.

The workaround I found for this issue is simple; just enclose the img tag in a div tag, and put the style attribute on the div tag instead of the img tag:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
  <div style="position:absolute;bottom:20px">
    <img src="AnyKey.gif">
  </div>
</body>
</html>

This odd behavior doesn't happen in the other browsers I tested (IE7 and Firefox 2.0).

I am looking forward to the day when IE6 has been phased out enough that needing to code around its occasional quirky behavior is no longer necessary -- but that day is most likely years away yet!

Wednesday, April 18, 2007

Fix: "Networking is not installed or properly configured"

I was running into a problem earlier today on a secondary Windows XP SP2 machine of mine at work where although the machine could browse the Internet successfully and could ping other machines on the local network, it could not connect to any file shares (shared folders) on other machines on the local domain. Other machines on the network could still browse file shares with no problem.

On the machine experiencing the problem, in the Computer Name tab of the System Properties dialog (brought up from Control Panel | System), the "Network ID" and "Change" buttons were disabled (grayed out). A message at the bottom of the dialog indicated that the reason for this was that "networking is not installed or properly configured".

I was able to fix the problem by removing and re-installing the machine's Client for Microsoft Networks, as follows:

  • From the Control Panel, open Network Connections.
  • Right-click on my active Local Area Network connection and choose Properties.
  • In the Local Area Connection Properties dialog, select Client for Microsoft Networks, then click Uninstall. Close the dialog and reboot when prompted.
  • After rebooting, bring up the Local Area Connection Properties again.
  • Re-install the Client for Microsoft Networks by clicking the Install button, selecting Client from the Select Network Component Type dialog, then selecting Client for Microsoft Networks from the Select Network Client dialog. Click OK all the way back out, then reboot the machine once more when prompted.

I don't know enough about the internals of Windows networking to understand *why* this solution worked to fix this problem in my case -- only that it did work! I share the steps I took here in hopes that they might be helpful to others as well (as a possible alternative to more extreme solutions such as re-installing Windows!).

(Please do consider carefully before following these steps; Client for Microsoft Networks is a critical Windows networking component, and removing it -- even with the intention of subsequently re-installing it -- could possibly have other adverse affects on a system. For example, if the re-install of the Client for Microsoft Networks were to fail for whatever reason, the machine could be left in a state where the machine's network connectivity is even further adversely affected.)

Monday, April 02, 2007

Using both "left" and "right" properties in a CSS style

I recently was working on a web page where I needed to draw a rectangle that would always be 50 pixels from the left edge of the browser window and 100 pixels from the right edge of the browser window, and which would stretch/shrink to maintain these criteria as the browser window was resized by the user. (Essentially, the rectangle would be "anchored" to both the left and right edges of the browser window.)

This rectangle would otherwise always appear on the same place on the page, and thus could be set to use the position:absolute style. Anchored Rectangle I decided to use a simple <div> tag set with a background-color CSS property to render the rectangle on the page.

To accomplish this, at first I was thinking I would need to catch the browser's window resize event, and call a Javascript function that would check the browser window's new width, subtract from that width the right "padding" for the rectangle (100 pixels in this case), and set the resulting figure as the new width for the rectangle.

Then I hit upon an alternative solution which wouldn't involve any scripting at all: I could simply set both the left and right CSS properties of the rectangle. The browser would be responsible for maintaining the rectangle's distance from the left edge of the browser window as well as the rectangle's distance from the right edge of the window, and thus script to resize the rectangle would not be necessary. The width property would not need to be specified at all, since the browser itself would calculate the width required to keep the rectangle the specified distances from the left and right browser window edges.

This works great in IE7 and Firefox 2. Unfortunately, it doesn't work in IE6. Apparently IE6 just does not support the specification of both left and right properties, or both top and bottom properties, of a CSS element. Instead, you need to specify one or the other plus width or height (as appropriate).

I did end up finding an approach that would work with IE6 and still only need a single line of CSS (at least for IE support). For IE, the CSS width property can be set using IE's proprietary "expression" syntax as in this snippet of CSS:

left:50px; width:expression((this.parentNode.offsetWidth - 150) + 'px')
This sets the width of the element to which the style is applied to the width of the parent element (the browser window, in the case of top-level elements), minus the specified value (150 in the above example), which should be set to the sum of the left property value and the effective value for the right property. In the above example, the style would cause the element to be offset 50px from the left edge of the browser window and 100px (150 - 50 = 100) from the right edge of the window. The width of the element gets recalculated on-the-fly as the browser window is resized.

Note that the "expression" syntax is IE-only, so as far as I know, it won't work in Firefox or other browsers. It does work ok in both IE6 and IE7.

Also, use of "expression" relies on Javascript being enabled; in the example above, if Javascript is disabled, the rectangle doesn't render on the screen at all.