2012-01-30 4 views
0

Я смог программно создать окно инструмента расширения VS2010 из F # Interactive, самого окна инструмента, используя CreateToolWindow2. Assembly и Class аргументы I pass to CreateToolWindow2 соответствуют Panel (WinForms), который составляет окно инструмента. Ссылка на созданную панель «возвращается» через аргумент ref refControlObject.Inter-addin communication

Пометив сборку моей панели с атрибутом я получаю экземпляр возвратившись, ComVisible(true) за исключением, когда я пытаюсь получить доступ к любым членам экземпляра (из контекста F # Interactive) я получаю RemotingException: «Это Remoting прокси имеет нет канала, который означает, что на сервере нет зарегистрированных каналов сервера, которые прослушивают, или это приложение не имеет подходящего клиентского канала для разговора с сервером ».

Любые идеи, как обойти это препятствие?

+0

ли [это] (http://stackoverflow.com/questions/1657863/remoting-and-missing-channel-sinks) помочь? – Daniel

+0

@ Даниэль - спасибо, я это видел, и это выглядело связанным, но не понимало, как ответ может мне помочь (я почти никогда не работал с Remoting API). Часть моей проблемы может заключаться в том, что мой элемент управления панелью, уже наследующий от 'Panel', также не может наследовать от« MarshalByRefObject ». Более того, 'CreateToolWindow2' фактически создает экземпляр моей панели и возвращает ее мне ... не уверен, что мое отсутствие собственности на объект затруднит ситуацию (ссылаясь на« ... создавать каналы на обоих концах »). , –

+0

@ Daniel - на самом деле, 'Panel' в конечном счете наследуется от' MarshalByRefObject', поэтому, я думаю, у меня есть что-то для меня там ... –

ответ

1

Это немного примитивно, и я лично считаю его грязным, но всегда существует резерв использования файловой системы для управления связью. Назначьте временный файл, доступный как для аддинов, так и для управления блокировкой между ними, и вдруг у вас есть система связи с несколькими добавками. Это, конечно же, предполагает, что вам удобно менять оба дополнения для использования подхода (который я не уверен, что вы рассматриваете, что одна из добавлений, о которой идет речь, поставляется заранее).

+0

+1 для дурацкой, правдоподобной идеи! Но я держусь за более чистый подход! –

1

WCF service используя named pipes. Я делаю это сейчас, чтобы общаться между поверхностью дизайна некоторых действий WF4 и расширением визуальной студии.

Его очень просто сделать. Я не могу показать весь код, поскольку некоторые из них завернуты в хелперы, которые контролируют открытие и закрытие канала, но определение довольно простое и сделано все в коде.

Вам просто нужно определить связывающую

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

создать свой канал

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

и вы должны убедиться, что адрес конечной точки гарантированно будет то же самое в клиенте и сервере , которые совместно используют один и тот же процесс, но существуют в разных AppDomains. Простой способ сделать это состоит в объеме адреса в идентификатор процесса ...

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; 
} 

Вы будете иметь два действительных копий этого (один в клиентском AppDomain, один в надстройку AppDomain), но так как они оба находятся в одном и том же процессе, адрес хоста гарантированно будет одинаковым в обоих случаях, и вы не столкнетесь с проблемами, когда вы одновременно загружаете несколько экземпляров VS (без лишней таблицы запущенных объектов, спасибо).

Я сохраняю этот адресный код в базовом классе хоста. Открытие хост-канал также довольно легко:

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

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