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

1433 lines
39 KiB
C++

//+------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: cliptest.cpp
//
// Contents: Data Advise Holder tests
//
// Classes: CDataAdviseTestFormatEtc
// CTestAdviseSink
// CTestDaHolder
//
// Functions: TestPrimeFirstOnlyOnceNoData
// TestPrimeFirstOnlyOnceData
// DoRegisterNotifyDeregister
// TestRegisterNotifyDegister
// TestRegisterNotifyDegisterNoData
// TestNotifyOnStop
// TestNotifyOnce
// CreateMassRegistration
// DoMassUnadvise
// TestEnumerator
// LEDataAdviseHolderTest
//
// History: dd-mmm-yy Author Comment
// 25-May-94 ricksa author
//
//--------------------------------------------------------------------------
#include "oletest.h"
#include "gendata.h"
#include "genenum.h"
//+-------------------------------------------------------------------------
//
// Class: CDataAdviseTestFormatEtc
//
// Purpose: Hold FORMATETC used by the data advise holder unit tests
//
// Interface: GetFormatEtc - get a pointer to the FORMATETC
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
// Notes:
//
//--------------------------------------------------------------------------
class CDataAdviseTestFormatEtc
{
public:
CDataAdviseTestFormatEtc(void);
FORMATETC * GetFormatEtc(void);
private:
FORMATETC _formatetc;
};
//+-------------------------------------------------------------------------
//
// Member: CDataAdviseTestFormatEtc::CDataAdviseTestFormatEtc
//
// Synopsis: Initialize object
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
CDataAdviseTestFormatEtc::CDataAdviseTestFormatEtc(void)
{
_formatetc.cfFormat = RegisterClipboardFormat("OleTest Storage Format");
_formatetc.ptd = NULL;
_formatetc.dwAspect = DVASPECT_CONTENT;
_formatetc.lindex = -1;
_formatetc.tymed = TYMED_ISTORAGE;
}
//+-------------------------------------------------------------------------
//
// Member: CDataAdviseTestFormatEtc::GetFormatEtc
//
// Synopsis: Get pointer to standard format etc
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
FORMATETC *CDataAdviseTestFormatEtc::GetFormatEtc(void)
{
return &_formatetc;
}
// Global Formatec for all the data advise tests
CDataAdviseTestFormatEtc g_datfeDaTest;
//+-------------------------------------------------------------------------
//
// Class: CTestAdviseSink
//
// Purpose: Advise sink used to verify data advise holder
//
// Interface: QueryInterface - get new interface pointer
// AddRef - bump reference count
// Release - decrement reference count
// OnDataChange - data change notification
// OnViewChange - not implemented
// OnRename - not implemented
// OnSave - not implemented
// OnClose - not implemented
// ValidOnDataChange - verify all expected data change notification
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
// Notes: We only implement interface methods required for
// test of data advise holder.
//
//--------------------------------------------------------------------------
class CTestAdviseSink : public IAdviseSink
{
public:
CTestAdviseSink(CGenDataObject *pgdo);
// IUnknown methods
STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
STDMETHOD_(ULONG, AddRef)(void);
STDMETHOD_(ULONG, Release)(void);
// IAdviseSink methods
STDMETHOD_(void, OnDataChange)(FORMATETC *pFormatetc, STGMEDIUM *pStgmed);
STDMETHOD_(void, OnViewChange)(
DWORD dwAspect,
LONG lindex);
STDMETHOD_(void, OnRename)(IMoniker *pmk);
STDMETHOD_(void, OnSave)(void);
STDMETHOD_(void, OnClose)(void);
// Test methods used for verification
BOOL ValidOnDataChange(void);
private:
LONG _lRefs;
CGenDataObject * _pgdo;
BOOL _fValidOnDataChange;
};
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::CTestAdviseSink
//
// Synopsis: Initialize object
//
// Arguments: [pgdo] - generic data object
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
// Notes: pgdo being NULL means we don't expect a STGMEDIUM when
// the OnDataChange notification occurs.
//
//--------------------------------------------------------------------------
CTestAdviseSink::CTestAdviseSink(CGenDataObject *pgdo)
: _lRefs(1), _fValidOnDataChange(FALSE)
{
_pgdo = pgdo;
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::QueryInterface
//
// Synopsis: Return a new 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
//
//--------------------------------------------------------------------------
STDMETHODIMP CTestAdviseSink::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: CTestAdviseSink::AddRef
//
// Synopsis: Bump reference count
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CTestAdviseSink::AddRef(void)
{
return _lRefs++;
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::Release
//
// Synopsis: Decrement reference count
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CTestAdviseSink::Release(void)
{
assert(_lRefs >= 1);
return --_lRefs;
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::OnDataChange
//
// Synopsis: Notify of change in data
//
// Arguments: [pFormatetc] - FORMATETC of data
// [pStgmed] - storage medium for data
//
// Algorithm: Verify that the we recieved the expected FORMATEC. Then
// verify that we recieved the expected STGMEDIUM.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CTestAdviseSink::OnDataChange(
FORMATETC *pFormatetc,
STGMEDIUM *pStgmed)
{
// Verify the format
if (memcmp(g_datfeDaTest.GetFormatEtc(), pFormatetc, sizeof(FORMATETC))
== 0)
{
if (_pgdo != NULL)
{
// We have a data object that we can use to verify the format
// so we do.
_fValidOnDataChange =
_pgdo->VerifyFormatAndMedium(pFormatetc, pStgmed);
}
// We are expecting an empty STGMEDIUM so verify that it is
else if ((pStgmed->tymed == TYMED_NULL)
&& (pStgmed->pUnkForRelease == NULL))
{
_fValidOnDataChange = TRUE;
}
}
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::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
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CTestAdviseSink::OnViewChange(
DWORD dwAspect,
LONG lindex)
{
OutputString("CTestAdviseSink::OnViewChange Unexpectedly Called!\r\n");
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::OnRename
//
// Synopsis: Notifies of rename operation
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
// Notes: Not supported for this object
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CTestAdviseSink::OnRename(IMoniker *pmk)
{
OutputString("CTestAdviseSink::OnRename Unexpectedly Called!\r\n");
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::OnSave
//
// Synopsis: Notify that object was saved
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
// Notes: Not supported for this object
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CTestAdviseSink::OnSave(void)
{
OutputString("CTestAdviseSink::OnSave Unexpectedly Called!\r\n");
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::OnClose
//
// Synopsis: Notify object closed
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
// Notes: Not supported for this object
//
//--------------------------------------------------------------------------
STDMETHODIMP_(void) CTestAdviseSink::OnClose(void)
{
OutputString("CTestAdviseSink::OnClose Unexpectedly Called!\r\n");
}
//+-------------------------------------------------------------------------
//
// Member: CTestAdviseSink::ValidOnDataChange
//
// Synopsis: Verify that we recieved the expected OnDataChange notification
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CTestAdviseSink::ValidOnDataChange(void)
{
BOOL fResult = _fValidOnDataChange;
_fValidOnDataChange = FALSE;
return fResult;
}
// Preallocated structure used to mass advise registration testing
#define MAX_REGISTER 100
struct
{
CTestAdviseSink * ptas;
DWORD dwConnection;
} aMassAdvise[MAX_REGISTER];
//+-------------------------------------------------------------------------
//
// Class: CTestDaHolder
//
// Purpose: Test enumerator for data advise holder
//
// Interface: Verify - verify particular entry being enumerated
// VerifyAllEnmerated - verify all entries were enumerated once
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
class CTestDaHolder : public CEnumeratorTest
{
public:
CTestDaHolder(IEnumSTATDATA *penumAdvise, HRESULT& rhr);
BOOL Verify(void *);
BOOL VerifyAllEnmerated(void);
BOOL VerifyAll(void *, LONG);
private:
DWORD _cdwFound[MAX_REGISTER];
};
//+-------------------------------------------------------------------------
//
// Member: CTestDaHolder::CTestDaHolder
//
// Synopsis: Initialize object
//
// Arguments: [penumAdvise] - data advise holder enumerator
// [rhr] - HRESULT reference thorugh which to return an error
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
CTestDaHolder::CTestDaHolder(IEnumSTATDATA *penumAdvise, HRESULT& rhr)
: CEnumeratorTest(penumAdvise, sizeof(STATDATA), MAX_REGISTER, rhr)
{
// Zero out our table of counts
memset(&_cdwFound[0], 0, sizeof(_cdwFound));
}
//+-------------------------------------------------------------------------
//
// Member: CTestDaHolder::VerifyAllEnmerated
//
// Synopsis: Verify all objects got enumerated
//
// Returns: TRUE - all objects enumerated
// FALSE - error in enumeration
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CTestDaHolder::VerifyAllEnmerated(void)
{
for (int i = 0; i < MAX_REGISTER; i++)
{
if (_cdwFound[i] != 1)
{
OutputString("Entry %d enumerated %d times\r\n", i, _cdwFound[i]);
return FALSE;
}
// Reset for another test
_cdwFound[i] = 0;
}
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Member: CTestDaHolder::Verify
//
// Synopsis: Verify an enumeration entry
//
// Arguments: [pvEntry] - entry enumerated
//
// Returns: TRUE - enumerated entry is valid
// FALSE - obvious error in enumeration
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CTestDaHolder::Verify(void *pvEntry)
{
STATDATA *pstatdata = (STATDATA *) pvEntry;
// Verify the advf field
if ((pstatdata->advf == 0)
&& (memcmp(g_datfeDaTest.GetFormatEtc(), &pstatdata->formatetc,
sizeof(FORMATETC)) == 0))
{
// Can we find the connection?
for (int i = 0; i < MAX_REGISTER; i++)
{
if (pstatdata->dwConnection == aMassAdvise[i].dwConnection)
{
// Bump found count
_cdwFound[i]++;
// Everything is OK so tell the caller
return TRUE;
}
}
}
return FALSE;
}
//+-------------------------------------------------------------------------
//
// Member: CTestDaHolder::VerifyAll
//
// Synopsis: Verify that an array of all entries is valid
//
// Arguments: [pvEntries] - array of enumerated data
// [clEntries] - number of enumerated entries
//
// Returns: TRUE - enumerated entry is valid
// FALSE - obvious error in enumeration
//
// History: dd-mmm-yy Author Comment
// 02-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
BOOL CTestDaHolder::VerifyAll(void *pvEntries, LONG clEntries)
{
// Verify that the count is as expected.
if (clEntries != MAX_REGISTER)
{
return FALSE;
}
// Verify each entry in the array is reasonable
STATDATA *pstatdata = (STATDATA *) pvEntries;
for (int i = 0; i < MAX_REGISTER; i++, pstatdata++)
{
if (!Verify(pstatdata))
{
return FALSE;
}
}
// Verify that each entry was only referred to once
return VerifyAllEnmerated();
}
//+-------------------------------------------------------------------------
//
// Function: TestPrimeFirstOnlyOnceNoData
//
// Synopsis: Test one notification of
// ADVF_NODATA | ADVF_PRIMEFIRST | ADVF_ONLYONCE
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Create an test advise sink object. Register it with the
// advise holder which should cause the notification. Verify
// that the advise was notified and that no connection was
// returned.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestPrimeFirstOnlyOnceNoData(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
// Create an advise sink - the NULL means we don't want to validate
// the STGMEDIUM.
CTestAdviseSink tas(NULL);
DWORD dwConnection = 0;
// Register the advise
HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
ADVF_NODATA | ADVF_PRIMEFIRST | ADVF_ONLYONCE, &tas, &dwConnection);
// Confirm that the advise is notified and in the correct state
if (!tas.ValidOnDataChange())
{
OutputString("TestPrimeFirstOnlyOnceNoData OnDataChange invalid!\r\n");
return E_FAIL;
}
// Make sure the advise was not registered
if (dwConnection != 0)
{
OutputString("TestPrimeFirstOnlyOnceNoData got Connection!\r\n");
return E_FAIL;
}
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: TestPrimeFirstOnlyOnceData
//
// Synopsis: Test one notification of
// ADVF_PRIMEFIRST | ADVF_ONLYONCE
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Create an test advise sink object. Register it with the
// advise holder which should cause the notification. Verify
// that the advise was notified and that no connection was
// returned.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestPrimeFirstOnlyOnceData(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
// Create an advise sink that we can verify the STGMEDIUM
CTestAdviseSink tas(pgdo);
// Where to store the connection
DWORD dwConnection = 0;
// Register the advise
HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
ADVF_PRIMEFIRST | ADVF_ONLYONCE, &tas, &dwConnection);
// Confirm that the advise is notified and in the correct state
if (!tas.ValidOnDataChange())
{
OutputString("TestPrimeFirstOnlyOnceData OnDataChange invalid!\r\n");
return E_FAIL;
}
// Make sure the advise was not registered
if (dwConnection != 0)
{
OutputString("TestPrimeFirstOnlyOnceData got Connection!\r\n");
return E_FAIL;
}
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: DoRegisterNotifyDeregister
//
// Synopsis:
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pdo] - IDataObject interface
// [pgdo] - generic data object
// [advf] - advise flags to use
// [pszCaller] - name of test
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Create a test advise sink object. Register for an notification
// with the data advise holder. Confirm that the prime first
// notification worked. Confirm that the object did get
// registered. Tell the advise holder to notify all registered
// advises that the data changed. Confirm that the appropriate
// notification was sent. Then deregister the advise. Do it
// again to make sure the connection is no longer valid.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT DoRegisterNotifyDeregister(
IDataAdviseHolder *pdahTest,
IDataObject *pdo,
CGenDataObject *pgdo,
DWORD advf,
char *pszCaller)
{
// Create an advise sink that we can verify the STGMEDIUM
CTestAdviseSink tas(pgdo);
// Where to store the connection
DWORD dwConnection;
// Register the advise
HRESULT hr = pdahTest->Advise(pdo, g_datfeDaTest.GetFormatEtc(),
ADVF_PRIMEFIRST | advf, &tas, &dwConnection);
// Confirm that the advise is notified and in the correct state
if (!tas.ValidOnDataChange())
{
OutputString("%s First OnDataChange invalid!\r\n", pszCaller);
return E_FAIL;
}
// Make sure the advise is registered
if (dwConnection == 0)
{
OutputString("%s did not get Connection!\r\n", pszCaller);
return E_FAIL;
}
// Test regular data change
hr = pdahTest->SendOnDataChange(pdo, 0, 0);
if (hr != NOERROR)
{
OutputString("%s SendOnDataChange unexpected HRESULT = %lx!\r\n",
pszCaller, hr);
return E_FAIL;
}
// Confirm that the advise is notified and in the correct state
if (!tas.ValidOnDataChange())
{
OutputString("%s Second OnDataChange invalid!\r\n", pszCaller);
return E_FAIL;
}
// Test unadvise
hr = pdahTest->Unadvise(dwConnection);
if (hr != NOERROR)
{
OutputString("%s Unadvise unexpected HRESULT = %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
// Test second unadvise on the same connection
hr = pdahTest->Unadvise(dwConnection);
if (hr != OLE_E_NOCONNECTION)
{
OutputString("%s Second Unadvise Bad Hresult = %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: TestRegisterNotifyDegister
//
// Synopsis: Test a simple register/notify/deregister sequence
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestRegisterNotifyDegister(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
return DoRegisterNotifyDeregister(pdahTest, pgdo, pgdo, 0,
"TestRegisterNotifyDegister");
}
//+-------------------------------------------------------------------------
//
// Function: TestRegisterNotifyDegisterNoData
//
// Synopsis: Test a simple register/notify/deregister sequence with
// no data being returned.
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestRegisterNotifyDegisterNoData(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
return DoRegisterNotifyDeregister(pdahTest, pgdo, NULL, ADVF_NODATA,
"TestRegisterNotifyDegisterNoData");
}
//+-------------------------------------------------------------------------
//
// Function: TestNotifyOnStop
//
// Synopsis: Test a registration with a call of notify on stop
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Create a test object. Register it with the advise holder.
// Confirm that the connection was returned and that no
// notification occurred. Then tell the data advise holder
// to notify its registrations of a data change. Make sure
// that the advise was correctly notified. Finally, verify
// that we can deregister the advise and that its connection
// becomes invalid.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestNotifyOnStop(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
// Routine name for messages
char *pszCaller = "TestNotifyOnStop";
// Create an advise sink that we can verify the STGMEDIUM
CTestAdviseSink tas(pgdo);
// Where to store the connection
DWORD dwConnection;
// Register the advise
HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
ADVF_DATAONSTOP, &tas, &dwConnection);
// Make sure the advise is registered
if (dwConnection == 0)
{
OutputString("%s did not get Connection!\r\n", pszCaller);
return E_FAIL;
}
// Confirm that the data object was not notified
if (tas.ValidOnDataChange())
{
OutputString("%s Registration caused notification!\r\n", pszCaller);
return E_FAIL;
}
// Test regular data change
hr = pdahTest->SendOnDataChange(pgdo, 0, ADVF_DATAONSTOP);
if (hr != NOERROR)
{
OutputString("%s SendOnDataChange unexpected HRESULT = %lx!\r\n",
pszCaller, hr);
return E_FAIL;
}
// Confirm that the advise is notified and in the correct state
if (!tas.ValidOnDataChange())
{
OutputString("%s Second OnDataChange invalid!\r\n", pszCaller);
return E_FAIL;
}
// Test unadvise
hr = pdahTest->Unadvise(dwConnection);
if (hr != NOERROR)
{
OutputString("%s Unadvise unexpected HRESULT = %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
// Test second unadvise on the same connection
hr = pdahTest->Unadvise(dwConnection);
if (hr != OLE_E_NOCONNECTION)
{
OutputString("%s Second Unadvise Bad Hresult = %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: TestNotifyOnce
//
// Synopsis: Test a notify once advise
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Create a test advise object. Register it to be advised only
// once of a change. Confirm that we got a registration. Then
// tell the advise holder to notify its advises of a data
// change. Confirm that the correct notification occurred. Finally,
// confirm that we are no longer registered with the advise
// holder.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestNotifyOnce(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
// Routine name for messages
char *pszCaller = "TestNotifyOnce";
// Create an advise sink that we can verify the STGMEDIUM
CTestAdviseSink tas(pgdo);
// Where to store the connection
DWORD dwConnection;
// Register the advise
HRESULT hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
ADVF_ONLYONCE, &tas, &dwConnection);
// Make sure the advise is registered
if (dwConnection == 0)
{
OutputString("%s did not get Connection!\r\n", pszCaller);
return E_FAIL;
}
// Test regular data change
hr = pdahTest->SendOnDataChange(pgdo, 0, 0);
if (hr != NOERROR)
{
OutputString("%s SendOnDataChange unexpected HRESULT = %lx!\r\n",
pszCaller, hr);
return E_FAIL;
}
// Confirm that the advise is notified and in the correct state
if (!tas.ValidOnDataChange())
{
OutputString("%s Send OnDataChange invalid!\r\n", pszCaller);
return E_FAIL;
}
// Try a second notify
hr = pdahTest->SendOnDataChange(pgdo, 0, 0);
// Confirm that the advise is *not* notified
if (tas.ValidOnDataChange())
{
OutputString("%s Second OnDataChange unexpectedly succeeded!\r\n",
pszCaller);
return E_FAIL;
}
// Test unadvise - should fail since we requested to be notified
// only once.
hr = pdahTest->Unadvise(dwConnection);
if (hr != OLE_E_NOCONNECTION)
{
OutputString("%s Second Unadvise Bad Hresult = %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
return NOERROR;
}
//+-------------------------------------------------------------------------
//
// Function: CreateMassRegistration
//
// Synopsis: Register a large number of advise objects with a holder
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
// [pszCaller] - name of test
//
// Returns: NOERROR - all advises were registered
// E_FAIL - error in registration
//
// Algorithm: Create a MAX_REGISTER number of test advise objects and
// store them in the aMassAdvise array. Then register them
// all with the input advise holder.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT CreateMassRegistration(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo,
char *pszCaller)
{
// Create the advise sinks for the test for the test
for (int i = 0; i < MAX_REGISTER; i++)
{
aMassAdvise[i].ptas = new CTestAdviseSink(pgdo);
if (aMassAdvise[i].ptas == NULL)
{
OutputString(
"%s Advise create of test advise failed on %d!\r\n", pszCaller,
i);
return E_FAIL;
}
aMassAdvise[i].dwConnection = 0;
}
HRESULT hr;
// Register the advise sinks
for (i = 0; i < MAX_REGISTER; i++)
{
// Register the advise
hr = pdahTest->Advise(pgdo, g_datfeDaTest.GetFormatEtc(),
0, aMassAdvise[i].ptas, &aMassAdvise[i].dwConnection);
if (hr != NOERROR)
{
OutputString(
"%s Advise unexpected HRESULT = %lx on %d!\r\n", pszCaller,
hr, i);
return E_FAIL;
}
}
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Function: DoMassUnadvise
//
// Synopsis: Deregister all entries in the aMassAdvise array
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pszCaller] - name of test
//
// Returns: NOERROR - deregistration worked
// E_FAIL - error in deregistration
//
// Algorithm: For each entry in the aMassAdvise array, deregister it
// from the holder. Then confirm that its connection is
// no longer valid.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT DoMassUnadvise(
IDataAdviseHolder *pdahTest,
char *pszCaller)
{
HRESULT hr;
// Unadvise them
for (int i = 0; i < MAX_REGISTER; i++)
{
// Test unadvise
hr = pdahTest->Unadvise(aMassAdvise[i].dwConnection);
if (hr != NOERROR)
{
OutputString(
"%s Unadvise unexpected HRESULT = %lx on %d!\r\n", pszCaller,
hr, i);
return E_FAIL;
}
// Test second unadvise on the same connection
hr = pdahTest->Unadvise(aMassAdvise[i].dwConnection);
if (hr != OLE_E_NOCONNECTION)
{
OutputString(
"%s Second Unadvise Bad Hresult = %lx on %d!\r\n", pszCaller,
hr, i);
return E_FAIL;
}
}
// Delete the advise sinks for the test
for (i = 0; i < MAX_REGISTER; i++)
{
delete aMassAdvise[i].ptas ;
}
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Function: TestMassRegister
//
// Synopsis: Test registering a large number of advises with a holder
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Register a large number of test advises with the data advise
// holder. Then tell the advise holder to notify them of
// a change. Confirm that all registered entries were notified.
// Finally, deregister all the test advises.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestMassRegister(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
char *pszCaller = "TestMassRegister";
HRESULT hr = CreateMassRegistration(pdahTest, pgdo, "TestMassRegister");
if (hr != NOERROR)
{
return hr;
}
// Notify them of a change
hr = pdahTest->SendOnDataChange(pgdo, 0, 0);
// Verify that each was notified
for (int i = 0; i < MAX_REGISTER; i++)
{
if (!aMassAdvise[i].ptas->ValidOnDataChange())
{
OutputString(
"%s OnDataChange invalid for entry %d!\r\n", pszCaller, i);
return E_FAIL;
}
}
// Unadvise them and free the memory
return DoMassUnadvise(pdahTest, "TestMassRegister");
}
//+-------------------------------------------------------------------------
//
// Function: TestEnumerator
//
// Synopsis: Test the data advise holder enumerator
//
// Arguments: [pdahTest] - data advise holder we are testing
// [pgdo] - generic data object
//
// Returns: NOERROR - notification was correct
// E_FAIL - error in notification
//
// Algorithm: Create a large number of test advises and register them
// with the advise holder. Get an advise enumerator. Create
// a test enumerator object. Tell the test enumerator object
// to enumerate all the object in the holder. Verify that
// all objects were correctly enumerated. Then release the
// advise holder enumerator. Finally, deregister all the
// test advises from the advise holder.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT TestEnumerator(
IDataAdviseHolder *pdahTest,
CGenDataObject *pgdo)
{
char *pszCaller = "TestEnumerator";
// Do a mass register
HRESULT hr = CreateMassRegistration(pdahTest, pgdo, pszCaller);
if (hr != NOERROR)
{
return hr;
}
// Get an enumerator for this registration
IEnumSTATDATA *penumAdvise;
hr = pdahTest->EnumAdvise(&penumAdvise);
if (hr != NOERROR)
{
OutputString("%s EnumAdvise failed %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
// Create a test enumerator object
CTestDaHolder tdh(penumAdvise, hr);
if (hr != NOERROR)
{
OutputString(
"%s Failed creating CTestDaHolder %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
// Enmerate all 1 by 1
if (tdh.TestNext() != NOERROR)
{
OutputString(
"%s tdh.TestNext failed during enumeration\r\n", pszCaller);
return E_FAIL;
}
// Verify that all entries were enumerated
if (!tdh.VerifyAllEnmerated())
{
OutputString(
"%s tdh.VerifyAllEnmerated failed verification pass\r\n", pszCaller);
return E_FAIL;
}
// Do a test all
if (tdh.TestAll() != NOERROR)
{
OutputString(
"%s tdh.TestAll failed during enumeration\r\n", pszCaller);
return E_FAIL;
}
// Release the advise enumerator
if (penumAdvise->Release() != 0)
{
OutputString(
"%s Failed freeing advise enumerator %lx!\r\n", pszCaller, hr);
return E_FAIL;
}
// Release the registrations
return DoMassUnadvise(pdahTest, pszCaller);
}
//+-------------------------------------------------------------------------
//
// Function: LEDataAdviseHolderTest
//
// Synopsis: Unit test for the data advise holder.
//
// Returns: NOERROR - test passed
// E_FAIL - test failed.
//
// Algorithm: Create an advise holder object. Run through all the test
// cases. Return NOERROR if they succeed or stop with the first
// that fails.
//
// History: dd-mmm-yy Author Comment
// 01-Jun-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT LEDataAdviseHolderTest(void)
{
// Create a data object for use in the test
CGenDataObject *pgdo = new CGenDataObject;
assert(pgdo);
// Create a data advise holder
IDataAdviseHolder *pdahTest;
HRESULT hr = CreateDataAdviseHolder(&pdahTest);
if (hr != NOERROR)
{
OutputString(
"LEDataAdviseHolderTest CreateDataAdviseHolder Faild hr = %lx", hr);
return hr;
}
// Case 1: ADVF_PRIMEFIRST & ADVF_ONLYONCE & ADVF_NODATA
if ((hr = TestPrimeFirstOnlyOnceNoData(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 2: ADVF_PRIMEFIRST
if ((hr = TestPrimeFirstOnlyOnceNoData(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 3: Register/Notify/Deregister
if ((hr = TestRegisterNotifyDegister(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 4: Register/Notify/Deregister with no data returned
if ((hr = TestRegisterNotifyDegisterNoData(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 5: Test notify on stop
if ((hr = TestNotifyOnStop(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 6: Test notify only once
if ((hr = TestNotifyOnce(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 7: Test mass Register/Notify/Deregister
if ((hr = TestMassRegister(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// Case 8: Test Enumerator
if ((hr = TestEnumerator(pdahTest, pgdo)) != NOERROR)
{
return hr;
}
// We are done
DWORD dwFinalRefs = pdahTest->Release();
if (dwFinalRefs != 0)
{
OutputString(
"LEDataAdviseHolderTest Final Release is = %d", dwFinalRefs);
return E_FAIL;
}
pgdo->Release();
return NOERROR;
}