123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- #ifndef __RangeValueImpl_h__
- #define __RangeValueImpl_h__
- /////////////////////////////////////////////////////////////////////////////
- // RangeValueImpl.h | Declaration of the ITCRangeValueImpl template class.
- //
- /////////////////////////////////////////////////////////////////////////////
- // Range Value Macros
- #define DECLARE_RANGE_VALUE_INTERPRET_CHANGE(fn) \
- public: \
- bool InterpretChange(bool bChanged) \
- { \
- return fn##(bChanged); \
- }
- #define BEGIN_RANGE_VALUE_MAP(T) \
- public: \
- typedef HRESULT (T::*XRangeValueApplyProc)(long, long); \
- struct XRangeValueEntry \
- { \
- DISPID dispid; \
- const IID* piid; \
- long nValueMin; \
- long nValueMax; \
- long nValueDefault; \
- long nGranularity; \
- long nTickMarks; \
- XRangeValueApplyProc pfnApply; \
- }; \
- static UINT GetPageFieldTable(const XRangeValueEntry** ppTable) \
- { \
- static const XRangeValueEntry table[] = \
- {
- #define RANGE_VALUE_ENTRY_EX(dispid, iid, minv, maxv, defv, gran, tics, \
- fnApply) \
- {dispid, &iid, minv, maxv, defv, gran, tics, \
- (static_cast<XRangeValueApplyProc>(fnApply))},
- #define RANGE_VALUE_ENTRY(name, minv, maxv, defv, gran, tics) \
- {TCDISPID_##name, &IID_ITC##name, minv, maxv, defv, gran, tics, \
- (static_cast<XRangeValueApplyProc>(OnApply_##name))},
- #define END_RANGE_VALUE_MAP() \
- {0, 0, NULL, NULL, NULL} \
- }; \
- if (ppTable) \
- *ppTable = table; \
- return sizeofArray(table) - 1; \
- }
- /////////////////////////////////////////////////////////////////////////////
- // ITCRangeValueImpl
- template <class T, class _I, const IID* piid, const GUID* plibid,
- WORD wMajor = 1, WORD wMinor = 0>
- class ATL_NO_VTABLE ITCRangeValueImpl :
- public IDispatchImpl<_I, piid, plibid, wMajor, wMinor>
- {
- // Construction
- public:
- ITCRangeValueImpl() : m_pEntry(NULL)
- {
- // Get the derived class pointer
- T* pThis = static_cast<T*>(this);
- // Get the table of range value
- const T::XRangeValueEntry* pTable;
- UINT nCount = pThis->GetPageFieldTable(&pTable);
- // Find the piid in the table
- for (UINT i = 0; i < nCount; i++)
- {
- if (*pTable[i].piid == *piid)
- {
- // Save the range value entry
- m_pEntry = pTable + i;
- // Initialize the value to the default
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- m_nValue = pEntry->nValueDefault;
- break;
- }
- }
- // Ensure that the piid was found in the table
- assert(m_pEntry);
- }
- // Overrides
- public:
- bool InterpretChange(bool bChanged)
- {
- return bChanged;
- }
- // ITCRangeValue Interface Methods
- public:
- STDMETHOD(get_MinValue)(long* pnValue)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- CLEAROUT(pnValue, pEntry->nValueMin);
- return S_OK;
- }
- STDMETHOD(get_MaxValue)(long* pnValue)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- CLEAROUT(pnValue, pEntry->nValueMax);
- return S_OK;
- }
- STDMETHOD(get_DefaultValue)(long* pnValue)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- CLEAROUT(pnValue, pEntry->nValueDefault);
- return S_OK;
- }
- STDMETHOD(get_Granularity)(long* pnGranularity)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- CLEAROUT(pnGranularity, pEntry->nGranularity);
- return S_OK;
- }
- STDMETHOD(get_TickMarks)(long* pnTickMarks)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- // Interpret the tick mark count value
- long nTickMarks = pEntry->nTickMarks;
- if (-1 == nTickMarks)
- nTickMarks =
- DetermineTickMarks(pEntry->nValueMax + 1 - pEntry->nValueMin);
- CLEAROUT(pnTickMarks, nTickMarks);
- return S_OK;
- }
- STDMETHOD(put_RangeValue)(long nValue)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- // Load the specified value into a variant
- CComVariant var(nValue);
- // Call Invoke to set the current value
- DISPID dispid = pEntry->dispid;
- HRESULT hr = CComDispatchDriver::PutProperty(this, dispid, &var);
- if (FAILED(hr))
- {
- ATLTRACE2("ITCRangeValueImpl<%hs, %hs>::put_RangeValue(): ",
- TCTypeName(T), TCTypeName(_I));
- ATLTRACE1("Invoke failed on DISPID %08X\n", dispid);
- }
- // Return the last HRESULT
- return hr;
- }
- STDMETHOD(get_RangeValue)(long* pnValue)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- // Call Invoke to get the current value
- CComVariant var;
- DISPID dispid = pEntry->dispid;
- HRESULT hr = CComDispatchDriver::GetProperty(this, dispid, &var);
- if (FAILED(hr))
- {
- ATLTRACE2("ITCRangeValueImpl<%hs, %hs>::get_RangeValue(): ",
- TCTypeName(T), TCTypeName(_I));
- ATLTRACE1("Invoke failed on DISPID %08X\n", dispid);
- return hr;
- }
- // Ensure that the type is a long
- if (FAILED(hr = var.ChangeType(VT_I4)))
- return hr;
- // Copy the value to the specified [out] parameter
- CLEAROUT(pnValue, V_I4(&var));
- // Indicate success
- return S_OK;
- }
- STDMETHOD(put_CurrentValue)(long nValue)
- {
- assert(m_pEntry);
- T::XRangeValueEntry* pEntry = (T::XRangeValueEntry*)m_pEntry;
- // Validate the specified parameter
- if (nValue < pEntry->nValueMin || nValue > pEntry->nValueMax)
- return E_INVALIDARG;
- // Get the derived class pointer
- T* pThis = static_cast<T*>(this);
- // Lock the object
- pThis->Lock();
- // Set the property value
- long nValuePrev = m_nValue;
- HRESULT hr = TCComPropertyPut(pThis, m_nValue, nValue);
- if (SUCCEEDED(hr) && pThis->InterpretChange(nValuePrev != m_nValue))
- {
- // Apply the changed value
- __try
- {
- T::XRangeValueApplyProc pfnApply = pEntry->pfnApply;
- hr = (pThis->*pfnApply)(nValue, nValuePrev);
- }
- __except(1)
- {
- hr = RPC_E_SERVERFAULT;
- }
- // Unlock the object
- pThis->Unlock();
- // Fire the property change notification, if value was applied
- if (S_OK == hr)
- pThis->FireOnChanged(pEntry->dispid);
- }
- else
- {
- // Unlock the object
- pThis->Unlock();
- }
- // Return the last result
- return hr;
- }
- STDMETHOD(get_CurrentValue)(long* pnValue)
- {
- // Get the derived class pointer
- T* pThis = static_cast<T*>(this);
- // Get the property value
- return TCComPropertyGet(pThis, pnValue, m_nValue);
- }
- // Implementation
- protected:
- static long DetermineTickMarks(long nSteps)
- {
- // Declare an array of the preferred tick mark counts
- const static long nFreqs[] = {16, 16, 10, 12, 8};
- const static long nFreqCount = sizeofArray(nFreqs);
- assert(nFreqCount);
- // Use 1 if specified step count <= the largest preferred tick mark count
- if (nSteps <= nFreqs[0])
- return nSteps;
- // Loop thru preferred frequencies
- long nBestMod = nFreqs[0], nBestFreq = nFreqs[0];
- for (int i = 1; i < nFreqCount; ++i)
- {
- long nMod = nSteps % nFreqs[i];
- if (0 == nMod)
- return nFreqs[i];
- // Save this remainder and frequency if the best so far
- if (nMod < nBestMod)
- {
- nBestMod = nMod;
- nBestFreq = nFreqs[i];
- }
- }
- // If no even divisor amongst the preferred frequencies, check all others
- for (long iFreq = nFreqs[0]; iFreq > nFreqs[nFreqCount - 1]; --iFreq)
- {
- long nMod = nSteps % iFreq;
- if (0 == nMod)
- return nFreqs[i];
- // Save this remainder and frequency if the best so far
- if (nMod < nBestMod)
- {
- nBestMod = nMod;
- nBestFreq = nFreqs[i];
- }
- }
- // If still no even divisor, return the best match
- return nBestFreq;
- }
- // Data Members
- protected:
- long m_nValue;
- const void* m_pEntry;
- };
- /////////////////////////////////////////////////////////////////////////////
- #endif // !__RangeValueImpl_h__
|