<?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>2011-01-02T15:20:47Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 5.12</generator>

<entry>
    <title>CLR Hosting - A flexible, managed plugin system, part 2</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2010/08/clr-hosting---a-flexible-managed-plugin-system-part-2.html" />
    <id>tag:www.socketframework.com,2010:/blog//12.975</id>

    <published>2010-08-05T09:36:50Z</published>
    <updated>2011-01-02T15:20:47Z</updated>

    <summary>Last time I explained how the managed side of my flexible hosting server architecture was structured. I dealt with the IDL required to generate the COM interfaces which were used to communicate between unmanaged code and managed code and detailed...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p><a href="http://www.lenholgate.com/archives/000916.html">Last time</a> I explained how the managed side of my flexible hosting server architecture was structured. I dealt with the IDL required to generate the COM interfaces which were used to communicate between unmanaged code and managed code and detailed how the custom <code>AppDomainManager</code> object allowed me to load and execute managed code in such a way that it was easy to update the managed applications whilst the server was running.</p>

This time I'll cover the unmanaged side of things. This is actually where much of the complexity lives. The code that actually manages the creation and destruction of the application domains in which the managed applications run and which deals with wiring them up to the network endpoints that are accepting connections for them.]]>
        <![CDATA[<p>The unmanaged code has an object which represents the collection of applications that it runs. This <code>CApplicationCollection</code> class contains the CLR hosting code, <code>CManagedHost</code>, a collection of application details for each application that it is configured to run and an additional collection of running applications. Thus the application details collection represents all of the applications than CAN run and the application collection represents all of the applications that ARE running.</p>

<p>This allows me to load a set of applications that can be run when the server starts up and start them. I can then tell each network endpoint the name of the application that connections are to be routed to and as each new connection comes in the socket server that is managing that end point can look up the application by name in the <code>CApplicationCollection</code> and connect the connection to it. If the application is not running then the connection will fail and be closed after issuing an error message.</p>

<p>Since there's a difference between applications that the server CAN run and applications that ARE running I can easily restart an application by locating the running instance, telling it we're about to shut down and then unloading its application domain. Meanwhile I can create a new application domain, start a new copy of the managed application, based on the application details that are stored for the application, and insert it into the running applications collection. In fact I do this in reverse, starting and inserting the new application and then shutting down the old. This minimises the time when an application isn't available.</p>

<p>Whenever an application is stopped I need to be able to walk the list of connections that are currently connected to the application and terminate them. This requires that the unmanaged application objects maintain a collection of active connections. This deals with the 'kill' style restarts that I spoke of in the <a href="http://www.lenholgate.com/archives/000916.html">previous article</a>. To handle the 'kind' restarts I need to be able to keep a running application around after it has been removed from the running applications collection and only unload its application domain when all currently active connections have been completed. To enable this the application object is reference counted and the application domain is unloaded when the application object is deleted. This allows me to have each active connection hold a reference to the application that it is connected to and also have the <code>CApplicationCollection</code> hold a reference whilst it has the application in its collection of running applications. When the application is restarted it is removed from the running applications collection and the reference owned by the <code>CApplicationCollection</code> is released, now only the active connections are keeping the application alive and when the last of those ends the application domain is unloaded. Meanwhile we've already started a new copy of the application and placed it in the running applications collection and so new connections go to the new copy of the application and existing connections continue in the old copy.</p>

<p><img alt="ManagedApplicationCollection.png" src="http://www.lenholgate.com/blog/images/ManagedApplicationCollection.png" width="546" height="527" border="0" /></p>

<p>Automatic restarts are supported by enabling shadow copying on the application domains so that the assemblies aren't locked whilst the application is running and adding a directory change monitor to look for updated files. The directory change monitor starts a 10 second timer when it spots a file change and when the timer expires the application is restarted. The server demonstrates both kind and kill automatic restarts. The timer is necessary to prevent multiple restarts when files are updated by hand, ideally you set a timer for long enough to allow someone to copy or edit files and when the "quiet period" has expired the application is restarted. </p>

<p>Finally a management socket server presents a simple text based protocol that's accessible via telnet which allows the user to list and manipulate the applications. Right now you can't add new applications and endpoints to a running server but there's nothing in the architecture to prevent it. Likewise you can't remove endpoints but it could be added.</p>

This code is all included in a <a href="http://www.serverframework.com/ServerFramework/latest/Docs/socketsamples.html">new example server</a> for The&nbsp;Server&nbsp;Framework which will ship with version 6.3.]]>
    </content>
</entry>

<entry>
    <title>.Net 4.0 different AppDomain managers for different AppDomains</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2010/08/net-40-different-appdomain-managers-for-different-appdomains.html" />
    <id>tag:www.socketframework.com,2010:/blog//12.969</id>

    <published>2010-08-03T09:47:41Z</published>
    <updated>2011-01-02T15:15:17Z</updated>

    <summary>Whilst looking through the latest documentation for the AppDomainSetup class I see that you can now specify a new AppDomainManager object for each application domain that you create. This removes the duality of the pre 4.0 AppDomainManager as the manager...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[Whilst looking through the latest documentation for the <code><a href="http://msdn.microsoft.com/en-us/library/system.appdomainsetup_members.aspx">AppDomainSetup</a></code> class I see that you can now specify a new <code>AppDomainManager</code> object for each application domain that you create. This removes the duality of the pre 4.0 <code>AppDomainManager</code> as the manager that you specify when you start the CLR can now deal solely with the requirements of the default application domain and it can set a new <code>AppDomainManager</code> object for each application domain that it creates.]]>
        
    </content>
</entry>

<entry>
    <title>CLR Hosting - A flexible, managed plugin system, part 1</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2010/07/clr-hosting---a-flexible-managed-plugin-system-part-1.html" />
    <id>tag:www.socketframework.com,2010:/blog//12.968</id>

    <published>2010-07-29T17:27:03Z</published>
    <updated>2012-02-25T19:48:15Z</updated>

    <summary>I&apos;m working on some prototype code right now to improve the &quot;deployment characteristics&quot; of a socket server that I wrote for a client which uses CLR hosting to provide multiple managed applications within a single unmanaged host. The client wants...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" 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 working on some prototype code right now to improve the "deployment characteristics" of a socket server that I wrote for a client which uses CLR hosting to provide multiple managed applications within a single unmanaged host. The client wants to be able to start, stop and restart individual managed applications within the server so that during development or when a managed application is updated they don't need to restart the whole unmanaged server process to use a new version of a managed application. This is all quite easy to do using separate application domains for each managed "application" within the unmanaged host but, as always, the devil is in the detail. Their existing server is already using an application domain per application but no thought was given to being able to dynamically unload and reload applications whilst the unmanaged host was running. </p>

I've got to the point where I have a nice new server framework <a href="http://www.serverframework.com/ServerFramework/latest/Docs/socketsamples.html">example server</a> that demonstrates all of the functionality I need and so it feels like the right time to write about how I got here.]]>
        <![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=0735619883&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&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>Hosting the CLR is fairly straight forward and, from an unmanaged point of view, it's all just COM, so it's nice and familiar. First you obtain an instance of <code><a href="http://msdn.microsoft.com/en-us/library/ms164408.aspx">ICLRRuntimeHost</a></code> using whichever API is most appropriate for you, either <code><a href="http://msdn.microsoft.com/en-us/library/99sz37yh.aspx">CorBindToRuntimeEx()</a></code> or <code><a href="http://msdn.microsoft.com/en-us/library/dd537633.aspx">CLRCreateInstance()</a></code>, <code><a href="http://msdn.microsoft.com/en-us/library/dd233134.aspx">ICLRMetaHost</a></code> and <code><a href="http://msdn.microsoft.com/en-us/library/dd233121.aspx">ICLRRuntimeInfo</a></code>. Once you have your runtime host you can connect it to your unmanaged host by calling <code><a href="http://msdn.microsoft.com/en-us/library/ms164414.aspx">ICLRRuntimeHost::SetHostControl()</a></code>. With that done you provide an implementation of an <code><a href="http://msdn.microsoft.com/en-us/library/system.appdomainmanager.aspx">AppDomainManager</a></code>, tell the CLR the assembly and type to use and start the CLR. All of this is covered in <a href="http://www.amazon.co.uk/gp/product/0735619883?ie=UTF8&amp;tag=ramcom-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0735619883">Customizing the Microsoft.NET Framework Common Language Runtime</a><img src="http://www.assoc-amazon.co.uk/e/ir?t=ramcom-21&amp;l=as2&amp;o=2&amp;a=0735619883" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, which is well worth getting if you want to do this kind of thing.</p>

<p>The only thing that you really need to do in your custom <code>AppDomainManager</code> registered is make sure that you implement <code>InitializeNewDomain()</code> so that you set the flags to tell the CLR to register new application domains with your unmanaged host.</p>
<pre class="brush: cpp gutter: false">      public override void InitializeNewDomain(AppDomainSetup appDomainInfo)
      {
         // let the unmanaged host know about us
         InitializationFlags = AppDomainManagerInitializationOptions.RegisterWithHost;
      }
</pre>
<p>With that set you'll get a call into your <code><a href="http://msdn.microsoft.com/en-us/library/ms164473.aspx">IHostControl::SetAppDomainManager()</a></code> method for each application domain that's created. To be able to do anything interesting with your hosting powers you probably want to create an interface for communicating between your unmanaged host and your managed <code>AppDomainManager</code>, and possibly one for communicating back the other way. I find it easiest to create the interfaces in the old school COM way in an IDL file that is compiled into a type library and then imported into an assembly. For me this gives me all that I want without any of the cruftiness of the other ways of doing this. The IDL from my example server for its <code>AppDomainManager</code> looks like this.</p>
<pre class="brush: cpp gutter: false">   [
      object,
      uuid(0EC4D543-008A-4cd3-88DB-A5199F416251),
      helpstring("IManagedHost Interface"),
      pointer_default(unique)
   ]
   interface IManagedHost : IUnknown
   {
      HRESULT InitialiseDefaultAppDomain(
         [in] IUnmanagedHost *host);
  
      HRESULT CreateApplicationInNewAppDomain(
         [in] BSTR appDomainName,
         [in] BSTR applicationName,
         [in] BSTR applicationDirectory,
         [in] BSTR sharedDirectory,
         [in] BSTR configFileName,
         [in] BOOL enableShadowCopy,
         [out, retval] long *pDomainID);
  
      HRESULT Start(
         [in] BSTR assemblyName,
         [in] BSTR typeName,
         [in] BSTR applicationName,
         [out, retval] IManagedApplication **application);
  
      HRESULT RequestStop();
  
      HRESULT Stop();
   };
</pre>
<p>I then implement this in my managed <code>AppDomainManager</code> and QI for it when <code>IHostControl::SetAppDomainManager()</code> is called.</p>
<pre class="brush: cpp gutter: false">HRESULT CManagedHost::SetAppDomainManager(
  DWORD dwAppDomainID,
  IUnknown *pUnkAppDomainManager)
{
   ICriticalSection::Owner lock(m_criticalSection);
  
   DomainManagerMap::iterator it = m_domainManagers.find(dwAppDomainID);
  
   if (m_domainManagers.end() != it)
   {
      it-&gt;second = SafeRelease(it-&gt;second);
   }
  
   IManagedHost *pHost = 0;
  
   const HRESULT hr = pUnkAppDomainManager-&gt;QueryInterface(IID_IManagedHost, (void**)&amp;pHost);
  
   if (SUCCEEDED(hr))
   {
      m_domainManagers[dwAppDomainID] = pHost;
   }
  
   return hr;
}
</pre>
<p>When writing a system to load and unload plugins (or applications) you need to be aware that you can't unload the "default application domain". In effect there's the "default application domain" and all the other application domains (secondary application domains). Plugin code should be loaded into a new application domain so that it's isolated and so that it can be unloaded without needing to restart the hosting process. Since you can only have one type as an <code>AddDomainManager</code> for all application domains this can cause the custom <code>AppDomainManager</code> to have two distinct roles. The first is to be the manager of the default application domain. In this role it's responsible for creating new application domains. The second role is to be the manager of the secondary application domains, the ones which run the plugin code. This second role allows you to load your plugin code into your new application domains and control the execution of your plugins from unmanaged code.</p>

<p>In my example IDL above <code>Start()</code>, <code>RequestStop()</code> and <code>Stop()</code> are methods that can be called only in secondary application domains and <code>InitialiseDefaultAppDomain()</code> and <code>CreateApplicationInNewAppDomain()</code> must only be made onto the default application domain.</p>

<p><code>InitialiseDefaultAppDomain()</code> is called explicitly just after I start the CLR and set its error escalation policy. It allows me to pass an interface to the managed part of my hosting code that allows it to communicate with the unmanaged part, this interface is pretty simple.<br />
</p>
<pre class="brush: cpp gutter: false">   [
      object,
      uuid(AFF50626-DDCF-481c-9CE7-0F95B0E9E6D7),
      helpstring("IUnmanagedHost Interface"),
      pointer_default(unique)
   ]
   interface IUnmanagedHost : IHostLog
   {
      HRESULT ShutdownHost();
   }
  
   [
      object,
      uuid(7F153933-8BE3-45b6-B8C5-22B5EFA0B8FD),
      helpstring("IHostLog Interface"),
      pointer_default(unique)
   ]
   interface IHostLog : IUnknown
   {
      HRESULT LogMessage(
         [in] BSTR message);
   }
</pre>
<p>Strictly for demonstration purposes it allows the managed code to write to the same log file as my unmanaged code and it also allows the managed code to request the unmanaged host shut down. The initialise function also lets me set up event handlers for the default application domain (and for demonstration purposes these event handlers can use the log interface to keep me informed of what's going on).</p>

<p>Loading and running plugin code in the CLR is a two stage process. First I call <code>CreateApplicationInNewAppDomain()</code> on the default <code>AppDomainManager</code> which creates a new application domain and sets it up ready to run the plugin code.</p>
<pre class="brush: cpp gutter: false">      int IManagedHost.CreateApplicationInNewAppDomain(
         string appDomainName, 
         string applicationName, 
         string applicationDirectory, 
         string sharedDirectory,
         string configFile,
         int enableShadowCopy)
      {
         if (!defaultAppDomain)
         {
            throw new InvalidOperationException("Should only be called on the default application domain, not on \"" + this.appDomainName + "\"");
         }
  
         if (host == null)
         {
            throw new InvalidOperationException("Not initialised, call InitialiseDefaultAppDomain() first!");
         }
  
         AppDomainSetup setup = new AppDomainSetup();
  
         setup.ApplicationName = applicationName;
         setup.ApplicationBase = ".";
         setup.PrivateBinPath = ".;" + applicationDirectory + ";" + sharedDirectory;
         setup.ConfigurationFile = configFile;
  
         if (enableShadowCopy == 1)
         {
            setup.ShadowCopyFiles = "true";
            setup.CachePath = ".\\Cache\\" + applicationDirectory;
         }
  
         AppDomain appDomain = AppDomain.CreateDomain(appDomainName, null, setup);
  
         ManagedHost manager = (ManagedHost)appDomain.DomainManager;
  
         manager.SetupAppDomain(appDomainName, appDomain, host);
  
         return appDomain.Id;
      }
</pre>
<p>Note that once the default <code>AppDomainManager</code> has created a new application domain by calling <code>CreateDomain()</code> it can access the <code>AppDomainManager</code> of the new application domain and, in my case, initialise it. This is similar to what happens with the unmanaged code explicitly initialises the default <code>AppDomainManager</code> by calling <code>InitialiseDefaultAppDomain()</code>. </p>

<p>Once the new application domain has been created I can call <code>Start()</code> on its <code>AppDomainManager</code>, this simply loads the supplied assembly into the new application domain, creates an instance of the type that is the entry point for my application code, calls <code>OnApplicationStart()</code> on it to start the application, and returns interface to the application to unmanaged code so that it can be manipulated from there.</p>
<pre class="brush: cpp gutter: false">      IManagedApplication IManagedHost.Start(
         string assemblyName,
         string typeName,
         string applicationName)
      {
         if (defaultAppDomain)
         {
            throw new InvalidOperationException("Should only be called on the application domain that was created for application \"" + application + "\", not on the default application domain");
         }
  
         if (appDomainName != applicationName)
         {
            throw new InvalidOperationException("Should only be called on the application domain that was created for application \"" + application + "\", not on \"" + appDomainName + "\"");
         }
  
         Assembly assembly = Assembly.Load(assemblyName);
  
         object obj = assembly.CreateInstance(typeName);
  
         if (obj == null)
         {
            throw new TypeLoadException("Object \"" + typeName + "\" not found in assembly \"" + assemblyName + "\"");
         }
  
         this.application = (IManagedApplicationControl)obj;
  
         return application.OnApplicationStart(applicationName, host);
      }
</pre>
<p>My application interface looks like this:</p>
<pre class="brush: cpp gutter: false">   [
      object,
      uuid(DE2B37FB-190A-4ef9-9CD9-97CE94C3D5FE),
      helpstring("IManagedApplicationControl Interface"),
      pointer_default(unique)
   ]
   interface IManagedApplicationControl : IUnknown
   {
      HRESULT OnApplicationStart(
         [in] BSTR applicationName,
         [in] IHostLog *log,
         [out, retval] IManagedApplication **application);
  
      HRESULT OnApplicationStopRequested();
  
      HRESULT OnApplicationStop();
   };
  
   [
      object,
      uuid(19A68076-9C7E-4981-BE97-949803AEB76F),
      helpstring("IManagedApplication Interface"),
      pointer_default(unique)
   ]
   interface IManagedApplication : IUnknown
   {
      HRESULT OnConnectionEstablished(
         [in] ISocket *socket);
  
      HRESULT OnReadCompleted(
         [in] SAFEARRAY( BYTE ) data,
         [in] ISocket *socket);
  
      HRESULT OnConnectionClientClose(
         [in] ISocket *socket);
   };
</pre>
<p>The <code>IManagedApplicationControl</code> interface is used from within the custom <code>AppDomainManager</code> and allows it to start and stop the application. The <code>IManagedApplication</code> interface represents the interface that is presented to the unmanaged code. In this simple server example we pass some network events through from the unmanaged server host.</p>

<p>The simple example implementation looks something like this.</p>
<pre class="brush: cpp gutter: false">   class ManagedApplication : IManagedApplicationControl, IManagedApplication
   {
      private string name;
 
      private IHostLog log;
 
      private void LogMessage(string message)
      {
         log.LogMessage(name + ": " + message);
      }
 
      IManagedApplication IManagedApplicationControl.OnApplicationStart(
         string applicationName, 
         IHostLog log)
      {
         this.name = applicationName;
 
         this.log = log;
 
         LogMessage("OnApplicationStart");

         return this;
      }
 
      void IManagedApplicationControl.OnApplicationStopRequested()
      {
         LogMessage("OnApplicationStopRequested");
      }
 
      void IManagedApplicationControl.OnApplicationStop()
      {
         LogMessage("OnApplicationStop");
      }
 
      void IManagedApplication.OnConnectionEstablished(
         ISocket socket)
      {
         socket.WriteString("Welcome to CLR echo server: " + name + "\r\n");
 
         socket.Read();
      }
 
      void IManagedApplication.OnReadCompleted(
         byte[] data,
         ISocket socket)
      {
          socket.Write(data);
 
          socket.Read();
      }
 
      void IManagedApplication.OnConnectionClientClose(
         ISocket socket)
      {
         LogMessage("OnConnectionClientClose");
      }
   }
</pre>
<p>As network events occur the are passed through to the appropriate managed application which can deal with them. The unmanaged side of the call is simply a COM method call on an <code>IManagedApplication</code> instance.</p>

<p>I have two ways to stop an application. Firstly I can call <code>IManagedApplicationControl::Stop()</code> from the applications <code>AppDomainManager</code>. I call this just before I unload the application domain, the idea being that it allows the plugin code to clean up before it is destroyed. Secondly I can call <code>IManagedApplicationControl::RequestStop()</code>, this exists so that my hosting code can demonstrate immediate application domain clear down and 'once all existing connections have completed' application domain clear down. With plugin code that is accessed via network users you may want to restart an application (to upgrade it, for example) whilst there are existing users connected and allow those existing users to continue using the old application until they disconnect, OR you might want to just forcibly abort any existing connections and restart the application domain immediately. I call <code>IManagedApplicationControl::RequestStop()</code> if I'm going to allow the application domain to run until existing users have disconnected, this allows the managed application to react accordingly, such as suggesting to the users that they log off, or whatever.</p>

<p>Once I've decided to stop an application and all existing connections have terminated the <code>AppDomain</code> can be unloaded. I do this by calling <code><a href="http://msdn.microsoft.com/en-us/library/ms164417.aspx">ICLRRuntimeHost::UnloadAppDomain()</a></code> and passing it the ID that was returned when we created the new application domain.</p>

That's pretty much it as far as the interface between managed and unmanaged code is concerned. However, the story doesn't end there, on the unmanaged side there's quite a lot going on to allow us to dynamically load and unload managed applications whilst giving the option of allowing existing connections to complete before the application domain that they're running in is terminated, but <a href="http://www.lenholgate.com/blog/2010/08/clr-hosting---a-flexible-managed-plugin-system-part-2.html">I'll deal with that next time</a>...]]>
    </content>
</entry>

<entry>
    <title>.Net 4.0 Hosting</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2009/10/net-40-hosting.html" />
    <id>tag:www.socketframework.com,2009:/blog//12.930</id>

    <published>2009-10-23T10:38:07Z</published>
    <updated>2011-06-23T10:52:38Z</updated>

    <summary>I&apos;ve been playing with Visual Studio 2010 Beta 2 and .Net 4.0, building code, running tests, playing with the IDE, etc. The first issue that I&apos;ve come across with my existing codebase is that the .Net 2.0 hosting APIs (such...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="ENet" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" 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've been playing with Visual Studio 2010 Beta 2 and .Net 4.0, building code, running tests, playing with the IDE, etc. The first issue that I've come across with my existing codebase is that the .Net 2.0 hosting APIs (such as <a href="http://msdn.microsoft.com/en-us/library/99sz37yh(VS.100).aspx">CorBindToRuntimeEx</a>)are now deprecated and there's a whole new way of <a href="http://msdn.microsoft.com/en-us/library/dd380850(VS.100).aspx">hosting the CLR</a>.</p>

We've been quite successful in hosting the CLR from <a href="http://www.serverframework.com/products---the-clr-hosting-option.html">within our C++ servers</a>, either to provide servers that support a mix of managed/unmanaged plugins as a pluggable high performance windows application server or to provide network protocol support in C++ (such as ENet) with 'business logic' being written in managed code. The .Net 2.0 hosting API works OK but is not without <a href="http://www.lenholgate.com/archives/000675.html">some annoyances</a>.  Over the next couple of weeks I hope to take a look at the new hosting interface and report here on my findings. With any luck <a href="http://www.serverframework.com/">The&nbsp;Server&nbsp;Framework</a> will support the new hosting interfaces in release 6.2 which currently has no scheduled release date but which I expect will appear early in 2010.]]>
        
    </content>
</entry>

<entry>
    <title>CLR Hosting lifetime issues bite again...</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/11/clr-hosting-lifetime-issues-bite-again.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.788</id>

    <published>2007-11-12T12:23:04Z</published>
    <updated>2011-10-19T12:06:07Z</updated>

    <summary><![CDATA[I'm looking into adding CLR deadlock detection into the CLR hosting code that's used inside The&nbsp;Server&nbsp;Framework and, once again, the fact that you can't cleanly shutdown the CLR host is causing me problems... Since the CLR can't be stopped by...]]></summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Lock Explorer" 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 looking into adding CLR deadlock detection into <a href="http://www.serverframework.com/products---the-clr-hosting-option.html">the CLR hosting code</a> that's used inside <a href="http://www.serverframework.com/">The&nbsp;Server&nbsp;Framework</a> and, once again, the fact that you <a href="http://www.lenholgate.com/archives/000675.html">can't cleanly shutdown</a> the CLR host is causing me problems...</p>

<p>Since the CLR can't be stopped by a host without terminating the host process (and that's by design...) you need to be aware that any of the code that you have plugged into the CLR by way of the hosting interfaces can be called into during process shutdown. Since most of the code that you plug in will be in the form of COM objects you can rely on the COM reference counting to deal with cleaning up the objects (if the CLR could be relied on to release the references at any point...) but since you're now writing code that out-lives <code>main()</code> you have to be intimately aware of how this code uses other code that might rely on module level static variables, and other nastiness. Sure you wouldn't want to be relying on module level statics and the order of creation and destruction of those statics (which, as we know, is undefined across multiple modules) but if you're using the version of STL that ships with VS2005 in any of your hosting COM objects then you are... </p>

<p>My implementation if <code>IHostTaskManager</code> uses a <code>std::map</code> to keep track of its tasks. During process shutdown the CLR calls into my task manager to put a task to sleep, to do this I need to locate the task in my map and doing that relies on iterating the STL map and that, if <code>_HAS_ITERATOR_DEBUGGING</code> is enabled, seems to manipulate a global lock... Unfortunately the global lock has been destroyed by the time the CLR decides to shutdown ... Fortunately the global lock is kept alive by a reference counting class called <code>_Init_locks</code> which, although apparently undocumented, can be used to keep the locks that you need to use alive until the object that needs them is destroyed... So, by sticking an instance of <code>_Init_locks</code> into my task manager class I can make sure that it can iterate its collection after <code>main()</code> has returned and the process is shutting down...</p>

But it would be much nicer and easier if the <code>Stop()</code> method on <code>ICLRRuntimeHost</code> wasn't broken by design...]]>
        
    </content>
</entry>

<entry>
    <title>Hosting .Net takes me back to the &apos;Good ol&apos; days of COM&apos;</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/07/hosting-net-takes-me-back-to-the-good-ol-days-of-com.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.768</id>

    <published>2007-07-31T12:15:57Z</published>
    <updated>2010-12-27T19:38:24Z</updated>

    <summary>It&apos;s interesting, no, really, how the more things change the more they stay the same... I&apos;ve been doing COM for a long time. I first discovered COM back at Interlink when I was writing a windows version of a product...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        It&apos;s interesting, no, really, how the more things change the more they stay the same... I&apos;ve been doing COM for a long time. I first discovered COM back at Interlink when I was writing a windows version of a product call CardMaster which did credit card production. The system supported lots of different machines and each of these machines needed different drivers, the drivers were written in C and usually spoke to the machine via a serial port. In the DOS (actually Concurrent DOS, but...) version of the product I&apos;d used structures of function pointers that the driver populated during an &apos;open()&apos; call and which were returned to the application so that the application could use this &apos;opaque&apos; structure to access these machines polymorphically... Think v-tables without the rest of C++...
        <![CDATA[<p>Moving on to the windows version I knew that I wanted to package each driver in a dll so that we could ship new drivers to users without needing to send them a complete new build of the product... I'd worked through the whole <code>LoadLibrary()</code>, <code>GetProcAddress()</code> malarky and had a rather nice design that provided multiple interfaces to drivers but had two small holes in it; it was hard to manage the lifetime of the dlls so that they stayed loaded for the right amount of time and I had to come up with a couple of interfaces that would represent all drivers forever as it would be a pain to have to change all the drivers if I changed the interfaces.</p>

<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=1572313498&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>Just at this point in the development I went to a Microsoft conference. The hot new thing was COM, it seemed very similar to what I'd been designing and solved the dll unload problem with reference counts on the interfaces and the interface evolution problem with dynamic discovery using <code>QueryInterface()</code>. I bought Inside COM, ripped out my custom dll loading system and embraced COM; complete with tear off interfaces and my own COM library that provided the boilerplate implementations for factories and IUnknown, etc. COM was easy then, most, or maybe all of it was in process and marshalling was easy... So easy that often the rules of COM were broken and we developed in process interfaces that could never be marshalled out of process due to data types or design features used...</p>

<p>Time passed. I worked at CSFP which became CSFB and we did a lot of COM. Things were getting more complex, marshalling mattered, most of the time, dodgy designs started to fall away and things were good; well, most of the time, developing <a href="http://www.lenholgate.com/archives/000547.html">OLE-DB providers</a> was definitely not a 'good' period ;). COM contiunued to get gnarly and hairy and more complex and eventually had a + added on the end...</p>

I haven't done much COM recently, but <a href="http://www.lenholgate.com/archives/000683.html">hosting the CLR</a> in <a href="http://www.serverframework.com/">The&nbsp;Server&nbsp;Framework</a> requires COM to communicate with it... What I'm finding is that working with the CLR COM interfaces and exposing C++ code to the CLR via COM makes me feel like I'm working back in the, ahem, good ol' days of COM, that is right back at the start before it got all hairy... I'm not quite sure why...]]>
    </content>
</entry>

<entry>
    <title>Sometimes it almost seems that they don&apos;t want you to get the code to work...</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/07/sometimes-it-almost-seems-that-they-dont-want-you-to-get-the-code-to-work.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.765</id>

    <published>2007-07-24T21:32:15Z</published>
    <updated>2010-12-27T19:37:19Z</updated>

    <summary>I&apos;ve spent some time over the last few days playing around with my CLR hosting socket server example. I had stalled on a piece of client work, I&apos;ve got a bit of a head cold at the moment and my...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[I've spent some time over the last few days playing around with my <a href="http://www.serverframework.com/products---the-clr-hosting-option.html">CLR hosting</a> socket server example. I had stalled on a piece of client work, I've got a bit of a head cold at the moment and my brain just wasn't in the right place for what I was supposed to be doing so I picked up one of more interesting the items on my todo list and took a look at that instead... The bulk of the work flowed nicely but then, just at the end things stopped working for no apparent reason... I'd done what was suggested in the book, the code compiled, the CLR called into my host in the right way and then I got a security policy exception... Hmmm.]]>
        <![CDATA[<p>I'm looking at having my CLR hosting server control how assemblies are loaded by the CLR. This involves implementing a few COM interfaces (who said .Net killed COM?), mainly <code>IHostAssemblyManager</code> and <code>IHostAssemblyStore</code>. These allow you to jump through some hoops and eventually control how assemblies are loaded... I'd got to the bit where the CLR was finally calling <code>IHostAssemblyStore.ProvideAssembly()</code> on my host and I was checking the binding info and returning an <code>IStream</code> that contained the contents of the assembly file. This is how SQL Server hosts code that lives in the database and it works quite nicely (once you're trained to jump through the required hoops without asking too many questions). </p>

<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=0735619883&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>
So, I was returning a valid <code>IStream</code> which contained the correct assembly but my code still didn't run and I was getting security policy exceptions. I double checked my reference book, "<a href="http://www.amazon.co.uk/gp/product/0735619883?ie=UTF8&amp;tag=ramcom-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0735619883">Customizing the Microsoft.NET Framework Common Language Runtime</a><img src="http://www.assoc-amazon.co.uk/e/ir?t=ramcom-21&amp;l=as2&amp;o=2&amp;a=0735619883" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />" by <a href="http://www.google.com/search?sourceid=navclient&amp;ie=UTF-8&amp;rls=GGLC,GGLC:1970-01,GGLC:en&amp;q=Steven+Pratschner">Steven Pratschner</a>, and I seemed to be doing everything that I needed to be doing... I did a Google search and someone else had been having a <a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=122334&amp;SiteID=1">similar problem</a> and his final comment was that the book did mention the issue that he had but he hadn't noticed it... I checked things out and finally found the problem mentioned in a different chapter, some way further on from the actual code that dealt with assembly store customisation... It seems that if you provide your own assembly store then you also have to provide a managed HostSecurityManager which adds some "evidence" onto the assembly that you've loaded so that the CAS stuff works properly... The chapter where this is explained goes on to show how to create custom evidence and all kinds of clever things that I have no interest in and then, right at the end, subtly includes a comment about how the security manager implementation needs to add more evidence (in addition to all the custom stuff that the rest of the chapter had been dealing with). If this additional evidence isn't added then the new custom evidence wont work... The good thing is, for me at least, just adding the standard evidence works well enough for now. The loaded assemblies will have full trust but that's fine for my example.</p>

<p>So, the minimal managed security manager implementation that you need to get your custom assembly store working is something like this:</p>
<pre class="brush: cpp gutter: false">   public class SecurityManager : HostSecurityManager
   {
      public override HostSecurityManagerOptions Flags
      {
         get
         {
            return (HostSecurityManagerOptions.HostAssemblyEvidence | 
               HostSecurityManagerOptions.HostPolicyLevel);
         }
      }

      public override Evidence ProvideAssemblyEvidence(
         Assembly loadedAssembly, 
         Evidence inputEvidence)
      {
         if (loadedAssembly.HostContext == 42)
         {
            inputEvidence.AddHost(new Zone(SecurityZone.MyComputer));
         }</p>

         return inputEvidence;
      }
   }
</pre>
And now that I've worked around the fact that you can't reuse the <code>IStream</code> that you give out in one call to <code>IHostAssemblyStore.ProvideAssembly()</code> in another call (probably due to the cursor in the stream being wrong), everything seems to be working nicely.]]>
    </content>
</entry>

<entry>
    <title>Echoes from the CLR</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/03/echoes-from-the-clr.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.737</id>

    <published>2007-03-20T12:51:41Z</published>
    <updated>2010-12-27T13:56:36Z</updated>

    <summary>The work on the CLR hosting socket server example is going pretty well. I now have a server that can pass server notifications to managed code that either runs in an AppDomain per connection or within a single AppDomain (depending...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[The work on the <a href="http://www.lenholgate.com/archives/000675.html">CLR hosting</a> socket server <a href="http://www.lenholgate.com/archives/000683.html">example</a> is going pretty well. I now have a server that can pass server notifications to managed code that either runs in an AppDomain per connection or within a single AppDomain (depending on how isolated you want the user code to be). I think I'm pretty much there as far as what I want to demonstrate is concerned; it works and the line between managed and unmanaged code is likely to vary depending on a client's particular requirements so there's little point in extending the example code any further. Hopefully I'll get a chance to clean things up a little more and then do some performance comparisons between a pure unmanaged server, a pure managed server and a hybrid...]]>
        
    </content>
</entry>

<entry>
    <title>Socket Server that hosts the CLR</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/03/socket-server-that-hosts-the-clr.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.736</id>

    <published>2007-03-15T17:49:10Z</published>
    <updated>2010-12-27T13:56:14Z</updated>

    <summary><![CDATA[My investigations into CLR hosting are going well and today I built an echo sever based on The&nbsp;Server&nbsp;Framework and my CLR Hosting helper library. The idea is that the server can deal with the network IO and then hand off...]]></summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Socket Servers" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[My <a href="http://www.lenholgate.com/archives/000675.html">investigations</a> into <a href="http://www.lenholgate.com/archives/000674.html">CLR hosting</a> are going well and today I built an echo sever based on <a href="http://www.serverframework.com/">The&nbsp;Server&nbsp;Framework</a> and my <a href="http://www.serverframework.com/products---the-clr-hosting-option.html">CLR Hosting helper library</a>. The idea is that the server can deal with the network IO and then hand off the 'real work' to some .Net code. So far the integration is going pretty smoothly....]]>
        
    </content>
</entry>

<entry>
    <title>Dino Viehland on CLR hosting</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/02/dino-viehland-on-clr-hosting.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.729</id>

    <published>2007-02-13T12:13:08Z</published>
    <updated>2010-12-27T12:44:56Z</updated>

    <summary>This is mainly a reminder for me so that I can read this when I get back from Jackson Hole... Dino Viehland has written some interesting looking blog posts on how to implement the thread/task and syncrhonisation host managers for...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Geek Speak" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[<p>This is mainly a reminder for me so that I can read this when I get back from Jackson Hole...</p>

<a href="http://blogs.msdn.com/dinoviehland/default.aspx">Dino Viehland</a> has written some <a href="http://blogs.msdn.com/dinoviehland/archive/2004/08/16/215140.aspx">interesting looking blog posts</a> on how to implement the thread/task and syncrhonisation host managers for a hosted CLR. Note that this is all "Whidbey beta 1" stuff so, well, your milage may vary...]]>
        
    </content>
</entry>

<entry>
    <title>Lifetime management issues with CLR hosting</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/02/lifetime-management-issues-with-clr-hosting.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.728</id>

    <published>2007-02-12T16:41:03Z</published>
    <updated>2010-12-27T12:44:18Z</updated>

    <summary>I&apos;m still playing with hosting the CLR in C++ (using &quot;Customizing the Microsoft.NET Framework Common Language Runtime&quot; by Steven Pratschner as my guide)... It&apos;s an interesting journey but, once again, I wonder who makes the important technical decisions at Microsoft...</summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Rants" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en-us" xml:base="http://www.lenholgate.com/blog/">
        <![CDATA[I'm still playing with hosting the CLR in C++ (using "<a href="http://www.amazon.co.uk/gp/product/0735619883?ie=UTF8&amp;tag=ramcom-21&amp;linkCode=as2&amp;camp=1634&amp;creative=6738&amp;creativeASIN=0735619883">Customizing the Microsoft.NET Framework Common Language Runtime</a><img src="http://www.assoc-amazon.co.uk/e/ir?t=ramcom-21&amp;l=as2&amp;o=2&amp;a=0735619883" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />" by <a href="http://www.google.com/search?sourceid=navclient&amp;ie=UTF-8&amp;rls=GGLC,GGLC:1970-01,GGLC:en&amp;q=Steven+Pratschner">Steven Pratschner</a> as my guide)... It's an interesting journey but, once again, I wonder who makes the important technical decisions at Microsoft and how they sleep at night ;) .]]>
        <![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=0735619883&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>I'm currently playing with the <code>ICLRRuntimeHost</code> interface. This lets you load the CLR into your unmanaged process and gives you a remarkable amount of control over how the CLR that you're hosting operates. Unfortunately it's got some dubious design issues... Firstly you can only have one instance of the CLR hosted in your process; that's just about fair enough, I guess, but I'd still be curious to know why... Secondly, if you try and load a second or subsequent instance you'll get <code>S_FALSE</code> returned from your call to <code>CorBindToRuntimeEx()</code>... The error isn't currently documented in the online docs for the function... Interestingly, you get the same error whether you've requested the same version of the CLR with the same configuration settings or if you've requested a completely different version, so, it doesn't mean "you've already loaded the CLR like this" it means "you've already loaded a version of the CLR somehow". Again this isn't likely to be much of a problem as you can't <b>ever</b> unload the CLR so the first one that you load is the only one you can ever load... </p>

<p>Then there's the <code>Stop()</code> method on <code>ICLRRuntimeHost</code>... The docs for this are "interesting"; online we have "pre-release" docs which say: <i>"This method does not release resources to the host, unload application domains, or destroy threads. You must terminate the process to release these resources."</i>, whilst VS 2005 SP1's help says <i>"Do not call this method. The host cannot unload the runtime from a process."</i> which is amusing at best. What's more, if you DO call it then it seems to return <code>E_UNEXPECTED</code> if you call it before starting the CLR (which is probably what you'd expect) and it seems to work like a 'reference counted' "Stop" (you can call it as many times as you've called <code>Start()</code> and all except the last call returns <code>S_FALSE</code> and the last call returns <code>S_OK</code>), which, again, is pretty much what you might expect... Unfortunately, once it's returned <code>S_OK</code> the CLR in your process is screwed, not only is it stopped (probably not that cleanly if the docs are anything to go by) but you can't ever start another CLR in your process; though calling <code>CorBindToRuntimeEx()</code> still returns <code>S_FALSE</code>...</p>

<p>Of course none of this is really a "problem" if you use the code in the way that some of the docs that you might come across suggest that you should do but I do find myself wondering "Why was v2.0 of the .Net Common Language Runtime allowed to go out the door with this half arsed implementation of a new interface?" After all, if you use the 'backwards compatibility' excuse then, well, even if you were relying on using the functionality during the beta phase, you shouldn't be calling <code>Stop()</code> anymore so surely it's better to break any code that was using it rather than leaving it "working"? Or, if you really couldn't change the interface at that late a date then surely a method that's documented as "don't call this" should be a no-op inside and just return <code>S_OK</code> or <code>S_FALSE</code> the whole time and do nothing?</p>

<p>I'm also a bit concerned about the fact that you can't shut the CLR down cleanly once it's started... I'm a bit of a <a href="http://www.lenholgate.com/archives/000085.html">fan</a> of being able to start <b>and</b> stop my code, no matter how complex it is. The fact that it looks like the original design allowed for stopping the CLR and the actual implementation can't do that is a little worrying...</p>

<p>Of course this annoys me most simply because it makes testing any code that happens to host the CLR a much harder job. As is often the way, the implementation flaw in Microsoft's code leaks out and becomes a flaw in all the code that uses it... I can't test my code to load and host the CLR with various different, valid and invalid, options without starting a different process for each test... Bleugh... </p>

I think I need a new category of blog postings, "<a href="http://www.lenholgate.com/archives/cat_rants.html">Rants</a>", though perhaps most of my postings could be categorised that way...]]>
    </content>
</entry>

<entry>
    <title>Crapness in mscoree.h</title>
    <link rel="alternate" type="text/html" href="http://www.lenholgate.com/blog/2007/02/crapness-in-mscoreeh.html" />
    <id>tag:www.socketframework.com,2007:/blog//12.727</id>

    <published>2007-02-08T15:49:33Z</published>
    <updated>2010-12-27T12:43:32Z</updated>

    <summary><![CDATA[I'm playing around with hosting the CLR in C++ at present and have come across a bit of crapness in the mscoree.h file... #if (_MSC_VER &lt; 1300 || _WIN32_WINNT &lt; 0x0500) typedef VOID ( __stdcall *WAITORTIMERCALLBACK )( PVOID __MIDL_0011, BOOL...]]></summary>
    <author>
        <name>Len</name>
        
    </author>
    
        <category term=".Net" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="CLR Hosting" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Geek Speak" 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 playing around with hosting the CLR in C++ at present and have come across a bit of crapness in the <code>mscoree.h</code> file...</p>
<pre class="brush: cpp gutter: false">#if (_MSC_VER &lt; 1300 || _WIN32_WINNT &lt; 0x0500)
typedef VOID ( __stdcall *WAITORTIMERCALLBACK )(
    PVOID __MIDL_0011,
    BOOL __MIDL_0012);

#endif // (_MSC_VER &lt; 1300 || _WIN32_WINNT &lt; 0x0500)
</pre>]]>
        <![CDATA[<p>This effectively says, if you're using VC6 or you're compiling for less than v5 of Windows NT then you don't have this typedef so here it is... Unfortunately, if you're compiling with VC6 but you're using the platform SDK then you already have that typedef in <code>winbase.h</code> and, well, <code>mscoree.h</code> wont compile...</p>

<p>It's a pity that versions of the Platform SDK aren't identifiable by a <code>#define</code> as this would make it easy to solve this kind of problem (and lots of others!) in a neat and maintainable way, but...</p>

So far the best I've come up with is to wrap the inclusion of the real <core>mscoree.h</code> in my own include and check for use of VC6 and lie about the compilers age to <core>mscoree.h</code>... Anyone got any better suggestions?]]>
    </content>
</entry>

</feed>



