Two-way pipeline

Latest post 10-03-2008 9:48 AM by Melody. 0 replies.
  • 10-03-2008 9:48 AM

    • Melody
    • Top 10 Contributor
    • Joined on 04-26-2007
    • Syracuse, NY
    • Posts 245

    Two-way pipeline

    By JohnHMcCauley in VSTA Tech Discussions

    I have an Add-In that defines and implements a new class (extending the available object model dynamically) that another Add-In or the Host can make calls to.

    This is possible with MAF by implementing a two-way pipeline.

    Is this possible using VSTA?

    By Melody in VSTA Tech Discussions

    John,
    No, with VSTA the object model is represented through a proxy class which is not dynamic.  All types must be pre-defined.

    Hope this helps, please let me know if you have any questions.
    Thanks!

    By JohnHMcCauley in VSTA Tech Discussions

    Sorry I should have been clearer.

    The type is pre-defined by the Add-In. If the Add-In is loaded then another Add-In or Host should be able to make use of it.

    By Gary in VSTA Tech Discussions

    Starting with your first question:

    >>I have an Add-In that defines and implements a new class (extending the available object model dynamically) that another Add-In or the Host can make calls to.

    This is possible with MAF by implementing a two-way pipeline.

    Is this possible using VSTA?

    >> 

    There are two ways that I know of to accomplish this:

    1. Starting with the IExtendedEntryPoint.GetEntryPointObject and Type t.InvokeMember() as demonstrated, in the ShapeAppCSharpMacroRecording sample:

            internal void ExecuteMacroInternal(string macroName)

            {

                // If no Macros loaded

                if (this.application.VstaRuntimeIntegration.MacroAddIn == null)

                    return;

     

                IExtendedEntryPoint entryPoint = this.application.VstaRuntimeIntegration.MacroAddIn as IExtendedEntryPoint;

                System.Diagnostics.Debug.Assert(entryPoint != null);

                if (entryPoint == null)

                    return;

     

                object obj = entryPoint.GetEntryPointObject();

                Type t = obj.GetType();

                try

                {

                    t.InvokeMember(macroName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, null);

                    return;

                }

                catch (System.Runtime.Remoting.RemotingException ex)

                {

                    // Swallow remoting exception.

                    System.Diagnostics.Debug.WriteLine(ex.ToString());

                }

                catch (Exception e)

                {

                    System.Windows.Forms.MessageBox.Show("Error executing macro\n" + e.Message, "ShapeAppCSharp", MessageBoxButtons.OK, MessageBoxIcon.Error);

                }

     

                // Didn't find a method to invoke, so show a message box.

                System.Windows.Forms.MessageBox.Show("Unable to execute macro: " + macroName, "ShapeAppCSharp", MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

     And adding a method in the addin that allows passing objects, we get a little further:

    {

    ...host side code ie: CreatePart method can return System.Object objPart . . .

                object obj = entryPoint.GetEntryPointObject();

                Type t = obj.GetType();

                    MethodInfo objMethodInfo = t.GetMethod("CreatePart");

                    if ((objMethodInfo == null) || (objMethodInfo.GetParameters().Length > 0))

                        return;

                    try

                    {

                        System.Object objPart = objMethodInfo.Invoke(remoteObject, null);

                        classType = objPart.GetType();

                        PropertyInfo objPropertyInfo = classType.GetProperty("Label");

                        if (objPropertyInfo == null)

                            return;

     

                        System.Object objLabel = objPropertyInfo.GetValue(objPart,null);

                        MessageBox.Show(objLabel.ToString());

                       

                        objMethodInfo = objPropertyInfo.GetGetMethod(true);

                        objLabel = objMethodInfo.Invoke(objPart, null);

                        MessageBox.Show(objLabel.ToString());

                    }

                    catch (System.Runtime.Remoting.RemotingException)

                    {

                        return;

                    }

                    catch (Exception ex)

                    {

                        MessageBox.Show(String.Format("CreatePart Invocation failed: {0}", ex.Message), "Invocation Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);

                    }

     

     

     

            }

    ==

    Macro Code:

    ==

    using System;

    using System.Windows.Forms;

     

    namespace ShapeAppMacros.csproj

    {

        public partial class AppAddIn

        {

            public void AppAddIn_Startup(object sender, EventArgs e)

            {

     

            }

     

            public void AppAddIn_Shutdown(object sender, EventArgs e)

            {

     

            }

            public PartFamily CreatePart()

            {

                PartFamily part = new PartFamily();

                MessageBox.Show(part.Label);

                return new PartFamily();

            }

            #region ShapeAppCSharp Designer generated code

     

            /// <summary>

            /// Required method for Designer support - do not modify

            /// the contents of this method with the code editor.

            /// </summary>

            private void InternalStartup()

            {

                this.Startup += new System.EventHandler(AppAddIn_Startup);

                this.Shutdown += new System.EventHandler(AppAddIn_Shutdown);

            }

     

            #endregion

     

        }

        public class PartFamily

        {

            public PartFamily()

            {

                PartFamilyLabel = "2345";

                MessageBox.Show("2345");

     

            }

            string PartFamilyLabel = "1234";

            public string Label

            {

                get

                {

                    return PartFamilyLabel;

                }

                set

                {

                    PartFamilyLabel = value;

                }

            }

     

        }

    }

     

    ...The second way is more complicated.  I have not tried this, but it should be feasible:

    2. create a proxy assembly layer for the add-in's OM (ie: use proxygen) and reference the add-in OM proxy, for type info, from the host; implement the IEntryPoint stuff in a host-side class; host gets a remoteObject instance of the add-in after the add-in activates an assembly in the host-domain (also via a VSTA pipeline); host automates add-in   

    hope this helps.  let us know how you fare.

     

     

     

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