<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Rambling Comments</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/" />
    <link rel="self" type="application/atom+xml" href="http://www.lenholgate.com/blog/atom.xml" />
    <id>tag:www.lenholgate.com,2010-12-10:/blog//12</id>
    <updated>2010-12-29T14:44:13Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 5.12</generator>

<entry>
    <title>Excel 2010 XLL SDK</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2009/08/excel-2010-xll-sdk.html" />
    <id>tag:www.socketframework.com,2009:/blog//12.919</id>

    <published>2009-08-20T07:21:25Z</published>
    <updated>2010-12-29T14:44:13Z</updated>

    <summary>I&apos;m currently looking at the Excel 2010 XLL SDK which is part of the Office 2010 Technical Preview. I&apos;ve already built and tested my managed XLL system with Excel 2010 on x86 but I needed the new XLL SDK to...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="Managed XLL" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p>I'm currently looking at the Excel 2010 XLL SDK which is part of the Office 2010 Technical Preview. I've already built and tested my managed XLL system with Excel 2010 on x86 but I needed the new XLL SDK to be able to build for the x64 version of Excel. The SDK doesn't ship as part of the main Office 2010 installation, you have to ask for it.</p>

<p>So far things look reasonably good in x86 mode. The code that I have been developing worked fine in Excel 2010 without needing the new SDK at all; which is how it should be given there will be x86 XLLs out there that have been around since Excel v4... </p>

<p>The x64 side of things is looking a little less rosy at this point. It took me a while to set up the x64 builds for my projects and to deal with the inevitable warnings that you get from building as x86 and then switching to x64. That's all been dealt with and the XLL loads nicely into Excel 2010 and works fine right up to the point where it switches to managed code for the first time; during this transition one of Excel's threads goes off on one and pegs a cpu at 100% whilst Process Explorer's stack capture shows that it's somewhere deep inside of <code>CorBindToCurrentRuntime()</code>. I've narrowed the problem down and sent a variation on the 'generic' example XLL back to my Microsoft contact so that they can look at the problem. </p>

<p>So, right now, Excel 2010 x64 support for my managed XLLs is on hold.</p>

I haven't yet started to dig into the new SDK's features yet but there is native support for 'asynchronous' XLL functions (which look somewhat less powerful than the support for this kind of thing that I already have in place) and a few other new things. Right now my focus is on cleaning up the existing functionality that I have, testing with all versions of Excel and getting to the point where I can start my beta testing phase.]]>
        
    </content>
</entry>

<entry>
    <title>Asynchronous spreadsheet calls in a Managed XLL</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2009/07/asynchronous-spreadsheet-calls-in-a-managed-xll.html" />
    <id>tag:www.socketframework.com,2009:/blog//12.910</id>

    <published>2009-07-23T08:13:05Z</published>
    <updated>2010-12-29T14:37:23Z</updated>

    <summary>Once I got the simple managed Real Time Data servers working in Excel I decided it was time to add asynchronous worksheet functions. This is the last major feature on my todo list and once it&apos;s complete I&apos;ll be ready...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="Managed XLL" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p>Once I got the simple managed <a href="http://www.lenholgate.com/archives/000856.html">Real Time Data servers</a> working in Excel I decided it was time to add asynchronous worksheet functions. This is the last major feature on my todo list and once it's complete I'll be ready to start thinking about beta testing my Managed XLL product.</p>

<p>The idea behind asynchronous worksheet functions is that some worksheet functions may take a long time to complete and it would be better to run them in the background rather than have them block Excel's recalculations whilst they complete. This means that the Managed XLL needs to manage a thread pool for the asynchronous worksheet function execution and we need to deal with a few issues around passing results back to the sheet. The work that I did on managed RTD servers helped a lot for the asynchronous worksheet functions as I'd already solved the problems of calling into the correct AppDomain from arbitrary threads. Passing results back to the sheet was a bit more thorny; the asynchronous worksheet functions need to be marked as volatile so that Excel will recalculate them whenever a recalculation happens (even if none of their inputs have changed), and the Managed XLL needs to maintain state for each asynchronous call so that it knows if the call is ready to return results, or needs to be run again, or whatever. Finally we need some way of telling Excel to recalculate a given cell when the asynchronous worksheet function is complete; luckily Excel's COM automation interface comes to the rescue here. The result is pretty cool and once I had the basic asynchronous nature of the calls working I added the ability for them to return interim results as well. I still need to do some work to get all of this to work in versions of Excel prior to 2007 but that shouldn't be too hard, I hope.  </p>

