WARNING: Information and code here can easily be abused. Please do not use it as a crutch in application planning, but more for utter despair or experimentation. Thus I wrote this blog post from that perspective.
Silverlight 4 + OOB + Elevated Trust gives us the ability to use COM. That would be extremely useful (vs. really useful), except we cannot use just any COM class. It has to support IDispatch (COM automation). It also has to have a ProgID associated to it. That leaves you still with quite a few built-in COM objects to work with, as Justin document's quite well here. What about running our own native or .NET code? One would have to register a COM object first, which requires administrator rights. That’s no fun for an end user! Optimally, it would be nice to be able to add your desktop CLR objects as resources to your XAP, and from Silverlight code, be able to instantiate and use your Desktop .NET classes. This is a hack to do just that.
Huh? What does the hack do?
Let me explain it in code.
/* Create our Desktop .NET helper */
dynamic fullDotNetProxy = fullDotNetProxy = ComAutomationFactory.CreateObject("ClrProxy");
/* Have our .NET helper load up our .NET assembly we extracted from our SL app resources */
dynamic assembly = fullDotNetProxy.GetAssembly(m_assembliesPath + "\\Inject.Test.dll");
/* Get our .NET Type */
dynamic testClassType = fullDotNetProxy.GetDotNetType(assembly, " Inject.Test.TestClass");
/* Create an object instance of our .NET type */
m_testClass = fullDotNetProxy.CreateInstance(testClassType);
/* Run our RunMe method on our .NET object */
m_testClass.RunMe();
Hold on a second! Where did “ClrProxy” ProgID come from? That’s not built in to Windows! I thought we didn’t have to register anything?
That’s where it gets complicated. Or hacky. We actually use COM interop to inject a native DLL into the Silverlight process. Once injected we override some native methods that Silverlight uses internally to instantiate COM. Our hooked methods listens for when a ProgID of “ClrProxy” is requested and then goes into action.
Not bored yet. Explain further.
- Use WScript.Shell's "Run" method to execute rundll32.exe
- Rundll32.exe executes my native.dll.
- My native.dll get's the process Id and hWnd of the process that started it up (The Silverlight OOB Process)
- The native.dll is injected into the Silverlight process's and hooks it's WndProc
- The Silverlight process the hooks two methods in ole32.dll used by all windows applications to create COM objects
- In Silverlight code, every time you call ComAutomationFactory.CreateObject("ClrProxy") my hook will detect it and return a .NET 2.0 CLR object. The real CLR proxy class is very simple and I only expose some reflection routines so I can load up any .NET Dll. Silverlight facing code still uses the dynamic keyword.
So where do I get the code and how do I run the demo?
How to run the demo:
- Load up the project. Set the Silverlight web app as start up.
- Run the project, and install the SL app OOB.
- Click the only button on the window and watch SL talk to a .NET class w/o any registration
I left all the compiled dlls in there in case you were having trouble compiling the C++.
Here is the code: