title: When creating a reg-free managed COM object, how can I get the CLR to look in a directory different to the main application's executable?
body: <p>This is a kind of complex question, hitting on somewhat arcane areas relating to COM, the CLR, and reg-free COM.</p>
  
  <p>First, my main application is written in python. As such, it's codebase (in development) is at, say, C:\mainapp\main.py.</p>
  
  <p>Of course, on windows, it is C:\Python27\python.exe that executes the program.</p>
  
  <p>I now want to use reg-free COM from python (using win32com) to talk (using IDispatch) to a COM object written in C# that I control, that is located at C:\mainapp\ManagedCOMObject.dll</p>
  
  <hr>
  
  <p>Note: If you don't speak python / pythoncom, note that the call to Dispatch() eventually boils down to CoCreateInstance().</p>
  
  <hr>
  
  <h1>Attempt 1</h1>
  
  <pre><code>#main.py:
  
  import win32com.client
  CLSID_ManagedComObject_MyClass = "{zzzzz....}" #This is correct
  myclass = win32com.client.Dispatch(CLSID_ManagedComObject_MyClass)
  </code></pre>
  
  <h2>Result</h2>
  
  <p>Failure, because the object is not in the registry (as expected), and I didn't mention anything about manifest files, and python.exe's manifest obviously doesn't know about my object.</p>
  
  <hr>
  
  <h1>Attempt 2</h1>
  
  <pre><code>#main.py:
  
  ac = ActivationContext("C:\mainapp\myapp.manifest", asm_dir="C:\mainapp")
  with ac.activate():
      #The above two lines fill in a ACTCTX structure, call CreateActCtx, and call ActivateActCtx 
      import win32com.client
      CLSID_ManagedComObject_MyClass = "{zzzzz....}" #This is correct
      myclass = win32com.client.Dispatch(CLSID_ManagedComObject_MyClass)
  </code></pre>
  
  <p>-</p>
  
  <pre><code>#myapp.manifest:
  &lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;
  &lt;assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"&gt;
      &lt;assemblyIdentity type="win32" 
                  name="My.Main.App" 
                  version="1.0.0.0" 
                  processorArchitecture="x86" 
      /&gt;
      &lt;dependency&gt;
          &lt;dependentAssembly&gt;
              &lt;assemblyIdentity
                          name="ManagedComObject" 
                          version="1.0.0.0" 
                          processorArchitecture="msil" 
              /&gt;
          &lt;/dependentAssembly&gt;
      &lt;/dependency&gt;
  &lt;/assembly&gt;
  </code></pre>
  
  <p>Note that ManagedCOMObject has an embedded manifest, which declares the COM object using the clrClass tag.</p>
  
  <h2>Result</h2>
  
  <p>The ActicateActCtx call succeeds and correctly parses the manifests of myapp.manifest and ManagedComObject.dll - I verified this using sxstrace.exe.</p>
  
  <p>The call to CoCreateInstance fails with FileNotFound, after probing for C:\Python27\ManagedComObject.dll. The fusion log claims that PrivatePath is not set (presumable because python.exe.config doesn't exist), and simply does not look for the C# object in C:\mainapp.</p>
  
  <h1>Questions</h1>
  
  <ol>
  <li><p>Why is this failing? I believe it is because the CLR COM loader stub is unable to import my C# assembly. If it failed before this step, the CLR would not even load, so the very fact that it is probing and creating fusion logs leads me to belive it is because the CLR can't find ManagedCOMObject.dll.</p></li>
  <li><p>Note that the CLR is loaded - I believe this means that COM has successfully looked at the current activation context to find the registration. I don't know precisely what clrClass does in the manifest, but presumably it got the CLR loaded successfully.</p></li>
  <li><p>I assume now that the issue is the CLR is not paying attention to the ActCtx when loading assemblies. If I was writing managed code, I could hook into the AppDomain.CurrentDomain.AssemblyResolve event and find the DLL myself. Since instead i'm writing unmanaged code, and hosting the CLR only implicitly, can I somehow change my applications PrivatePath and/or how assemblies are probed?</p></li>
  </ol>