<p>From an addin developer's perspective asynchronous worksheet functions are as easy as this:</p>
<pre class="brush: cpp gutter: false">      [AsyncWorksheetFunction]
      static public int AsyncWorksheetFunction1(
         [Optional] [DefaultValue(10000)] int delay)
      {
         Thread.Sleep(delay);
          
         numCalls1++;
    
         return numCalls1;
      }
</pre>
<p>or maybe this if you want to return interim results or abort a call if requested to do so...</p>
<pre class="brush: cpp gutter: false">      [AsyncWorksheetFunction]
      static public int AsyncWorksheetFunction2(
         [DefaultValue(10000)] int delay,
         IAsyncWorksheetFunctionCall call)
      {
         for (int i = 0; i &lt; delay; ++i)
         {
            Thread.Sleep(1);
 
            if (call.BreakRequested())
            {
               break;
            }
 
            if (i % 100 == 0)
            {
               call.ReturnInterimResult(i);
            }
         }
 
         numCalls2++;
 
         return numCalls2;
      }
</pre>
As with my 'results objects' there are XLL worksheet functions and commands that allow you to monitor the state of async calls and next on the list is a simple dialog that will allow you to monitor and control the thread pool and the work queue into it.]]>
        
    </content>
</entry>

<entry>
    <title>Error: Cannot pass a GCHandle across AppDomains</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2009/07/error-cannot-pass-a-gchandle-across-appdomains.html" />
    <id>tag:www.socketframework.com,2009:/blog//12.909</id>

    <published>2009-07-13T17:07:09Z</published>
    <updated>2010-12-29T14:36:31Z</updated>

    <summary>I&apos;m currently working on adding easy to use Real Time Data server support to my Managed XLL Excel Addin system. This lets you use the =RTD() functionality of Excel to push real time data into your spreadsheets without needing to...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="Managed XLL" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p>I'm currently working on adding easy to use Real Time Data server support to my <a href="http://www.lenholgate.com/archives/000787.html">Managed XLL Excel Addin</a> system. This lets you use the <code>=RTD()</code> functionality of <a href="http://support.microsoft.com/kb/289150">Excel</a> to push real time data into your spreadsheets without needing to <a href="http://weblogs.asp.net/kennykerr/archive/2008/11/28/Rtd4.aspx">understand COM</a> and without needing to register any COM objects on your machine. You simply add some attributes to your managed code, compile your assembly and drop it in the same directory as the Managed XLL and it does the rest. This is working well and makes Excel Real Time Data servers VERY easy to write.</p>

<p>Anyway, during this I came across a slight problem. The architecture is such that  I create a custom AppDomain for the managed code that the XLL hosts inside of Excel. The XLL then causes unmanaged callbacks into this managed code when the various Excel RTD COM object functions are called. The bridge between the unmanaged code and the managed code is a <code>gcroot&lt;&gt;</code> that holds onto the managed code inside the unmanaged wrapper via a <code>GCHandle</code>. The COM call eventually calls through this <code>gcroot&lt;&gt;</code> and into the managed code. Unfortunately unmanaged code knows nothing of AppDomains and (it seems from reading <a href="http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/">this</a>) that an AppDomain is chosen arbitrarily when the unmanaged call into the managed code occurs. This causes the code to fail with a "Cannot pass a GCHandle across AppDomains" exception.</p>

<p>Luckily for me, <a href="http://lambert.geek.nz/">Miral</a>, over at <a href="http://lambert.geek.nz/">Thoughts from Mirality</a> has already solved this issue and covers the problem and a solution <a href="http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/">here</a>. The trick is that you need to use a delegate, which knows about the AppDomain that it relates to, and then call through the delegate by converting it to a function pointer. This effectively marshals the unmanaged call into the correct AppDomain before executing the managed code.</p>

