bullseyeproppage.cpp
来自「《ATL深入解析》随书源码」· C++ 代码 · 共 416 行
CPP
416 行
// BullsEyePropPage.cpp : Implementation of CBullsEyePropPage
#include "stdafx.h"
#include "BullsEyeCtl.h"
#include "BullsEyePropPage.h"
/////////////////////////////////////////////////////////////////////////////
// IPropertyPage interface methods
/**************/
/* SetObjects */
/**************/
// Implementation notes:
// Visual Basic 6 does not obey the stated requirements for this method.
// Here are the requirements:
// The property page is required to keep the pointers returned by this method
// or others queried through them. If these specific IUnknown pointers are held,
// the property page must call IUnknown::AddRef through each when caching them,
// until the time when IPropertyPage::SetObjects is called with cObjects equal to zero.
// At that time, the property page must call IUnknown::Release through each pointer,
// releasing any objects that it held.
// The caller must provide the property page with these objects before calling
// IPropertyPage::Activate, and should call IPropertyPage::SetObjects with zero
// as the parameter when deactivating the page or when releasing the object entirely.
// Each call to SetObjects with a non-NULL ppUnk parameter must be matched with a
// later call to SetObjects with zero in the cObjects parameter.
// Visual Basic 6 can repeatedly call SetObjects with non-zero in the cObjects parameter
// with no intervening call to SetObjects with zero as the cObjects parameter.
// To reproduce:
// In design mode: Add control(s) to form. Select control(s).
// Display the controls' property page(s) (View Property Pages (Shift+F4)).
// VB calls SetObjects with a non-zero cObjects to send the selected object(s)
// to the property page (as it should).
// Change a property using VB's View Property Window (F4)
// VB calls SetObjects *again* with a non-zero cObjects presumably so that the
// the property page reloads the changed property from the object(s).
// Implementing IPropertyNotifySink on the property page (the correct way to
// receive property change notifications) doesn't affect this behavior.
// Visual Basic 6 normally *never* calls SetObjects with zero in the cObjects parameter.
// To reproduce:
// Do the above and close the VB project.
// Notice that SetObjects is never called to release the object array.
// Workaround is to released the array in the property page destructor
// if it isn't already released.
// Visual Basic 6 only calls SetObjects with zero in the cObjects parameter when
// a preceding call to SetObjects with a non-zero value for cObjects returns
// a failure status.
STDMETHODIMP CBullsEyePropPage::SetObjects(ULONG cObjects, IUnknown** ppUnk)
{
ATLTRACE2(atlTraceControls,2,_T("CBullsEyePropPage::SetObjects\n"));
if (ppUnk == NULL) return E_POINTER;
///////////////////////////////////////////////////////
// Remove previous objects, connections, and cookies //
///////////////////////////////////////////////////////
CleanupObjectArray();
///////////////////////////////////////////////////////////////////
// Allocate new object array, make connections, and save cookies //
///////////////////////////////////////////////////////////////////
if (cObjects > 0) {
// Allocate object array
ATLTRY(m_ppUnk = new LPUNKNOWN[cObjects]);
if (m_ppUnk == NULL) return E_OUTOFMEMORY;
// Allocate connection cookies
ATLTRY(m_pCookies = new DWORD[cObjects]);
if (m_pCookies == NULL) {
delete [] m_ppUnk;
m_ppUnk = NULL;
return E_OUTOFMEMORY;
}
// Make a connection to each object's connection point
for (UINT i = 0; i < cObjects; i++) {
// Ensure object supports the default interface...
// We need this interface to send changes back to object
HRESULT hr = ppUnk[i]->QueryInterface (IID_IBullsEye, (void**)&m_ppUnk[i]);
if (FAILED(hr)) return hr;
// Establish a connection point from object to our sink...
// We need this to receive change notifications from the object
hr = AtlAdvise(m_ppUnk[i],
static_cast<IPropertyNotifySink*>(this),
IID_IPropertyNotifySink,
&m_pCookies[i]);
// if (FAILED(hr)) return hr;
}
}
m_nObjects = cObjects;
////////////////////////////////////////////////////////////
// Transfer properties from first object to property page //
////////////////////////////////////////////////////////////
InitializeControlsFromObject (DISPID_UNKNOWN);
return S_OK;
}
/************/
/* Activate */
/************/
STDMETHODIMP CBullsEyePropPage::Activate(HWND hWndParent, LPCRECT pRect, BOOL bModal)
{
ATLTRACE(_T("CBullsEyePropPage::Activate\n"));
HRESULT hr = IPropertyPage2Impl<CBullsEyePropPage>::Activate(hWndParent, pRect, bModal);
if (SUCCEEDED (hr) && DISPID_UNKNOWN != m_EditProperty) {
EditProperty (m_EditProperty);
m_EditProperty = DISPID_UNKNOWN;
}
return hr;
}
/*********/
/* Apply */
/*********/
STDMETHODIMP CBullsEyePropPage::Apply(void)
{
ATLTRACE(_T("CBullsEyePropPage::Apply\n"));
SetPropertiesFromControls(DISPID_UNKNOWN);
m_bDirty = FALSE;
m_flags = 0;
return S_OK;
}
/****************/
/* EditProperty */
/****************/
STDMETHODIMP CBullsEyePropPage::EditProperty(DISPID dispid)
{
ATLTRACE(_T("CBullsEyePropPage::EditProperty\n"));
m_EditProperty = dispid;
if (IsWindow()) {
switch (dispid) {
case DISPID_BEEP:
::SetFocus(GetDlgItem (IDC_BEEP));
break;
case DISPID_ENABLED:
::SetFocus(GetDlgItem (IDC_ENABLED));
break;
case DISPID_RINGCOUNT:
::SetFocus(GetDlgItem (IDC_RINGCOUNT));
break;
case DISPID_BACKSTYLE:
::SetFocus(GetDlgItem (IDC_TRANSPARENT));
break;
default:
return E_INVALIDARG;
}
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IPropertyNotifySink interface methods
STDMETHODIMP CBullsEyePropPage::OnChanged(DISPID dispid)
{
InitializeControlsFromObject (dispid);
return S_OK;
}
STDMETHODIMP CBullsEyePropPage::OnRequestEdit(DISPID dispid)
{
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CBullsEyePropPage window message handlers
/****************/
/* OnInitDialog */
/****************/
LRESULT CBullsEyePropPage::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
InitializeControlsFromObject (DISPID_UNKNOWN);
return 0;
}
/************/
/* OnCreate */
/************/
LRESULT CBullsEyePropPage::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
INITCOMMONCONTROLSEX ic = { sizeof (ic), ICC_UPDOWN_CLASS };
BOOL bInit = InitCommonControlsEx (&ic);
return 0;
}
/*************/
/* OnDestroy */
/*************/
LRESULT CBullsEyePropPage::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CleanupObjectArray();
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CBullsEyePropPage control notification handlers
/*****************/
/* OnClickedBeep */
/*****************/
LRESULT CBullsEyePropPage::OnClickedBeep(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
m_beepNew = (BST_CHECKED == SendDlgItemMessage (wID, BM_GETCHECK)) ? VARIANT_TRUE : VARIANT_FALSE;
if (m_beepNew != m_beepOrig)
m_flags |= BEEP_CHANGED;
else
m_flags &= ~BEEP_CHANGED;
SetDirty (m_flags != 0);
return 0;
}
/********************/
/* OnClickedEnabled */
/********************/
LRESULT CBullsEyePropPage::OnClickedEnabled(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
m_enabledNew = (BST_CHECKED == SendDlgItemMessage (wID, BM_GETCHECK)) ? VARIANT_TRUE : VARIANT_FALSE;
if (m_enabledNew != m_enabledOrig)
m_flags |= ENABLED_CHANGED;
else
m_flags &= ~ENABLED_CHANGED;
SetDirty (m_flags != 0);
return 0;
}
/*********************/
/* OnChangeRingCount */
/*********************/
LRESULT CBullsEyePropPage::OnChangeRingCount(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
BOOL bTranslated = FALSE;
m_ringCountNew = (short) GetDlgItemInt (IDC_RINGCOUNT, &bTranslated, FALSE);
if (!bTranslated || m_ringCountNew < 1 || m_ringCountNew > 9) {
// Non-numeric or out of range value in edit control - reinitialize it
SendDlgItemMessage (IDC_SPIN1, UDM_SETPOS, 0, MAKELONG(m_ringCountNew, 0));
return 0;
}
if (m_ringCountOrig != m_ringCountNew)
m_flags |= RINGCOUNT_CHANGED;
else
m_flags &= ~RINGCOUNT_CHANGED;
SetDirty (m_flags != 0);
return 0;
}
/************************/
/* OnClickedTransparent */
/************************/
LRESULT CBullsEyePropPage::OnClickedTransparent(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
m_transparentNew = (BST_CHECKED == SendDlgItemMessage (wID, BM_GETCHECK)) ? 1 : 0;
if (m_transparentNew != m_transparentOrig)
m_flags |= TRANSPARENT_CHANGED;
else
m_flags &= ~TRANSPARENT_CHANGED;
SetDirty (m_flags != 0);
return 0;
}
/********************************/
/* InitializeControlsFromObject */
/********************************/
void CBullsEyePropPage::InitializeControlsFromObject(DISPID dispid)
{
// The array already contains IBullsEye* so this is redundant...
CComQIPtr<IBullsEye> pBullsEye = m_ppUnk[0];
if (DISPID_RINGCOUNT == dispid || DISPID_UNKNOWN == dispid) {
// Get RingCount property
HRESULT hr = pBullsEye->get_RingCount (&m_ringCountOrig);
ATLASSERT (SUCCEEDED (hr));
m_ringCountNew = m_ringCountOrig;
if (IsWindow ()) {
SendDlgItemMessage (IDC_SPIN1, UDM_SETRANGE, 0, MAKELONG(9, 1));
SendDlgItemMessage (IDC_SPIN1, UDM_SETPOS, 0, MAKELONG(m_ringCountOrig, 0));
}
}
if (DISPID_BEEP == dispid || DISPID_UNKNOWN == dispid) {
// Get Beep property
HRESULT hr = pBullsEye->get_Beep (&m_beepOrig);
ATLASSERT (SUCCEEDED (hr));
m_beepNew = m_beepOrig;
if (IsWindow ()) {
SendDlgItemMessage (IDC_BEEP, BM_SETCHECK, m_beepOrig ? BST_CHECKED : BST_UNCHECKED);
}
}
if (DISPID_ENABLED == dispid || DISPID_UNKNOWN == dispid) {
// Get Enabled property
HRESULT hr = pBullsEye->get_Enabled (&m_enabledOrig);
ATLASSERT (SUCCEEDED (hr));
m_enabledNew = m_enabledOrig;
if (IsWindow ()) {
SendDlgItemMessage (IDC_ENABLED, BM_SETCHECK, m_enabledOrig ? BST_CHECKED : BST_UNCHECKED);
}
}
if (DISPID_BACKSTYLE == dispid || DISPID_UNKNOWN == dispid) {
// Get Enabled property
HRESULT hr = pBullsEye->get_BackStyle (&m_transparentOrig);
ATLASSERT (SUCCEEDED (hr));
m_transparentNew = m_transparentOrig;
if (IsWindow ()) {
SendDlgItemMessage (IDC_TRANSPARENT, BM_SETCHECK, m_transparentOrig ? BST_CHECKED : BST_UNCHECKED);
}
}
}
/*****************************/
/* SetPropertiesFromControls */
/*****************************/
void CBullsEyePropPage::SetPropertiesFromControls(DISPID dispid)
{
// In case QI failed in SetObjects
if (!m_ppUnk || !m_ppUnk[0]) return;
// For all objects in array...
for (UINT i = 0; i < m_nObjects; i++) {
// Get the appropriate interface...
CComQIPtr<IBullsEye> pBullsEye = m_ppUnk[i];
// Update the RingCount property, if requested and required
if ((DISPID_RINGCOUNT == dispid || DISPID_UNKNOWN == dispid) &&
m_flags & RINGCOUNT_CHANGED) {
pBullsEye->put_RingCount(m_ringCountNew); // Update property
m_ringCountOrig = m_ringCountNew; // Prop page and property synced
m_flags &= ~RINGCOUNT_CHANGED; // Clear changed flag
}
// Update the Beep property, if requested and required
if ((DISPID_BEEP == dispid || DISPID_UNKNOWN == dispid) &&
m_flags & BEEP_CHANGED) {
pBullsEye->put_Beep(m_beepNew); // Update property
m_beepOrig = m_beepNew; // Prop page and property synced
m_flags &= ~BEEP_CHANGED; // Clear changed flag
}
// Update the Enabled property, if requested and required
if ((DISPID_ENABLED == dispid || DISPID_UNKNOWN == dispid) &&
m_flags & ENABLED_CHANGED) {
pBullsEye->put_Enabled(m_enabledNew); // Update property
m_enabledOrig = m_enabledNew; // Prop page and property synced
m_flags &= ~ENABLED_CHANGED; // Clear changed flag
}
// Update the BackStyle property, if requested and required
if ((DISPID_BACKSTYLE == dispid || DISPID_UNKNOWN == dispid) &&
m_flags & TRANSPARENT_CHANGED) {
pBullsEye->put_BackStyle(m_transparentNew); // Update property
m_transparentOrig = m_transparentNew; // Prop page and property synced
m_flags &= ~TRANSPARENT_CHANGED; // Clear changed flag
}
}
}
/**********************/
/* CleanupObjectArray */
/**********************/
void CBullsEyePropPage::CleanupObjectArray()
{
// Free existing array of objects, if any
if (m_ppUnk != NULL && m_nObjects > 0) {
for (UINT i = 0; i < m_nObjects; i++) {
if (NULL == m_ppUnk[i]) break;
// Unadvise the connection
AtlUnadvise(m_ppUnk[i], IID_IPropertyNotifySink, m_pCookies[i]);
m_ppUnk[i]->Release();
}
delete [] m_ppUnk;
delete [] m_pCookies;
}
// Currently no objects in list
m_ppUnk = NULL;
m_pCookies = NULL;
m_nObjects = 0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?