Q:
I'm having problem loading the addin dll's. I followed the
ShapeAppMacroRecordingCSharp sample and used the following steps,
1. InstantiateServiceProvider()
2. LoadAddins() 'This function compiles the path for each dll to be loaded and invokes the LoadAddin() on each dll
3. LoadAddin()
Try
'AddInStore.Update("C:\Program Files\Common Files\Microsoft Shared\VSTA\Pipeline")
'AddInStore.Rebuild("C:\Program Files\Common Files\Microsoft Shared\VSTA\Pipeline")
Dim addInToken As Collection(Of AddInToken) = AddInStore.FindAddIn(GetType(IEntryPoint), Microsoft.VisualStudio.Tools.Applications.AddInStoreExtensions.DefaultPipelinePath, addInPath, startUpClass)
'System.Diagnostics.Debug.Assert(addInToken.Count >= 1)
If addInToken.Count = 0 Then
Return Nothing
End If
Dim addIn As IEntryPoint = Nothing
If (addInProcess Is Nothing) Then
addIn = addInToken(0).Activate(Of IEntryPoint)(AddInSecurityLevel.FullTrust)
Else
addIn = addInToken(0).Activate(Of IEntryPoint)(addInProcess, AddInSecurityLevel.FullTrust)
End If
addIn.Initialize(Me.serviceProvider)
'This is where the error occurs, I get an "Unable to load one or more of the requested types" error. Specifically, it was failing at the following line in the proxy project:
void
Microsoft.VisualStudio.Tools.Applications.Runtime.IEntryPoint.Initialize
(global::System.IServiceProvider serviceProvider)
{
...
this.remoteObject = this.providerHost.GetHostObject(this.PrimaryType,
this.PrimaryCookie) as frmTBD;
...
}
Note: I implemented the IHostItemProvider interface following the sample
with a constructor and the GetHostObject() routine.
addIn.InitializeDataBindings()
addIn.FinishInitialization()
Return addIn
Catch ex As Exception
System.Diagnostics.Trace.WriteLine(ex.ToString())
System.Diagnostics.Debug.Assert(False)
'MsgBox(ex.ToString)
Return Nothing
End Try
A:
For the problem you're having, at the this.providerHost.GetHotObject(this.PrimaryType, this.PrimaryCookie) as frmTBD, there are a few possibilities. VB naming conventions lead me to believe that frmTBD is a form. Check that the primary cookie and primary type match between the host and the add-in (look in the designer file associated with the add-in
code file). Check that the primary type is included in the HostTypeMapProvider.
If frmTBD isn't a form, the cookies and types match, and the type is in the HostTypeMapProvider..
Q:
Yes, frmTBD is a form, which is currently set to be the startup object in the solution. As for the proxy file, I didn't make much change to the auto generated cs file. Should I do anything special for the form if it is a startup item?
Also, I believe the primary cookie and primary type do match between the host and the addin. I noticed one thing kinda peculiar, in the ShapeAppVB sample (BTW, when I extracted the zip, a bunch of files are PW protected and I simply skipped them), as I stepped through the LoadAddin routine in the VSTARunTimeIntegration module, specifically at the following line:
addIn.Initialize(Me.serviceProvider)
The two subroutines in the HostTypeMapProvider module get invoked to look up and return the types and then your implementation of the GetHostObject (in HostItemProvider) gets called too, whereas in my case, the following function gets called instead (in the proxy file),
void
Microsoft.VisualStudio.Tools.Applications.Runtime.IEntryPoint.Initialize (global::System.IServiceProvider serviceProvider)
Any idea how this might be the case? Also, in the ShapeAppVB sample, how did you come up with the vb version of the HostTypeMapProvider? Is there a way to generate the vb version?
A:
Ok, easy stuff first:
>primary cookie and primary type do match
Good- this is not the problem, but often when an add-in won't load it is.
>how did you come up with the vb version of the HostTypeMapProvider?
Unfortunately, ProxyGen only outputs in C#. For HostTypeMapProviders, I use a vb template then a macro to translate the types. I'm including both below and as attachments (in the solution items).
Less easy:
>frmTBD is a form
This is a problem. Forms are non-proxiable- they cannot pass through the proxy layer, therefore you do not want to expose them directly to VSTA. We have a lot of material available about this in our forms and you may want to check out this blog.
VSTA works with Object Models. Object Models work with forms.
So if your Object Model works with a form, and you want VSTA to interact with the form, then you must expose a proxiable part of your Object Model which handles the VSTA interactions with the form. I'm including a VS08 vb form sample. This sample is a lot like the ShapeApp samples, but much simpler. The ShapeApp Object Models interact with forms in a similiar way. If you want to use the registration file included in the sample, extract it to C:\VBSamples.
>The two subroutines in the HostTypeMapProvider module get invoked to look up and return the types and then your implementation of the GetHostObject (in HostItemProvider) gets called too, whereas in my case, the following function gets called instead (in the proxy file).
I've seen this before a lot, usually it means that the proxy is out of sync. This could cause larger errors, but generally it just prevents you from stepping through the proxy because it is using/loading a different copy of it (its getting the proxy from the add-in, it will only step through it if that is the same proxy that is in the host solution). ShapeApp appears to go to another location in the host file, while yours goes to the proxy, because the ShapeApp add-in is grabbing a different proxy. To fix this, delete all instances of the proxy from the GAC, rebuild the proxy solution, then rebuild the add-in.
Template:
'This file works as a template for VB HostTypeMapProviders.
' Copy and paste the types generated by ProxyGen into the bconstructor below.
' Then run the HTMProvider_TranslateTypesToVB macro with this file selected.
Public Class HostTypeMapProvider : Implements Microsoft.VisualStudio.Tools.Applications.Runtime.ITypeMapProvider
Dim typeToCanonicalName As System.Collections.Generic.Dictionary(Of System.Type, System.String) = _ New System.Collections.Generic.Dictionary(Of System.Type, System.String)()
Dim canonicalToTypeName As System.Collections.Generic.Dictionary(Of System.String, System.Type) = _ New System.Collections.Generic.Dictionary(Of System.String, System.Type)()
Friend Sub New()
'add types here to translate.
'Run HTMProvider_TranslateTypesToVB macro with this doc selected
End Sub
Public Function GetCanonicalNameForType(ByVal type As System.Type)As String Implements Microsoft.VisualStudio.Tools.Applications.Runtime.ITypeMapProvider.GetCanonicalNameForType
'default fetch from dictionary
If typeToCanonicalName.ContainsKey(type) Then
Return typeToCanonicalName(type)
End If
Return Nothing
End Function
Public Function GetTypeForCanonicalName(ByVal canonicalName As String) As System.Type Implements Microsoft.VisualStudio.Tools.Applications.Runtime.ITypeMapProvider.GetTypeForCanonicalName
'default fetch from the dictionary
If canonicalToTypeName.ContainsKey(canonicalName) Then
Return canonicalToTypeName(canonicalName)
End If
Return Nothing
End Function
End Class
Macro:
Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Public Module HTMProvider_TranslateTypesToVB
'Translates the types found in a HostTypeMapProvider from C# to VB
Public Sub HTMProvider_TranslateTypesToVB()
'make syntax changes
FindReplaceAll(";", "")
FindReplaceAll("<", "( Of ")
FindReplaceAll(">", ")")
FindReplaceAll("typeof", "gettype")
'correct the formatting
DTE.ExecuteCommand("Edit.FormatDocument")
End Sub
'replaces all occurences of the find string with the replace string
Private Sub FindReplaceAll(ByVal inFind As String, ByVal inReplace As String)
DTE.Find.FindWhat = inFind
DTE.Find.ReplaceWith = inReplace
DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument
DTE.Find.MatchInHiddenText = True
DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral
DTE.Find.Action = vsFindAction.vsFindActionReplaceAll
If (DTE.Find.Execute() = vsFindResult.vsFindResultNotFound) Then
‘Throw New System.Exception("vsFindResultNotFound")
End If
End Sub
End Module
We implemented this function in the VSTARunTimeIntegration module.
Public Function ExecuteAddInFunction(ByVal strFunctionName As String, Optional ByVal objParms As System.Object() = Nothing) As Object
Dim addIn As IExtendedEntryPoint = Me.addInList(0) 'Always try the first add-in
Dim remoteObject As Object = addIn.GetEntryPointObject
Dim methodInfo As MethodInfo = remoteObject.GetType.GetMethod(strFunctionName)
Dim objReturn As Object
If Not objParms Is Nothing Then
'objReturn = methodInfo.Invoke(remoteObject, Nothing, Nothing, objParms, Nothing)
objReturn = methodInfo.Invoke(remoteObject, objParms)
Else
objReturn = methodInfo.Invoke(remoteObject, Nothing)
End If
Return objReturn
End Function
Q:
How did you make your collection classes, e.g, ShapeCollection, DrawingCollection, etc. MarshalByRefObject?
These are automatically marshal by reference because they do not inherit a base class.
Q:
ProxyGen.exe Error: 11030 : The following types are not remotable, because they do not have the MarshalByRefObject class in their type hierarchy. The proxies that will be generated for the types cannot marshal calls from the add-in to the host application. To generate usable proxies, the types must have the MarshalByRefObject class in their type hierarchy.
A:
You are running into problems because your lowest base class is using an external reference as a base class.
A possible work around would be to expose the class as a non-CollecitonBase (which would then make the class MarshalByRefObject). This does not mean you have to change the class in the host to a non-CollectionBase class.
To do this, add methods that you wish to use from CollectionBase to the class which now inherits it. Then use ProxyGen to create an updated descriptor file,
remove the base type from the descriptor file prior to generating the proxy.
The proxy will now expose the methods you added from CollectionBase and MarshalByRefObject will be in the type hierarchy. I believe this will solve the error.
Q:
Occasionally we get the following error when loading/running the add-in. Is there a recommended way to handle this? Should we specify the lease time of the service? Or maybe we can monitor the IServiceProvider object in the runtime integration module?
"xxx.rem has been disconnected or does not exist at the server".
A:
This problem has been seen at run time for loaded macro projects.
Scenario:
1) User opens ShapeAppMacroRecordingCSharp
2) User records a macro or launches the VSTA IDE- either of which loads the macros assembly
3) Host application is left idle for longer than 5 minutes
4) User attempts to run a macro
5) Error "xxx.rem has been disconnected or does not exist at the server" occurs
There is a bug outside of VSTA that is causing this unwanted garbage collection. This will be fixed in SP1 for .NET 3.5.
Posted
May 26 2009, 01:43 PM
by
BillL