[ Home | Syllabus | Course Notes | Assignments | Search]


Connectable Objects
Motivation:
Example: NOMS: sharing message folders - how to inform of deleted or added messages?
SOLUTION: Connectable Objects (that is objects which can call the client)


Client Code
Client has to provide an interface to the sink to be used by the connectable object
// client.cpp #define _WIN32_DCOM #include <olectl.h> #include <conio.h> #include <iostream.h> #include "Component\component.h" class CSink : public IOutGoing { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // IOutGoing HRESULT __stdcall GotMessage(int Message); CSink() : m_cRef(0) { } ~CSink() { } private: long m_cRef; }; //......
HRESULT CSink::GotMessage(int Message) { if(Message == (int)'b' || Message == (int)'B') PlaySound("BrockschmidtQuack", NULL, SND_RESOURCE|SND_ASYNC); cout << "CSink::GotMessage is " << (char)Message << endl; return S_OK; }
void main() { cout << "Client: Calling CoInitialize()" << endl; CoInitializeEx(NULL, COINIT_MULTITHREADED); // why multi-threaded? IUnknown* pUnknown; cout << "Client: Calling CoCreateInstance()" << endl; CoCreateInstance(CLSID_InsideDCOM, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown); ISum* pSum; cout << "Client: Calling QueryInterface() for ISum on " << pUnknown << endl; HRESULT hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum); if(FAILED(hr)) cout << "QueryInterface FAILED" << endl; int sum; pSum->Sum(17, 2, &sum); cout << "pSum->Sum(17, 2) = " << sum << endl; IConnectionPointContainer* pConnectionPointContainer; hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer); if(SUCCEEDED(hr)) { IConnectionPoint* pConnectionPoint; hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint); cout << "FindConnectionPoint returns " << hr << " pConnectionPoint = " << pConnectionPoint << endl; CSink* mySink = new CSink; DWORD dwCookie; pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie); cout << "Press any key to exit" << endl; _getch(); // wait until user wants client to stop pConnectionPoint->Unadvise(dwCookie); pConnectionPoint->Release(); pConnectionPointContainer->Release(); } cout << "Client: Calling Release() for pSum" << endl; hr = pSum->Release(); cout << "Client: Calling Release() for pUnknown" << endl; hr = pUnknown->Release(); cout << "Client: Calling CoUninitialize()" << endl; CoUninitialize(); }
Component needs to also support IConnectionPointContainer
class CInsideDCOM : public ISum, IConnectionPointContainer, IConnectionPoint
// NOTICE multiple inheritance of interfaces
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);
// IConnectionPointContainer
HRESULT __stdcall EnumConnectionPoints(IEnumConnectionPoints** ppEnum);
HRESULT __stdcall FindConnectionPoint(REFIID riid, IConnectionPoint** ppCP);
// IConnectionPoint
HRESULT __stdcall GetConnectionInterface(IID* pIID);
HRESULT __stdcall GetConnectionPointContainer(IConnectionPointContainer** ppCPC);
HRESULT __stdcall Advise(IUnknown* pUnknown, DWORD* pdwCookie);
HRESULT __stdcall Unadvise(DWORD dwCookie);
HRESULT __stdcall EnumConnections(IEnumConnections** ppEnum);
// ISum
HRESULT __stdcall Sum(int x, int y, int* retval);
CInsideDCOM() : m_cRef(0) { g_cComponents++; }
~CInsideDCOM() { cout << "Component: CInsideDCOM::~CInsideDCOM()" << endl, g_cComponents--; }
private:
long m_cRef;
};
HRESULT CInsideDCOM::Advise(IUnknown* pUnknown, DWORD* pdwCookie)
{
cout << "Advise" << endl;
*pdwCookie = 1;
return pUnknown->QueryInterface(IID_IOutGoing, (void**)&g_pOutGoing);
}
HRESULT CInsideDCOM::Unadvise(DWORD dwCookie)
{
cout << "Unadvise" << endl;
g_pOutGoing->Release();
return NOERROR;
}
HRESULT CInsideDCOM::FindConnectionPoint(REFIID riid, IConnectionPoint** ppCP)
{
if(riid == IID_IOutGoing)
{
cout << "Component: CInsideDCOM::FindConnectionPoint() for IID_IOutGoing" << endl;
return QueryInterface(IID_IConnectionPoint, (void**)ppCP);
}
return E_NOINTERFACE;
}
IDL file
// component.idl
import "unknwn.idl";
[ object, uuid(10000001-0000-0000-0000-000000000001),
oleautomation ]
interface ISum : IUnknown
{
HRESULT Sum(int x, int y, [out, retval] int* retval);
}
[ object, uuid(10000005-0000-0000-0000-000000000001),
oleautomation ]
interface IOutGoing : IUnknown
{
HRESULT GotMessage(int Message);
}
[ uuid(10000003-0000-0000-0000-000000000001),
helpstring("Inside DCOM Component Type Library"),
version(1.0) ]
library Component
{
importlib("stdole32.tlb");
interface ISum;
interface IOutGoing;
[ uuid(10000002-0000-0000-0000-000000000001) ]
coclass InsideDCOM
{
interface ISum;
[source] interface IOutGoing;
}
};