<p>Miral's example code was enough to help me along my way but I stumbled a couple of times before I solved my particular version of the problem so I thought it would be worth documenting what I needed to do to get this to work for me.</p>

<p>Lets say we have the following unmanaged callback. Some code that knows nothing about managed code wants to call the following function:</p>
<pre class="brush: cpp gutter: false">void Connect(
   const long topicId, 
   const JetByteTools::Win32::StringVector &amp;topics, 
   const bool getNewValue, 
   VARIANT &amp;result);
</pre>
<p>The first thing we need to do is create a typedef for the function signature and a managed class that can provide us with the delegate that we need to be able to call this correctly. Something like this, perhaps:</p>
<pre class="brush: cpp gutter: false">typedef void (__stdcall ConnectFnc)(
   const long topicId, 
   const JetByteTools::Win32::StringVector &amp;topics, 
   const bool getNewValue, 
   VARIANT &amp;result);
 
ref class ConnectDelegate
{
   public :
 
      ConnectDelegate();
         :  m_delegate(gcnew Delegate(this, &amp;ConnectDelegate::Connect))
      {
      }
 
      ConnectFnc *GetDelegateFunctionPointer();
      {
         return   (ConnectFnc*)(Marshal::GetFunctionPointerForDelegate(m_delegate).ToPointer());
      }
 
   private :
 
      void Connect(
         long topicId, 
         JetByteTools::Win32::StringVector &amp;topics, 
         bool getNewValue, 
         VARIANT &amp;result)
      {
         // YOUR CODE GOES HERE and is executed in the correct AppDomain...
      }
 
      delegate void Delegate(
         long topicId, 
         JetByteTools::Win32::StringVector &amp;topics, 
         bool getNewValue, 
         VARIANT &amp;result);
 
      Delegate ^m_delegate;
};
</pre>
<p>The managed code that you want to execute inside the correct AppDomain lives in <code>ConnectDelegate::Connect()</code>. The constructor of our class simply creates the delegate to call the function and <code>GetDelegateFunctionPointer()</code> does <a href="http://en.wikipedia.org/wiki/Does_exactly_what_it_says_on_the_tin">exactly what it says on the tin</a>. An instance of the <code>ConnectDelegate</code> class needs to be created by code that is running inside the AppDomain that you want your unmanaged callback to call into.</p>

<p>It might look like you can then simply call <code>ConnectDelegate::GetDelegateFunctionPointer()</code> from your unmanaged code to obtain a function pointer and make your callback, but unfortunately you need one further level of indirection before that's possible. As I said at the start, the problem is that calling through a <code>GCHandle</code> via a <code>gcroot&lt;&gt;</code> from unmanaged code gives a "Cannot pass a GCHandle across AppDomains" exception. Well, right now you still need a <code>gcroot&lt;&gt;</code> to hold onto your <code>ConnectDelegate</code> so that you can call it from unmanaged code and calling <code>ConnectDelegate::GetDelegateFunctionPointer()</code> calls through that <code>GCHandle</code> and raises the exact same exception... The trick is that you also need to call <code>ConnectDelegate::GetDelegateFunctionPointer()</code> from within your target AppDomain and then store away the function pointer for later use. Since this leaves you with a <code>gcroot&lt;ConnectDelegate^&gt;</code> and a <code>ConnectFnc*</code> to hold onto in unmanaged code I put together a simple unmanaged class which manages both of these and provides an overloaded function call operator to make it easy to call the <code>ConnectFnc*</code>. The result is something like this:</p>
<pre class="brush: cpp gutter: false">class ConnectFunction
{
   public :
 
      ConnectFunction()
         :   m_pDelegate(0),
             m_pFunction(0)
      {
      }
 
      ~ConnectFunction()
      {
         delete m_pDelegate;
      }
 
      void operator()(
         const long topicId, 
         const JetByteTools::Win32::StringVector &amp;topics, 
         const bool getNewValue, 
         VARIANT &amp;result) const
      {
         m_pFunction(topicId, topics, getNewValue, result);
      }
 
      void Setup()
      {
         m_pDelegate = new gcroot&lt;connectdelegate^&gt;(gcnew ConnectDelegate());   
 
         m_pFunction = (*m_pDelegate)-&gt;GetDelegateFunctionPointer();
      }
 
   private :
 
      gcroot&lt;ConnectDelegate ^&gt; *m_pDelegate;
 
      ConnectFnc *m_pFunction;
 
      // No copies do not implement
      ConnectFunction(const ConnectFunction &amp;rhs);
      ConnectFunction &amp;operator=(const ConnectFunction &amp;rhs);
};
</pre>
<p>You can then create an instance of this class and then call <code>Setup()</code> from within your target AppDomain. You can then use the function call operator on your instance from within your unmanaged code to make the callback. You can move the body of <code>Setup()</code> into the constructor if you like, my particular situation requires two stage construction.</p>

