POLYPROP.CPP
/* 
 * POLYPROP.CPP 
 * Polyline Property Page Chapter 24 
 * 
 * Server module code and class code CPolyPropertyPage class. 
 * 
 * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 
 * 
 * Kraig Brockschmidt, Microsoft 
 * Internet  :  kraigb@microsoft.com 
 * Compuserve:  >INTERNET:kraigb@microsoft.com 
 */ 
 
 
#define INITGUIDS 
#include "polyprop.h" 
 
 
//Count number of objects and number of locks. 
ULONG       g_cObj=0; 
ULONG       g_cLock=0; 
HINSTANCE   g_hInst=NULL;   //For resources 
 
#ifdef WIN32 
TCHAR       g_szObj[]=TEXT("Object"); 
#else 
TCHAR       g_szObjHi[]=TEXT("ObjectHi"); 
TCHAR       g_szObjLo[]=TEXT("ObjectLo"); 
#endif 
 
/* 
 * LibMain(32) 
 * 
 * Purpose: 
 *  Entry point conditionally compiled for Win32 and Windows 
 *  3.1.  Provides the proper structure for each environment. 
 */ 
 
#ifdef WIN32 
BOOL WINAPI LibMain32(HINSTANCE hInstance, ULONG ulReason 
    , LPVOID pvReserved) 
    { 
    g_hInst=hInstance; 
 
    if (DLL_PROCESS_DETACH==ulReason) 
        { 
        return TRUE; 
        } 
    else 
        { 
        if (DLL_PROCESS_ATTACH!=ulReason) 
            return TRUE; 
        } 
 
    return TRUE; 
    } 
#else 
int PASCAL LibMain(HINSTANCE hInstance, WORD wDataSeg 
    , WORD cbHeapSize, LPSTR lpCmdLine) 
    { 
    if (0!=cbHeapSize) 
        UnlockData(0); 
 
    g_hInst=hInstance; 
    return (int)hInstance; 
    } 
#endif 
 
 
 
/* 
 * DllGetClassObject 
 * DllCanUnloadNow 
 * Standard COM exports for DLL servers. 
 */ 
 
HRESULT APIENTRY DllGetClassObject(REFCLSID rclsid, REFIID riid 
    , PPVOID ppv) 
    { 
    CPolyPPFactory *pPF; 
    HRESULT         hr; 
 
    if (CLSID_PolylinePropPage!=rclsid) 
        return ResultFromScode(E_FAIL); 
 
    //Check that we can provide the interface 
    if (IID_IUnknown!=riid && IID_IClassFactory!=riid) 
        return ResultFromScode(E_NOINTERFACE); 
 
    //Return our factory's IClassFactory 
    pPF=new CPolyPPFactory(); 
 
    if (NULL==pPF) 
        return ResultFromScode(E_OUTOFMEMORY); 
 
    //If the factory hasn't the interface, delete it 
    hr=pPF->QueryInterface(riid, ppv); 
 
    if (FAILED(hr)) 
        delete pPF; 
    else 
        g_cObj++; 
 
    return hr; 
    } 
 
 
STDAPI DllCanUnloadNow(void) 
    { 
    SCODE   sc; 
 
    //Our answer is whether there are any object or locks 
    sc=(0L==g_cObj && 0L==g_cLock) ? S_OK : S_FALSE; 
    return ResultFromScode(sc); 
    } 
 
 
 
/* 
 * CPolyPPFactory::CPolyPPFactory 
 * CPolyPPFactory::~CPolyPPFactory 
 * CPolyPPFactory::QueryInterface 
 * CPolyPPFactory::AddRef 
 * CPolyPPFactory::Release 
 */ 
 
CPolyPPFactory::CPolyPPFactory(void) 
    { 
    m_cRef=0L; 
    return; 
    } 
 
CPolyPPFactory::~CPolyPPFactory(void) 
    { 
    return; 
    } 
 
STDMETHODIMP CPolyPPFactory::QueryInterface(REFIID riid, PPVOID ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid || IID_IClassFactory==riid) 
        *ppv=this; 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CPolyPPFactory::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
 
