//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: oleadv.cpp // // Contents: implementation of unit test for Ole Advise Holder // // Classes: CTestPretendMoniker // COaTestAdviseSink // COaTestObj // // Functions: NotifyOfChanges // TestSingleOleAdvise // TestMassOleAdvise // TestOleAdviseHolderEnumerator // LEOleAdviseHolderTest // // History: dd-mmm-yy Author Comment // 27-May-94 ricksa author // //-------------------------------------------------------------------------- #include "oletest.h" #define MAX_OA_TO_REGISTER 100 //+------------------------------------------------------------------------- // // Class: CTestPretendMoniker // // Purpose: Use where we need a moniker to confirm reciept of OnRename // // Interface: QueryInterface - get a new interface // AddRef - add a reference // Release - remove a reference // VerifySig - verify signiture is correct // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: This only supports IUnknown // //-------------------------------------------------------------------------- class CTestPretendMoniker : public IUnknown { public: CTestPretendMoniker(void); // IUnknown methods HRESULT __stdcall QueryInterface(REFIID riid, LPVOID FAR* ppvObj); ULONG __stdcall AddRef(void); ULONG __stdcall Release(void); BOOL VerifySig(void); private: enum Sigs { SIG1 = 0x01020304, SIG2 = 0x04030201 }; LONG _lRefs; Sigs _sig1; Sigs _sig2; }; //+------------------------------------------------------------------------- // // Member: CTestPretendMoniker::CTestPretendMoniker // // Synopsis: Initialize object // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- CTestPretendMoniker::CTestPretendMoniker(void) : _lRefs(0), _sig1(SIG1), _sig2(SIG2) { // Header does all the work } //+------------------------------------------------------------------------- // // Member: CTestPretendMoniker::VerifySig // // Synopsis: Verify signiture is as expected // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- BOOL CTestPretendMoniker::VerifySig(void) { return (_sig1 == SIG1 && _sig2 == SIG2); } //+------------------------------------------------------------------------- // // Member: CTestPretendMoniker::QueryInterface // // Synopsis: Return a supported interface // // Arguments: [riid] - interface id requested // [ppvObj] - where to put the interface // // Returns: S_OK - we are returning an interface // E_NOINTERFACE - we do not support the requested interface // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT __stdcall CTestPretendMoniker::QueryInterface( REFIID riid, LPVOID *ppvObj) { if (IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_IMoniker, riid)) { AddRef(); *ppvObj = this; return NOERROR; } *ppvObj = NULL; return E_NOINTERFACE; } //+------------------------------------------------------------------------- // // Member: CTestPretendMoniker::AddRef // // Synopsis: Bump reference count // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- ULONG __stdcall CTestPretendMoniker::AddRef(void) { return _lRefs++; } //+------------------------------------------------------------------------- // // Member: CTestPretendMoniker::Release // // Synopsis: Decrement the reference count // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- ULONG __stdcall CTestPretendMoniker::Release(void) { assert(_lRefs >= 1); return --_lRefs; } //+------------------------------------------------------------------------- // // Class: COaTestAdviseSink // // Purpose: Advise sink for use in testing the Ole Advise Holder // // Interface: QueryInterface - get supported interface pointer // AddRef - bump reference count // Release - decrement reference count // OnDataChange - not implemented // OnViewChange - not implemented // OnRename - rename notification // OnSave - save notification // OnClose - close notification // VerifyNotifications - verify all expected notifications arrived // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: We only support parts of advise sink we need to test the // advise holder. // //-------------------------------------------------------------------------- class COaTestAdviseSink : public IAdviseSink { public: COaTestAdviseSink(void); // IUnknown methods HRESULT __stdcall QueryInterface(REFIID riid, LPVOID FAR* ppvObj); ULONG __stdcall AddRef(void); ULONG __stdcall Release(void); // IAdviseSink methods void __stdcall OnDataChange(FORMATETC *pFormatetc, STGMEDIUM *pStgmed); void __stdcall OnViewChange( DWORD dwAspect, LONG lindex); void __stdcall OnRename(IMoniker *pmk); void __stdcall OnSave(void); void __stdcall OnClose(void); // Test methods used for verification BOOL VerifyNotifications(void); private: LONG _lRefs; BOOL _fOnCloseNotify; BOOL _fOnSaveNotify; BOOL _fOnRenameNotify; }; //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::COaTestAdviseSink // // Synopsis: Initialize advise sink // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- COaTestAdviseSink::COaTestAdviseSink(void) : _lRefs(1), _fOnCloseNotify(FALSE), _fOnSaveNotify(FALSE), _fOnRenameNotify(FALSE) { // Header does all the work } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::QueryInterface // // Synopsis: Return requested interface pointer // // Arguments: [riid] - interface id requested // [ppvObj] - where to put the interface // // Returns: S_OK - we are returning an interface // E_NOINTERFACE - we do not support the requested interface // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT __stdcall COaTestAdviseSink::QueryInterface( REFIID riid, LPVOID *ppvObj) { if (IsEqualGUID(IID_IUnknown, riid) || IsEqualGUID(IID_IAdviseSink, riid)) { AddRef(); *ppvObj = this; return NOERROR; } *ppvObj = NULL; return E_NOINTERFACE; } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::AddRef // // Synopsis: Bump reference count // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- ULONG __stdcall COaTestAdviseSink::AddRef(void) { return _lRefs++; } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::Release // // Synopsis: Decrement reference count // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- ULONG __stdcall COaTestAdviseSink::Release(void) { assert(_lRefs >= 1); return --_lRefs; } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::OnDataChange // // Synopsis: Notify of change in data // // Arguments: [pFormatetc] - FORMATETC of data // [pStgmed] - storage medium for data // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: Not supported for this object // //-------------------------------------------------------------------------- void __stdcall COaTestAdviseSink::OnDataChange( FORMATETC *pFormatetc, STGMEDIUM *pStgmed) { OutputString("COaTestAdviseSink::OnDataChange Unexpectedly Called!\r\n"); } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::OnViewChange // // Synopsis: Notify that view should change // // Arguments: [dwAspect] - specifies view of the object // [lindex] - which piece of view changed // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: Not supported for this object // //-------------------------------------------------------------------------- void __stdcall COaTestAdviseSink::OnViewChange( DWORD dwAspect, LONG lindex) { OutputString("COaTestAdviseSink::OnViewChange Unexpectedly Called!\r\n"); } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::OnRename // // Synopsis: Notifies of rename operation // // Arguments: [pmk] - new full name of the object // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- void __stdcall COaTestAdviseSink::OnRename(IMoniker *pmk) { // Verify that we get the pretend moniker CTestPretendMoniker *ptpm = (CTestPretendMoniker *) pmk; if (ptpm->VerifySig()) { _fOnCloseNotify = TRUE; } else { OutputString("OnRename got a bad moniker\r\n"); } } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::OnSave // // Synopsis: Notifies that object has been saved // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- void __stdcall COaTestAdviseSink::OnSave(void) { _fOnSaveNotify = TRUE; } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::OnClose // // Synopsis: Notifies that object has been closed // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- void __stdcall COaTestAdviseSink::OnClose(void) { _fOnRenameNotify = TRUE; } //+------------------------------------------------------------------------- // // Member: COaTestAdviseSink::VerifyNotifications // // Synopsis: Verify that we recieved expected notifications // // Returns: TRUE - we recieved expected notification // FALSE - we didn't receive expected notifications // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: This resets the values after returning the result // //-------------------------------------------------------------------------- BOOL COaTestAdviseSink::VerifyNotifications(void) { // Save the result of all the notifications BOOL fResult = _fOnCloseNotify && _fOnSaveNotify && _fOnRenameNotify; // Reset the notifications _fOnCloseNotify = FALSE; _fOnSaveNotify = FALSE; _fOnRenameNotify = FALSE; // Let caller know the result of the notifications return fResult; } //+------------------------------------------------------------------------- // // Class: COaTestObj // // Purpose: Provides place to keep information related to an advise // // Interface: Register - register advise with holder // VerifyNotified - verify that object was notified by holder // Revoke - revoke registration with holder // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: // //-------------------------------------------------------------------------- class COaTestObj { public: COaTestObj(void); HRESULT Register(IOleAdviseHolder *poah, char *pszCaller); HRESULT VerifyNotified(void); HRESULT Revoke(void); private: COaTestAdviseSink _otas; DWORD _dwConnection; IOleAdviseHolder * _poah; char * _pszTest; }; //+------------------------------------------------------------------------- // // Member: COaTestObj::COaTestObj // // Synopsis: Initialize object // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- COaTestObj::COaTestObj(void) : _dwConnection(0) { // Header does all the work } //+------------------------------------------------------------------------- // // Member: COaTestObj::Register // // Synopsis: Register advise with the holder // // Arguments: [poah] - pointer to the advise holder // [pszTest] - name of the test // // Returns: S_OK - registration was successful // E_FAIL - registration failed // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT COaTestObj::Register(IOleAdviseHolder *poah, char *pszTest) { // Register the advise HRESULT hr = poah->Advise(&_otas, &_dwConnection); // Make sure results are sensible if (hr != NOERROR) { OutputString("%s Registration failed hr = %lx\r\n", pszTest, hr); return E_FAIL; } if (_dwConnection == 0) { OutputString("%s Connection not updated\r\n", pszTest); return E_FAIL; } // Save these for the revoke _pszTest = pszTest; _poah = poah; return NOERROR; } //+------------------------------------------------------------------------- // // Member: COaTestObj::VerifyNotified // // Synopsis: Verify that our advise was notified of changes // // Returns: S_OK - advise was notified of changes // E_FAIL - object was not notified. // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT COaTestObj::VerifyNotified(void) { if (!_otas.VerifyNotifications()) { OutputString("%s Object not correctly notified\r\n", _pszTest); return E_FAIL; } return NOERROR; } //+------------------------------------------------------------------------- // // Member: COaTestObj::Revoke // // Synopsis: Revoke our advise registration with advise holder // // Returns: S_OK - advise was successfully deregistered // E_FAIL - revokation experience unexpected result // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT COaTestObj::Revoke(void) { // Remove the advise registration HRESULT hr = _poah->Unadvise(_dwConnection); if (hr != NOERROR) { OutputString("%s Revoke failed hr = %lx\r\n", _pszTest, hr); return E_FAIL; } // Try the unadvise one more time to make sure it took hr = _poah->Unadvise(_dwConnection); if (hr != OLE_E_NOCONNECTION) { OutputString("%s Second revoke bad hr = %lx\r\n", _pszTest, hr); return E_FAIL; } return NOERROR; } //+------------------------------------------------------------------------- // // Function: NotifyOfChanges // // Synopsis: Run through list of possible notifications for advise // // Arguments: [poahForTest] - advise holder we are testing // [pszTest] - test description // // Returns: NOERROR - all notifications reported success // Any Other - error occurred during notification // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: We currently only do the public notifications // //-------------------------------------------------------------------------- HRESULT NotifyOfChanges(IOleAdviseHolder *poahForTest, char *pszTest) { // Notify Renamed CTestPretendMoniker tpm; HRESULT hr = poahForTest->SendOnRename((IMoniker *) &tpm); if (hr != NOERROR) { OutputString("%s SendOnRename failed hr = %lx\r\n", pszTest); return hr; } // Notify of save hr = poahForTest->SendOnSave(); if (hr != NOERROR) { OutputString("%s SendOnSave failed hr = %lx\r\n", pszTest); return hr; } // Notify of close hr = poahForTest->SendOnClose(); if (hr != NOERROR) { OutputString("%s SendOnClose failed hr = %lx\r\n", pszTest); return hr; } return NOERROR; } //+------------------------------------------------------------------------- // // Function: TestSingleOleAdvise // // Synopsis: Test advise holder with only a single advise // // Arguments: [poahForTest] - advise holder we are testing // // Returns: NOERROR - test was successfully passed // Any Other - test failed // // Algorithm: Create a test object. Register that test object with the // advise holder. Tell adviser holder to notify all its objects // of changes. Verify that test object was notified. Revoke // the registration of the test object with the advise holder. // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT TestSingleOleAdvise(IOleAdviseHolder *poahForTest) { char *pszTest = "TestSingleOleAdvise"; COaTestObj oto; // Register a single advise HRESULT hr = oto.Register(poahForTest, pszTest); if (hr != NOERROR) { return hr; } // Notifiy it of changes hr = NotifyOfChanges(poahForTest, pszTest); if (hr != NOERROR) { return hr; } // Verify that notifications occurred hr = oto.VerifyNotified(); if (hr != NOERROR) { return hr; } // Revoke all advises return oto.Revoke(); } //+------------------------------------------------------------------------- // // Function: TestMassOleAdvise // // Synopsis: Test registering a very large number of advises // // Arguments: [poahForTest] - advise holder we are testing // // Returns: NOERROR - test was successfully passed // Any Other - test failed // // Algorithm: Create a large number of test objects. Then register all // those with the advise holder for changes. Tell advise holder // to notify all its registered objects of changes. Verify that // each of the test objects recieved a notification. Finally, // revoke all the test object registrations. // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT TestMassOleAdvise(IOleAdviseHolder *poahForTest) { char *pszTest = "TestMassOleAdviseHolder"; // Create a large number of advises COaTestObj aoto[MAX_OA_TO_REGISTER]; HRESULT hr; // Register all the advises for (int i = 0; i < MAX_OA_TO_REGISTER; i++) { hr = aoto[i].Register(poahForTest, pszTest); if (hr != NOERROR) { OutputString("%s Failed on Loop %d\r\n", pszTest, i); return hr; } } // Notify all the advises of changes hr = NotifyOfChanges(poahForTest, pszTest); if (hr != NOERROR) { return hr; } // Verify all objects were notified for (i = 0; i < MAX_OA_TO_REGISTER; i++) { hr = aoto[i].VerifyNotified(); if (hr != NOERROR) { OutputString("%s Failed on Loop %d\r\n", pszTest, i); return hr; } } // Revoke all registrations for (i = 0; i < MAX_OA_TO_REGISTER; i++) { hr = aoto[i].Revoke(); if (hr != NOERROR) { OutputString("%s Failed on Loop %d\r\n", pszTest, i); return hr; } } return NOERROR; } //+------------------------------------------------------------------------- // // Function: TestOleAdviseHolderEnumerator // // Synopsis: Test the OLE Advise Holder enumerator // // Arguments: [poahForTest] - OLE advise holder we are testing // // Returns: NOERROR - test passed // Any Other - test failed // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // // Notes: We currently just verify that the enumerator is not implemented // //-------------------------------------------------------------------------- HRESULT TestOleAdviseHolderEnumerator(IOleAdviseHolder *poahForTest) { char *pszCaller = "TestOleAdviseHolderEnumerator"; // Confirm no enumerator IEnumSTATDATA *penumAdvise; HRESULT hr = poahForTest->EnumAdvise(&penumAdvise); if (hr != E_NOTIMPL) { OutputString("%s EnumAdvise Hresult = %lx\r\n", pszCaller, hr); return E_FAIL; } if (penumAdvise != NULL) { OutputString("%s EnumAdvise returned advise not NULL\r\n", pszCaller); return E_FAIL; } return NOERROR; } //+------------------------------------------------------------------------- // // Function: LEOleAdviseHolderTest // // Synopsis: Unit test for advise holders // // Returns: NOERROR - test passed // Any Other - test failed // // Algorithm: First we verify that a large number of verification work. Then // we verify that a large number of registrations work. Finally, // we verify that the enumerator for the OLE advise holder // behaves as expected. // // History: dd-mmm-yy Author Comment // 01-Jun-94 Ricksa Created // //-------------------------------------------------------------------------- HRESULT LEOleAdviseHolderTest(void) { IOleAdviseHolder *poahForTest; HRESULT hr = CreateOleAdviseHolder(&poahForTest); // Test a single registration if ((hr = TestSingleOleAdvise(poahForTest)) != NOERROR) { return hr; } // Test a large number of registrations if ((hr = TestMassOleAdvise(poahForTest)) != NOERROR) { return hr; } // Test Enumerator if ((hr = TestOleAdviseHolderEnumerator(poahForTest)) != NOERROR) { return hr; } // Release the advise holder DWORD dwFinalRefs = poahForTest->Release(); if (dwFinalRefs != 0) { OutputString( "LEOleAdviseHolderTest Final Release is = %d", dwFinalRefs); return E_FAIL; } return NOERROR; }