Pass non-mscorlib MarshalByValue object to an AddIn

Latest post 04-02-2008 5:38 PM by Melody. 6 replies.
  • 03-05-2008 4:42 PM

    Pass non-mscorlib MarshalByValue object to an AddIn

    Using the typemap code generated by proxygen to create the TypeInfrastructureManager adds entries for the types I've defined as my API as well as almost 1200 entries for classes in mscorlib.  If I attempt to pass a marshalByValue object (e.g. System.Data.DataSet) to an addin that is not part of my API or mscorlib I get the exception included at the end of this post.

    Do I need to manually add entries to the TypeInfrastructureManager for system classes not part of mscorlib inorder to be able to return them from a method call?

    Exception Details:
    System.Reflection.TargetInvocationException, mscorlib
    System.Collections.Generic.KeyNotFoundException, mscorlib

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.

    Server stack trace:
       at System.ThrowHelper.ThrowKeyNotFoundException()
       at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
       at Microsoft.VisualStudio.Tools.Applications.TypeInfrastructureManager.GetCanonicalName(TypeDescription localType)
       at Microsoft.VisualStudio.Tools.Applications.TypeInfrastructureManager.GetCanonicalName(Type localType)
       at Microsoft.VisualStudio.Tools.Applications.RemoteTypeAdapter.System.AddIn.Contract.Automation.IRemoteTypeContract.GetCanonicalName()
       at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
       at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
       at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg, Int32 methodPtr, Boolean fExecuteInContext)

    Exception rethrown at [0]:
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at System.AddIn.Contract.Automation.IRemoteTypeContract.GetCanonicalName()
       at Microsoft.VisualStudio.Tools.Applications.TypeInfrastructureManager.LocalTypeFromRemoteType(IRemoteTypeContract typeToFind)
       at Microsoft.VisualStudio.Tools.Applications.RemoteParameterInfo.InitializeInfo(MemberInfo parentMember, RemoteParameterData data)
       at Microsoft.VisualStudio.Tools.Applications.RemoteParameterInfo..ctor(MemberInfo parentMember, RemoteParameterData data, TypeInfrastructureManager typeInfrastructureManager)
       at Microsoft.VisualStudio.Tools.Applications.RemoteMethodInfo..ctor(RemoteType parentType, IRemoteMethodInfoContract contract, TypeInfrastructureManager typeInfrastructureManager)
       at Microsoft.VisualStudio.Tools.Applications.RemoteType.CreateCacheMethodInfo(IRemoteMethodInfoContract contract)
       at Microsoft.VisualStudio.Tools.Applications.RemoteType.GetMethodImpl(String name, BindingFlags bindingFlags, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
       at System.Type.GetMethod(String name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
  • 03-07-2008 9:42 AM In reply to

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

    Re: Pass non-mscorlib MarshalByValue object to an AddIn

    You need to generate a proxy (ie: use proxygen with the system.data.dll assembly) or provide a contract for each type that's not an intrinsic type (Reference vs. Value: Types, Passing and Marshalling) inorder to be able to return them from a method call.

    If you are stuck, we can duplicate your method call types in a simple sample and find the best way to support them across the AppDomain boundary.

    What version of VSTA are you integrating?

  • 03-12-2008 4:44 PM In reply to

    Re: Pass non-mscorlib MarshalByValue object to an AddIn

    Thank-you for the information.  After reviewing the article linked to in your reply and looking into the VSTA documentation a bit more I've decided to change my approach.  Rather than returning a DataSet class that is accessed via a 'Contract'.  I would prefer to return intrinsic types.  Actually arrays of structures that include intrisic types.  To answer your question I am using VSTA 1.0.  I believe 2.0 is still in a beta phase.

    Where should such structures be defined to make them accessible to my host and proxy objects?  I tried defining them in the same assembly as my host classes.  But when I try to update a field on one of these structures that was passed to my proxy it appeared to result in a remoted call (see stack trace below). 

    Partial stacktrace when updating field 'columns':
     Microsoft.VisualStudio.Tools.Applications.SerializableObjectContractFormatter.Serialize(Object serialize, Type typeToUse, TypeInfrastructureManager typeInfrastructureManager)
       at Microsoft.VisualStudio.Tools.Applications.TypeServices.CreateSerializableRemoteArgument(Object objToPack, Type typeToUse, Boolean isByRef, TypeInfrastructureManager typeInfrastructureManager)
       at Microsoft.VisualStudio.Tools.Applications.TypeServices.CreateArrayRemoteArgument(Array objToPack, Type typeToReflect, Boolean isByRef, TypeInfrastructureManager typeInfrastructureManager)
       at Microsoft.VisualStudio.Tools.Applications.TypeServices.RemoteArgumentFromObject(Object objToPack, Type typeToReflect, Boolean isByRef, Boolean isOut, TypeInfrastructureManager typeInfrastructureManager)
       at Microsoft.VisualStudio.Tools.Applications.RemoteFieldInfo.SetValue(Object target, Object value, BindingFlags invokeAttr, Binder Binder, CultureInfo culture)
       at System.Reflection.FieldInfo.SetValue(Object obj, Object value)
       at Stars.Automation.DataMatrixInfo.set_columns(DataMatrixColumnInfo[] value)
  • 03-24-2008 1:41 PM In reply to

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

    Re: Pass non-mscorlib MarshalByValue object to an AddIn

    cphilpot,
    >Where should such structures be defined to make them accessible to my host and proxy objects?
    You should define the structures in the same assembly as your host class. 

    >But when I try to update a field on one of these structures that was passed to my proxy it appeared to result in a remoted call (see stack trace below).

    I'm not sure I understand what the problem is.  I was able to modify shape app to work with an array of structures and it ran without error.  Are you getting an error or just wondering why the call was remoted?

    Thanks,
       -Melody

    BTW
    Here's what I did- if this doesn't match what you are doing please let me know.

    In the ShapeAppBasicCSharp VSTA v 1 sample I added the following property of an array of structs to the application class:

    private Point[] points_value;
    public
    Point[] points
    {
       get { return points_value; }
       set { points_value = value;}
    }


    and initialized it in the constructor:

    points_value = new Point[2];
    points_value[0] = CreatePoint(1, 1);
    points_value[1] = CreatePoint(2, 2);


    I did have to manually correct the proxy to reflect the type Point[] instead of Point for the property.

    In the add-in I successfully executing the following lines:

    Point[] ps = this.points;
    ps[0].X = 3;


  • 03-31-2008 1:38 PM In reply to

    Re: Pass non-mscorlib MarshalByValue object to an AddIn

    I am getting an error and am also concerned that field updates to the structure are remoted.

    I am trying to use arrays of structures within other structures.  They represent rather complex requests that are hard to implement using simple parameters to a function.  I had expected structures to be passed by value.  I attempted to return a structure to VSTA code then change some fields before passing the structure back (to the host) for further processing.  I got an exception when trying to update the fields.  Looking at the proxy generated from proxygen it appears to have defined a structure to represent the one I defined in my host but the structure uses remoting to access the fields of the real structure.  I.e. the structure is not being passed by value even though I did apply the 'Serializable' attribute to my structure.


  • 04-01-2008 2:15 PM In reply to

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

    Re: Pass non-mscorlib MarshalByValue object to an AddIn

    What error are you getting?  I didn't see any in the stack trace.
  • 04-02-2008 5:38 PM In reply to

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

    Re: Pass non-mscorlib MarshalByValue object to an AddIn

    I have not been able to get an error message by updating a field in a struct which is an array in another struct.  If you would like me to take a look at this please send a reproducible sample to vstasupport@summsoft.com .

    Here are my findings:


    1)  Passing a struct containing an array of structs and passing an array of structs.

    I added the following classes to the ShapeAppBasicCSharp sample:

        [Serializable]

        public struct OutterStruct

        {

            private string Oname;

            public string OName

            {

                get { return Oname; }

                set { Oname = value; }

            }

     

            private int Oid;

            public int OId

            {

                get { return Oid; }

                set { Oid = value; }

            }

     

            private InnerStruct[] sarray;

            public InnerStruct[] Sarray

            {

                get { return sarray; }

                set { sarray = value; }

            }

        }

     

        [Serializable]

        public struct InnerStruct

        {

            private string Iname;

            public string IName

            {

                get { return Iname; }

                set { Iname = value; }

            }

     

            private int Iid;

            public int IId

            {

                get { return Iid; }

                set { Iid = value; }

            }

        }

    I also added a property of type OutterStruct and methods to create instances of the inner and outter struct. 

    I added a method which takes in an OutterStruct and alters the name and id properties, then alters the name and id properties of the array of InnerStructs.  What I found is that the outter struct properties name and id behave as if they are passed by value, when the method is exited those properties revert to their original values.  However, the array of structs behaves as if it is passed by reference, when the method is exited the properties of the structs in the array do not revert to their original values.  This behavior is consistent- calling the method from an add-in has the same affect on the OutterStruct passed in as if it were called by the host.

    I also added a method which takes in an InnerStruct[] and alters the name and id properties of each struct in the array.  What I found is that when this method is called from VSTA the array of structs behaves as if it is passed by value, the values of the properties of the structs in the array revert back to their original values when the method is exited.  However, when this method is called from within the host the array of structs behaves as if it is passed by reference, the values of the properties of the structs in the array do not revert back to their original values when the method is exited.  VSTA should behave in the same way that Visual Studio does and behave as if it passes the array of structs by reference, not value.  This is due to a problem with the equals and get has code methods and I believe there is a work around.

     


    2)  Updating information in a struct and in a struct which is in an array of structs within a struct

    I added a method which sets a local variable (LoS) of type OutterStruct to the property oStruct (property of the application class, type OutterStruct).  When a property like name or id is changed, it behaves as if it is changed by value- changing the variable LoS doesn't affect the property oStruct and changing the property oStruct does not change the variable LoS.  However, changing a property of a struct in the array of structs within the outter struct behaves as if it is by reference- changing the value of the name or id of a struct in the array of structs in the variable LoS does change the property of the struct in the array of struts in oStruct and vice versa.  In VSTA, (also using a local variable LoS) the by value property changes (of properties like name and id) reflect the way Visual Studio handles this- by value.  However, the changing a property of a struct in the array of structs in the outter struct doesn't work.  The property in the struct in the array of structs in the outter struct does not change in the local variable or the application property.  This is due to a problem with the equals and get hash code methods and I believe there is a work around.

     

    >am also concerned that field updates to the structure are remoted.
    In VSTA v 1, everything exists on the host side therefore everything is remoted.  VSTA v 2 handles structs completely differently.  I will look into this issue in VSTA v 2 and let you know what I find.

    If you would like to see the modified shape app sample I based these findings are please e-mail me at VSTASupport@summsoft.com and I will get you a copy.

     

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