Share via


COM Shim Wizard 2.3.1.0

We’ve released a slight update to the COM Shim Wizard. This is available as a free download here, and the covering article is on MSDN here. The differences Between v2.3.0.0 and v2.3.1.0 are summarized below.

Setup

The major difference between v2.3.0.0 and v2.3.1.0 is that v2.3.0.0 was built to install with Visual Studio 2005, whereas v2.3.1.0 installs with either Visual Studio 2005 or Visual Studio 2008, or both. The setup for the COM Shim Wizard now gives you the option to choose which version or versions of Visual Studio to install for. There are 3 additional enhancements to the setup for the COM Shim Wizard v2.3.1.0:

1. The setup disables installation on a per-user basis. This is because installing per-user (and therefore registering to HKCU) causes problems on Vista with UAC turned on, or when running Visual Studio in an elevated process.

2. The custom actions are set to NoImpersonate, so that they work correctly on Vista with UAC on.

3. The setup is formatted so that any error messages are displayed (otherwise they are not visible in Vista, the user just sees Error 2869).

CLR Start Bug

I documented this fix as a community comment added to the MSDN documentation for the COM Shim Wizard v2.3.0.0. Part of what the shim does is to load the CLR: it does this by calling CorBindToRuntimeEx. We test the return from CorBindToRuntimeEx, and if it's S_FALSE, this indicates that the CLR has already been loaded. In the released version of the shim, if we get S_FALSE, we simply return.

However, there is a scenario where the CLR could already have been loaded but not started. It's an unusual scenario: it could happen if some other managed code was loaded into the process but never executed. The problem is that the shim code assumes that if the CLR is loaded it is not necessary for us to start it. Of course, if the only other things in the process that load the CLR are all shims created with the COM Shim Wizard, then this assumption would be true – because the first one to load would have loaded the CLR and started it. However, this assumption doesn't hold if there are other native components that load the CLR but don't start it.

We fixed this in the code generated by v2.3.1.0 of the wizard by simply removing the test for S_FALSE – this works because we do call Start later on.

Post-build step to copy ManagedAggregator.dll

In v2.3.0.0, a post-build step in the generated shim project copies the ManagedAggregator.dll from the \bin\debug folder unconditionally. We changed this in v2.3.1.0 to copy the dll from the target folder for each project configuration. For example, for a standard debug configuration, it will copy from \bin\debug; but for a release configuration, it will copy from \bin\release.

