
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;
> > };