Как COM выбирает, как маршалировать интерфейс? - PullRequest
6 голосов
/ 12 ноября 2009

Насколько я понимаю, существует три способа реализации маршаллинга в COM:

  • typelib marshalling
  • прокси / заглушка маршаллинг
  • реализация IMarshal объектом

Теперь, как компонент потребитель (пользователь) выбирает, какой из них будет использоваться? Решает ли он сам и использует ли он предпочтительный способ, или он вызывает какую-то встроенную функцию, и это решает проблему для него?

В настоящее время у меня возникает следующее: мой компонент реализует пользовательский интерфейс ICustomInterface, который также реализуется компонентом другой компании. Мой компонент не имеет typelib и не реализует IMarshal. Системный реестр содержит ключ HKCR \ Interface {uuidof (ICustomInterface)} \ ProxyStubClsid32 с GUID прокси / заглушки, который можно отследить до библиотеки, предоставленной этой другой компанией.

Теперь, когда мой потребитель компонента инициализирует мой компонент, он вызывает QueryInterface (), запрашивая IMarshal из моего компонента, а когда возвращает E_NOINTERFACE, он просто ничего не делает. Почему это так - почему библиотека прокси / заглушки другой компании не запускается?

Ответы [ 2 ]

5 голосов
/ 16 ноября 2009

Среда выполнения COM будет использовать маршаллинг typelib (oleautomation), если вы пометите свой интерфейс как стандартный маршалер, добавив его CLSID {00020424-0000-0000-C000-000000000046} в HKCR\Interfaces\{iid}\ProxyStubClsid (где {iid} - GUID вашего интерфейса). Вам также необходимо зарегистрировать библиотеку типов, чтобы среда выполнения извлекала информацию о параметрах, и вы можете использовать только определенное подмножество типов. Здесь есть еще (старая) информация здесь и здесь .

Если вы хотите использовать собственный прокси / заглушку, сгенерированный компилятором MIDL из вашей IDL, вам нужно будет изменить запись реестра интерфейса на CLSID этого прокси-объекта. Это позволяет использовать более широкий диапазон типов, например, «сырые» массивы.

Если вы поддерживаете IMarshal, это то, что будет использоваться в предпочтении к любому из этих механизмов. Это означает, что вы можете изменить свой объект, чтобы агрегировать маршалер со свободной резьбой (используя его реализацию IMarshal) без необходимости что-либо изменять в реестре. Это позволит избежать создания прокси.

Надеюсь, это поможет.

0 голосов
/ 12 ноября 2009

Я немного заржавел, но есть ли у вас функция с именем blindquery в вашем проекте? (обычно он объявляется мастером, если вы создали проект C ++ ATL). Точка останова внутри функции. Функция, генерируемая мастером, часто имеет проблемы с интерфейсом запроса, возвращающим E_NOINTERFACE из-за ошибочного кода.

редактировать (найти пример кода) из моего старого проекта _ вслепую

class ATL_NO_VTABLE CChildEvents :
    public CComObjectRootEx <CComSingleThreadModel>,
    public CComCoClass<CChildEvents, &CLSID_ChildEvents>,
    public IDispatchImpl<IChildEvents, &IID_IChildEvents, &LIBID_XXX>
{
public:
    CChildEvents(void) :
    m_pItfMgr(0)
    {
    }

    /* called from internalQI to tear off a new blind interface */
    static HRESULT WINAPI   _BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD dw);

    DECLARE_REGISTRY_RESOURCEID(IDR_CHILDEVENTS)
    DECLARE_PROTECT_FINAL_CONSTRUCT()

    BEGIN_COM_MAP(CChildEvents)
        COM_INTERFACE_ENTRY(IChildEvents)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY_FUNC_BLIND(0, _BlindQuery)
    END_COM_MAP()
};


HRESULT WINAPI CChildEvents::_BlindQuery(void *pvThis, REFIID riid, void **ppv, DWORD /* dw */ )
{
    HRESULT hr = E_NOINTERFACE;
    USES_CONVERSION;

    try
    {
        if(pvThis == NULL)
        {
            ATLASSERT(FALSE);
        }
        else
        {
            /*
            * cast the pvThis pointer to the actual class £
            * so we can use it here £
            * reinterpret_cast should be safe since we're calling ourself
            */
            CChildEvents    *pThis = reinterpret_cast < CChildEvents * > (pvThis);
            if(pThis == NULL)
            {
                ATLASSERT(FALSE);
            }
            else
            {

                    /* check to see if it matches on of our children's DIID */
                                    if(memcmp(&riid,&l_someotherguid,sizeof(GUID)) == 0) {

                        /* if so cast to a IDispatch -- the standard for event interfaces */
                        *ppv = reinterpret_cast < IDispatch * > (pvThis);

                        /* addref */
                        pThis->AddRef();

                        /* reply */
                        hr = S_OK;

                }
            }
        }
    }
    catch(...)
    {
        ATLASSERT(FALSE);
    }

    /* must not be in our map - tell them to GO FISH */
    return(hr);
}
...