windows-nt/Source/XPSP1/NT/com/oleutest/oletest/oleadv.cpp
2020-09-26 16:20:57 +08:00

944 lines
24 KiB
C++

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