none
VSTO Addin does not load with IDTExtensibility2 Addin & WindowsFormsSynchronizationContext RRS feed

  • Question

  • Hi Friends,

    I have two add-ins for Excel 2010 one is developed using VSTO and another one is using IDTExtensibility2.

    The VSTO Addin does not get loaded if the IDTExtensibility2 loads first and shows a Windows Form in its "Connect" method.

    if the IDTE Addin does not shows a windows form both of the addin getting loaded.

    After debugging into the VSTO Code,
     The call to download the GetManifests() hangs and it always get timeout. So the vsto addin does not get loaded.

    (Microsoft.VisualStudio.Tools.Applications.Hosting.dll!Microsoft.VisualStudio.Tools.Applications.Deployment.ClickOnceAddInDeploymentManager.GetManifests(System.TimeSpan timeout)

    The GetManifests() function internally calls the System.Deployment.Application.DeploymentManager.BindAsyncWorker() to download the manifest.

    The BindAsyncWorker() downlaods the manifest using the System.ComponentModel.AsyncOperation.Post() 

    The DeploymentManager creates an instance of the AsyncOperation using the AsyncOperationManager.CreateOperation(). Which uses the AsyncOperationManager.SynchronizationContext property.

    The problem lies on the AsyncOperationManager.SynchronizationContext property. The default value is "System.Threading.SynchronizationContext". if the IDTE2 addin loads first and shows a windows form, The windows form changes the SynchronizationContext property to "System.Windows.Forms.WindowsFormsSynchronizationContext". 

    Since the IDTE2 Addin & VSTO loader both runs in DefaultAppDomain. The VSTO loader's System.Deployment.Application.DeploymentManager also uses the changed WindowsFormsSynchronizationContext to download the manifest. 

    The GetManifests() relies on some events and wait handle to get the manifest downloaded. 

    Once the context is changes to the WindowsFormsSynchronizationContext the events will not getting fired, Only the main thread is running. Once the main thread is timeout ( the waiting thread) all the events getting fired. Since the main thread to download the manifest is timed out the vsto addin does not getting downloaded.

    The problem may be the events also tried to fire in the Main Thread.

    Is there a way to solve the problem? 

    I have attached Two Sample projects to reproduce the issue. 
    https://www.dropbox.com/s/u3p9m7yux09em2b/OfficePlugin.zip

    ExcelIDTE2 - DTE Excel Addin
    ExcelVstoAddIn - VSTO Excel Addin.

    Comment the two lines to show the form in ExcelIDTE2.Connect.Connect(). Both the addins will getting loaded. Once you un-comment the two lines only the DTE addin will getting loaded. And excel wait for 60 seconds to load the VSTO addin and times out.

    With Thanks

    Prakash

     
    Thursday, November 15, 2012 7:15 AM

Answers

  • if it depends on it to be this specific class, it will break anyway if any VSTO based add-in is loaded after it, don't you agree?

    but to answer your question - no, i was thinking about dummy add-in that will load your addin (calling 'Connect' on it) after all processing is done in Excel (by posting windows message to message pump). Your idea about reverting contexts will work only if order of add-in can be always controlled, and it cannot.

    Thursday, November 15, 2012 12:04 PM
  • Ok, let's dissect this one by one:

    This IDTE2 plugin still has problem if it depends on WinFormsSynchronizationContext (assuming it sets it explicitly, and this is not done by .NET framework itself), because any VSTO based plugin that loads _after_ him will set synchronization context to its own on main AppDomain due to the way VSTO loader works, so if it needs it then it is broken anyway.

    As for order, - yes, you cannot define it or depend on it so this is a dead end.

    And no, if you create your own IDTE2 or ny other add-in that will load your one, you will not have a problem, because algorithm that i described is not based on order. Excel in main thread start to load add-ins (order does not matter). Your dummy add-in loads and posts windows message to message pump (which will be processed only _after_ excel finish all work and is not busy anymore). Excel continues loading add-ins, this rogue add-in with winforms get loaded, shows it widnow, then everything finishes and message pump finds your message to process, takes it off the queue and calls your code, which will load your 'real ' addin.

    Thursday, November 15, 2012 1:14 PM
  • 1. make new dummy add-in that is not based on VSTO

    2. inside that add-in startup event create winformssynchronizationcontext and use it Post metchod passing your function

    3. that function will iterate through Excel Addins collection, find your 'real' VSTO based addin and set Connect to true on it, which will cause excel to load it, vsto to start, etc.

    of course i never had such problems with other add-ins so i;m not 100% sure it will work, but worth a try

    Thursday, November 15, 2012 1:46 PM
  • i wrongly assumed that functions will be named the same in outlook and excel :-) apparently it is Installed property of add-in that matters in this situation according to http://msdn.microsoft.com/en-us/library/office/aa141014(v=office.10).aspx

    in http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.addin(v=office.14).aspx they also mention using Workbooks(add-in name) method to ensure that add-in is actually loaded into workbook. Try first one and see if it works and if not, add this second check.

    Friday, November 16, 2012 9:26 AM

