CAppSoundsManager
v1.09
Welcome to CAppSoundsManager, an C++ class which encapsulates the area of "Application
Sounds". These are the sounds which end-users can customize in the Sound tab
of the "Sounds and Audio Devices" control panel applet. The class is based
in part upon the "CSoundMgr" class developed by Paul DiLascia for the
May 2006 edition of the MSDN Magazine
To get you started you should probably read the DiLascia article at
http://download.microsoft.com/download/3/a/7/3a7fa450-1f33-41f7-9e6d-3aa95b5a6aea/MSDNMagazineMay2006en-us.chm
Features
- Implements a simple easily maintainable MAP based approach to application
sounds.
- Implementations registration and un-registration methods through code
- Unlike the DiLascia implementation which requires the end user to create
logical names as well as registry names in addition to the sound id for each
application sound you want to set up, CAppSoundsManager only requires that you
setup one id and figures out all the other values from this by looking in your
application's resources.
- Whether or not specific sounds should be played from resources if they are
not setup can be individually configured.
- Unlike the DiLascia implementation, the code does not use AfxGetAppName()
for the filename for registration. This approach would cause problems if the
Application name is different than you exe filename.
- Supports the "DispFileName" registry entry for both Application
names and individual sounds. This allows the code to work on MUI builds unlike
the DiLascia implementation. For further information on this and Application
Sound registration details, please see Larry Osterman's WebLog at
https://docs.microsoft.com/en-us/archive/blogs/larryosterman/a-peek-behind-the-beep.
- Works equally well in Unicode as well as ASCII builds.
- Automatically links to the Windows Multimedia library namely "Winmm.lib"
- Include in the download is the AppSoundsManager modules along with a VC
2017 project to build a test app to exercise most of the classes functionality.
- Supports registration of file system based sounds.
- Supports the concept of disabled sounds.
Copyright
- You are allowed to include the source code in any product (commercial, shareware,
freeware or otherwise) when your product is released in binary form.
- You are allowed to modify the source code in any way you want except you
cannot modify the copyright details at the top of each module.
- If you want to distribute source code with your application, then you are
only allowed to distribute versions released by the author. This is to maintain
a single distribution point for the source code.
Usage
Ok, so you've decided that you want to add sounds to your MFC application and
you want to use this class. The steps required to get the class up and running are:
- In a new header file of say "MySoundsManager.h", define a class
derived from CAppSoundsManager as such:
#pragma once
#include "AppSoundsManager.h"
#include "Resource.h"
class CMySoundsManager : public CAppSoundsManager
{
BEGIN_APP_SOUNDS()
END_APP_SOUNDS()
};
- Between the BEGIN_APP_SOUNDS and END_APP_SOUND macros, insert one of the
APP_SOUND_* macros to define a single application sound. For example in the
sample app we have 2 application sounds defined as follows:
BEGIN_IMPLEMENT_APP_SOUNDS(CMySoundsManager)
APP_SOUND_FROM_RESOURCE(IDR_STARTUP_SOUND)
APP_SOUND_FROM_FILE(IDR_SHUTDOWN_SOUND,
_T("%APPPATH%\\shutdown.wav"))
END_IMPLEMENT_APP_SOUNDS(CMySoundsManager).
- Currently 4 APP_SOUND_* macros are defined.
APP_SOUND_FROM_RESOURCE:
This macro sets up a sound with no default value in the registry. If a value
is specified in the registry then that sound will be played, and if no sound
is specified in the registry then the code will attempt to play the sound as
an embedded WAVE file resource.
APP_SOUND_FROM_FILE: This macro sets
up a sound with the specified path in the registry. There is one replaceable
parameter of "%APPPATH%" which corresponds to the path where the application
is located.
APP_SOUND_DEFAULT_NONE: This macro sets up a sound with no
default value in the registry and the code will only play the sound if the end
user specifies a value in the control panel applet. You can think of this as
a disabled application sound which requires the end user to configure it in
the control panel before any sound is played.
APP_SOUND_EX: This macro
allows the developer complete control over all the settings for a particular
application sound.
Each sound in the map corresponds to a "CAppSound"
instance in an array which the CAppSoundsManager class has setup through the
use of the macros above. The first value you pass to the macros specify a resource
id for the WAVE file, which if you are using APP_SOUND_FROM_RESOURCE you should
embed in your application's rc file. In addition you should create a string
resource of the same value which defines the Friendly name for this sound which
will appear in the control panel applet. See TestSounds.rc included in the download
for a concrete example of doing this.
- To create more sounds for your application just add more entries to the
map and WAVE (optional) and string resources to your rc file.
- Create an instance of CMySoundsManager which will live for the lifetime
of your application. In an MFC app, you would normally do this in your CWinApp
derived class. For example:
#include "resource.h"
#include "MySoundsManager.h"
class CTestSoundsApp : public CWinApp
{
public:
CTestSoundsApp();
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
CMySoundsManager m_SoundsManager;
};
Early on in the running of your application you should call the Initialize()
method. This allows you to specify the Friendly name of your application, the
string resource value for your application and the resource handle to use for
loading resources. The Friendly Name string and resource id are used during
the Register call (discussed next).
- If you want to create the various values required in the registry for Application
Sounds through code, then you can use the Register method in conjunction with
the IsRegistered method. The sample app included in the download uses the following
code early on in the app's InitInstance method:
HRESULT hr = m_SoundsManager.IsRegistered();
if (FAILED(hr) || (hr == S_FALSE))
m_SoundsManager.Register();
Unregistration is also supported thro the UnRegister method. Alternatively
you could implement this logic in your install program and perhaps customize
the sounds up front in the registry.
- Then in the various places in your app, where you want to play the sounds,
you simply call the PlaySound method along with the appropriate ID. For example
in the start-up of the sample app we have a call to
m_SoundsManager.PlaySound(IDR_STARTUP_SOUND,
SND_ASYNC);
Note how you can pass additional flags to the PlaySound
method. In this case we pass SND_ASYNC to say that the start-up sound should
be played in the background while our test app continues to load. In our sample
app, we also have a shutdown sound and we call it as follows, after the dialog
is closed:
m_SoundsManager.PlaySound(IDR_SHUTDOWN_SOUND,
SND_SYNC);
Again notice how this time we pass the additional "SND_SYNC"
flag. This is necessary to tell Windows to not return until the sound has completed
playing. If we were not to include this flag, then you would only hear a small
snippet of the shutdown sound (or perhaps none at all).
In your particular
application you would make calls to the PlaySound method at the various logical
points in your application for each of the sounds you have setup in your map.
- Various additional methods are included in the CAppSoundsManager class to
customize the class further. For example you can enable / disable playing of
sounds through the SetEnable method. The sample app included in the download
includes 2 buttons to interactively play the two sounds as well as show the
values associated with each sound as setup in the registry. Play around with
the Sounds control panel applet and rerun the sample app to see the effects.
History
v1.09 (24 April 2022)
- Updated copyright details.
- Updated the code to use C++ uniform initialization for all variable
declarations.
v1.08 (4 May 2020)
- Fixed more Clang-Tidy static code analysis warnings in the code.
v1.07 (14 March 2020)
- Updated copyright details.
- Fixed more Clang-Tidy static code analysis warnings in the code.
v1.06 (20 October 2018)
- Updated copyright details
- Fixed a number of C++ core guidelines compiler warnings. These changes
mean that the code will now only compile on VC 2017 or later.
- Removed all code which supported CAPPSOUNDSMANAGER_MFC_EXTENSIONS code
path
v1.05 (2 December 2017)
- Updated copyright details.
- Replaced NULL throughout the codebase with nullptr. This means that the
minimum requirement for the framework is now VC 2010.
- Replaced BOOL throughout the codebase with bool.
- Replaced CString::operator LPC*STR() calls throughout the codebase with
CString::GetString calls
v1.04 (24 January 2016)
- Updated copyright details.
- Updated the code to clean compile on VC 2008 - 2015
- The IsRegistered method now use ATL:CRegKey and returns a HRESULT return
value
- The GetCurrentSoundFromRegistry method now uses ATL::CRegKey and returns
a HRESULT return value
- The Register method now uses ATL::CRegKey and returns a HRESULT return value
- The RegisterSound method now uses ATL::CRegKey and returns a HRESULT return
value
- The UnRegister method now uses ATL::CRegKey and returns a HRESULT return
value
- The Initialize method now returns a HRESULT return value
- The CAppSoundsManager::UnRegister method now uses ATL::CRegKey::RecurseDeleteKey
instead of SHDeleteKey.
- Added SAL annotations to all the code.
- Reworked the classes to optionally compile without MFC. By default the class
now use STL classes and idioms but if you define CAPPSOUNDSMANAGER_MFC_EXTENSIONS
the class will revert back to the MFC behaviour.
v1.03 (4 January 2009)
- Updated copyright details.
- Removed VC 6 style AppWizard comments from the code
- Removed unused CAppSoundsManager destructor
- The code has now been updated to support VC 2005 or later only
- Fixed a potential buffer overwrite in CAppSoundsManager::GetCurrentSoundFromRegistry.
This bug was spotted with Code Analysis.
- Code now compiles cleanly using Code Analysis (/analyze)
- The Register method has been completely rewritten and refactored
- The Unregister method now uses SHDeleteKey to ensure key values which have
subkeys are cleanly removed from the registry. The code in this method has also
been refactored.
v1.02 (14 June 2007)
- Updated Register and UnRegister methods to preserve last error code if it
cannot open the "HKCU\AppEvents\EventLabels" registry key.
- Updated copyright details.
v1.01 (22 September 2006)
- The existing APP_SOUND macro has been renamed to APP_SOUND_FROM_RESOURCE.
- Now supports registration of file based wave files using the APP_SOUND_FROM_FILE
macro.
- Now supports the concept of a disabled sound, where the sound will only
be played if the end-user configures the value in the control panel through
the new APP_SOUND_DEFAULT_NONE macro.
v1.0 (22 September 2006)
Contacting the Author
PJ Naughter
Email: pjna@naughter.com
Web: http://www.naughter.com
24 April 2022