0

I have been able to programmatically create a VS2010 AddIn Tool Window from the F# Interactive, itself a Tool Window, using CreateToolWindow2. The Assembly and Class arguments I pass to CreateToolWindow2 correspond to a Panel (WinForms) which makes up the Tool Window. A reference to the created panel is "returned" through the ControlObject out ref argument.

Having marked my panel's assembly with the ComVisible(true) attribute I do get the instance returned, except when I try to access any members of the instance (from the context of the F# Interactive) I get a RemotingException: "This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server."

Any ideas how to get around this hurdle?

Stephen Swensen
  • 22,107
  • 9
  • 81
  • 136
  • Does [this](http://stackoverflow.com/questions/1657863/remoting-and-missing-channel-sinks) help? – Daniel Jan 30 '12 at 05:41
  • @Daniel - thanks, I had seen that, and it looked related, but didn't see how the answer could help me (I have only scarcely ever worked with the Remoting API). Part of my trouble may be that my panel control, already inheriting from `Panel`, can't also inherit from `MarshalByRefObject`. Moreover, `CreateToolWindow2` actually creates the instance of my panel and hands it back to me... not sure if my lack of ownership of the object will make things difficult (referring to "...create channels on both ends."). – Stephen Swensen Jan 30 '12 at 05:52
  • @Daniel - actually, `Panel` does ultimately inherit from `MarshalByRefObject`, so I guess I've got something going for me there... – Stephen Swensen Jan 30 '12 at 06:02

2 Answers2

1

It's a bit primitive and personally I consider it dirty but there is always the fallback of using the file system to manage the communication. Designate a temp file accessible by both addins and manage locking between them and suddenly you have a cross-addin communication system. This of course assumes that you're comfortable changing both addins to use the approach (which I'm not sure you would be considering one of the addins in question comes prepackaged).

M.Babcock
  • 18,753
  • 6
  • 54
  • 84
1

WCF service using named pipes. I'm doing this now to communicate between the design surface of some WF4 activities and a visual studio extension.

Its very simple to do. I can't show all the code as some of it is wrapped up in helpers that control opening and closing the channel, but the definition is pretty simple and is done all in code.

You just need to define a binding

var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
binding.ReceiveTimeout = TimeSpan.FromMinutes(1);

create your channel

var channelFactory = new ChannelFactory<IServiceInterface>(binding, endpointAddress);

and you have to make sure that the endpoint address is guaranteed to be the same in both the client and server, which both share the same process but exist in different AppDomains. A simple way to do this is to scope the address to the process ID...

private const string AddressFormatString =
    "net.pipe://localhost/Company/App/HostType/{0}";
private static string _hostAddress;

public static string HostAddress()
{
    if (_hostAddress == null)
        _hostAddress = string.Format(
                           AddressFormatString, 
                           Process.GetCurrentProcess().Id);
    return _hostAddress;
}

You'll have two actual copies of this (one in the client appdomain, one in the addin appdomain) but since they are both in the same process the host address is guaranteed to be the same in both and you won't run into issues where you have multiple instances of VS loaded at the same time (no freaking Running Object Table, thanks).

I keep this address code in the base host class. Opening the host channel is also pretty easy:

Host = new ServiceHost(this, new Uri(HostAddress()));

var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);    
Host.AddServiceEndpoint(typeof(IServiceInterface), binding, HostAddress());
Host.Open();