/////////////////////////////////////////////////////////////////////// // local.cpp - Out of Proc Component that implements the // // connectable object protocol // // // // Eddon & Eddon, Inside Distributed COM, authors: // // Jim Fawcett, CSE791 - Distributed Objects, Cosmetic Modifications // /////////////////////////////////////////////////////////////////////// #define _WIN32_DCOM #include // For cout #include // For connection point interfaces #include "Component\component.h" // Generated by MIDL #include "registry.h" // For registration functions using namespace std; long g_cComponents = 0; long g_cServerLocks = 0; HANDLE g_hEvent; IOutGoing* g_pOutGoing; const NUM_CONNECTION_POINTS = 1; const CCONNMAX = 2; /////////////////////////////////////////////////////////////////////// // class to enumerate connection points // class CEnumConnectionPoints : public IEnumConnectionPoints { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // IEnumConnectionPoints HRESULT __stdcall Next(ULONG cConnections, IConnectionPoint** rgpcn, ULONG* pcFetched ); HRESULT __stdcall Skip(ULONG cConnections); HRESULT __stdcall Reset(); HRESULT __stdcall Clone(IEnumConnectionPoints** ppEnum); CEnumConnectionPoints(IUnknown* pUnkRef, void** rgpCP); ~CEnumConnectionPoints(); private: long m_cRef; IUnknown* m_pUnkRef; // IUnknown for ref counting int m_iCur; // Current element IConnectionPoint* m_rgpCP[NUM_CONNECTION_POINTS]; // Array of connection points }; // // void** rpgCP is used so that this constructor can accept either // CConnectionPoint** from CInsideDCOM::EnumConnectionPoints or // IConnectionPoint** from CEnumConnectionPoints::Clone // This could also be done by overloading the constructor and duplicating // some of this code CEnumConnectionPoints::CEnumConnectionPoints( IUnknown* pUnkRef, void** rgpCP) : m_cRef(0) { g_cComponents++; m_iCur = 0; m_pUnkRef = pUnkRef; // m_rgpCP is a pointer to an array of IConnectionPoints // or CConnectionPoints for(int count = 0; count < NUM_CONNECTION_POINTS; count++) ((IUnknown*)rgpCP[count]) ->QueryInterface(IID_IConnectionPoint, (void**)&m_rgpCP[count]); } CEnumConnectionPoints::~CEnumConnectionPoints() { g_cComponents--; if(m_rgpCP != NULL) for(int count = 0; count < NUM_CONNECTION_POINTS; count++) m_rgpCP[count]->Release(); } ULONG CEnumConnectionPoints::AddRef() { m_pUnkRef->AddRef(); return ++m_cRef; } ULONG CEnumConnectionPoints::Release() { m_pUnkRef->Release(); if(--m_cRef != 0) return m_cRef; delete this; return 0; } // HRESULT CEnumConnectionPoints::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown || riid == IID_IEnumConnectionPoints) *ppv = (IEnumConnectionPoints*)this; else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } HRESULT CEnumConnectionPoints::Next( ULONG cConnections, IConnectionPoint** rgpcn, ULONG* pcFetched ) { if(rgpcn == NULL) return E_POINTER; if(pcFetched == NULL && cConnections != 1) return E_INVALIDARG; if(pcFetched != NULL) *pcFetched = 0; while(m_iCur < NUM_CONNECTION_POINTS && cConnections > 0) { *rgpcn = m_rgpCP[m_iCur++]; if(*rgpcn != NULL) (*rgpcn)->AddRef(); if(pcFetched != NULL) (*pcFetched)++; cConnections--; rgpcn++; } return S_OK; } HRESULT CEnumConnectionPoints::Skip(ULONG cConnections) { if(m_iCur + cConnections >= NUM_CONNECTION_POINTS) return S_FALSE; m_iCur += cConnections; return S_OK; } // HRESULT CEnumConnectionPoints::Reset() { m_iCur = 0; return S_OK; } HRESULT CEnumConnectionPoints::Clone(IEnumConnectionPoints** ppEnum) { if(ppEnum == NULL) return E_POINTER; *ppEnum = NULL; // Create the clone CEnumConnectionPoints* pNew = new CEnumConnectionPoints(m_pUnkRef, (void**)m_rgpCP); if(pNew == NULL) return E_OUTOFMEMORY; pNew->AddRef(); pNew->m_iCur = m_iCur; *ppEnum = pNew; return S_OK; } // /////////////////////////////////////////////////////////////////////// // class to implement component's main interface ISum // class CConnectionPoint; // forward reference class CInsideDCOM : public ISum, public IConnectionPointContainer, public IProvideClassInfo2 { 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 ); // IProvideClassInfo2 HRESULT __stdcall GetClassInfo(ITypeInfo** pTypeInfo); HRESULT __stdcall GetGUID(DWORD dwGuidKind, GUID* pGUID); // ISum HRESULT __stdcall Sum(int x, int y, int* retval); CInsideDCOM(); ~CInsideDCOM(); private: long m_cRef; CConnectionPoint* m_rgpConnPt[NUM_CONNECTION_POINTS]; }; // /////////////////////////////////////////////////////////////////////// // class to implement connection points // class CConnectionPoint : public IConnectionPoint { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // IConnectionPoint HRESULT __stdcall GetConnectionInterface(IID *pIID); HRESULT __stdcall GetConnectionPointContainer( IConnectionPointContainer** ppCPC ); HRESULT __stdcall Advise(IUnknown* pUnknownSink, DWORD* pdwCookie); HRESULT __stdcall Unadvise(DWORD dwCookie); HRESULT __stdcall EnumConnections(IEnumConnections** ppEnum); CConnectionPoint(CInsideDCOM* pObj, REFIID refiid); ~CConnectionPoint(); private: int m_cRef; CInsideDCOM* m_pObj; IID m_iid; int m_cConn; int m_nCookieNext; unsigned m_rgnCookies[CCONNMAX]; IUnknown* m_rgpUnknown[CCONNMAX]; }; // /////////////////////////////////////////////////////////////////////// // implementation of main component class // CInsideDCOM::CInsideDCOM() : m_cRef(0) { g_cComponents++; m_cRef = 0; // Initialize all the connection points to NULL for(int count = 0; count < NUM_CONNECTION_POINTS; count++) m_rgpConnPt[count] = NULL; // Create our connection point m_rgpConnPt[0] = new CConnectionPoint(this, IID_IOutGoing); m_rgpConnPt[0]->AddRef(); // Additional connection points could be instantiated here } CInsideDCOM::~CInsideDCOM() { g_cComponents--; for(int count = 0; count < NUM_CONNECTION_POINTS; count++) if(m_rgpConnPt[count] != NULL) delete m_rgpConnPt[count]; } // /////////////////////////////////////////////////////////////////////// // class to enumerate connections // class CEnumConnections : public IEnumConnections { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // IEnumConnections HRESULT __stdcall Next( ULONG cConnections, CONNECTDATA* rgpcd, ULONG* pcFetched ); HRESULT __stdcall Skip(ULONG cConnections); HRESULT __stdcall Reset(); HRESULT __stdcall Clone(IEnumConnections** ppEnum); CEnumConnections(IUnknown* pUnknown, int cConn, CONNECTDATA* pConnData); ~CEnumConnections(); private: int m_cRef; IUnknown* m_pUnkRef; // IUnknown for ref counting unsigned m_iCur; // Current element unsigned m_cConn; // Number of connections CONNECTDATA* m_rgConnData; // Source of connections }; // CEnumConnections::CEnumConnections( IUnknown* pUnknown, int cConn, CONNECTDATA* pConnData) : m_cRef(0) { g_cComponents++; m_pUnkRef = pUnknown; m_iCur = 0; m_cConn = 0; m_rgConnData = new CONNECTDATA[cConn]; if(m_rgConnData != NULL) for(int count = 0; count < cConn; count++) { m_rgConnData[count] = pConnData[count]; m_rgConnData[count].pUnk->AddRef(); } } CEnumConnections::~CEnumConnections() { g_cComponents--; if(m_rgConnData != NULL) { for(unsigned count = 0; count < m_cConn; count++) m_rgConnData[count].pUnk->Release(); delete [] m_rgConnData; } } HRESULT CEnumConnections::Next( ULONG cConnections, CONNECTDATA* rgpcd, ULONG* pcFetched ) { if(pcFetched == NULL && cConnections != 1) return E_INVALIDARG; if(pcFetched != NULL) *pcFetched = 0; if(rgpcd == NULL || m_iCur >= m_cConn) return S_FALSE; unsigned cReturn = 0; while(m_iCur < m_cConn && cConnections > 0) { *rgpcd++ = m_rgConnData[m_iCur]; m_rgConnData[m_iCur++].pUnk->AddRef(); cReturn++; cConnections--; } if(pcFetched != NULL) *pcFetched = cReturn; return S_OK; } // HRESULT CEnumConnections::Skip(ULONG cConnections) { if(m_iCur + cConnections >= m_cConn) return S_FALSE; m_iCur += cConnections; return S_OK; } HRESULT CEnumConnections::Reset() { m_iCur = 0; return S_OK; } HRESULT CEnumConnections::Clone(IEnumConnections** ppEnum) { if(ppEnum == NULL) return E_POINTER; *ppEnum = NULL; // Create the clone CEnumConnections* pNew = new CEnumConnections(m_pUnkRef, m_cConn, m_rgConnData); if(NULL == pNew) return E_OUTOFMEMORY; pNew->AddRef(); pNew->m_iCur = m_iCur; *ppEnum = pNew; return S_OK; } HRESULT CEnumConnections::QueryInterface(REFIID riid, void** ppv) { if(IID_IUnknown == riid || IID_IEnumConnections == riid) *ppv = (IEnumConnections*)this; else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } ULONG CEnumConnections::AddRef() { return ++m_cRef; } ULONG CEnumConnections::Release() { if(--m_cRef != 0) return m_cRef; delete this; return 0; } // /////////////////////////////////////////////////////////////////////// // implementation of connection points // CConnectionPoint::CConnectionPoint(CInsideDCOM* pObj, REFIID riid) : m_cRef(0) { g_cComponents++; m_iid = riid; // Don't need AddRef/Release since we are nested inside CInsideDCOM m_pObj = pObj; for(int count = 0; count < CCONNMAX; count++) { m_rgpUnknown[count] = NULL; m_rgnCookies[count] = 0; } m_cConn = 0; m_nCookieNext = 10; // Arbitrary starting cookie value } CConnectionPoint::~CConnectionPoint() { g_cComponents--; for(int count = 0; count < CCONNMAX; count++) if(m_rgpUnknown[count] != NULL) { m_rgpUnknown[count]->Release(); m_rgpUnknown[count] = NULL; } } HRESULT CConnectionPoint::QueryInterface(REFIID riid, void** ppv) { if(IID_IUnknown == riid || IID_IConnectionPoint == riid) *ppv = (IConnectionPoint*)this; else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } // ULONG CConnectionPoint::AddRef() { return ++m_cRef; } ULONG CConnectionPoint::Release() { if(--m_cRef != 0) return m_cRef; delete this; return 0; } HRESULT CConnectionPoint::GetConnectionInterface(IID *pIID) { if(pIID == NULL) return E_POINTER; *pIID = m_iid; return S_OK; } HRESULT CConnectionPoint::GetConnectionPointContainer( IConnectionPointContainer** ppCPC ) { return m_pObj->QueryInterface(IID_IConnectionPointContainer,(void**)ppCPC); } HRESULT CConnectionPoint::Advise(IUnknown* pUnknownSink, DWORD* pdwCookie) { IUnknown* pSink; *pdwCookie = 0; if(m_cConn == CCONNMAX) return CONNECT_E_ADVISELIMIT; if(FAILED(pUnknownSink->QueryInterface(m_iid, (void**)&pSink))) return CONNECT_E_CANNOTCONNECT; for(int count = 0; count < CCONNMAX; count++) if(m_rgpUnknown[count] == NULL) { m_rgpUnknown[count] = pSink; m_rgnCookies[count] = ++m_nCookieNext; *pdwCookie = m_nCookieNext; break; } m_cConn++; // Hack here to copy pointer to a global variable // so that we can use it from main() g_pOutGoing = (IOutGoing*)pSink; return NOERROR; } // HRESULT CConnectionPoint::Unadvise(DWORD dwCookie) { if(dwCookie == 0) return E_INVALIDARG; for(int count = 0; count < CCONNMAX; count++) if(dwCookie == m_rgnCookies[count]) { if(m_rgpUnknown[count] != NULL) { m_rgpUnknown[count]->Release(); m_rgpUnknown[count] = NULL; } m_cConn--; return NOERROR; } return CONNECT_E_NOCONNECTION; } HRESULT CConnectionPoint::EnumConnections(IEnumConnections** ppEnum) { *ppEnum = NULL; CONNECTDATA* pCD = new CONNECTDATA[m_cConn]; for(int count1 = 0, count2 = 0; count1 < CCONNMAX; count1++) if(m_rgpUnknown[count1] != NULL) { pCD[count2].pUnk = (IUnknown*)m_rgpUnknown[count1]; pCD[count2].dwCookie = m_rgnCookies[count1]; count2++; } CEnumConnections* pEnum = new CEnumConnections(this, m_cConn, pCD); delete [] pCD; return pEnum->QueryInterface(IID_IEnumConnections, (void**)ppEnum); } // /////////////////////////////////////////////////////////////////////// // more implementation of main component class // HRESULT CInsideDCOM::EnumConnectionPoints(IEnumConnectionPoints** ppEnum) { cout << "Component: CInsideDCOM::EnumConnectionPoints()" << endl; CEnumConnectionPoints* pEnum = new CEnumConnectionPoints( reinterpret_cast(this), (void**)m_rgpConnPt ); return pEnum->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum); } HRESULT CInsideDCOM::FindConnectionPoint(REFIID riid,IConnectionPoint** ppCP) { if(riid == IID_IOutGoing) { cout << "Component: CInsideDCOM::FindConnectionPoint() for IID_IOutGoing" << endl; return m_rgpConnPt[0]->QueryInterface(IID_IConnectionPoint, (void**)ppCP); } return E_NOINTERFACE; } HRESULT CInsideDCOM::GetClassInfo(ITypeInfo** pTypeInfo) { ITypeLib* pTypeLib; LoadRegTypeLib(LIBID_Component, 1, 0, LANG_NEUTRAL, &pTypeLib); HRESULT hr = pTypeLib->GetTypeInfoOfGuid(CLSID_InsideDCOM, pTypeInfo); pTypeLib->Release(); return hr; } HRESULT CInsideDCOM::GetGUID(DWORD dwGuidKind, GUID* pGUID) { if(pGUID == NULL) return E_INVALIDARG; *pGUID = IID_IOutGoing; return S_OK; } // ULONG CInsideDCOM::AddRef() { return ++m_cRef; } ULONG CInsideDCOM::Release() { if(--m_cRef != 0) return m_cRef; SetEvent(g_hEvent); delete this; return 0; } HRESULT CInsideDCOM::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown) *ppv = reinterpret_cast(this); else if(riid == IID_ISum) { cout << "Component: CInsideDCOM::QueryInterface() for ISum returning " << this << endl; *ppv = (ISum*)this; } else if(riid == IID_IConnectionPointContainer) { cout << "Component: CInsideDCOM::QueryInterface() " << "for IConnectionPointContainer" << endl; *ppv = (IConnectionPointContainer*)this; } else if(riid == IID_IProvideClassInfo) { MessageBox(NULL, "QueryInterface", "IProvideClassInfo", MB_OK); *ppv = NULL; return E_NOINTERFACE; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } // HRESULT CInsideDCOM::Sum(int x, int y, int* retval) { cout << "Component: CInsideDCOM::Sum() " << x << " + " << y << " = " << x + y << endl; *retval = x + y; return S_OK; } /////////////////////////////////////////////////////////////////////// // class factory class // class CFactory : public IClassFactory { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); // IClassFactory HRESULT __stdcall CreateInstance( IUnknown *pUnknownOuter, REFIID iid, void** ppv ); HRESULT __stdcall LockServer(BOOL bLock); CFactory() : m_cRef(0) { g_cComponents++; } ~CFactory() { g_cComponents--; } private: long m_cRef; }; // ULONG CFactory::AddRef() { return ++m_cRef; } ULONG CFactory::Release() { if(--m_cRef != 0) return m_cRef; delete this; return 0; } HRESULT CFactory::QueryInterface(REFIID iid, void** ppv) { if((iid == IID_IUnknown) || (iid == IID_IClassFactory)) *ppv = (IClassFactory *)this; else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } HRESULT CFactory::CreateInstance( IUnknown *pUnknownOuter, REFIID iid, void** ppv ) { if(pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION; CInsideDCOM *pInsideDCOM = new CInsideDCOM; cout << "Component: CFactory::CreateInstance() " << pInsideDCOM << endl; if(pInsideDCOM == NULL) return E_OUTOFMEMORY; // QueryInterface probably for IID_IUNKNOWN return pInsideDCOM->QueryInterface(iid, ppv); } HRESULT CFactory::LockServer(BOOL bLock) { if(bLock) g_cServerLocks++; else g_cServerLocks--; return S_OK; } // /////////////////////////////////////////////////////////////////////// // registration // void RegisterComponent() { ITypeLib* pTypeLib; LoadTypeLibEx(L"component.exe", REGKIND_DEFAULT, &pTypeLib); RegisterServer( "component.exe", CLSID_InsideDCOM, "Inside DCOM Sample #1", "Component.InsideDCOM", "Component.InsideDCOM.1", NULL ); } /////////////////////////////////////////////////////////////////////// // commandline handler // void CommandLineParameters(int argc, char** argv) { RegisterComponent(); if(argc < 2) { cout << "No parameter, but registered anyway..." << endl; exit(false); } char* szToken = strtok(argv[1], "-/"); if(_stricmp(szToken, "RegServer") == 0) { RegisterComponent(); cout << "RegServer" << endl; exit(true); } if(_stricmp(szToken, "UnregServer") == 0) { UnRegisterTypeLib(LIBID_Component, 1, 0, LANG_NEUTRAL, SYS_WIN32); UnregisterServer( CLSID_InsideDCOM, "Component.InsideDCOM", "Component.InsideDCOM.1" ); cout << "UnregServer" << endl; exit(true); } if(_stricmp(szToken, "Embedding") != 0) { cout << "Invalid parameter" << endl; exit(false); } } // /////////////////////////////////////////////////////////////////////// // component entry point // - register and unregister component // - run server // void main(int argc, char** argv) { CommandLineParameters(argc, argv); g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); CoInitializeEx(NULL, COINIT_MULTITHREADED); DWORD dwRegister; IClassFactory *pCFactory = new CFactory(); CoRegisterClassObject( CLSID_InsideDCOM, pCFactory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister ); Sleep(200); cout << "\nPress any key to fire an event at the client" << "\n the letter b or B will cause the client to play a wav file" << "\n any other key cause client to display the key value\n" << endl; HANDLE handles[2] = { g_hEvent, GetStdHandle(STD_INPUT_HANDLE) }; while( WaitForMultipleObjects(2, handles, FALSE, INFINITE) - WAIT_OBJECT_0 == 1 ) { INPUT_RECORD ir; DWORD read; ReadConsoleInput(handles[1], &ir, 1, &read); if(ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown == TRUE) g_pOutGoing->GotMessage(ir.Event.KeyEvent.uChar.AsciiChar); } CoRevokeClassObject(dwRegister); CoUninitialize(); }