Some general questions

Latest post 09-16-2008 4:06 AM by wangym. 30 replies.
  • 06-01-2007 11:43 AM

    • eli
    • Top 25 Contributor
    • Joined on 06-01-2007
    • Posts 12

    Some general questions

    Hi,

    I'm evaluating if we could use VSTA in our software, but I have some general question about features I would like to have:

    • Is it possible to have a dynamic object model? I would like to 'register' my object model at startup, because not all information is available at compiler time.
    • Is it necessary to register every host application with VSTA? Suppose I have 2 versions of the same program, do I need to register them both, or can I somehow register all current and future versions at once?
    And then one small detail that I encountered:
    • I noticed from the examples that if the hosting application stops, the IDE is not terminated as well. I suppose it is possible to couple these two?
    Thanks,
    eli
  • 06-02-2007 12:21 AM In reply to

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

    Re: Some general questions

    Eli,

    In version 1 of VSTA, dynamic object models are not supported.  We expect that to change.

    >>I would like to 'register' my object model at startup, because not all information is available at compiler time.

    I'm not sure what you mean by 'register' your object model.  But there are some ways to work around the limitations of the compiled proxy layer that exposes the host application's object model..

    Does the host application have a COM or managed object model?

    >>Is it necessary to register every host application with VSTA?

    No, for version resilience, the proxy/adapter types must continue to support the OM types of each version.

    Addins use a specific version of a proxy assembly.  The proxy assembly can work with any version of the host.

     

    >>I noticed from the examples that if the hosting application stops, the IDE is not terminated as well. I suppose it is possible to couple these two?

    Yes, using the DTE for example: mDTE.Debugger.Stop(true);  and mDTE.Quit();

  • 06-03-2007 7:11 AM In reply to

    • eli
    • Top 25 Contributor
    • Joined on 06-01-2007
    • Posts 12

    Re: Some general questions

    Hi Gary,

    thanks for the quick reply.

    Maybe I can explain a bit more what I would like to do.
    There is a static object model in the application that I want to expose to the add-ins. This object model is currently not COM nor in managed code, but adding that would not be a very big problem. Proygen.exe can be used to expose this data model, so no problems here.

    Then I want to provide the add-ins with an object model that has no matching representation in the hosting application. For example, I would like the add-in to be able to things like this:

    MyObject myObject = new MyObject;
    myObject.someProperty = 10;

    where neither 'MyObject' nor 'someProperty' are known at compile time.

    I hope that clarifies my question.

    regards,
    eli
  • 06-05-2007 8:54 AM In reply to

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

    Re: Some general questions

    >>I would like the add-in to be able to things like this:

    >>MyObject myObject = new MyObject;
    >>myObject.someProperty = 10;

    >>where neither 'MyObject' nor 'someProperty' are known at compile time.
    ==

    You can do this syntax in the add-in assembly with VB.Net

    What you cannot do (in version 1 of the sdk) is pass the unknown type object over to the host application without a proxied type.

    If there is something I've missed, let me know.

  • 06-05-2007 10:46 AM In reply to

    • eli
    • Top 25 Contributor
    • Joined on 06-01-2007
    • Posts 12

    Re: Some general questions

    And to make that work, I cannot use proxygen to create a proxy but I will have to create a proxy by hand, right?

    eli
  • 06-05-2007 1:37 PM In reply to

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

    Re: Some general questions

    You can use proxygen to create proxies for most object types, except System.Object, System.Type across. Classes like Type or Assembly can potentially leak types across breaking isolation. In VSTA v1.0 there will be a SerializationException when trying to pass them.

    System.Object is the first and most important illegal type. You may *never* have a parameter or return value typed as System.Object. Why? Hopefully this is obvious, but "object" represents "any type" or some type that may *not* be defined within the closed system. The system is no longer closed if Object is exposed.

    So Object is illegal, along with System.Type, because Object and Type represent arbitrary types that may not be accounted for in the closed system. At best passing an arbitrary object or type across the domain boundary will simply fail -- the type won't be visible to the host AppDomain and fail to load. At worst it can be an elevation of privilege security hole. If a malicious addin can cause an arbitrary type to be loaded in a less restricted AppDomain, static constructors and initializers can run and run arbitrary, perhaps malicious, code.

    There are a few other types specifically forbidden. MarshalByRefObject, obviously, for the same reason as Object. Any of the types in the System.Reflection namespace (with the exception of the enums) because they carry with them references to arbitrary types. And, as a catchall here, anything else that can cause any arbitrary type to be loaded is illegal.

     (http://blogs.msdn.com/tq/archive/2005/09/22/472998.aspx)

    You can also create custom contracts and resolve them with your own adapter:

    Instead of using the type map, handle the AdapterResolve event (the code below goes on the host side):

    This event is fired everytime the TIM is needed to resolve a type on the host side.

    typeInfrastructureManager.AdapterResolve += new AdapterResolveHandler(typeInfrastructureManager_AdapterResolve);

    System.AddIn.Contract.IContract typeInfrastructureManager_AdapterResolve(object sender, AdapterResolveEventArgs e)

    {

        if (e.ObjectToPack is <yourtypehere>.)

        {

                TypeInfrastructureManager tim = (TypeInfrastructureManager) sender;

                return new RemoteObjectAdapter(typeof(<yourtypehere>), e.ObjectToPack, tim);

        }

        return null;

    }

  • 06-06-2007 3:05 AM In reply to

    • eli
    • Top 25 Contributor
    • Joined on 06-01-2007
    • Posts 12

    Re: Some general questions

    Gary,

    I think you misunderstood what I actually want to do. If I go back to my code snippet from above (with corrected syntax :-) :

    MyObject myObject = new MyObject();
    myObject.someProperty = 10;


    What I want to accomplish is that an add-in writer can write this code even if the type 'MyObject' and the property 'someProperty' are not known at compile time.

    My host application should discover the existence of these types by reading some setting at startup, and then make it available to the add-in.

    // at startup: register types in add-in object model

    String typeName = readTypeFromSetting(); // returns 'MyObject'
    GenericType *type = createGenericType(typeName);
    String propName =
    readPropertyFromSetting(type) // returns 'someProperty'
    GenericProperty *propType = createGenericProperty(type, propName);


    In the ideal case the add-in code from the start of this post should execute something like this in the host application:

    // during add-in execution
    GenericObject *genObj = createGenericObject(type);
    assignGenericIntProperty(genObj, propType, 10);


    So my main problem is on how to let the add-in parser know that 'MyObject' and 'someProperty' exist.

    I hope this makes things clear, if not, please let me know.
    regards,
    eli

  • 06-06-2007 7:16 AM In reply to

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

    Re: Some general questions

    >>And to make that work, I cannot use proxygen to create a proxy but I will have to create a proxy by hand, right?

    Since the Adapter side of the proxy layer is available to the host, it could be altered at runtime, programatically (ie: new types added), but the compiled proxy assembly would have to provide the MyObject type to the addin as a placeholder to be resolved with the MyObject on the Host side. 

    I've been playing with VB.Net's late-bound object feature, lately.  It may offer some more freedom (on the addin side) for this approach.


     

     

  • 06-06-2007 7:31 AM In reply to

    • eli
    • Top 25 Contributor
    • Joined on 06-01-2007
    • Posts 12

    Re: Some general questions

    I see, and since it is not possible for me to provide such a placeholder, I cannot provide a truly dynamic object model.

    I don't know anything about the late-bound in VB.Net, but I will have a look at that.

    Thanks for your answers and your patience!
    eli
  • 06-06-2007 9:52 AM In reply to

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

    Re: Some general questions

    BTW:  I believe that the Orcas release of VSTA will provide a way to pass arbitrary objects created in the add-in to the host as late-bound objects.  VB.Net allows for late-bound (runtime) type resolution.  Essentially VB provides the plumbing (undercover) to invoke class members (methods, properties, events) at runtime .

    Here, the Host Code explicitly invokes Addin method which returns late-bound object.  This should work in next release of VSTA (which will follow the release of VS Orcas):

        Friend Function CreateGadget() As Object
            Dim hostItems() As IEntryPointContract = GetHostItems()

            If (Not (hostItems) Is Nothing) Then
                Dim remoteObjectContract As IRemoteObjectContract = CType(hostItems(0).GetEntryPointObject.QueryContract(GetType(IRemoteObjectContract).AssemblyQualifiedName), IRemoteObjectContract)
                Dim remoteObject As RemoteObject = New RemoteObject(remoteObjectContract, New TypeInfrastructureManager)
                Dim classtype As System.Type = remoteObject.GetType()
                Dim omethodInfo As MethodInfo = classtype.GetMethod("CreateGadget")
                If ((omethodInfo Is Nothing) OrElse (omethodInfo.GetParameters.Length > 0)) Then
                    'TODO: Warning!!! continue If
                End If
                Try
                    Return omethodInfo.Invoke(remoteObject, Nothing)
                Catch ex As System.Runtime.Remoting.RemotingException
                    ' Ignore remoting exception.
                    Return Nothing
                Catch e As Exception
                    System.Windows.Forms.MessageBox.Show(("Error creating part" & vbLf + e.Message))
                    Return Nothing
                End Try
            Else
                Return Nothing
            End If

        End Function

    Macro Code
    Partial Class Application

           Private Sub Application_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup

           End Sub

           Private Sub Application_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown

           End Sub

          Public Function CreateGadget() As GadgetFamily
            Return New GadgetFamily
          End Function

    End Class

    Public Class GadgetFamily
        Private m_string As String = "1234"

        Public Property Test() As String
            Get
                Return m_string
            End Get
            Set(ByVal value As String)
                m_string = value
            End Set
        End Property

    End Class

  • 08-05-2008 5:22 AM In reply to

    Re: Some general questions

    I use VSTA 2.0 CTP.

    Hello, I have near the same question about dynamic programming.
    In my project, user can layout .NET component dynamically at runtime.
    e.g. add an System.Windows.Forms.Label, or 3-party user control.
    So when generating proxy file, I don't know the collection of types.
    When new control added, I call the following code:

            internal void AddHostObject(Control ctrl)
            {
                string cookie = ctrl.Name + "$" + ctrl.GetType().FullName + "$ThisApplication";
                IVstaHostItem item = addInProperty.HostAdapter.ProjectHostItems["ThisApplication"].ProgrammingModelHostItem;
                IVstaHostObject hostObject = item.HostObjects.Add(ctrl.Name, ctrl.GetType().FullName, cookie);
            }

    e.g. add a System.Windows.Forms.Label control named Lable1.

    Label1 will be added to VSTA project correctly(?) with type  System.Windows.Forms.Label.
    When compiling, VSTA complain that the reference can't be found.
    I add the System.Windows.Forms to the project.
    compile passed.
    when loading, a ArgumentNullException throw at <Proxy.cs>:
    "this.providerHost.GetHostObject(global::System.Type.GetType(primaryType), primaryCookie);"
    with argument name "localType".

            public object GetHostObject(string primaryType, string primaryCookie)
            {
                if (this.providerHost == null)
                {
                    throw new global::System.NullReferenceException("HostItemProvider is not initialized");
                }
                return this.providerHost.GetHostObject(global::System.Type.GetType(primaryType), primaryCookie);
            }

    I don't know what's wrong.
    GetHostObject of my HostItemProvider wasn't called yet.
    Maybe I mixed the proxy type and local type?
    Shouldn't I add System.Windows.Forms reference in the VSTA project?
    How to resolve this problem?

    Thanks.

  • 08-05-2008 10:02 AM In reply to

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

    Re: Some general questions

    VSTA 2.0 SDK includes the Dynamic Programming Model (DPM) sample (ShapeAppDynamicProgrammingModelCSharp) which shows that instances of known types (in the sample, there are documents and shapes) can be added, named, re-named, and removed from the project. 

    >>When generating proxy file, I don't know the collection of types.

    If you can define the types in your proxy prior to run time, Dynamic Programming Model may meet your needs.  3rd party user control types will probably not be defined when creating your proxy layer. 

  • 08-05-2008 9:25 PM In reply to

    Re: Some general questions

    Think about excel, user can add 3rd party controls and can program them with VBA(VSTA in the future?).
    How can I use VSTA do the job like that?

    When I try to control my Mainform of host application from VSTA addin,
    I got a long canonicalName from the call:
    public System.Type GetTypeForCanonicalName(string canonicalName)

    "Microsoft.VisualStudio.Tools.Applications.Adapter.v9.0, Microsoft.VisualStudio.Tools.Applications.DynamicProxy`1[[System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"

    and proxygen didn't gen the canonicalName and type.
    Is it impossible to control UI in the host application from VSTA addin?

    Thanks.
  • 08-06-2008 9:51 AM In reply to

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

    Re: Some general questions

    With COM components that have their own typelib, it is possible to generate an interop assembly and set a reference to it in the addin, pass an IUnknown or IDispatch* to the compoenent from the host through the proxy (with and late bind to it (at run-time) with a strong type cast in the add-in.

    This proxy code asks the host application for an instance of Excel and returns an object to the addin that can be cast to Excel's 'Application' object (the root of Excel's object model):

    [return: global::System.Runtime.InteropServices.MarshalAsAttribute(global::System.Runtime.InteropServices.UnmanagedType.IDispatch)]

    public virtual object CreateExcelInstance()

    {

    object excelObj;

    object pExcelObj = this.RemoteObject.CreateExcelInstance();

    System.IntPtr pDispExcel = global::System.Runtime.InteropServices.Marshal.GetIDispatchForObject(pExcelObj);

    excelObj = global::System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(pDispExcel);

    global::System.Runtime.InteropServices.Marshal.Release(pDispExcel);

    return excelObj;// this.RemoteObject.CreateExcelInstance();

    }

     With managed components, I suppose that something similar is possible.  VB addins provide more inherent support for late binding to types than C# does.

    Host UI is controlled through an abstraction of it inn the object model.

    For instance, the 'Visible' property in the ShapeAppBasicCSharp sample's object model (the

    Microsoft.VisualStudio.Tools.Applications.Samples.ShapeApp.Application class):

    /// <summary>

    /// Gets or sets the flag indicating whether the application form is visible

    /// or not.

    /// </summary>

    /// <value>

    /// The flag indicating whether the application form is visible or not.

    /// </value>

    public bool Visible

    {

    get

    {

    return form.Visible;

    }

    set

    {

    form.Visible = value;

    }

    }

  • 08-13-2008 5:46 AM In reply to

    Re: Some general questions

    Thanks, Gary.
    Is there attibutes I can assign to the class will be used as EntryPoint, so I don't have to manually modify the object model describe file every time?
    And is there any tool could generate the UI control's abstraction? I think it's possible.
Page 1 of 3 (31 items) 1 2 3 Next > | RSS
Copyright Summit Software Company, 2008. All rights reserved.