Singleton class factory using ROT??? 
Author Message
 Singleton class factory using ROT???

Hello all,

I need to create some "machine-wide" singleton objects so the same object is
obtained each time that CoCreateInstance is called in any process. To do so,
I created the following custom classfactory (at the bottom), to be assigned
to the corresponding CoClass using DECLARE_CLASSFACTORY_EX.

This works ok in the first process that creates the objects, but when a
second process tries to load the singleton objects, either GetActiveObject()
fails and a new object is created or GetActiveObject() succeeds but calling
QueryInterface on the obtained IUnknown* will return E_NOINTERFACE.

Please could anybody tell me what I am doing wrong? I have the suspicion
that it has to do with the COM threading model / apartment model.

Thanks in advance,

Jorge.

template <const GUID *pclsid>
class CCoCMTCSingleton : public CComClassFactory
{
public:

 HRESULT FinalRelease()
 {
  return RevokeActiveObject(m_dwReg, NULL);
 }

 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
 {
  //Preconditions
  if (ppvObj == NULL)
   return E_POINTER;
  if (pUnkOuter != NULL)
   return CLASS_E_NOAGGREGATION;
  ATLASSERT(pclsid != NULL);

  //Query for a possible running object
  HRESULT hr;
  CComPtr<IUnknown> spUnkObj;
  if (FAILED(hr = GetActiveObject(*pclsid, NULL, &spUnkObj)))
  {
   //Create a new object and add it to the ROT
   if (SUCCEEDED(hr = CComClassFactory::CreateInstance(pUnkOuter,
IID_IUnknown, (LPVOID*)&spUnkObj)))
   {
    if (FAILED(hr = RegisterActiveObject(spUnkObj, *pclsid,
ACTIVEOBJECT_WEAK, &m_dwReg)))
    {
     if (hr == MK_S_MONIKERALREADYREGISTERED)
     {
      RevokeActiveObject(m_dwReg, NULL);
      hr = E_UNEXPECTED;
     }
    }
   }
  }

  ATLASSERT(SUCCEEDED(hr));

  if (SUCCEEDED(hr))
   hr = spUnkObj->QueryInterface(riid, ppvObj);

  ATLASSERT(SUCCEEDED(hr));

  return hr;
 }

private:

 ULONG m_dwReg;

Quote:
};



Wed, 21 Sep 2005 00:25:34 GMT  
 Singleton class factory using ROT???
To become a machine-wide singleton, your COM object must be an
out-of-process object(COMEXE). If your COM object is out-of-process, all
activations(CoCreateInstance) will return pointer to an instance of your COM
object. COM will create one if there is none, and COM will return the
interface to existing one if there is one. You don't need to write any
special code for singleton.
But your COM object must be thread-safe if your COMEXE is multi-threaded .
i.e if your EXE thread call CoInitializeEx(NULL, COINIT_MULTITHREADED) to
enter into MTA.
Out-of-process COM objects live in the same apartment as the thread that
creates them.
On Apartment issue, check following article.
http://www.codeguru.com/activex/COMApartments1.html

regards,
mna


Quote:
> Hello all,

> I need to create some "machine-wide" singleton objects so the same object
is
> obtained each time that CoCreateInstance is called in any process. To do
so,
> I created the following custom classfactory (at the bottom), to be
assigned
> to the corresponding CoClass using DECLARE_CLASSFACTORY_EX.

> This works ok in the first process that creates the objects, but when a
> second process tries to load the singleton objects, either
GetActiveObject()
> fails and a new object is created or GetActiveObject() succeeds but
calling
> QueryInterface on the obtained IUnknown* will return E_NOINTERFACE.

> Please could anybody tell me what I am doing wrong? I have the suspicion
> that it has to do with the COM threading model / apartment model.

> Thanks in advance,

> Jorge.

> template <const GUID *pclsid>
> class CCoCMTCSingleton : public CComClassFactory
> {
> public:

>  HRESULT FinalRelease()
>  {
>   return RevokeActiveObject(m_dwReg, NULL);
>  }

>  STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void**
ppvObj)
>  {
>   //Preconditions
>   if (ppvObj == NULL)
>    return E_POINTER;
>   if (pUnkOuter != NULL)
>    return CLASS_E_NOAGGREGATION;
>   ATLASSERT(pclsid != NULL);

>   //Query for a possible running object
>   HRESULT hr;
>   CComPtr<IUnknown> spUnkObj;
>   if (FAILED(hr = GetActiveObject(*pclsid, NULL, &spUnkObj)))
>   {
>    //Create a new object and add it to the ROT
>    if (SUCCEEDED(hr = CComClassFactory::CreateInstance(pUnkOuter,
> IID_IUnknown, (LPVOID*)&spUnkObj)))
>    {
>     if (FAILED(hr = RegisterActiveObject(spUnkObj, *pclsid,
> ACTIVEOBJECT_WEAK, &m_dwReg)))
>     {
>      if (hr == MK_S_MONIKERALREADYREGISTERED)
>      {
>       RevokeActiveObject(m_dwReg, NULL);
>       hr = E_UNEXPECTED;
>      }
>     }
>    }
>   }

>   ATLASSERT(SUCCEEDED(hr));

>   if (SUCCEEDED(hr))
>    hr = spUnkObj->QueryInterface(riid, ppvObj);

>   ATLASSERT(SUCCEEDED(hr));

>   return hr;
>  }

