Several VSTA questions/problems

Latest post 04-10-2007 3:15 PM by Gary. 9 replies.
  • 02-20-2007 4:46 AM

    Several VSTA questions/problems

    Hello,

    I'm currently evaluating VSTA for a future use in our product and ran into several problems or questions that I wasn't able to solve in the last couple of days. Maybe someone at Summit can help me out.

    Proxygen problems:
    Is proxygen going to be able to generate a proxy.cs from multiple assemblies anytime soon? I did the manual editing of the proxy (suggested in the other forum thread) which worked fine, but as our object model (and the number dlls involved) grows it gets more difficult to manage the proxy file by hand.

    Event problems:
    The application crashes when an addin does not unregister an event-handler when it gets unloaded while the application runs (RPCException or AppDomainUnloadedException). This can be solved by adding a try catch block and then remove the EventHandler in the host-app but I guess there is probably a better way to solve this.
    The thing is most add-in developers won't even know you need to unregister an event so there is no guarantee the host-app will function like our customer expect it.

    Debug problems:
    How can I invoke the shutdown event of the add-in that is currently loaded in the debugcontext of the addInProcess when debugging is stopped by the user? I only see the AddInProcessExited event which doesnt allow me to unload the addin properly (exceptions occur when I try to access the context).

    How can I start a release build from the host-app after debugging was stopped by the user? That would allow me to have the release build add-in up to date (for example the user changes the code while debugging and when debugging stops those changes are not in the release add-in).

    Performance problems:
    Transfering data between add-in and host-application is quite slow: is it possible to load the addin into the same appdomain as the host-application to speed up the transfer process or is there anything else I could do to improve this situation? This would be very important to know as our application manages huge data files. In my test-app transfering 40mb between host-app and add-in took already about 20 seconds which is quite alot.

    Networking:
    Is it possible to use the proxy architecture of VSTA to create a "remote control" add-in that controls the host-app over a tcp/ip network? I currently don't know how this would work but maybe you guys have an idea.

    Thanks for your time!
    Regards, Andreas


  • 02-20-2007 6:08 AM In reply to

    Re: Several VSTA questions/problems

    Regarding the performance problem:

    I loaded the addin by passing "new AppDomainBinding(AppDomain.CurrentDomain);" which solved the performance problem completely. The downside of this approach is probably that the stability of the host-app is at risk when add-in developers do funky stuff in their add-ins. Is there another approach to avoid the performance lag?

    Thanks!

  • 02-20-2007 2:50 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 293

    Re: Several VSTA questions/problems

    Hello Andreas,

    Thank you for evaluating VSTA!

    >>Is proxygen going to be able to generate a proxy.cs from multiple assemblies anytime soon?

    We have received many similar requests... the VSTA team has promised many improvements with the next version of ProxyGen.

    >>The application crashes when an addin does not unregister an event-handler when it gets unloaded while >>the application runs (RPCException or AppDomainUnloadedException).

    This is a problem we have observed and reported to Microsoft.

    >>How can I invoke the shutdown event of the add-in that is currently loaded in the debugcontext of the >>addInProcess when debugging is stopped by the user?

    The ShapeAppAdvancedCSharp sample shows the shutdown sequence when the app lis closed in extension.Disconnect.  If I comment out the dte debugger.quit and dte.quit portion,  I can catch the macro's Application_Shutdown event in the addin when UnloadContext(macroContext) is called inside the extension.Disconnect

           internal void Disconnect()

            {

                if (this.dte != null)

                {

                    if (this.dte.Mode == EnvDTE.vsIDEMode.vsIDEModeDebug)

                    {

                        this.dte.Debugger.Stop(true);

                    }

                    this.dte.Quit();

                }

                try

                {

                    if (this.appAddInContext != null)

                    {

                        UnloadContext(this.appAddInContext);

                    }

                }

                catch

                {

                    //  Ignore the exception. We don't want to crash if the process has already been destroyed.

                }

                try

                {

                    if (this.macroContext != null)

                    {

                        UnloadContext(macroContext);

                    }

                }

                catch

                {

                    //  Ignore the exception. We don't want to crash if the process has already been destroyed.

                }

     

                try

                {

                    if (this.addInProcess != null)

                    {

                        this.addInProcess.AddInProcessExited -= new System.EventHandler(AddInProcessExitedMacro);

                        this.addInProcess.Dispose();

                        this.addInProcess = null;

                    }

                }

                catch

                {

                    //  Ignore the exception. We don't want to crash if the process has already been destroyed.

                }

            }

     

    The ShapeAppAdvancedCSharp app also catches the DTE's dteEvents_OnBeginShutdown, which may be of interest to you.

    void dteEvents_OnBeginShutdown()

    {

    this.buildEvents.OnBuildDone -= new EnvDTE._dispBuildEvents_OnBuildDoneEventHandler(BuildEvents_OnBuildDone);

    this.solutionEvents.AfterClosing -= new EnvDTE._dispSolutionEvents_AfterClosingEventHandler(solutionEvents_AfterClosing);

    this.dte = null;

    }

    >>How can I start a release build from the host-app after debugging was stopped >>by the user?

    You'll have to explain "stopped by the user" -- do you mean stopped on a breakpoint, 'break all' or 'stop debugging'?

    >>How can I start a release build from the host-app

    If by 'start a release build', you literally mean invoking the IDE 'Build' command on the loaded addin project programatically from the host app, you would use the DTE to do this.

    If by 'start a release build' you mean load/run the release build addin assembly .dll...

    Using the ShapeAppAdvancedCSharp as an example: The application can load (start) and unload any addin .dll whenever desired.  If the user has started debugging, the VSTA debugger will notify the host application.  The DTE events may also be useful.... but in any case, the host app will load any addin assembly it can discover.  The ShapeApp sample loads the last build of the macro .Dll whenever the debugger stops, which causes some quirky behavior,  but you can design your application's addin discovery and activation however you wish.

    >>Performance problems:

    One good way to increase performance is to create custom Contracts for the data structures you use to transfer data through the proxy layer.  Ideally, we want to transfer the data in big chunks.  Proxygen  breaks everything (cross-appdomain serialization) down into fundamental data types (int, double, string, etc...) which is fine for general usage, but it may not be for optimal performance.  If you'll provide some a concrete examples of what and how you transfer between the host and the addin, I can make some suggestions and show code example(s). 

    I see (in 2nd post) that you've already experimented with sharing the host app domain.  Sharing the same AppDomain will increase speed but the addin cannot be unloaded independent of the host app. 

    >>Is it possible to use the proxy architecture of VSTA to create a "remote >>control" add-in that controls the host-app over a tcp/ip network?

    I will have to investigate this remote addin idea and get back to you.

    Regards, Gary Depue - Summit Software

  • 02-22-2007 2:56 AM In reply to

    Re: Several VSTA questions/problems

    Hello Gary,

    thanks for your detailed answers - they helped me quite a bit already.

    About the custom contract:
    You wrote that the proxy breaks down every type into base-types. The situation in our case is quite easy then I guess, as we only want to pass a huge array of a base type, say int[10000,10000] or byte[100000,100000] to the add-in. In my test-app I used int[1000,1000] which took already over 10seconds.

    The code in the add-in looked like this:
    int[,] localData = this.ActiveDocument.Data.RawData;

    The use of this is that add-ins (coded by our customers) are able to visualize our data or perform some kind filter on the data and then write it back.

    Maybe you can give me a kick start for a custom contract that could speed up the transfer in that special case.

    Thanks! Andreas




  • 02-22-2007 9:06 AM In reply to

    Re: Several VSTA questions/problems

    Hello again,

    I try to explain my debugging problem mentioned in the first post a little more in detail.

    Problem unloading debug add-ins properly (accessing the debuContext fails)
    In the AddInProcessExited event handler I try to unload the add-in that is currently in the debug context (which was created by calling addInController.CreateContext(...)). This is done to avoid the event problems mentioned before.
    After that I want to load the release version of add-in that was debugged before into the standard context (which works). The problem is I can't unload the debugged add-in.

    When I try this for example (context was created with the help of the addInController):

        if (m_contextDebug != null)
        {
            foreach (AddInCollection collection in m_contextDebug)
            {
                collectionsInContexts.Add(collection);
            }
        }
    I get an Exception telling me that this cast doesnt work. I don't know how to access that debugContext object (the standard context created without the addInController is not affected)

    You mentioned the ShapeApp example: When you stop debugging of the macro project, the context (and its add-ins) doesnt get unloaded properly. Instead the context is just overwritten by calling macroContext = new Context(...), so there is no propery unloading of the macro add-in in this example.

    Hope this clears my problem up a little.

    Thanks for you time and effort.
    Andreas
  • 02-22-2007 4:25 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 293

    Re: Several VSTA questions/problems

    Hello Andreas,

    >>Is it possible to use the proxy architecture of VSTA to create a "remote >>control" add-in that controls the host-app over a tcp/ip network?

    In the current version of VSTA we do not provide anything that would let a client side host application run add-ins on a server. There has been a number of requests for click-once (or auto-update) deployment support of addins (which would provide a means to discover add-ins from a server and deploy them on a client) so we hope that this will make the vNext feature list.  But even with click-once deployment, the addins would still be run on the client.

    Regards,  Gary

  • 02-26-2007 9:45 AM In reply to

    Re: Several VSTA questions/problems

    Hi Gary,

    thanks for looking into the remote problem.

    Can you give me some further advice for the other 2 things I was refering to in my follow up posts (unloading addins from a debug context and most importantly the custom contracts)?

    Thanks alot.
    Regards, Andreas
  • 03-06-2007 10:58 AM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 293

    Re: Several VSTA questions/problems

    Hello Andreas,

    I am pursuing your question about unloading addins with the VSTA team.  If you supply a clear, isolated example of the problem for me to run and send along to Microsoft, that would be a great help.

    I have nearly completed a VAO sample demonstrating a custom contract and will send it along to you asap.

    In the meantime, I'll send you a rough one using testcon.

    Regards,  Gary

  • 03-22-2007 3:31 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 293

    Re: Several VSTA questions/problems

    This External process (seamless) debug problem has been confirmed here and with the VSTA team at Microsoft.

    Will keep you posted regarding their advice for resolution/workaround.

    Regards,

    Gary/VSTA support team

  • 04-10-2007 3:15 PM In reply to

    • Gary
    • Top 10 Contributor
    • Joined on 07-13-2006
    • Posts 293

    Re: Several VSTA questions/problems

    The MS VSTA team responds to this issue as follows:

     

    In the 3rd proc scenario (Non-Destructive Seamless Debugging) the context is a transparent proxy created in the 3rd proc, not in the host’s process.  When the 3rd proc is destroyed, so is this context.

     

    So, it looks like all the host has to do is catch the exception.  All the cleanup is done automatically when the 3rd proc is destroyed:.

    Further details:

    The context throws an exception [because]as the same is created as a remote context in an external process which no longer exists when we do a ctrl Alt break to stop debugging. (Refer to the RemoteProcessCreation image for marked process that is created behind the scenes to support the debugging scenario)

     

    Best way to verify the same is to have System.Runtime.Remoting.RemotingServices.IsTransparentProxy(context.contract).

     

     

    In the Alt F11 scenario/ NDD case the debugging happens via the add in load in an external process

    The context created here is a transparent proxy here(created in remote process) and unload is attempted in AddInMacroExited event that gets fired after process dies  (external process that loads the addin), so context is no longer valid.

     

    =End of Microsoft comments=

    =======================================

    Summit’s Repro Steps:

    1.        Open ShapeAppAdvancedCSharp SDK Sample project in VS

    2.        In extension.cs, add this  line to AddInProcessExitedMacro event handler:

            private void AddInProcessExitedMacro(object sender, EventArgs args)

            {

                System.Diagnostics.Debug.Assert(this.isDebugging);

                try

                {

                    UnloadContext(this.macroContext);çAdd this line

                    this.addInProcess = null;

                 this.addInController = null;

    3. In extension.cs, comment out the ‘catch’ block so that the thrown exception is seen

            private void UnloadContext(Context context)

            {

                try

                {

                    foreach (AddInCollection coll in context)

                    {

                        foreach (AddIn a in coll)

                        {

                            if (a.IsLoaded)

                                a.Unload(TimeSpan.FromSeconds(5));

                        }

                    }

                }

     

                //catch ç Comment out this block

                //{

                //    // Ignore the exception. Throw in the case where the hosting process is shut down.

                //}

                finally

                {

                    context = null;

                }

          }

    4.    Run application from VS, Alt + F11 (or select menu to show the VSTA IDE), open default macro project, and set a breaakpoint in the startup event:

           private void TheApplication_Startup(object sender, EventArgs e)

           {ç Set Breakpoint here from inside VSTA IDE

    5.         F5 to Run/Debug the addin from the VSTA IDE

    6.        When the breakpoint in the macro/addin’s startup event is hit in VSTA IDE, Stop debugging (Ctl + Alt + Break).

    7.        Exception: Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.VisualStudio.Tools.Applications.ComChannel.Internal.IComRemotingServer'. This operation failed because the QueryInterface call on the COM component for the interface with IID…

    ====================

    I’m not sure that this is helpful to you because I believe that you are looking for a way to explicitly unload the extern proc debugged addin.

     

    So to do any addin unhook/ cleanup, we must catch the addin/debugger before AddInProcessExitedMacro, because, at this event, the external proc is already killed.

     

    I looked at other events in the DTE and the only one that looks like it would work so far is the CommandBar click event :

    private EnvDTE.CommandBarEvents commandBarEvents;

    Track down which commandbar button stops debugging and hookup the click event

    this.commandBarEvents = dte.Events.get_CommandBarEvents(...)

    this.commandBarEvents.Click +=new EnvDTE._dispCommandBarControlEvents_ClickEventHandler(commandBarEvents_Click);

    When the stop debug button is clicked, or matching accel key, the click event should allow the host app to do any necessary unhooking/addin teardown.  This could be used in conjunction with debugger stopped status from the dte to determine that the user stopped the debug session.

     

     

    -G

    Filed under:
Page 1 of 1 (10 items) | RSS
Copyright Summit Software Company, 2008. All rights reserved.