This is crying out to be generalised with a template or two, but for now that's left as an exercise for the reader...]]>
        
    </content>
</entry>

<entry>
    <title>Managed XLL Excel Addins</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2008/06/managed-xll-excel-addins.html" />
    <id>tag:www.socketframework.com,2008:/blog//12.840</id>

    <published>2008-06-25T07:55:20Z</published>
    <updated>2010-12-29T09:41:27Z</updated>

    <summary>Back in December and January I was working on the initial phases of a system to allow the development of custom Excel worksheet functions in managed code using the Excel XLL &apos;C&apos; interface (Excel4v). Phase 1 finished with us having...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="Managed XLL" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p>Back in <a href="http://www.lenholgate.com/archives/000740.html">December</a> and <a href="http://www.lenholgate.com/archives/000749.html">January</a> I was working on the initial phases of a system to allow the development of custom Excel worksheet functions in managed code using the Excel XLL 'C' interface (Excel4v). Phase 1 finished with us having a pretty workable system that the client could go live with. The only problem was that we skipped the key ease of use part of the project due to time and budget constraints. Whilst the C++ side of the system worked and we could marshal values from Excel types to managed types and back again and we could dispatch calls to managed code we had to hardcode the marshalling information in the C++ code and rebuild the XLL to add new functionality. </p>

<p>I've just completed phase 2 of this project and it now works just like we originally envisaged. Managed code can be decorated with custom attributes and the XLL uses reflection to work out which classes within an assembly are being exposed to Excel. It then looks for <code>[WorksheetFunction]</code> attributes and exposes individual functions to Excel whilst working out all of the marshalling requirements itself. Additional attributes allow you to specify that some parameters are optional or have default values. More attributes allow for the definition of custom Excel menus and the provision of the code behind them. By annotating a suitable constructor you can have an <code>IManageAddins</code> interface passed into your managed class when it's constructed and this lets you call back into the XLL framework and/or Excel to do things like enable and disable menu items, etc. Several custom types allow us to pass ranges of Excel cells into and out of managed code, and our standard marshalling can deal with converting Excel ranges that contain consistent types to arrays of native managed types. Volatile and command equivalent worksheet functions are supported and, all in all, it all seems to work pretty nicely. </p>

<p>When the XLL is loaded it reads its configuration from a config file and loads the specified assemblies, parses them for attributes, builds and registers the appropriate data structures and wires up the XLL entry points to the appropriate marshaller and from there into managed code.</p>

The next phase is likely to be the inclusion of 'results object' which can be used to store and manipulate returned ranges by name. At this point I'll have something similar to the system I wrote in <a href="http://www.lenholgate.com/archives/000617.html">C++ back in 2001</a>, but this time all of the complex stuff just works and the developers can settle back and get on with writing the business logic.]]>
        
    </content>
</entry>

