public class MyClass : SameEvents
{
private UCOMIConnectionPoint _ConnectionPoint;
private int _Cookie = -1;
private object _ComObject;
public MyClass()
{
// создать COM объект
_ComObject = ...;
}
public void Connect()
{
// подключаемся к событию
UCOMIConnectionPointContainer icpc = (UCOMIConnectionPointContainer)_ComObject;
Guid g = typeof(SameEvents).GUID;
icpc.FindConnectionPoint(ref g, out this._ConnectionPoint);
// первый параметр — this, потому что MyClass реализует SameEvents
this._ConnectionPoint.Advise(this, out this._Cookie);
}
public void Disconnect()
{
if (this._Cookie != -1)
this._ConnectionPoint.Unadvise(this._Cookie);
1) COM объект должен быть зарегистрирован (см. утилиту regsvr32)
2) Надо знать CLSID необходимого COM объекта.
CLSID можно найти в Type Info, например, в "Ole/COM Object Viewer", увидим примерно следующее:
[
uuid(...),
version(...),
helpstring(...)
]
library BestComObjects
{
...
[
uuid(45FD11F9-DE38-497e-9986-9907A8814B18), // CLSID СOM-объекта
helpstring("Best COM object"),
control
] coclass BestCom { // СOM-объект
interface ISameInterface1;
[default] interface ISameInterface2;
[b]source[/b]] dispinterface SameEvents; // источник событий ...
};
...
}
Либо надо знать PROGID. Для этого открываем regedit. Потом задаем поиск "Best COM object" (без кавычек). В дереве cлева, имя открытой папки — это есть PROGID, например, Best.Object
3) Создаем COM-объект
// если знаем CLSID
Guid g = new Guid("45FD11F9-DE38-497e-9986-9907A8814B18");
Type t = Type.GetTypeFromCLSID(g, true);
object myComObj = Activator.CreateInstance(t);
— или —
// если знаем PROGID
string progid = "Best.Object";
Type t = Type.GetTypeFromProgID(progid, true);
object myComObj = Activator.CreateInstance(t);
— или —
Если COM объект был подключен к проекту через VS.IDE, т.е. c помощью Add Reference.
Надо написать клиета на C#, который взаимодействовал бы с уже написанным COM-сервером. Клиент должен получать COM-овские сообщения от сервера.
Про сервер точно известно, что для него можно написать C++ клиент, который получал бы от него COM-сообщения (через ConnectionPoint). Есть работающий пример.
Вопрос: могло ли так получится, что сервер не поддерживает возможность такого взаимодействия с C#-клиентом? Какие требования предъявляет C# к COM-клиенту, чтобы они могли взаимодействовать таким образом? Может, какое-то из этих требований не выполняется.
Потому что про предыдущую версию сервера сами авторы утверждали, что возможность взаимодействия с .NET отсутствует.
Вобщем, ключевой вопрос — про требования, предъявляемые C#-клиентом к COM-серверу.
Вопрос возник потому, что я написал клиента на C#, который, по идее, должен работать. Так вот, он нормально вызывает методы Сервера, но никаких сообщений от него не получает.
Требования C# к COM-серверу
От:
Аноним
Дата:
17.02.05 17:03
Оценка:
> Надо написать клиета на C#, который взаимодействовал бы с уже написанным COM-сервером. Клиент должен получать COM-овские сообщения от сервера.
Пример подключения к исходящим событиям COM-объекта, например, WebBrowser'а:
SinkHelper sh = new SinkHelper(this.WebBrowser, new Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), new Event_SinkHelper());
sh.Advise();
...
Здравствуйте, Eugene Sh, Вы писали:
ES>Вопрос возник потому, что я написал клиента на C#, который, по идее, должен работать. Так вот, он нормально вызывает методы Сервера, но никаких сообщений от него не получает.
Если на C++ работает, то и на шарпе должен работать. Специфичных требований нет.
Думаю, ты что-то не так делаешь. Покажи код клиента.
PS: а ты вообще на события-то подписываешься?
В человечишке все должно быть прекрасненьким: и одёжка, и душенка, и мордочка, и мыслишки.
Здравствуйте, bo, Вы писали:
bo>Покажи код клиента.
using System;
using CTIOSCLIENTLib;
namespace LicenseManagerConsole
{
/// <summary>
/// Summary description for Class1.
/// </summary>class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
CTIOSCLIENTLib.Session session = new CTIOSCLIENTLib.Session();
session.OnConnection += new _IAllEvents_OnConnectionEventHandler(session_OnConnection);
session.OnConnectionClosed += new _IAllEvents_OnConnectionClosedEventHandler(session_OnConnectionClosed);
session.OnConnectionFailure += new _IAllEvents_OnConnectionFailureEventHandler(session_OnConnectionFailure);
session.OnConnectionRejected += new _IAllEvents_OnConnectionRejectedEventHandler(session_OnConnectionRejected);
CTIOSCLIENTLib.Arguments rArgs = new CTIOSCLIENTLib.ArgumentsClass();
/*
тут была настройка rArgs...
*/int returnCode = session.Connect(rArgs);
Console.Read();
CTIOSCLIENTLib.Arguments rDiscArgs = new CTIOSCLIENTLib.ArgumentsClass();
session.Disconnect(rDiscArgs);
}
public static void session_OnConnection(CTIOSCLIENTLib.Arguments rArgs)
{
Console.WriteLine("session_OnConnection!!!");
}
private static void session_OnConnectionClosed(Arguments pIArguments)
{
Console.WriteLine("session_OnConnectionClosed!!!");
}
private static void session_OnConnectionFailure(Arguments pIArguments)
{
Console.WriteLine("session_OnConnectionFailure!!!");
}
private static void session_OnConnectionRejected(Arguments pIArguments)
{
Console.WriteLine("session_OnConnectionRejected!!!");
}
}
}
Что я сделал:
1) добавил в проект reference на COM-dll`ки, в которых реализованы нужные мне классы. Для них были созданы .NET-dll`ки
2) строчки такого типа:
session.OnConnection += new _IAllEvents_OnConnectionEventHandler(session_OnConnection);
были созданы автоматически Visual Studio .NET. Сам я только написал "session.OnConnection += new", а дальше VS сам предложил мне подставить остальное. Так что ошибок там быть не должно.
Судя по документации, после вызова session.Connect() должно прийти сообщение об успехе или неудаче коннекта. Вот оно то и не приходит.
У меня не компилировалось, поэтому я сделал некоторые предположения относительно поправок.
Сразу извиняюсь, если понял неправильно.
А>SinkHelper sh = new SinkHelper(this.WebBrowser, new Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), new Event_SinkHelper()); А>sh.Advise(); А>...
Тут не надо поменять выделенное местами?
А>[GuidAttribute("34A715A0-6587-11D0-924A-0020AFC7AC4D")] А>[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] А>[ComImportAttribute] А>interface DWebBrowserEvents2 А>{ А> [DispId(0x000000fc)] void NavigateComplete2(object pDisp, ref object URL); А>}
В моём случае, GuidAttribute надо посмотреть через OLE/COM Object Viewer для интерфейса событий?
Я создал небольшую COM dll-ку, с которой и общается моё C#-приложение. dll-ка просто перенаправляет вызовы от C# к другому COM-серверу. А при получении событий от COM-сервера генерит аналогичное событие. И вот его моё C#-приложение уже удачно ловит.
И тут недавно заметил такую особенность. Если в моём приложении стоит атрибут [STAThread] перед методом Main, то сообщения не приходят! Без атрибута всё работает.
Может, всё дело было только в этом? C# и COM-приложение использовали разные потоковые модели?
Как узнать, какую модель использует COM-сервер?