Thursday, April 20, 2006 11:51 PM
codingsanity
Hosting WinForms Controls in IE
Hosting controls in IE is easy. Most of the time. Simply create a Windows Control Library, and then put that DLL in the path of your html/aspx page which will host the control. Now, all you need to do is put an object tag in your page which references the control. The classid for the object tag must be of the form: "DllName.dll#Namespace.ControlName". Voila, your control will now appear.
Making debugging a pain in the neck
Well, maybe. There's various security issues with the browser and .NET Framework that may bite you badly here. Suffice it to say that you may spend quite a bit of time playing around with various settings. One piece of advice that may assist in your debugging is to remember that IE caches stuff, so when you make any changes to the control itself, go into Tools->Internet Options and use the Delete Files button in the General Tab.
However, that's not enough on it's own, since .NET also stores a "cache" in the form of the download cache. You'll have to clear this out by using "gacutil /cdl". However, before doing this you'll need to close down the IE session that hosted your control, as it will be locking this cache. Note that I said IE session, not IE instance. If you opened any new IE windows from that instance of IE, or opened it from any others, they all need to be closed down, even if they opened before you navigated to the hosting page.
If you're struggling to get your control to even appear, you might want to go into Internet Options, Settings, View Files, and then look for a file called "?FusionBindError...". Copy this file out somewhere onto your hard disk since you won't be able to view it from here. It'll have a weird name (different from it's one in the Temporary Intenet Files folder I mean). This may contain information that will help you find out why your control can't be loaded.
Alternatively, it may be a problem with IIS not being able to find DLLs or their dependencies. The IIS logs come in handy for this, just go look for 404's with .dll in the same line.
I wanna access the control from JavaScript!
Of course. I mean you're hosting it in your page, and obviously you may want to respond to events fired by the control, and you may also want to set properties on the control. The important thing to remember here is that IE is a COM-based system, and doesn't understand .NET events, properties and methods.
IDispatch, how we've missed you
So the first thing you're going to have to do is create a COM IDispatch interface for your control. Before you sign off in hopelessness, this is actually quite easy to do inside .NET. Create a stock-standard .NET interface, and put your members in. Now all the members are going to be methods, even the properties and events, which may seem a bit weird. So you'd define events as:
void EventOne(object sender, System.EventArgs e);
and properties as:
string Property();
This might seem a bit strange, but COM doesn't really have the concept of properties and events, they're all just methods (much as it might seem otherwise). In a sense .NET is the same, it's just better at hiding it.
Right, now we've got our interface, what next? Well, we're going to have to make it COM-compatible. We do this by applying a GuidAttribute to the interface, with a unique GUID. We also need to mark the interface as being of type IDispatch. Don't worry about this too much, it's basically saying it supports something similar to Reflection (yes, in COM you need to tell it this explicitly). Javascript uses IDispatch exclusively to access methods. To mark the interface as such, just apply the InterfaceTypeAttribute using a parameter of ComInterfaceType.InterfaceIsIDispatch.
DISPIDs are love
Now the interface itself is accessible to JavaScript, but the methods aren't. COM has a weird thing where every member of an interface has a number that identifies it called the DISIP. There are good reasons for this, but you really, really do not want to know. Trust me. So what we must now do is decorate each member with the DispIdAttribute. The parameter must be a number 1 or above, and each member must have a unique number. Technically you can give DISPIDs with lower values (way into the negatives even), but most of these have special meanings for COM, so I'd seriously advise against it.
So now we go to your control. Add members and events and stuff just as you normally would. Properties are proper properties, events are proper events. You must implement the items you declared in your interface, but do not implement the interface itself. The reason is that this interface is a special type of interface known as a COM source interface. What we'll do is decorate the control with the ComSourceInterfacesAttribute, passing in the fully qualified name of our IDispatch interface.
Time to USE this stuff
Okay, now we're ready for the JavaScript. We do all the steps to deploy our DLL to IIS, and into the web page as I discussed above, except now we can write script code that will access that object.
Some pit traps to avoid
There's one big caveat though. The assembly must have the "Security:Allow calls to unmanaged assemblies" permission. Probably the easiest way to do this is by granting FullTrust to the assembly via the .NET Framework Configuration Tool.
Oh, one other thing. Make sure all your assemblies have an explicit assembly version set (i.e. no *s in AssemblyVersion). If not, you may get some very weird compatibility errors between client and server.
Configuration
Now what about configuration? One would think that you might put the config for your control in the web.config file, but you'd be very wrong. You see, you're running Internet Explorer, not a web page, so the config has to be for IE. The good news is that the config file isn't on the client machine, but is on the web site. Just create a file called "iexplore.exe.config" and put it in the site root. Note, that's not the virtual directory, but the site root. So if it's localhost, then the config goes at http://localhost/iexplore.exe.config.
Conclusion
I hope this helps. Most of this information is available elsewhere, but trust me it can be a pain tracking it all down. Many other blogs have much more detailed information on the Code Access Security issues, or the Fusion binding issues, or the debugging, but I haven't yet found any with all the information easily summarised.
Code
To help out, I've posted a sample project at my web site. You can also find it as an attachment to this post.
Unzip it to a directory, and then build it. Create a new Virtual Directory on your web site, and copy the TestEvents.html page to that site. Also copy in the IEEvents.dll. Then copy the iexplore.exe.config to the root of your site. For example, C:\InetPub\wwwroot.
Filed under: Code