C# IConnectionPointContainer.FindConnectionPoint выдает исключение
Я пытаюсь реализовать модуль ATL COM с точкой подключения. Исходный код для этого является в значительной степени образцом, который я скопировал на примере из главы 12 Семинара разработчика для COM и ATL 3.0 Эндрю У. Троелсена.
Это много кода с тремя исходными файлами (почти все визуализировано в Visual Studio).
Я думаю, что есть все, что мне нужно. Существует подкласс _IFooEvents_CP.h для обработки событий, и класс реализует IConnectionPointImpl: using namespace ATL;
template <class T>
class CProxy_IFooEvents : public IConnectionPointImpl<T, &__uuidof( _IFooEvents ), CComDynamicUnkArray>
{
// WARNING: This class may be regenerated by the wizard
public:
HRESULT Fire()
{
//...
// event proxy code
//...
}
}
Затем в шапке моего кокласса (Фу, конечно):
// Foo.h : Declaration of the CFoo
#pragma once
#include "resource.h" // main symbols
#include "ConnectionPointTest_i.h"
#include "_IFooEvents_CP.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif
using namespace ATL;
// CFoo
class ATL_NO_VTABLE CFoo :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CFoo, &CLSID_Foo>,
public IConnectionPointContainerImpl<CFoo>,
public IDispatchImpl<IFoo, &IID_IFoo, &LIBID_ConnectionPointTestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public CProxy_IFooEvents<CFoo>
{
public:
CFoo()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_FOO)
BEGIN_COM_MAP(CFoo)
COM_INTERFACE_ENTRY(IFoo)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CFoo)
CONNECTION_POINT_ENTRY(__uuidof(_IFooEvents))
END_CONNECTION_POINT_MAP()
Кроме того, в файле idl объявлен источник пересылки событий и все настроено благодаря мастеру точек подключения ATL, который я использовал для создания этой вещи:
library ConnectionPointTestLib
{
importlib("stdole2.tlb");
[
uuid(25EAB56B-884A-4AA9-B470-BAA975E08343)
]
dispinterface _IFooEvents
{
properties:
methods:
[id(1), helpstring("test")] HRESULT bar();
};
[
uuid(54B6050F-1090-4660-9DF0-D8A0853F96CF)
]
coclass Foo
{
[default] interface IFoo;
[default, source] dispinterface _IFooEvents;
};
};
Итак, у меня есть реализация интерфейса контейнера точки подключения, у меня есть точка подключения на карте точек подключения, и я заранее объявил функцию события для реализации на стороне клиента.
Компилируется без предупреждения или ошибки. Тогда на стороне C# у меня есть следующее:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using ConnectionPointTestLib;
namespace TestConnectionPoint
{
class EventSink
{
public EventSink() { }
public void bar()
{
Console.WriteLine("hello");
Console.ReadLine();
}
}
class Program
{
static void Main(string[] args)
{
try
{
ConnectionPointTestLib.IFoo cpTest = new ConnectionPointTestLib.Foo();
IConnectionPointContainer icpc;
icpc = (IConnectionPointContainer)cpTest;
IConnectionPoint icp;
Guid id = typeof(Foo).GUID;
icpc.FindConnectionPoint(ref id, out icp);
EventSink es = new EventSink();
int cookie;
icp.Advise(es, out cookie);
cpTest.testCP();
Console.ReadLine();
}
catch (COMException e)
{
Console.WriteLine(e);
Console.ReadLine();
}
}
}
}
Исключение выдается в этой строке:
icpc.FindConnectionPoint(ref id, out icp);
и код ошибки является экзотическим: 0x80040200. Я не мог найти этот код в любом месте, но я думаю, что это не официальный код Windows. По крайней мере, я не смог найти его в списке MSDN.
Я скопировал код клиента из примера, который нашел в Интернете, так что, возможно, я пропустил шаг.
Позже: как отметил @Hans Passant, код ошибки - CONNECT_E_NOCONNECTION. Насколько я понимаю, это означает, что интерфейс не предоставляет никаких соединений. Но, насколько я могу судить (и я новичок в этой игре), я сделал все, что мне нужно, чтобы иметь здесь исходящий интерфейс.
Я чувствую, что пропустил какой-то крошечный магический шаг.