STDMETHODIMP_(ULONG) CPolyPPFactory::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    delete this; 
    g_cObj--; 
    return 0; 
    } 
 
 
 
/* 
 * CPolyPPFactory::CreateInstance 
 * CPolyPPFactory::LockServer 
 */ 
 
STDMETHODIMP CPolyPPFactory::CreateInstance(LPUNKNOWN pUnkOuter 
    , REFIID riid, PPVOID ppvObj) 
    { 
    PCPolyPropPage      pObj; 
    HRESULT             hr; 
 
    *ppvObj=NULL; 
    hr=ResultFromScode(E_OUTOFMEMORY); 
 
    //No aggregation supported 
    if (NULL!=pUnkOuter) 
        return ResultFromScode(CLASS_E_NOAGGREGATION); 
 
    //Create the object passing function to notify on destruction. 
    pObj=new CPolyPropPage(g_hInst); 
 
    if (NULL==pObj) 
        return hr; 
 
    if (pObj->Init()) 
        hr=pObj->QueryInterface(riid, ppvObj); 
 
    //Kill the object if initial creation or Init failed. 
    if (FAILED(hr)) 
        delete pObj; 
    else 
        g_cObj++; 
 
    return hr; 
    } 
 
 
STDMETHODIMP CPolyPPFactory::LockServer(BOOL fLock) 
    { 
    if (fLock) 
        g_cLock++; 
    else 
        g_cLock--; 
 
    return NOERROR; 
    } 
 
 
 
/*** 
 *** CPolyPropPage implementation 
 ***/ 
 
 
/* 
 * CPolyPropPage::CPolyPropPage 
 * CPolyPropPage::~CPolyPropPage 
 * 
 * Constructor Parameters: 
 *  hInst           HINSTANCE of the module 
 */ 
 
CPolyPropPage::CPolyPropPage(HINSTANCE hInst) 
    { 
    m_cRef=0L; 
 
    m_hInst=hInst; 
    m_hDlg=NULL; 
 
    //Default sizes 
    m_cx=300; 
    m_cy=100; 
 
    m_pIPropertyPageSite=NULL; 
    m_ppObj=NULL; 
    m_cObjects=0; 
 
    m_uIDLastLine=ID_LINESOLID; 
    m_crLastBack=0; 
    m_crLastLine=0; 
 
    m_fDirty=FALSE; 
    return; 
    } 
 
CPolyPropPage::~CPolyPropPage(void) 
    { 
    if (NULL!=m_hDlg) 
        DestroyWindow(m_hDlg); 
 
    FreeAllObjects(); 
    ReleaseInterface(m_pIPropertyPageSite); 
    return; 
    } 
 
 
/* 
 * CPolyPropPage::QueryInterface 
 * CPolyPropPage::AddRef 
 * CPolyPropPage::Release 
 */ 
 
STDMETHODIMP CPolyPropPage::QueryInterface(REFIID riid, PPVOID ppv) 
    { 
    *ppv=NULL; 
 
    if (IID_IUnknown==riid || IID_IPropertyPage==riid) 
        *ppv=this; 
 
    if (NULL!=*ppv) 
        { 
        ((LPUNKNOWN)*ppv)->AddRef(); 
        return NOERROR; 
        } 
 
    return ResultFromScode(E_NOINTERFACE); 
    } 
 
 
STDMETHODIMP_(ULONG) CPolyPropPage::AddRef(void) 
    { 
    return ++m_cRef; 
    } 
 
 
STDMETHODIMP_(ULONG) CPolyPropPage::Release(void) 
    { 
    if (0!=--m_cRef) 
        return m_cRef; 
 
    g_cObj--; 
    delete this; 
    return 0; 
    } 
 
 
 
 
/* 
 * CPolyPropPage::Init 
 * 
 * Purpose: 
 *  Performs initialization operations that might fail. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  BOOL            TRUE if initialization successful, FALSE 
 *                  otherwise. 
 */ 
 
BOOL CPolyPropPage::Init(void) 
    { 
    //Nothing to do 
    return TRUE; 
    } 
 
 
 
 