> private:

>  ULONG m_dwReg;
> };



Fri, 30 Sep 2005 15:31:22 GMT  
 Singleton class factory using ROT???
Dear Mna,

Thanks for all the information. The article at Code Guru proved to be
quite helpful. I realised how big mistakes I was doing, like trying to
share unmarshaled interface pointers.

Unfortunately, I am implementing my COM classes into a DLL and this is
a project constraint. Is there any way of having a machine-wide
singleton COM object living in a DLL?

I tried to improve my singleton class factory using CoMarshalInterface
and CoUnmarshalInterface but then I found the same problem: How do I
share the IStream from which the interface would be unmarshaled?

I have been also reading the excellent book "Developer's workshop to
COM and ATL 3.0" by Andrew Troelsen and I tried to use dllhost.exe as
a surrogate process in order to have a single object per machine
served from dllhost.exe. Unfortunately, this means changing quite a
lot of my code and I am running out of time...

Please anyone has any suggestions? I am sure that I may be doing basic
mistakes. In that case, could anyone point them out and/or tell me
where to find more information on the subject?

If it is possible to create a machine-wide singleton object living in
a DLL and I manage to create it, I will post the code here. I am sure
that I am not the only one with this problem.

With best regards,

Jorge.

Quote:

> To become a machine-wide singleton, your COM object must be an
> out-of-process object(COMEXE). If your COM object is out-of-process, all
> activations(CoCreateInstance) will return pointer to an instance of your COM
> object. COM will create one if there is none, and COM will return the
> interface to existing one if there is one. You don't need to write any
> special code for singleton.
> But your COM object must be thread-safe if your COMEXE is multi-threaded .
> i.e if your EXE thread call CoInitializeEx(NULL, COINIT_MULTITHREADED) to
> enter into MTA.
> Out-of-process COM objects live in the same apartment as the thread that
> creates them.
> On Apartment issue, check following article.
> http://www.codeguru.com/activex/COMApartments1.html

> regards,
> mna



> > Hello all,

> > I need to create some "machine-wide" singleton objects so the same object
>  is
> > obtained each time that CoCreateInstance is called in any process. To do
>  so,
> > I created the following custom classfactory (at the bottom), to be
>  assigned
> > to the corresponding CoClass using DECLARE_CLASSFACTORY_EX.

> > This works ok in the first process that creates the objects, but when a
> > second process tries to load the singleton objects, either
>  GetActiveObject()
> > fails and a new object is created or GetActiveObject() succeeds but
>  calling
> > QueryInterface on the obtained IUnknown* will return E_NOINTERFACE.

> > Please could anybody tell me what I am doing wrong? I have the suspicion
> > that it has to do with the COM threading model / apartment model.

> > Thanks in advance,

> > Jorge.

> > template <const GUID *pclsid>
> > class CCoCMTCSingleton : public CComClassFactory
> > {
> > public:

> >  HRESULT FinalRelease()
> >  {
> >   return RevokeActiveObject(m_dwReg, NULL);
> >  }

> >  STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void**
>  ppvObj)
> >  {
> >   //Preconditions
> >   if (ppvObj == NULL)
> >    return E_POINTER;
> >   if (pUnkOuter != NULL)
> >    return CLASS_E_NOAGGREGATION;
> >   ATLASSERT(pclsid != NULL);

> >   //Query for a possible running object
> >   HRESULT hr;
> >   CComPtr<IUnknown> spUnkObj;
> >   if (FAILED(hr = GetActiveObject(*pclsid, NULL, &spUnkObj)))
> >   {
> >    //Create a new object and add it to the ROT
> >    if (SUCCEEDED(hr = CComClassFactory::CreateInstance(pUnkOuter,
> > IID_IUnknown, (LPVOID*)&spUnkObj)))
> >    {
> >     if (FAILED(hr = RegisterActiveObject(spUnkObj, *pclsid,
> > ACTIVEOBJECT_WEAK, &m_dwReg)))
> >     {
> >      if (hr == MK_S_MONIKERALREADYREGISTERED)
> >      {
> >       RevokeActiveObject(m_dwReg, NULL);
> >       hr = E_UNEXPECTED;
> >      }
> >     }
> >    }
> >   }

> >   ATLASSERT(SUCCEEDED(hr));

> >   if (SUCCEEDED(hr))
> >    hr = spUnkObj->QueryInterface(riid, ppvObj);

> >   ATLASSERT(SUCCEEDED(hr));

> >   return hr;
> >  }

> > private:

> >  ULONG m_dwReg;
> > };



Sat, 08 Oct 2005 16:31:15 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. Utilizing a Singleton Class Factory

2. ATL Singleton and Singleton Class also from C++

3. ServerXMLHTTP0x80040111 Class factory could not create the class)

4. Using ROT from NT service

5. Reconnecting process using the ROT and the Moniker framework

6. handing out interface pointers *only* to an instance - class factory not wanted

7. Class factories in EXEs

8. noncreatable ATL objects, the class factory, and VB

9. One ATL Component 2 class factories

10. Custom Class Factory

11. The Class Factory of ATL

12. COM/ATL component without a factory class

 

 
Powered by phpBB® Forum Software