Comments

  • Anonymous
    August 29, 2008
    Thanks Andrew - Highly appreciated.Kind regards,Dennis
  • Anonymous
    August 29, 2008
    Dennis - thanks, you're very welcome :-)
  • Anonymous
    September 05, 2008
    Andrew,According to the documentation the shim dll should have the Registry setting of vsdrpCOM. But shouldn't it read vsdrpCOMSelfReg instead?Kind regards,Dennis
  • Anonymous
    September 06, 2008
    Dennis - vsdrpCOMSelfReg causes the DLL to be invoked at install time to register, requiring dependencies to be present and laid down in the right order; plus, the code runs at that point. The regular vsdrpCOM setting runs the registration at the time the MSI is built, and puts the registration data into the MSI itself. Then, at install time, the file gets copied and Windows writes the registry entries, making this almost always the better way because you're not depending on registration code to work at install/uninstall time, just at MSI build time.Also, from the perspective of a system admin, vsdrpCOM is better because Windows can always reliably roll back an installation done this way. Conversely, vsdrpCOMSelfReg allows the developer to put any arbitrary code in their reg/unreg functions (not limited to registration/unregistration) - and the admin is at the mercy of the developer to make sure the 'unreg' is a complete roll-back of the 'reg'.
  • Anonymous
    September 06, 2008
    Andrew,Point taken - Thanks for the detailed information.What about installation on Vista? Do we need to install it under HKLM User Settings?Kind regards,Dennis
  • Anonymous
    September 07, 2008
    Please disregard my previously comment. A type error caused some issues.Kind regards,Dennis
  • Anonymous
    September 10, 2008
    is this working with office 2003 too?i have a strange behaviour when using excel 2003 udfs: the com add in gets registered and loaded - i can see it in excel, select it as add-in and i also can debug it. the add-in gets initalized at excel startup (i can debug ctor and onconnection), but shortly afterwards it seems the add-in crashes. when i'm opening the function wizard of excel the add-in tries for a second time, but again, after ctor and onconnection the object dies and there are no udf entries in the wizard.ps: the com object works fine via vba (createobject())!
  • Anonymous
    September 10, 2008
    interzone - yes, I tested this with Excel 2003 also. It should work the same way as with Excel 2007. Are you sure you have the typelib registered? Without the typelib, Excel will not be able to determine what functions the add-in exposes.
  • Anonymous
    September 10, 2008
    hi andrew!you are right! i've missed the tlbs. is it neccessary to keep also the tlb of the managed dll file or is only the C++ dll tlb the important one?cheers!
  • Anonymous
    September 10, 2008
    interzone - that depends on what you've put into each typelib. Typically, the tlb for the managed add-in contains all the information about the functions that you're exposing, while the tlb for the shim typically is very minimal and does not contain this information. So, in the default case, you need to register the tlb for the add-in, not the shim.However, you could put the full function information into the IDL for the shim if you want to, and then register the tlb for the shim. Either way works. It tends to be better to use the add-in's tlb because that always gets built (if you have Register for COM interop checked) every time you make changes to the add-in itself. The shim doesn't actually implement any of the UDFs in the add-in, so it would be a little strange to built this UDF information into the shim tlb.
  • Anonymous
    September 10, 2008
    currently i'm deploying both tlb files. i'm using the windows installer for deployment and the only thing i'm doing besides setting the shim output to vsdrpCOM is copying these tlb files into the setup directory. it's working on each tested machne now, but is that enough? because you are talking about registering the tlb - do i need regtlib to do that?
  • Anonymous
    September 12, 2008
    interzone - you're right, the typelib doesn't need to be registered, so long as it is in the same folder as the shim/add-in. When you build the add-in, and set "Register for COM interop", this builds the typelib and also registers it as an atomic operation - but this is only on the dev machine, of course. On the target user machine, you don't need to register it.
  • Anonymous
    November 01, 2008
    The comment has been removed
  • Anonymous
    November 02, 2008
    Karl - yes, the shim does explicitly avoid the mscoree problem. I suspect your setup project is not registering the various DLLs correctly. The only way you would end up with mscoree.dll registered for the add-in is if the add-in DLL itself is registered - which it should not be, if you're using a shim. (I assume you're installing the add-in on a different machine from the one where you're developing and building it.)In the covering article on MSDN, there's a note that says: "If you build a setup project for your add-in, you should add the primary output of both the shim and the ManagedAggregator projects to your setup. You should also change the value of the Register property for all three project outputs. Set this to vsdrpCOM for the shim DLL, and vsdrpDoNotRegister for both the original add-in DLL and the ManagedAggregator DLL."
  • Anonymous
    November 03, 2008
    I want to deploy the add-in to x64 platform. How can this tool support on x64. I have tried some method. But I found that the add-in was always in inactive add-ins and have a runtime error when loaded. But I cannot know what was the error.So could you help please?
  • Anonymous
    November 13, 2008
    iceeyes - this is a Visual Studio 2005/2008 tool. Visual Studio is 32-bit, and it runs on 32-bit and 64-bit OS's - so you should have no problem installing and running the COM Shim wizards on 64-bit.The COM Shim wizards generate only 32-bit add-in code - because right now Office only supports 32-bit. 32-bit Office will run of course on 64-bit OS's - so again, you should have no problem installing and running an add-in on 64-bit.If you are still experiencing problems, please supply more details of exactly what you're trying to do.
  • Anonymous
    December 04, 2008
    Thanks andreww, I have already figure out the x64 problem.But now I have a problem with OneNote. Because this wizard don't support OntNote, but we need a shim for OneNote.I have tried select another application like PPT, then I modify the registry. But it doesn't work for OneNote.How to do that?Thank you.
  • Anonymous
    December 26, 2008
    iceeyes1021 - The wizard doesn't support OneNote because OneNote doesn't support COM add-ins.
  • Anonymous
    February 18, 2009
    The comment has been removed
  • Anonymous
    February 19, 2009
    VSP - it's difficult to figure out what might be happening - this really needs debugging. Please can you send me the simplest possible solution that reproduces this problem? If so, I can take a look at it.
  • Anonymous
    February 19, 2009
    This happens only when a 3rd party add-in is enabled.  When that add-in is disabled, UnloadDomain returns from my add-in during exit. I do not have source for that add-in. But that add-in is not using Shim and in the COMAdd-ins dialog it shows the .manifest file.Thanks,
  • Anonymous
    February 19, 2009
    VSP - hmm... this is interesting. The primary purpose of the shim is to provide isolation between loaded add-ins at the appdomain level: each add-in gets loaded into its own independent appdomain that its shim creates for it. If the 3rd party add-in you mention is registered with a .manifest, then it is almost certainly a VSTO v2 add-in. VSTO add-ins also get loaded into their own independent appdomain because the VSTO runtime contains a variation of the shim functionality. All of which means that there should be NO interaction between these add-ins, and the 3rd party add-in should not be causing a problem with the appdomain unload code in your add-in.So this is a bit of a mystery.What is the 3rd party add-in?Do these add-ins communicate with each other via the COMAddIns collection?
  • Anonymous
    February 19, 2009
    I created a Word 2007 Add-in based on VSTO 2 and simply built the add-in. Now my Word contains only two add-ins one based on VSTO and another based on this Shim. When I close the Word, it stays in the memory.Thanks,
  • Anonymous
    February 21, 2009
    VSP - thanks, I am investigating this, and I will get back to you as soon as I can.
  • Anonymous
    February 26, 2009
    VSP - thanks again for bringing this problem to our attention.The problem is that the ManagedAggregator.CreateAggregatedInstance method is taking in an IComAggregator object (the CConnectProxy object, which is the outer object in the aggregation), but is not releasing it. This is a problem because the object was passed from the native shim code to the managed aggregator code and wrapped as an RCW. If we don’t release the RCW, the CLR will potentially hold on to it (and the underlying COM object) until the corresponding AppDomain is unloaded. However, in the current implementation the AppDomain is unloaded when COM object’s reference counter reaches zero. This essentially constitutes a circular reference problem thus preventing the host from terminating cleanly. The fix is simple: in the finally block, add a call to Marshal.ReleaseComObject on the outer object:public void CreateAggregatedInstance(   string assemblyName, string typeName, IComAggregator outerObject){   IntPtr pOuter = IntPtr.Zero;   IntPtr pInner = IntPtr.Zero;   try   {       pOuter = Marshal.GetIUnknownForObject(outerObject);       object innerObject =           AppDomain.CurrentDomain.CreateInstanceAndUnwrap(           assemblyName, typeName);       pInner = Marshal.CreateAggregatedObject(pOuter, innerObject);       outerObject.SetInnerPointer(pInner);   }   finally   {       if (pOuter != IntPtr.Zero)       {           Marshal.Release(pOuter);       }       if (pInner != IntPtr.Zero)       {           Marshal.Release(pInner);       }       // Call ReleaseComObject on the outer object (ConnectProxy)       // to make sure we delete the RCW, and prevent the CLR from       // holding onto it indefinitely (and keeping the host alive).       Marshal.ReleaseComObject(outerObject);   }}Not sure when we'll be able to release an update to the shim wizard, but I'll post the workaround to MSDN also. Thanks again for your feedback.
  • Anonymous
    February 26, 2009
    A customer (VSP) was using the COM Shim and identified a scenario where a bug in the shim code could
  • Anonymous
    February 26, 2009
    With this change it is working fine.Thank you very much.
  • Anonymous
    March 10, 2009
    The comment has been removed
  • Anonymous
    March 10, 2009
    RichL - no, you don't have to replace the shim - the shim contains no code that is specific to your interface, and it doesn't care what changes you make to the interface. On the other hand, it does specify the name of the class that implements IDTExtensibility2 as well as the public key token for that add-in assembly - so you'd have to update that code if you change any of those items.Does the add-in work correctly without the shim? Is the typelib registered correctly?
  • Anonymous
    March 10, 2009
    The comment has been removed
  • Anonymous
    June 21, 2009
    The comment has been removed
  • Anonymous
    July 13, 2009
    Sumant - the MDA is innocuous - you can ignore it. What's happening is the CCLRLoader destructor is running very late - it's running when the Excel process terminates and the CLR itself is getting unloaded. Unfortunately, the CCLRLoader destructor attempts to call Release on the appdomain object - and it's too late to do this.If you really want to avoid the MDA, you can change the RTD shim code to unload the appdomain and release the appdomain pointer during the FinalRelease of the RTDProxy object. You can see how to do this if you look at the code generated for an add-in. We changed the add-in shim code a couple of times since the last time the RTD shim code was last updated.
  • Anonymous
    July 20, 2009
    Thanks a ton Andrew! I changed the shim code as you suggested, and it now works like a charm! =)Sumant