views:

204

answers:

2

As I get it there're three ways to implement marshalling in COM:

  • typelib marshalling
  • proxy/stub marshalling
  • implementing IMarshal by the object

now how does the component consumer (user) choose which one will be used? Does it decide on its own and use the preferred way or does it call some built-in function and it solves the problem for it?

I currently experience the following: my component implements a custom interface ICustomInterface that is also implemented by a component from another company. My component doesn't have a typelib and doesn't implement IMarshal. The system registry contains the HKCR\Interface{uuidof(ICustomInterface)}\ProxyStubClsid32 key with a GUID of the proxy/stub that can be traced to a library provided by that other company.

Now when my component consumer initializes my component it calls QueryInterface() requesting IMarshal from my component and when returned E_NOINTERFACE it just does nothing. Why is this - why doesn't proxy/stub library from the other company kick in?

A: 

I am a bit rusty at this, but do you have a function named blindquery in your project ? (its usually declared by the wizard if you created a C++ ATL project). Breakpoint inside the function. The function is generated by the wizard often has problems with queryinterface returning E_NOINTERFACE due to buggy code.

edit (found sample code) from my old project _blindquery

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);
}
Andrew Keith
Nope, I don't have one. I tried the wizard with all reasonable settings and it doesn't declare such a function. I also Googled for this name - no reasonable matches. May it be that you misspelled the name?
sharptooth
i dug into my old code and found that the blind query was actually my own function . LOL.. use this macro http://msdn.microsoft.com/en-us/library/5b6w5bwx(VS.80).aspx
Andrew Keith
Well, this is a nice way of hooking into the QI(). But that's all - the function is called for a set of iterfaces, IMarshal included, for no apparent reasons.
sharptooth
+1  A: 

The COM runtime will use typelib (oleautomation) marshalling if you mark your interface as using the standard marshaler by adding its CLSID {00020424-0000-0000-C000-000000000046} under HKCR\Interfaces\{iid}\ProxyStubClsid (where {iid} is the GUID of your interface). You'll need to have a typelibrary registered too, in order for the runtime to extract the parameter information, and you can only use a certain subset of types. There's some more (old) information here and here.

If you want to use a custom proxy/stub, as generated by the MIDL compiler from your IDL, then you'll need to change the interface registry entry to be the CLSID of that proxy object instead. This enables you to use a wider range of types, e.g. "raw" arrays.

If you support IMarshal then that's what'll be used in preference to either of these mechanisms. This means you can change your object to aggregate the free-threaded marshaler (using its implementation of IMarshal) without having to change anything in the registry. This will avoid any proxies being created.

Hope this helps.

voyce
But why do I see that strange behaviour - specifically the runtime first QIs my component for IMarshal and when it gets E_NOINTERFACE it just bails out, not trying to lookup the HKCR\Interface\{InterfaceId} key?
sharptooth
Have you seen the docs here http://msdn.microsoft.com/en-us/library/ms678428%28VS.85%29.aspx ? Maybe you could put together a small test case that calls CoMarshalInterface (which is ultimately what the COM runtime will do), and trace through to see what happens. I tried it and with regmon I could see it hitting the registry.
voyce

related questions