<entry>
    <title>Currently reading: Excel add-in development in C/C++</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2008/01/currently-reading-excel-add-in-development-in-cc.html" />
    <id>tag:www.socketframework.com,2008:/blog//12.802</id>

    <published>2008-01-09T09:57:37Z</published>
    <updated>2010-12-28T13:26:41Z</updated>

    <summary>As I mentioned a while back, I&apos;m writing a managed XLL style add-in system for Excel for one of my clients at the moment. This is going pretty well, most of the custom marshalling code is now done and we...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="Books" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Managed XLL" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p><iframe align="right" src="http://rcm-uk.amazon.co.uk/e/cm?t=ramcom-21&amp;o=2&amp;p=8&amp;l=as1&amp;asins=0470024690&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>As I mentioned a <a href="http://www.lenholgate.com/archives/000740.html">while back</a>, I'm writing a managed XLL style add-in system for Excel for one of my clients at the moment. This is going pretty well, most of the custom marshalling code is now done and we can write code in C# and expose it to Excel as worksheet functions.</p>

<p>Over Christmas I picked up a copy of <a href="http://www.amazon.co.uk/gp/product/0470024690?ie=UTF8&amp;tag=ramcom-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0470024690">Excel Add-in Development in C/C++: Applications in Finance</a><img src="http://www.assoc-amazon.co.uk/e/ir?t=ramcom-21&amp;l=as2&amp;o=2&amp;a=0470024690" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /> by Steve Dalton. This is a book that I wished I had back in 2001 when I first started writing XLLs. It's full of otherwise hard to find information about how you work with, and around, the C API that Excel exposes for the development of XLL add-ins. So far, every time I remember a gotcha from my previous XLL development projects I can look up a solution for it in the book. I'm also learning a lot of useful things about how I can stretch the C API even further than I did on my last projects. The books is pretty dense; I'm not sure how approachable it would be to someone who'd never developed an XLL, though it does come with a CD of sample code and it explains XLLs from first principles (including how to set up your first XLL project in various versions of Visual Studio). It's a good reference book though (and that's what I need).</p>

Highly recommended.]]>
        
    </content>
</entry>

<entry>
    <title>Managed Excel addins</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/12/managed-excel-addins.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.793</id>

    <published>2007-12-11T12:08:43Z</published>
    <updated>2010-12-27T22:06:27Z</updated>

    <summary>One of my current clients has got me drifting back towards my Investment Banking roots by developing an Excel addin for them. Luckily for me it&apos;s a banking client with a twist compared to my previous banking clients; they&apos;re happy...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="Managed XLL" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p>One of my current clients has got me drifting back towards my Investment Banking roots by developing an Excel addin for them. Luckily for me it's a banking client with a twist compared to my previous banking clients; they're happy for me to work as an external consultant, doing most of the work from my office at home and working on my contract terms.</p>

<p>The development work so far has been quite interesting. I'm building a prototype XLL style Excel addin that allows worksheet functions to be developed in C#. There are commercial products out there that do this, but my client wants me to write one for them. This takes me back to some work that I did for a <a href="http://www.lenholgate.com/archives/000617.html">previous banking client</a> where I wrote some XLLs that allowed them to talk to their back-end servers from Excel using CORBA; in that system the XLLs were all in C++, this time around the idea is that the 'meat' of the XLL functionality will be in managed code.</p>

<p>The past few days have been interesting. My initial prototype was a C++ dll that hosted the CLR. This was, in retrospect, always going to have problems. The CLR can only be hosted once within a process and, once loaded, it can't be unloaded. XLLs by their very nature can be unloaded and reloaded and "other things" could cause Excel to host the CLR itself... The initial prototype did, at least, allow me to get a thin thread of functionality all the way through from Excel to managed code and back, but it quickly became apparent that it was a dead-end.</p>

<p>The current prototype involves a straight C++ XLL which dynamically loads a C++/CLI dll which then configures a new AppDomain and loads the managed addin code. Since one of my client's requirements is "xcopy deployment" (and the ability to configure the managed XLL loader to load numerous managed addins) the first problem to overcome was that of loading code into a new AppDomain when the new AppDomain had a different assembly search path to the default domain. Due to the way communication between AppDomains is managed this was a little more complex than I expected. </p>