/* 
 * CPolyPropPage::FreeAllObjects 
 * 
 * Purpose: 
 *  Releases all the objects from IPropertyPage::SetObjects 
 * 
 * Parameters: 
 *  None 
 */ 
 
void CPolyPropPage::FreeAllObjects(void) 
    { 
    UINT        i; 
 
    if (NULL==m_ppObj) 
        return; 
 
    for (i=0; i < m_cObjects; i++) 
        ReleaseInterface(m_ppObj[i]); 
 
    delete [] m_ppObj; 
    m_ppObj=NULL; 
    m_cObjects=0; 
    return; 
    } 
 
 
 
/* 
 * CPolyPropPage::SetPageSite 
 * 
 * Purpose: 
 *  Provides the property page with the IPropertyPageSite 
 *  that contains it.  SetPageSite(NULL) will be called as 
 *  part of the close sequence. 
 * 
 * Parameters: 
 *  pPageSite       LPPROPERTYPAGESITE pointer to the site. 
 */ 
 
STDMETHODIMP CPolyPropPage::SetPageSite 
    (LPPROPERTYPAGESITE pPageSite) 
    { 
    if (NULL==pPageSite) 
        ReleaseInterface(m_pIPropertyPageSite) 
    else 
        { 
        HWND        hDlg; 
        RECT        rc; 
 
        m_pIPropertyPageSite=pPageSite; 
        m_pIPropertyPageSite->AddRef(); 
 
        //We ignore locales 
 
        /* 
         * Load the dialog and determine the size it will be to 
         * return through GetPageSize.  We just create the dialog 
         * here and destroy it again to retrieve the size, 
         * leaving Activate to create it for real. 
         */ 
        hDlg=CreateDialogParam(m_hInst 
            , MAKEINTRESOURCE(IDD_POLYLINEPROPS), GetDesktopWindow() 
            , (DLGPROC)PolyPropPageProc, 0L); 
 
        //If creation fails, use default values set in constructor 
        if (NULL!=hDlg) 
            { 
            GetWindowRect(hDlg, &rc); 
            m_cx=rc.right-rc.left; 
            m_cy=rc.bottom-rc.top; 
 
            DestroyWindow(hDlg); 
            } 
        } 
 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::Activate 
 * 
 * Purpose: 
 *  Instructs the property page to create a window in which to 
 *  display its contents, using the given parent window and 
 *  rectangle.  The window should be initially visible. 
 * 
 * Parameters: 
 *  hWndParent      HWND of the parent window. 
 *  prc             LPCRECT of the rectangle to use. 
 *  fModal          BOOL indicating whether the frame is modal. 
 */ 
 
STDMETHODIMP CPolyPropPage::Activate(HWND hWndParent 
    , LPCRECT prc, BOOL fModal) 
    { 
    if (NULL!=m_hDlg) 
        return ResultFromScode(E_UNEXPECTED); 
 
    m_hDlg=CreateDialogParam(m_hInst 
        , MAKEINTRESOURCE(IDD_POLYLINEPROPS) 
        , hWndParent, PolyPropPageProc, (LPARAM)this); 
 
    if (NULL==m_hDlg) 
        return ResultFromScode(E_OUTOFMEMORY); 
 
    //Move the page into position and show it. 
    SetWindowPos(m_hDlg, NULL, prc->left, prc->top 
        , prc->right-prc->left, prc->bottom-prc->top, 0); 
 
return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::Deactivate 
 * 
 * Purpose: 
 *  Instructs the property page to destroy its window that was 
 *  created in Activate. 
 * 
 * Parameters: 
 *  None 
 */ 
 
STDMETHODIMP CPolyPropPage::Deactivate(void) 
    { 
    if (NULL==m_hDlg) 
        return ResultFromScode(E_UNEXPECTED); 
 
    DestroyWindow(m_hDlg); 
    m_hDlg=NULL; 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::GetPageInfo 
 * 
 * Purpose: 
 *  Fills a PROPPAGEINFO structure describing the page's size, 
 *  contents, and help information. 
 * 
 * Parameters: 
 *  pPageInfo       LPPROPPAGEINFO to the structure to fill. 
 */ 
 
STDMETHODIMP CPolyPropPage::GetPageInfo(LPPROPPAGEINFO pPageInfo) 
    { 
    IMalloc     *pIMalloc; 
 
    if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) 
        return ResultFromScode(E_FAIL); 
 
    pPageInfo->pszTitle=(LPOLESTR)pIMalloc->Alloc(80*sizeof(TCHAR)); 
 
    if (NULL!=pPageInfo->pszTitle) 
       #ifdef WIN32ANSI 
        wcscpy(pPageInfo->pszTitle, OLETEXT("General")); 
       #else 
        lstrcpy(pPageInfo->pszTitle, TEXT("General")); 
       #endif 
 
    pIMalloc->Release(); 
 
pPageInfo->size.cx      = m_cx; 
    pPageInfo->size.cy      = m_cy; 
pPageInfo->pszDocString = NULL; 
pPageInfo->pszHelpFile  = NULL; 
pPageInfo->dwHelpContext= 0; 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::SetObjects 
 * 
 * Purpose: 
 *  Identifies the objects that are being affected by this property 
 *  page (and all other pages in the frame).  These are the object 
 *  to which to send new property values in the Apply member. 
 * 
 * Parameters: 
 *  cObjects        ULONG number of objects 
 *  ppUnk           IUnknown ** to the array of objects being 
 *                  passed to the page. 
 */ 
 
STDMETHODIMP CPolyPropPage::SetObjects(ULONG cObjects 
    , IUnknown **ppUnk) 
    { 
    BOOL        fRet=TRUE; 
 
    FreeAllObjects(); 
 
    if (0!=cObjects) 
        { 
        UINT        i; 
        HRESULT     hr; 
 
        m_ppObj=new IPolylineControl * [(UINT)cObjects]; 
 
    for (i=0; i < cObjects; i++) 
        { 
            hr=ppUnk[i]->QueryInterface(IID_IPolylineControl 
                , (void **)&m_ppObj[i]); 
 
            if (FAILED(hr)) 
                fRet=FALSE; 
        } 
    } 
 
    //If we didn't get one of our objects, fail this call. 
    if (!fRet) 
        return ResultFromScode(E_FAIL); 
 
    m_cObjects=cObjects; 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::Show 
 * 
 * Purpose: 
 *  Instructs the page to show or hide its window created in 
 *  Activate. 
 * 
 * Parameters: 
 *  nCmdShow        UINT to pass to ShowWindow. 
 */ 
 
STDMETHODIMP CPolyPropPage::Show(UINT nCmdShow) 
    { 
    if (NULL==m_hDlg) 
        ResultFromScode(E_UNEXPECTED); 
 
    ShowWindow(m_hDlg, nCmdShow); 
 
    //Take the focus 
    if (SW_SHOWNORMAL==nCmdShow || SW_SHOW==nCmdShow) 
SetFocus(m_hDlg); 
 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::Move 
 * 
 * Purpose: 
 *  Instructs the property page to change its position. 
 * 
 * Parameters: 
 *  prc             LPCRECT containing the new position. 
 */ 
 
STDMETHODIMP CPolyPropPage::Move(LPCRECT prc) 
    { 
    SetWindowPos(m_hDlg, NULL, prc->left, prc->top 
        , prc->right-prc->left, prc->bottom-prc->top, 0); 
 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::IsPageDirty 
 * 
 * Purpose: 
 *  Asks the page if anything's changed in it, that is, if the 
 *  property values in the page are out of sync with the objects 
 *  under consideration. 
 * 
 * Parameters: 
 *  None 
 * 
 * Return Value: 
 *  HRESULT         NOERROR if dirty, S_FALSE if not. 
 */ 
 
STDMETHODIMP CPolyPropPage::IsPageDirty(void) 
    { 
    return ResultFromScode(m_fDirty ? S_OK : S_FALSE); 
    } 
 
 
 
 
/* 
 * CPolyPropPage::Apply 
 * 
 * Purpose: 
 *  Instructs the page to send changes in its page to whatever 
 *  objects it knows about through SetObjects.  This is the only 
 *  time the page should change the objects' properties, and not 
 *  when the value is changed on the page. 
 * 
 * Parameters: 
 *  None 
 */ 
 
STDMETHODIMP CPolyPropPage::Apply(void) 
    { 
    UINT        i; 
    UINT        iLine, iLineNew; 
    COLORREF    crNew; 
    BOOL        fChanged; 
 
    if (0==m_cObjects) 
        return NOERROR; 
 
    /* 
     * The dialog's last known line selection is in m_uIDLastLine, 
     * colors in m_crLastBack and m_crLastLine, so we can just 
     * send these to IPolylineControl member functions. 
     * We the test if the change took place to determine whether 
     * we set our dirty flag. 
     */ 
 
    iLine=m_uIDLastLine-ID_LINEMIN; 
    fChanged=FALSE; 
 
    for (i=0; i < m_cObjects; i++) 
        { 
        m_ppObj[i]->put_LineStyle(iLine); 
        iLineNew=m_ppObj[i]->get_LineStyle(); 
 
        fChanged |= (iLine!=iLineNew); 
 
        m_ppObj[i]->put_BackColor(m_crLastBack); 
        crNew=m_ppObj[i]->get_BackColor(); 
 
        fChanged |= (m_crLastBack!=crNew); 
 
        m_ppObj[i]->put_LineColor(m_crLastLine); 
        crNew=m_ppObj[i]->get_LineColor(); 
 
        fChanged |= (m_crLastLine!=crNew); 
        } 
 
    m_fDirty=!fChanged; 
    return NOERROR; 
    } 
 
 
 
/* 
 * CPolyPropPage::Help 
 * 
 * Purpose: 
 *  Invokes help for this property page when the user presses 
 *  the Help button.  If you return NULLs for the help file 
 *  in GetPageInfo, the button will be grayed.  Otherwise the 
 *  page can perform its own help here. 
 * 
 * Parameters: 
 *  pszHelpDir      LPCOLESTR identifying the default location of 
 *                  the help information 
 * 
 * Return Value: 
 *  HRESULT         NOERROR to tell the frame that we've done our 
 *                  own help.  Returning an error code or S_FALSE 
 *                  causes the frame to use any help information 
 *                  in PROPPAGEINFO. 
 */ 
 
STDMETHODIMP CPolyPropPage::Help(LPCOLESTR pszHelpDir) 
    { 
    /* 
     * We can either provide help ourselves, or rely on the 
     * information in PROPPAGEINFO. 
     */ 
    return ResultFromScode(S_FALSE); 
    } 
 
 
 
 
/* 
 * CPolyPropPage::TranslateAccelerator 
 * 
 * Purpose: 
 *  Provides the page with the messages that occur in the frame. 
 *  This gives the page to do whatever it wants with the message, 
 *  such as handle keyboard mnemonics. 
 * 
 * Parameters: 
 *  pMsg            LPMSG containing the keyboard message. 
 */ 
 
STDMETHODIMP CPolyPropPage::TranslateAccelerator(LPMSG lpMsg) 
    { 
    //No keyboard interface supported here 
    return ResultFromScode(E_NOTIMPL); 
    } 
 
 
 
/* 
 * PolyPropPageProc 
 * 
 * Purpose: 
 *  Dialog procedure for the Polyline Property Page. 
 */ 
 
BOOL APIENTRY PolyPropPageProc(HWND hDlg, UINT iMsg 
    , WPARAM wParam, LPARAM lParam) 
    { 
    PCPolyPropPage      pObj; 
    WORD                wID; 
    UINT                i; 
    COLORREF            rgColors[16]; 
    CHOOSECOLOR         cc; 
 
   #ifdef WIN32 
    pObj=(PCPolyPropPage)(ULONG)GetProp(hDlg, g_szObj); 
   #else 
    pObj=(PCPolyPropPage)MAKELONG((WORD)GetProp(hDlg, g_szObjLo) 
       , (WORD)GetProp(hDlg, g_szObjHi)); 
   #endif 
 
    switch (iMsg) 
        { 
        case WM_INITDIALOG: 
            pObj=(PCPolyPropPage)(ULONG)lParam; 
           #ifdef WIN32 
            SetProp(hDlg, g_szObj, (HANDLE)lParam); 
           #else 
            SetProp(hDlg, g_szObjHi, (HANDLE)HIWORD(lParam)); 
            SetProp(hDlg, g_szObjLo, (HANDLE)LOWORD(lParam)); 
           #endif 
 
            if (NULL==pObj) 
                return TRUE; 
 
            /* 
             * If we have one object then we can try to set the 
             * right field in the dialog box.  Otherwise we could 
             * ask for the value from all of the objects and see 
             * if they all match. 
             */ 
            if (1==pObj->m_cObjects) 
                { 
                UINT        iLine; 
 
                iLine=pObj->m_ppObj[0]->get_LineStyle(); 
 
                CheckRadioButton(hDlg, ID_LINESOLID 
                    , ID_LINEDASHDOTDOT, iLine+ID_LINEMIN); 
 
                SetFocus(GetDlgItem(hDlg, iLine+ID_LINEMIN)); 
 
                pObj->m_uIDLastLine=iLine; 
 
                pObj->m_crLastBack=pObj->m_ppObj[0]->get_BackColor(); 
                pObj->m_crLastLine=pObj->m_ppObj[0]->get_LineColor(); 
                } 
 
            return FALSE; 
 
        case WM_DESTROY: 
           #ifdef WIN32 
            RemoveProp(hDlg, g_szObj); 
           #else 
            RemoveProp(hDlg, g_szObjHi); 
            RemoveProp(hDlg, g_szObjLo); 
           #endif 
            return FALSE; 
 
        case WM_COMMAND: 
            wID=LOWORD(wParam); 
 
            switch (wID) 
                { 
                case ID_LINESOLID: 
                case ID_LINEDASH: 
                case ID_LINEDOT: 
                case ID_LINEDASHDOT: 
                case ID_LINEDASHDOTDOT: 
                    if (NULL==pObj) 
                        break; 
 
                    //Selecting the same one doesn't dirty 
                    if (pObj->m_uIDLastLine==wID) 
                        break; 
 
                    //Save the most recently selected 
                    pObj->m_uIDLastLine=LOWORD(wParam); 
                    pObj->m_fDirty=TRUE; 
 
                    if (NULL!=pObj->m_pIPropertyPageSite) 
                        { 
                        pObj->m_pIPropertyPageSite 
                            ->OnStatusChange(PROPPAGESTATUS_DIRTY); 
                        } 
 
                    break; 
 
 
                case ID_COLORLINE: 
                case ID_COLORBACK: 
                    if (NULL==pObj) 
                        break; 
 
                    for (i=0; i<16; i++) 
                        rgColors[i]=RGB(0, 0, i*16); 
 
                    memset(&cc, 0, sizeof(CHOOSECOLOR)); 
                    cc.lStructSize=sizeof(CHOOSECOLOR); 
                    cc.lpCustColors=rgColors; 
                    cc.hwndOwner=GetParent(hDlg); 
                    cc.Flags=CC_RGBINIT; 
                    cc.rgbResult=(ID_COLORBACK==wID) 
                        ? pObj->m_crLastBack 
                        : pObj->m_crLastLine; 
 
                    if (ChooseColor(&cc)) 
                        { 
                        COLORREF    cr; 
                        ; 
                        if (ID_COLORBACK==wID) 
                            { 
                            cr=pObj->m_crLastBack; 
                            pObj->m_crLastBack=cc.rgbResult; 
                            } 
                        else 
                            { 
                            cr=pObj->m_crLastLine; 
                            pObj->m_crLastLine=cc.rgbResult; 
                            } 
 
                        pObj->m_fDirty=(cr!=cc.rgbResult); 
 
                        if (pObj->m_fDirty 
                            && NULL!=pObj->m_pIPropertyPageSite) 
                            { 
                            pObj->m_pIPropertyPageSite 
                                ->OnStatusChange(PROPPAGESTATUS_DIRTY); 
                            } 
                        } 
                    break; 
 
                } 
            break; 
        } 
    return FALSE; 
    }