Absolute COM Confusion - взаимодействие C # с ранним связыванием - PullRequest
3 голосов
/ 07 октября 2009

Я целый день боролся с VStudio, Google и другими инструментами и сайтами и не нашел решения - ПОМОГИТЕ !!

У меня есть два интерфейса COM (чистый COM, без ATL):

IMyClassFactory и IMyClass с соответствующими реализациями

Я хочу использовать их из C #, НО без регистрации COM-сервера с regsvr32. Я открываю фабрику классов с помощью CoRegisterClassObject и могу успешно создавать объекты IMyClass с помощью CoCreateInstance из неуправляемого кода.

Итак, взаимодействие C # ...

Я создал оболочку .NET с tlbimp myComServer.tlb и загрузил ее как ссылку на мой клиент на C #.

Затем, когда я пытаюсь создать экземпляр IMyClass, я получаю:

An unhandled exception of type 'System.InvalidCastException' occurred in COMTestClient.exe

Additional information: Unable to cast COM object of type 'MyComServerLib.MyClass' to interface type 'MyComServerLib.IMyClass'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{9F8CBFDC-8117-4B9F-9BDC-12D2E6A92A06}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

Теперь я добавил следы в QueryInterface, и единственные случаи, когда я возвращаю E_NOINTERFACE, это когда он запрашивает какой-либо из интерфейсов, связанных с Marshal, или IManagedObject.

Как мне это исправить ??

РЕДАКТИРОВАТЬ: мой файл IDL:

import "unknwn.idl";

[
    object, 
    uuid(...), 
    nonextensible,
    pointer_default(unique)
]
interface IMyClass : IUnknown
{
    HRESULT(SetFirstNumber)(long nX1);

    HRESULT(SetSecondNumber)(long nX2);

    HRESULT(DoTheAddition)([out,retval] long *pBuffer);
};

[
    uuid(...)
]
library MyLib
{
    importlib("stdole2.tlb");

    [
        uuid(...)
    ]
    coclass IMyClassImpl
    {
        [default] interface IMyClass;
    };
}

Ответы [ 2 ]

4 голосов
/ 07 октября 2009

Вам нужно либо разрешить маршалинг вашего интерфейса (т. Е. Пометить его как «локальный» в файле .idl, чтобы он попал в библиотеку типов, и в прокси / заглушку), либо объединить маршаллер со свободной резьбой, если вы идете этим путем.

Чтобы собрать FTM, я сделал что-то вроде этого:

#define DECLARE_FTM() \
protected: CComPtr<IUnknown> _m_Marshal; \
DECLARE_GET_CONTROLLING_UNKNOWN() \
public: HRESULT FinalConstruct() \
{ return CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&_m_Marshal); }

#define COM_INTERFACE_ENTRY_FTM() COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal,_m_Marshal.p)

Затем в вашей COM-карте:

BEGIN_COM_MAP(Blah)
    COM_INTERFACE_ENTRY(IBlah)
    COM_INTERFACE_ENTRY_FTM()
END_COM_MAP()
DECLARE_FTM()

Я отмечаю, что вы не используете ATL и тому подобное - вам нужно изменить это так, чтобы ваша реализация QueryInterface возвращала указатель FTM при запросе IMarshal.

Обратите внимание, что агрегирование FTM не является чем-то, что действительно может быть сделано легко, - оно делает ряд небезопасных предположений, которые не всегда верны. Например, ваш класс не может использовать любые интерфейсы, которые сами по себе не являются свободными.

Другая альтернатива в основном, как сказал @ [Franci Penov], вам нужно убедиться, что ваш интерфейс может быть настроен. Насколько я понимаю, есть стандартный маршаллер, который может маршалировать любой интерфейс в библиотеке типов, или вы (то есть компилятор midl делает это более или менее автоматически) можете создать прокси / заглушку dll (или объединить код для прокси / заглушки в вашу собственную dll), которая может упорядочить его для вас.

Эта статья здесь более подробно описывает процесс создания и регистрации прокси / заглушки .

1 голос
/ 07 октября 2009
  1. Переместите ваш интерфейс в раздел библиотеки. Это получит свое определение в библиотеке типов.
  2. Пометить ваш интерфейс как oleautomation. Это пометит его как интерфейс, который можно маршалировать с помощью стандартного маршаллера и информации о typelib, в отличие от прокси / заглушки, сгенерированной компилятором midl. (ПРИМЕЧАНИЕ: хотя oleautomation происходит из старого мира OLE, ваш интерфейс не требует наследования от IDispatch)
...