All replies

  • maybe try before showing your first winform to capture current SynchronizationContext and restore it inside that form's Load or Shown events? (i;m not sure about second one since it gets posted to message pump so it gets raised after all current processing is done so there might be a race condition)

    Thursday, November 15, 2012 8:10 AM
  • thanks for your reply Damian

    The DTE Add-in is a third party addin. I does not have control over it.

    I have used the .net reflector to peek into its source code.

    Thursday, November 15, 2012 10:06 AM
  • then currently i can only think of 2 ways to circumvent it:

    1. try making add-in that installs via msi and is loaded locally froom disk - it should bypass checking version and downloading of VSTO addin

    2. make your add-in based on IDTE2 or other technology (like .net with c++ using shim wizard)

    Thursday, November 15, 2012 10:28 AM
  • 1. My addin is not deployed via clickonce. It is installed from MSI setup and I speficed "|vstolocal". I think the VSTO loader always use same way to load the click once / local addins.

    2. I cannot change my addin to a DTE2 since I have used many of the features in VSTO also my VSTO addin is bigger in functionality and code.

    Thursday, November 15, 2012 10:36 AM
  • What VSTO specific features do you use? Most of it will also be available with COM Shim Wizard (ribbon, CTP, etc.).

    If however this is not an option i guess you could develop second addin that will load your first one after that IDTE2 shows its form.

    Thursday, November 15, 2012 10:45 AM
  • Did you mean, To write another IDTE2 dummay addin which changes the context back to System.Threading.SynchronizationContext. So that the vsto add-in will get loaded?

    Will not it break the existing DTE2 Addin. Since it expects the WindowsFormsSynchronizationContext? 

    Thursday, November 15, 2012 11:06 AM
  • if it depends on it to be this specific class, it will break anyway if any VSTO based add-in is loaded after it, don't you agree?

    but to answer your question - no, i was thinking about dummy add-in that will load your addin (calling 'Connect' on it) after all processing is done in Excel (by posting windows message to message pump). Your idea about reverting contexts will work only if order of add-in can be always controlled, and it cannot.

    Thursday, November 15, 2012 12:04 PM
  • >if it depends on it to be this specific class, it will break anyway if any VSTO based add-in is loaded after it

    No. VSTO Loader loads each managed vsto addin in a separate appdomain. So changing the synchronization context inside an VSTO addin does not affect any other VSTO/DTE2 addin. The IDTE2 addin and VSTO loader both loads in DefaultAppDomain so the problem.

    Also I do not know how to define the order of addin load :(. If another DTE2 addin loaded and shows a windows form after my dummy DTE2 addin we still have a problem.

    >i was thinking about dummy add-in that will load your addin (calling 'Connect' on it) after all processing is done in Excel (by posting windows message to message pump).

    That does not fit for my case. That was bit complicated too.

    The main reason we used the VSTO addin is for it's isolation with the underlaying process (Creating a separate AppDomain for every vsto addin).  So that any problem or crash in my add-in does not affect the process (word/excel).

    Thursday, November 15, 2012 1:03 PM
  • Ok, let's dissect this one by one:

    This IDTE2 plugin still has problem if it depends on WinFormsSynchronizationContext (assuming it sets it explicitly, and this is not done by .NET framework itself), because any VSTO based plugin that loads _after_ him will set synchronization context to its own on main AppDomain due to the way VSTO loader works, so if it needs it then it is broken anyway.

    As for order, - yes, you cannot define it or depend on it so this is a dead end.

    And no, if you create your own IDTE2 or ny other add-in that will load your one, you will not have a problem, because algorithm that i described is not based on order. Excel in main thread start to load add-ins (order does not matter). Your dummy add-in loads and posts windows message to message pump (which will be processed only _after_ excel finish all work and is not busy anymore). Excel continues loading add-ins, this rogue add-in with winforms get loaded, shows it widnow, then everything finishes and message pump finds your message to process, takes it off the queue and calls your code, which will load your 'real ' addin.

    Thursday, November 15, 2012 1:14 PM
  • >This IDTE2 plugin still has problem if it depends on WinFormsSynchronizationContext (assuming it sets it explicitly, and this is not done by .NET framework itself)

    It was set .net framework itself (inside the constructor of the System.Windows.Control class).

    >the dummy addin

    I partially understand the solution you provided. Following is my understating 

    The dummy addin will be a IDTE2 addin or you want to make my VSTO addin to IDTE2?

    > Your dummy add-in loads and posts windows message to message pump (which will be processed only _after_ excel finish all work and is not busy anymore). 

    I know a little about window messages. I do not know how to post window messages to excel process. Are you sure that my window messages only getting processed after all the add-in getting loaded?

    >Excel continues loading add-ins, this rogue add-in with winforms get loaded, shows it window, then everything finishes and message pump finds your message to process

    If I keep my addin as VSTO addin will not it get loaded ?

    >takes it off the queue and calls your code, which will load your 'real ' addin.

    How can we defer loading of my addin until i receive my window message?

    Thursday, November 15, 2012 1:31 PM
  • 1. make new dummy add-in that is not based on VSTO

    2. inside that add-in startup event create winformssynchronizationcontext and use it Post metchod passing your function

    3. that function will iterate through Excel Addins collection, find your 'real' VSTO based addin and set Connect to true on it, which will cause excel to load it, vsto to start, etc.

    of course i never had such problems with other add-ins so i;m not 100% sure it will work, but worth a try

    Thursday, November 15, 2012 1:46 PM
  • >that function will iterate through Excel Addins collection, find your 'real' VSTO based addin and set Connect to true on it, which will cause excel to load it, vsto to start, etc.

    http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.addin_members.aspx

    how to set connect to true? I have not found any property like that. Can you give a sample code?

    Friday, November 16, 2012 5:39 AM
  • i wrongly assumed that functions will be named the same in outlook and excel :-) apparently it is Installed property of add-in that matters in this situation according to http://msdn.microsoft.com/en-us/library/office/aa141014(v=office.10).aspx

    in http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.addin(v=office.14).aspx they also mention using Workbooks(add-in name) method to ensure that add-in is actually loaded into workbook. Try first one and see if it works and if not, add this second check.

    Friday, November 16, 2012 9:26 AM