<p>To load an assembly into a new AppDomain and then execute code in that AppDomain you need to also load the assembly that contains the types that you're accessing in the new AppDomain into the AppDomain that's doing the loading... Well, you do if you want to use a class that's derived from <code>MarshalByRefObject</code> and which uses transparent proxies to talk across AppDomain boundaries. </p>

<p>The <a href="http://blogs.msdn.com/suzcook/archive/2003/06/12/57169.aspx">recommended way to do things</a>, with code like this:</p>
<pre class="brush: cpp gutter: false">      AppDomainSetup ^setup = gcnew AppDomainSetup();
      
      setup-&gt;ApplicationName = "My App";
      setup-&gt;ApplicationBase = gcnew String(GetModulePathName(hInst));
  
      AppDomain^ newDomain = AppDomain::CreateDomain( "newDomain", nullptr, setup );
  
      Object ^obj = newDomain-&gt;CreateInstanceFromAndUnwrap(
         "MyAssembly",
         "MyType");
  
      MyType ^myType = (MyType^)obj;
  
      myType-&gt;DoThing();
</pre>
<p>requires that "MyAssembly" is loaded into both the newly created AppDomain (as that's where you want to run the code!) and also into the current AppDomain (as "MyType" is needed by the transparant proxy to allow you to talk across AppDomain boundaries to the code in the new AppDomain.</p>

<p>Since the default AppDomain has an assembly search path that's different to the assembly search path for the new AppDomain we have to somehow make the required assembly available to both AppDomains.</p>

<p>My first step was to include the required type in the assembly that's doing the AppDomain creation. I figured that since this assembly was already loaded in the AppDomain that things would "just work". Unfortunately they didn't. The code above resulted in an exception when the cast from <code>obj</code> to <code>MyType</code> took place; "Unable to cast transparent proxy". Changing the cast to a <code>dynamic_cast</code> solved that problem but didn't actually work, the resulting object was in the wrong AppDomain.</p>

<p>It seems that even though the assembly that contained the type that was required was already loaded in the AppDomain it was still loaded again during the cast (possibly because of some identity assembly issue due to the fact that the executing assembly was loaded as a C++ dll which just happens to contain managed code...). Anyway. The assembly loader was looking to load the assembly again and when it did it treated the two copies of the assembly that it had loaded as different and the types were not considered to be equal... Which makes sense, in a frustrating kind of way.</p>

<p>After banging my head on the desk for a while I came up with a solution. I needed to get involved with the assembly loading for the current AppDomain and registering a <code>ResolveEventHandler</code> for the AppDomain's <code>AssemblyResolve</code> event could allow that... I plugged in the event handler and tried to run the code again, the handler was called and the full name of my assembly was passed in... By implementing my event handler like this:</p>
<pre class="brush: cpp gutter: false">ref class Resolver
{
   public :
  
      static Assembly ^Resolve(
         Object ^sender, 
         ResolveEventArgs ^args)
      {
         if (args-&gt;Name == Assembly::GetExecutingAssembly()-&gt;FullName)
         {
            return Assembly::GetExecutingAssembly();
         }
  
         return nullptr;
      }
};
</pre>
<p>I could return the current assembly when asked for it, and prevent another copy being loaded... This seemed to be enough to get the code to work...<p>
<pre class="brush: cpp gutter: false">      AppDomain::CurrentDomain-&gt;AssemblyResolve += gcnew ResolveEventHandler(Resolver::Resolve);
  
      AppDomainSetup ^setup = gcnew AppDomainSetup();
      
      setup-&gt;ApplicationName = "My App";
      setup-&gt;ApplicationBase = gcnew String(GetModulePathName(hInst));
  
      AppDomain^ newDomain = AppDomain::CreateDomain( "newDomain", nullptr, setup );
  
      Object ^obj = newDomain-&gt;CreateInstanceFromAndUnwrap(
         Assembly::GetExecutingAssembly()-&gt;Location,
         "MyType");
  
      MyType ^myType = (MyType^)obj;
  
      myType-&gt;DoThing();
</pre>
<p>Will result in <code>DoThing()</code> being executed in the new AppDomain.</p>

And now, finally, I can write the code that loads the managed addin assembly...]]>
        
    </content>
</entry>

</feed>



