BEEPPROP.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:19k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * BEEPPROP.CPP
  3.  * Beeper Property Page Chapter 16
  4.  *
  5.  * Server module code and class code CBeeperPropertyPage class.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13. #define INITGUIDS
  14. #include "beepprop.h"
  15. //Count number of objects and number of locks.
  16. ULONG       g_cObj=0;
  17. ULONG       g_cLock=0;
  18. HINSTANCE   g_hInst=NULL;   //For resources
  19. #ifdef WIN32
  20. TCHAR       g_szObj[]=TEXT("Object");
  21. #else
  22. TCHAR       g_szObjHi[]=TEXT("ObjectHi");
  23. TCHAR       g_szObjLo[]=TEXT("ObjectLo");
  24. #endif
  25. /*
  26.  * LibMain(32)
  27.  *
  28.  * Purpose:
  29.  *  Entry point conditionally compiled for Win32 and Windows
  30.  *  3.1.  Provides the proper structure for each environment.
  31.  */
  32. #ifdef WIN32
  33. BOOL WINAPI LibMain32(HINSTANCE hInstance, ULONG ulReason
  34.     , LPVOID pvReserved)
  35.     {
  36.     g_hInst=hInstance;
  37.     if (DLL_PROCESS_DETACH==ulReason)
  38.         {
  39.         return TRUE;
  40.         }
  41.     else
  42.         {
  43.         if (DLL_PROCESS_ATTACH!=ulReason)
  44.             return TRUE;
  45.         }
  46.     return TRUE;
  47.     }
  48. #else
  49. int PASCAL LibMain(HINSTANCE hInstance, WORD wDataSeg
  50.     , WORD cbHeapSize, LPSTR lpCmdLine)
  51.     {
  52.     if (0!=cbHeapSize)
  53.         UnlockData(0);
  54.     g_hInst=hInstance;
  55.     return (int)hInstance;
  56.     }
  57. #endif
  58. /*
  59.  * DllGetClassObject
  60.  * DllCanUnloadNow
  61.  * Standard COM exports for DLL servers.
  62.  */
  63. HRESULT APIENTRY DllGetClassObject(REFCLSID rclsid, REFIID riid
  64.     , PPVOID ppv)
  65.     {
  66.     CBeeperPPFactory *pBF;
  67.     HRESULT         hr;
  68.     if (CLSID_BeeperPropertyPage!=rclsid)
  69.         return ResultFromScode(E_FAIL);
  70.     //Check that we can provide the interface
  71.     if (IID_IUnknown!=riid && IID_IClassFactory!=riid)
  72.         return ResultFromScode(E_NOINTERFACE);
  73.     //Return our beeper factory's IClassFactory
  74.     pBF=new CBeeperPPFactory();
  75.     if (NULL==pBF)
  76.         return ResultFromScode(E_OUTOFMEMORY);
  77.     //If the factory hasn't the interface, delete it
  78.     hr=pBF->QueryInterface(riid, ppv);
  79.     if (FAILED(hr))
  80.         delete pBF;
  81.     else
  82.         g_cObj++;
  83.     return hr;
  84.     }
  85. STDAPI DllCanUnloadNow(void)
  86.     {
  87.     SCODE   sc;
  88.     //Our answer is whether there are any object or locks
  89.     sc=(0L==g_cObj && 0L==g_cLock) ? S_OK : S_FALSE;
  90.     return ResultFromScode(sc);
  91.     }
  92. /*
  93.  * CBeeperPPFactory::CBeeperPPFactory
  94.  * CBeeperPPFactory::~CBeeperPPFactory
  95.  * CBeeperPPFactory::QueryInterface
  96.  * CBeeperPPFactory::AddRef
  97.  * CBeeperPPFactory::Release
  98.  */
  99. CBeeperPPFactory::CBeeperPPFactory(void)
  100.     {
  101.     m_cRef=0L;
  102.     return;
  103.     }
  104. CBeeperPPFactory::~CBeeperPPFactory(void)
  105.     {
  106.     return;
  107.     }
  108. STDMETHODIMP CBeeperPPFactory::QueryInterface(REFIID riid, PPVOID ppv)
  109.     {
  110.     *ppv=NULL;
  111.     if (IID_IUnknown==riid || IID_IClassFactory==riid)
  112.         *ppv=this;
  113.     if (NULL!=*ppv)
  114.         {
  115.         ((LPUNKNOWN)*ppv)->AddRef();
  116.         return NOERROR;
  117.         }
  118.     return ResultFromScode(E_NOINTERFACE);
  119.     }
  120. STDMETHODIMP_(ULONG) CBeeperPPFactory::AddRef(void)
  121.     {
  122.     return ++m_cRef;
  123.     }
  124. STDMETHODIMP_(ULONG) CBeeperPPFactory::Release(void)
  125.     {
  126.     if (0!=--m_cRef)
  127.         return m_cRef;
  128.     delete this;
  129.     g_cObj--;
  130.     return 0;
  131.     }
  132. /*
  133.  * CBeeperPPFactory::CreateInstance
  134.  * CBeeperPPFactory::LockServer
  135.  */
  136. STDMETHODIMP CBeeperPPFactory::CreateInstance(LPUNKNOWN pUnkOuter
  137.     , REFIID riid, PPVOID ppvObj)
  138.     {
  139.     PCBeeperPropPage    pObj;
  140.     HRESULT             hr;
  141.     *ppvObj=NULL;
  142.     hr=ResultFromScode(E_OUTOFMEMORY);
  143.     //No aggregation supported
  144.     if (NULL!=pUnkOuter)
  145.         return ResultFromScode(CLASS_E_NOAGGREGATION);
  146.     //Create the object passing function to notify on destruction.
  147.     pObj=new CBeeperPropPage(g_hInst);
  148.     if (NULL==pObj)
  149.         return hr;
  150.     if (pObj->Init())
  151.         hr=pObj->QueryInterface(riid, ppvObj);
  152.     //Kill the object if initial creation or Init failed.
  153.     if (FAILED(hr))
  154.         delete pObj;
  155.     else
  156.         g_cObj++;
  157.     return hr;
  158.     }
  159. STDMETHODIMP CBeeperPPFactory::LockServer(BOOL fLock)
  160.     {
  161.     if (fLock)
  162.         g_cLock++;
  163.     else
  164.         g_cLock--;
  165.     return NOERROR;
  166.     }
  167. /***
  168.  *** CBeeperPropPage implementation
  169.  ***/
  170. /*
  171.  * CBeeperPropPage::CBeeperPropPage
  172.  * CBeeperPropPage::~CBeeperPropPage
  173.  *
  174.  * Constructor Parameters:
  175.  *  hInst           HINSTANCE of the module
  176.  */
  177. CBeeperPropPage::CBeeperPropPage(HINSTANCE hInst)
  178.     {
  179.     m_cRef=0L;
  180.     m_hInst=hInst;
  181.     m_uIDTemplate=IDD_BEEPERPROPS_0;
  182.     m_hDlg=NULL;
  183.     //Default sizes
  184.     m_cx=300;
  185.     m_cy=100;
  186.     m_pIPropertyPageSite=NULL;
  187.     m_ppIBeeper=NULL;
  188.     m_cObjects=0;
  189.     m_uIDLastSound=IDC_BEEPDEFAULT;
  190.     m_fDirty=FALSE;
  191.     m_lcid=LOCALE_USER_DEFAULT;
  192.     return;
  193.     }
  194. CBeeperPropPage::~CBeeperPropPage(void)
  195.     {
  196.     if (NULL!=m_hDlg)
  197.         DestroyWindow(m_hDlg);
  198.     FreeAllObjects();
  199.     ReleaseInterface(m_pIPropertyPageSite);
  200.     return;
  201.     }
  202. /*
  203.  * CBeeperPropPage::QueryInterface
  204.  * CBeeperPropPage::AddRef
  205.  * CBeeperPropPage::Release
  206.  */
  207. STDMETHODIMP CBeeperPropPage::QueryInterface(REFIID riid, PPVOID ppv)
  208.     {
  209.     *ppv=NULL;
  210.     if (IID_IUnknown==riid || IID_IPropertyPage==riid)
  211.         *ppv=this;
  212.     if (NULL!=*ppv)
  213.         {
  214.         ((LPUNKNOWN)*ppv)->AddRef();
  215.         return NOERROR;
  216.         }
  217.     return ResultFromScode(E_NOINTERFACE);
  218.     }
  219. STDMETHODIMP_(ULONG) CBeeperPropPage::AddRef(void)
  220.     {
  221.     return ++m_cRef;
  222.     }
  223. STDMETHODIMP_(ULONG) CBeeperPropPage::Release(void)
  224.     {
  225.     if (0!=--m_cRef)
  226.         return m_cRef;
  227.     g_cObj--;
  228.     delete this;
  229.     return 0;
  230.     }
  231. /*
  232.  * CBeeperPropPage::Init
  233.  *
  234.  * Purpose:
  235.  *  Performs initialization operations that might fail.
  236.  *
  237.  * Parameters:
  238.  *  None
  239.  *
  240.  * Return Value:
  241.  *  BOOL            TRUE if initialization successful, FALSE
  242.  *                  otherwise.
  243.  */
  244. BOOL CBeeperPropPage::Init(void)
  245.     {
  246.     //Nothing to do
  247.     return TRUE;
  248.     }
  249. /*
  250.  * CBeeperPropPage::FreeAllObjects
  251.  *
  252.  * Purpose:
  253.  *  Releases all the objects from IPropertyPage::SetObjects
  254.  *
  255.  * Parameters:
  256.  *  None
  257.  */
  258. void CBeeperPropPage::FreeAllObjects(void)
  259.     {
  260.     UINT        i;
  261.     if (NULL==m_ppIBeeper)
  262.         return;
  263.     for (i=0; i < m_cObjects; i++)
  264.         ReleaseInterface(m_ppIBeeper[i]);
  265.     delete [] m_ppIBeeper;
  266.     m_ppIBeeper=NULL;
  267.     m_cObjects=0;
  268.     return;
  269.     }
  270. /*
  271.  * CBeeperPropPage::SetPageSite
  272.  *
  273.  * Purpose:
  274.  *  Provides the property page with the IPropertyPageSite
  275.  *  that contains it.  SetPageSite(NULL) will be called as
  276.  *  part of the close sequence.
  277.  *
  278.  * Parameters:
  279.  *  pPageSite       LPPROPERTYPAGESITE pointer to the site.
  280.  */
  281. STDMETHODIMP CBeeperPropPage::SetPageSite
  282.     (LPPROPERTYPAGESITE pPageSite)
  283.     {
  284.     if (NULL==pPageSite)
  285.         ReleaseInterface(m_pIPropertyPageSite)
  286.     else
  287.         {
  288.         HWND        hDlg;
  289.         RECT        rc;
  290.         LCID        lcid;
  291.         m_pIPropertyPageSite=pPageSite;
  292.         m_pIPropertyPageSite->AddRef();
  293.         if (SUCCEEDED(m_pIPropertyPageSite->GetLocaleID(&lcid)))
  294.             m_lcid=lcid;
  295.         /*
  296.          * Now that we know the locale we're running under, we can
  297.          * load the dialog and determine the size it will be to
  298.          * return through GetPageSize.  We just create the dialog
  299.          * here and destroy it again to retrieve the size,
  300.          * leaving Activate to create it for real.
  301.          */
  302.         switch (PRIMARYLANGID(m_lcid))
  303.             {
  304.             case LANG_GERMAN:
  305.                 m_uIDTemplate=IDD_BEEPERPROPS_7;
  306.                 break;
  307.             case LANG_NEUTRAL:
  308.             case LANG_ENGLISH:
  309.             default:
  310.                 m_uIDTemplate=IDD_BEEPERPROPS_0;
  311.                 break;
  312.             }
  313.         hDlg=CreateDialogParam(m_hInst
  314.             , MAKEINTRESOURCE(m_uIDTemplate), GetDesktopWindow()
  315.             , (DLGPROC)BeepPropPageProc, 0L);
  316.         //If creation fails, use default values set in constructor
  317.         if (NULL!=hDlg)
  318.             {
  319.             GetWindowRect(hDlg, &rc);
  320.             m_cx=rc.right-rc.left;
  321.             m_cy=rc.bottom-rc.top;
  322.             DestroyWindow(hDlg);
  323.             }
  324.         }
  325.     return NOERROR;
  326.     }
  327. /*
  328.  * CBeeperPropPage::Activate
  329.  *
  330.  * Purpose:
  331.  *  Instructs the property page to create a window in which to
  332.  *  display its contents, using the given parent window and
  333.  *  rectangle.  The window should be initially visible.
  334.  *
  335.  * Parameters:
  336.  *  hWndParent      HWND of the parent window.
  337.  *  prc             LPCRECT of the rectangle to use.
  338.  *  fModal          BOOL indicating whether the frame is modal.
  339.  */
  340. STDMETHODIMP CBeeperPropPage::Activate(HWND hWndParent
  341.     , LPCRECT prc, BOOL fModal)
  342.     {
  343.     if (NULL!=m_hDlg)
  344.         return ResultFromScode(E_UNEXPECTED);
  345.     m_hDlg=CreateDialogParam(m_hInst, MAKEINTRESOURCE(m_uIDTemplate)
  346.         , hWndParent, BeepPropPageProc, (LPARAM)this);
  347.     if (NULL==m_hDlg)
  348.         return ResultFromScode(E_OUTOFMEMORY);
  349.     //Move the page into position and show it.
  350.     SetWindowPos(m_hDlg, NULL, prc->left, prc->top
  351.         , prc->right-prc->left, prc->bottom-prc->top, 0);
  352. return NOERROR;
  353.     }
  354. /*
  355.  * CBeeperPropPage::Deactivate
  356.  *
  357.  * Purpose:
  358.  *  Instructs the property page to destroy its window that was
  359.  *  created in Activate.
  360.  *
  361.  * Parameters:
  362.  *  None
  363.  */
  364. STDMETHODIMP CBeeperPropPage::Deactivate(void)
  365.     {
  366.     if (NULL==m_hDlg)
  367.         return ResultFromScode(E_UNEXPECTED);
  368.     DestroyWindow(m_hDlg);
  369.     m_hDlg=NULL;
  370.     return NOERROR;
  371.     }
  372. /*
  373.  * CBeeperPropPage::GetPageInfo
  374.  *
  375.  * Purpose:
  376.  *  Fills a PROPPAGEINFO structure describing the page's size,
  377.  *  contents, and help information.
  378.  *
  379.  * Parameters:
  380.  *  pPageInfo       LPPROPPAGEINFO to the structure to fill.
  381.  */
  382. STDMETHODIMP CBeeperPropPage::GetPageInfo(LPPROPPAGEINFO pPageInfo)
  383.     {
  384.     IMalloc     *pIMalloc;
  385.     if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  386.         return ResultFromScode(E_FAIL);
  387.     pPageInfo->pszTitle=(LPOLESTR)pIMalloc->Alloc(CCHSTRINGMAX);
  388.     if (NULL!=pPageInfo->pszTitle)
  389.         {
  390.         UINT        ids=IDS_0_PAGETITLE;
  391.         if (PRIMARYLANGID(m_lcid)==LANG_GERMAN)
  392.             ids=IDS_7_PAGETITLE;
  393.        #ifdef WIN32ANSI
  394.         char        szTemp[80];
  395.         LoadString(m_hInst, ids, szTemp, CCHSTRINGMAX);
  396.         MultiByteToWideChar(CP_ACP, 0, szTemp, -1
  397.            , pPageInfo->pszTitle, 80);
  398.        #else
  399.         LoadString(m_hInst, ids, pPageInfo->pszTitle, CCHSTRINGMAX);
  400.        #endif
  401.         }
  402.     pIMalloc->Release();
  403. pPageInfo->size.cx      = m_cx;
  404.     pPageInfo->size.cy      = m_cy;
  405. pPageInfo->pszDocString = NULL;
  406. pPageInfo->pszHelpFile  = NULL;
  407. pPageInfo->dwHelpContext= 0;
  408.     return NOERROR;
  409.     }
  410. /*
  411.  * CBeeperPropPage::SetObjects
  412.  *
  413.  * Purpose:
  414.  *  Identifies the objects that are being affected by this property
  415.  *  page (and all other pages in the frame).  These are the object
  416.  *  to which to send new property values in the Apply member.
  417.  *
  418.  * Parameters:
  419.  *  cObjects        ULONG number of objects
  420.  *  ppUnk           IUnknown ** to the array of objects being
  421.  *                  passed to the page.
  422.  */
  423. STDMETHODIMP CBeeperPropPage::SetObjects(ULONG cObjects
  424.     , IUnknown **ppUnk)
  425.     {
  426.     BOOL        fRet=TRUE;
  427.     FreeAllObjects();
  428.     if (0!=cObjects)
  429.         {
  430.         UINT        i;
  431.         HRESULT     hr;
  432.         m_ppIBeeper=new IBeeper * [(UINT)cObjects];
  433.     for (i=0; i < cObjects; i++)
  434.         {
  435.             hr=ppUnk[i]->QueryInterface(IID_IBeeper
  436.                 , (void **)&m_ppIBeeper[i]);
  437.             if (FAILED(hr))
  438.                 fRet=FALSE;
  439.         }
  440.     }
  441.     //If we didn't get one of our objects, fail this call.
  442.     if (!fRet)
  443.         return ResultFromScode(E_FAIL);
  444.     m_cObjects=cObjects;
  445.     return NOERROR;
  446.     }
  447. /*
  448.  * CBeeperPropPage::Show
  449.  *
  450.  * Purpose:
  451.  *  Instructs the page to show or hide its window created in
  452.  *  Activate.
  453.  *
  454.  * Parameters:
  455.  *  nCmdShow        UINT to pass to ShowWindow.
  456.  */
  457. STDMETHODIMP CBeeperPropPage::Show(UINT nCmdShow)
  458.     {
  459.     if (NULL==m_hDlg)
  460.         ResultFromScode(E_UNEXPECTED);
  461.     ShowWindow(m_hDlg, nCmdShow);
  462.     //Take the focus
  463.     if (SW_SHOWNORMAL==nCmdShow || SW_SHOW==nCmdShow)
  464. SetFocus(m_hDlg);
  465.     return NOERROR;
  466.     }
  467. /*
  468.  * CBeeperPropPage::Move
  469.  *
  470.  * Purpose:
  471.  *  Instructs the property page to change its position.
  472.  *
  473.  * Parameters:
  474.  *  prc             LPCRECT containing the new position.
  475.  */
  476. STDMETHODIMP CBeeperPropPage::Move(LPCRECT prc)
  477.     {
  478.     SetWindowPos(m_hDlg, NULL, prc->left, prc->top
  479.         , prc->right-prc->left, prc->bottom-prc->top, 0);
  480.     return NOERROR;
  481.     }
  482. /*
  483.  * CBeeperPropPage::IsPageDirty
  484.  *
  485.  * Purpose:
  486.  *  Asks the page if anything's changed in it, that is, if the
  487.  *  property values in the page are out of sync with the objects
  488.  *  under consideration.
  489.  *
  490.  * Parameters:
  491.  *  None
  492.  *
  493.  * Return Value:
  494.  *  HRESULT         NOERROR if dirty, S_FALSE if not.
  495.  */
  496. STDMETHODIMP CBeeperPropPage::IsPageDirty(void)
  497.     {
  498.     return ResultFromScode(m_fDirty ? S_OK : S_FALSE);
  499.     }
  500. /*
  501.  * CBeeperPropPage::Apply
  502.  *
  503.  * Purpose:
  504.  *  Instructs the page to send changes in its page to whatever
  505.  *  objects it knows about through SetObjects.  This is the only
  506.  *  time the page should change the objects' properties, and not
  507.  *  when the value is changed on the page.
  508.  *
  509.  * Parameters:
  510.  *  None
  511.  */
  512. STDMETHODIMP CBeeperPropPage::Apply(void)
  513.     {
  514.     UINT        i;
  515.     UINT        lSound, lSoundNew;
  516.     BOOL        fChanged;
  517.     if (0==m_cObjects)
  518.         return NOERROR;
  519.     /*
  520.      * The dialog's last known Sound selection is in
  521.      * m_uIDLastSound, so we can just send it via
  522.      * IBeeper::put_Sound.  Since this method has no
  523.      * return value, we have to ask for it again to
  524.      * see if it really changed because the client may
  525.      * be blocking changes through IPropertyNotifySink,
  526.      * in which case we do not clear the dirty flag.
  527.      */
  528.     lSound=(IDC_BEEPDEFAULT==m_uIDLastSound) ? 0L : m_uIDLastSound;
  529.     fChanged=TRUE;
  530.     for (i=0; i < m_cObjects; i++)
  531.         {
  532.         m_ppIBeeper[i]->put_Sound(lSound);
  533.         lSoundNew=m_ppIBeeper[i]->get_Sound();
  534.         fChanged &= (lSound==lSoundNew);
  535.         }
  536.     m_fDirty=!fChanged;
  537.     return NOERROR;
  538.     }
  539. /*
  540.  * CBeeperPropPage::Help
  541.  *
  542.  * Purpose:
  543.  *  Invokes help for this property page when the user presses
  544.  *  the Help button.  If you return NULLs for the help file
  545.  *  in GetPageInfo, the button will be grayed.  Otherwise the
  546.  *  page can perform its own help here.
  547.  *
  548.  * Parameters:
  549.  *  pszHelpDir      LPCOLESTR identifying the default location of
  550.  *                  the help information
  551.  *
  552.  * Return Value:
  553.  *  HRESULT         NOERROR to tell the frame that we've done our
  554.  *                  own help.  Returning an error code or S_FALSE
  555.  *                  causes the frame to use any help information
  556.  *                  in PROPPAGEINFO.
  557.  */
  558. STDMETHODIMP CBeeperPropPage::Help(LPCOLESTR pszHelpDir)
  559.     {
  560.     /*
  561.      * We can either provide help ourselves, or rely on the
  562.      * information in PROPPAGEINFO.
  563.      */
  564.     return ResultFromScode(S_FALSE);
  565.     }
  566. /*
  567.  * CBeeperPropPage::TranslateAccelerator
  568.  *
  569.  * Purpose:
  570.  *  Provides the page with the messages that occur in the frame.
  571.  *  This gives the page to do whatever it wants with the message,
  572.  *  such as handle keyboard mnemonics.
  573.  *
  574.  * Parameters:
  575.  *  pMsg            LPMSG containing the keyboard message.
  576.  */
  577. STDMETHODIMP CBeeperPropPage::TranslateAccelerator(LPMSG lpMsg)
  578.     {
  579.     //No keyboard interface supported here
  580.     return ResultFromScode(E_NOTIMPL);
  581.     }
  582. /*
  583.  * BeepPropPageProc
  584.  *
  585.  * Purpose:
  586.  *  Dialog procedure for the Beeper Property Page.
  587.  */
  588. BOOL APIENTRY BeepPropPageProc(HWND hDlg, UINT iMsg
  589.     , WPARAM wParam, LPARAM lParam)
  590.     {
  591.     PCBeeperPropPage    pObj;
  592.     WORD                wID;
  593.    #ifdef WIN32
  594.     pObj=(PCBeeperPropPage)(ULONG)GetProp(hDlg, g_szObj);
  595.    #else
  596.     pObj=(PCBeeperPropPage)MAKELONG((WORD)GetProp(hDlg, g_szObjLo)
  597.        , (WORD)GetProp(hDlg, g_szObjHi));
  598.    #endif
  599.     switch (iMsg)
  600.         {
  601.         case WM_INITDIALOG:
  602.             pObj=(PCBeeperPropPage)(ULONG)lParam;
  603.            #ifdef WIN32
  604.             SetProp(hDlg, g_szObj, (HANDLE)lParam);
  605.            #else
  606.             SetProp(hDlg, g_szObjHi, (HANDLE)HIWORD(lParam));
  607.             SetProp(hDlg, g_szObjLo, (HANDLE)LOWORD(lParam));
  608.            #endif
  609.             if (NULL==pObj)
  610.                 return TRUE;
  611.             SetFocus(GetDlgItem(hDlg, IDOK));
  612.             /*
  613.              * If we have one object then we can try to set the
  614.              * right field in the dialog box.  Otherwise we could
  615.              * ask for the value from all of the objects and see
  616.              * if they all match.
  617.              */
  618.             if (1==pObj->m_cObjects)
  619.                 {
  620.                 UINT        iButton;
  621.                 iButton=(UINT)pObj->m_ppIBeeper[0]->get_Sound();
  622.                 if (0==iButton)
  623.                     iButton=IDC_BEEPDEFAULT;
  624.                 CheckRadioButton(hDlg, IDC_BEEPDEFAULT
  625.                     , IDC_BEEPASTERISK, iButton);
  626.                 pObj->m_uIDLastSound=iButton;
  627.                 }
  628.             return FALSE;
  629.         case WM_DESTROY:
  630.            #ifdef WIN32
  631.             RemoveProp(hDlg, g_szObj);
  632.            #else
  633.             RemoveProp(hDlg, g_szObjHi);
  634.             RemoveProp(hDlg, g_szObjLo);
  635.            #endif
  636.             return FALSE;
  637.         case WM_COMMAND:
  638.             wID=LOWORD(wParam);
  639.             switch (wID)
  640.                 {
  641.                 case IDC_BEEPDEFAULT:
  642.                 case IDC_BEEPHAND:
  643.                 case IDC_BEEPQUESTION:
  644.                 case IDC_BEEPEXCLAMATION:
  645.                 case IDC_BEEPASTERISK:
  646.                     if (NULL==pObj)
  647.                         break;
  648.                     //Selecting the same one doesn't dirty
  649.                     if (pObj->m_uIDLastSound==wID)
  650.                         break;
  651.                     //Save the most recently selected
  652.                     pObj->m_uIDLastSound=LOWORD(wParam);
  653.                     pObj->m_fDirty=TRUE;
  654.                     if (NULL!=pObj->m_pIPropertyPageSite)
  655.                         {
  656.                         pObj->m_pIPropertyPageSite
  657.                             ->OnStatusChange(PROPPAGESTATUS_DIRTY);
  658.                         }
  659.                     break;
  660.                 case IDOK:
  661.                     /*
  662.                      * We could call the object's Beep, but
  663.                      * as it's property page, we know what
  664.                      * it will do so we can just do it.
  665.                      */
  666.                     if (NULL!=pObj)
  667.                         MessageBeep(pObj->m_uIDLastSound);
  668.                     break;
  669.                 }
  670.             break;
  671.         }
  672.     return FALSE;
  673.     }