I recently faced the design challenge of getting an application and gadget to communicate. How to solve the problem? Well, what better way to talk between applications than Windows Communication Foundation (WCF). After all, it is the inheritor of the .NET Remoting legacy, which is what would be used in the past. It was quite enjoyable to return to writing WCF code, which I hadn't done for awhile. It really is the analog to WPF in terms of beautifully factored code architecture. In part 1, I'll show my first prototype, which used an XBAP gadget acting as both a server and a client that sends mouse movements over WCF to trackball either the application or the gadget. In part 2, I'll show my second prototype, which shows an ActiveX-based gadget acting as a client to the application and databinding to the application's data model. I subclass ObservableCollection and show the beginnings of what I dubbed SerializedObservableCollection. Download the code and gadgets.
Before explaining how I went about coding this, please be aware of all the issues with WPF gadgets raised in this post.
The first project remotes mouse move behaviors such that you can trackball the gadget and change the application. Or, you can trackball the application and update the gadget. In this case, the gadget is an XBAP. Now, because XBAPs run in partial trust, I had to change the XBAP security settings to allow for WCF, which requires full trust. This was just a matter of tweaking the settings in the security tab of the project properties. Because the XBAP is being launched from the file system, this does not present any deployment problems. Were the XBAP to be deployed from a serer, the certificate used to sign the XBAP needs to be installed in the trusted publishers list on the user's machine. In an installation routine, one could call certmgr /i under the covers. The other option here would be to place the WCF code in a seperate assembly marked as Allow Partially Trusted Callers (APTCA) and register it in the GAC. To protect the APTCA assembly, it should be locked down using FriendsAssembly concept (InternalsVisibleTo). That way only the Xbap that put the APTCA assembly can call into it. In this case, XBAP itself can stay in sandbox but APTCA assembly acts as a proxy between XBAP and full trust calls. I haven't done this myself but I've been told it works.
The way the WCF architecture works in this sample is that the gadget and application each act as both a server and a client. So, when you are trackballing the gadget, it is acting as a client to the application and sends messages about mouse position to the application, which is listening. As soon as the application is trackballed, the roles flip and the application then acts as the client and sends its mouse events to the gadget, which listens as a server.
All the communication uses the netNamedPipe binding of WCF. This is established in the app.config file. One interesting fact is that the messages between the app and gadget are signed and encrypted, which is cool. No other rogue application could sniff the traffic between the gadget and application. I have turned off the metadata exchange features of WCF. This means that to create my client proxy for talking to the service, I had to either use svcutil.exe on the application itself or, rather than generate a client, I could just craft up my own proxy, which I did. After all, no one else is going to consume the service but my own code. In fact, all the code is in a dll called RemoteMouse, which is shared by the XBAP gadget project and the application.
One area that was a little tricky was protecting both the gadget and the application for the possbility that one would not be alive. I achieved this by instantiating the client proxy on a seperate thread. If I get an exception from the server -- which would most likely occur if the gadget wasn't launched or the application wasn't launched -- I brute force null out the client and create a new one in a do/while loop every second. This might sound expensive, but turns out not to be. I found this approach easier than handling lots of events within WCF around the CommunicationState enumeration. One thing I don't do is nicely disconnect from the server, which I should do.
The way I host WCF within WPF is based on a sample in the SDK in the Cross Technology Samples/Integration Samples for the .NET Framework 3.0 Features called Hosting A WCF Service in WPF. It turns out to be pretty simple and elegant. I have an interface called IDisplay, which is implemented by the Trackball control. Then, when I create the WCF service, I pass a reference to the trackball class to the service in the constructor to the service. I can then call methods on the trackball from the WCF service. Pretty nifty!
To install, double click the RemoteMouse.gadget file. Then, compile the cubeapp_exe solution. If you don't have VS installed on Vista, no problem. Just use the trick Tim Sneath outlines here, as every build of Vista has all the tools needed to compile .NET 3.0 apps.