Site MapMicrosoft Foundation Classes

If you have Cookies enabled,
you can check to see if any files you have downloaded
have been updated since you downloaded them
by clicking here.


My intention is to provide simple, free access to useable solutions to common but difficult programming problems.

If you know any better solutions then please e-mail me so that everyone can share your wisdom!

Be aware that I use a non-standard "Coding Style"... and its infectious...

Helpers

You may find some of these useful:
If you have useful constants or comments to make the usage of any of these clearer, please e-mail me.
CString _fastcall itoa(int i) {
  char s[20];
  itoa(i, s, 10);//s.Format("%i", i);
  return s;
}

CString _fastcall itoa(long i) {
  char s[20];    // CString S;
  ltoa(i, s, 10);// S.Format("%l", i);
  return s;      // return S;
}

CString _fastcall itoa(double i) {
  char s[20];                // CString S;
  ltoa((long)(i+0.5), s, 10);// S.Format("%l", i+0.5);
  return s;                  // return S;
}

#define   Black RGB(  0,  0,  0)
#define  DkGray RGB(128,128,128)
#define  LtGray RGB(192,192,192)
#define   White RGB(255,255,255)
#define     Red RGB(255,  0,  0)
#define   Green RGB(  0,255,  0)
#define    Blue RGB(  0,  0,255)
#define  Yellow RGB(255,255,  0)
#define Magenta RGB(255,  0,255)
#define    Cyan RGB(  0,255,255)

void ShowLastError() {
  LPVOID lpMsgBuf; // Default language:
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
  MessageBox(NULL, (LPTSTR)lpMsgBuf, "Error Information", MB_OK|MB_ICONINFORMATION);
  LocalFree(lpMsgBuf);
}

#define Redraw(nID) {GetDlgItem(nID)->RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);}

void SizeComboDrop(CComboBox* Combo) {
  CRect Rect;
  Combo->GetDroppedControlRect(Rect);
  Combo->ShowWindow(SW_HIDE); //The SetWindowPos insists on opening and closing the popup...
  Combo->SetWindowPos(NULL,0,0,Rect.Width(), min(::GetSystemMetrics(SM_CYFULLSCREEN), (Combo->GetCount()+1)*Combo->GetItemHeight(0)+Combo->GetItemHeight(-1)), SWP_NOZORDER|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE);
  Combo->ShowWindow(SW_SHOW);
}

Subclassing Dialog Controls

Its Easy to Add Functionality to Windows Controls!

So you want to use a Control, but the one provided by windows doesn't quite do everything you want...
Or, perhaps you just want a simple CWnd that gives you access to all the events
You've seen other programs do what you want, so it must be possible...
But how do you add functionality to a control?
From code examples available on the Web, there seem to be lots of ways...
Most of them are quite involved.
Fortunately there is a single line of code that does the job - all you need to do is understand what it does!
So...
We'll tackle extending a control's functionality first:
You want, for example, a Tree Control but you need it to Load and Save (Serialize) its data.
First you create a class derived from CTreeControl:
class CSerializingTree : public CTreeCtrl {
public:
  CSerializingTree() {}
  virtual ~CSerializingTree() {}

  void Serialize(CArchive& ar);
};
Then you create an instance of it to use (in your Dialog class header file):
CSerializingTree SerializingTree;
Now put a Tree Control on your dialog box (I'll assume you've left it called IDC_TREE1 here).
This makes it easy for you to add a client edge and use Class Wizard to create Event Handlers.
Now all thats left is to tell windows that the Control on your Dialog box is to represent your subclassed Tree...
This is one line of code put in your OnInitDialog() Event Handler:
SerializingTree.SubclassDlgItem(IDC_TREE1,this);
This is so easy to use once you know it, but knowing about it seems to be very rare!

OK, So now we'll show how to access the fundamental events of a simple control: CButton.
The easiest way is [View Menu][ClassWizard][Add Class...][New...]
Set [Base Class] to CButton and Name to CMyButton and all thats left is to create event handlers and an instance in your application.
Heres a good routine to demonstrate the use of an unusual CButton Event handler:
void CMyButton::OnMouseMove(UINT nFlags, CPoint point) {
  CRect rect; // Get the bounds of the control (just the client area)
  GetClientRect(rect);
  static bool WasIn=false; // Check the mouse is inside the control
  if(rect.PtInRect(point)) {
    if(!WasIn) { // This is the OnMouseEnter area
      SetWindowText("Over");
      SetCapture();
    }else SetWindowText("Moved Again");  // This else wouldn't normally be used.
    WasIn=true;
  }else{ //This is the OnMouseLeave area:
    SetWindowText("Out");
    ReleaseCapture();
    WasIn=false;
  }
  CButton::OnMouseMove(nFlags, point);
}
There are three ways to Create control instances:
  1. Use ClassWizard to create a Member Variable:
    Create a control on your dialog,
    go to [View Menu][ClassWizard][Member Variables][Select your Dialog Class][Select your Control][Add Variable...] give it a name.
  2. Attach the control manually (if you're not using DoDataExchange):
    Create a control on your dialog,
    add
    CMyButton MyButton;
    to your Dialog Header file,
    add
    MyButton.SubclassDlgItem(IDC_BUTTON1,this);
    to your Dialog Class OnInitDialog() Method.

  3. Create the control dynamically:
    add
    CMyButton MyButton;
    to your Dialog Header file,
    add
    MyButton.CreateEx(...);
    to your Dialog Class OnInitDialog() Method.

Application Path

Get the Path and FileName of the Current Application

The complete Path and filename are available in several ways... but the fastest is just to use:
  CString Path(*__argv);
Folk who don't know that you can directly access argv and argc by prefixing them with two underscores may use GetCommandLine() or this method:
  char Buffer[2*MAX_PATH]; // Allow space for Path AND FileName here.
  GetModuleFileName(GetModuleHandle(NULL), Buffer, sizeof(Buffer));
If you just want the path then use this:
  CString Path(*__argv);
  int i=Path.ReverseFind('\\')+1;
  if(i) Path=Path.Left(i);

Single Instance Application

Single Instance Application

You can't make the "Control Panel" appear twice at the same time like most dialog boxes...
If you want to limit your Application to be Single Instance there are several approaches and, as usual, I've picked the one with the least code.
To just stop extra instances all you need is this struct in your application's InitInstance():
BOOL CMyApp::InitInstance() {
  CreateMutex(0, FALSE, "MyApp-SingleInstance");
  if(GetLastError()==ERROR_ALREADY_EXISTS || GetLastError()==ERROR_ACCESS_DENIED) return FALSE;
  ...
All you need to know about CreateMutex is that Windows will only let one instance of your Application create a Mutex of a given name.
The system closes the Mutex automatically when your Application terminates.
The call fails with ERROR_ACCESS_DENIED if the Mutex was created by another Instance because we gave no SECURITY_ATTRIBUTES.
So thats enough to stop other instances being created - but if you try to run two instances of Control Panel, the first instance becomes Active...
To do this we must add code to get the second instance to search for the first instance and activate its Main Window.
So we have to get the newer Instance to search and find the older Instance - and the older Instance to tell us its Main Window's Handle so that we can activate it.
This involves more bits of code...
To start with we want a Unique Identifier for the Application, so in your Application's Header File put the following Global number and the code for the search which is encapsulated in a structure: (Incedentally, RU12 is short for "Are You One Too" which is what Searcher is asking all existing Windows).
const UINT UWM_RU12=RegisterWindowMessage("MyApp-SingleInstance-UWM_RU12");
struct SingleInstance {
  SingleInstance() {
    CreateMutex(0, FALSE, "MyApp-SingleInstance");
//The system closes the handle automatically when the process terminates
//The call fails with ERROR_ACCESS_DENIED if the Mutex was created by another Instance because we gave no SECURITY_ATTRIBUTES
  if(GetLastError()==ERROR_ALREADY_EXISTS || GetLastError()==ERROR_ACCESS_DENIED) {
      HWND hOther=0;
      EnumWindows(Searcher, (LPARAM)&hOther);
      if(hOther) { // Try to activate the older Instance
        SetForegroundWindow(hOther);
        ShowWindow(hOther, IsZoomed(hOther) ? SW_MAXIMIZE : SW_RESTORE); //Needed for windows that have been maximized, then minimized, then hidden.
      }
      exit(0); // Terminates this Instance
  } }
  static BOOL CALLBACK Searcher(HWND hWnd, LPARAM lParam) {
    DWORD Result;
    if(!SendMessageTimeout(hWnd, UWM_RU12, 0,0,  SMTO_BLOCK | SMTO_ABORTIFHUNG, 500, &Result)
    || Result!=UWM_RU12) return TRUE; // Continue searching
    *((HWND*)lParam)=hWnd;            // Found it!
    return FALSE;                     // Stop searching
  }
};

class CMyApp : public CWinApp {
...
In your Application's .cpp file all you need to do is create an instance of this structure before your CWinApp instance.
So, in the line above CMyApp theApp insert SingleInstance Instance;...
SingleInstance Instance;
CPostEApp theApp;
Now we just have to make the older Instance reply to our Searcher Message (UWM_RU12) and tell us its Main Window's Handle so we can activate it...
The "Main Window" will be CMainFrm in Document/View Applications, or the "main Dialog class" (created by your CMyApp class) in Dialog Applications.
In the Main Window's Header File, find the DECLARE_MESSAGE_MAP() line and immediately above insert the RU12 line:
  //}}AFX_MSG_MAP
  afx_msg LRESULT RU12(WPARAM, LPARAM) {return UWM_RU12;}
  DECLARE_MESSAGE_MAP()
And in the Main Window's .cpp File, find the END_MESSAGE_MAP() line and immediately above insert the RU12 line:
  //}}AFX_MSG_MAP
  ON_REGISTERED_MESSAGE(UWM_RU12, RU12)
END_MESSAGE_MAP()
You can test what you have done by:
  1. Compile a Debug version
  2. Use Windows Explorer to find and run your Debug Excecutable (leave it running)
  3. Use DevStudio to try to run another instance....
If you put breakpoints on the constructor for CMyApp and SingleInstance, it should get to the constructor for SingleInstance first, find and activate the other Instance, then exit without ever getting to the constructor for CMyApp.

Easy, safe Threads

Threads

First make sure you have a MultiThreaded Application set up: [Project][Settings][C/C++][Code Generation][Use Run-time Library] should have a Multithreaded option selected.
I've wrapped everything you need in a class called CThread.
CThread is a abstract class that allows a derived class to run a Main() function in a separate Thread.
This is the shortest and safest code to use and extend for the control of Threads.
I use ::CreateThread because you don't need to use DuplicateHandle to get the Threads Handle and you don't need a Window to create the Thread.
I create my own implementation of Sleep(Time) which uses MsgWaitForMultipleObjects to avoid hanging and deadlocking.
When the class gets destroyed the destructor offers any running Thread the chance to exit gracefully.
If a Thread doesn't Stop within 3 seconds of being told to, it is considered hung and gets Terminated.

To use it, put the code that is to run in a separate Thread in a class derived from CThread and impement a void CMain():
Heres an example for a CDialog:
class CFManClientDlg : public CDialog, public CThread {
public:
  CFManClientDlg(CWnd* pParent = NULL) {Start();} // <--This starts the new Thread running the Main() function;
  void Main() {
    ...
  }
  ...
};
This example makes a Window with a counting TitleBar:
class CMyThread : public CThread {
  CWnd* Owner;
public:
  CMyThread(CWnd* pWnd) : Owner(pWnd) {}
  void Main() {
    CString S, Old;
    Owner->GetWindowText(Old);
    int i=0;
    while(!Abort) { // we must exit quickly and safely when Abort is true.
      S.Format("%i", ++i);
      Owner->SetWindowText(S);
      Sleep(200);
    }
//  for(;;); // hang the thread to test TerminateThread. If you uncomment this and click [Start] or [Stop] you'll get Memory leaks (being the CStrings [S] and [Old]) because the Thread was Terminated.
    if(::IsWindow(Owner->m_hWnd)) Owner->SetWindowText(Old);
  }
};
To use CMythread, create a Dialog Application (called ThreadTester in this example) with a couple of buttons [Start] and [Stop].
In the dialog header put the above CMyThread class definition and an #include to Thread.h, and:
  virtual ~CThreadTesterDlg() {delete Thread;}
  CMyThread* Thread;
In the .cpp file add these lines to OnInitDialog():
  Thread=new CMyThread(this);
  Thread->Start();
Then use ClassWizard to add button Handlers for the Start and Stop Buttons and make them look like this:
  void CThreadTesterDlg::OnStart() {if(!Thread->Start()) Thread->Main();} // If we can't do it in a separate Thread, do it in this one.
  void CThreadTesterDlg::OnStop () {if(!Thread->Stop ()) SetWindowText(Thread->IsRunning() ? "Runaway Thread!" : "Thread had hung!");}
When you click [Start] the Dialog's Title Bar will start counting.
When you click [Stop] the Dialog's Title Bar will be restored to the Application's Title.
Clicking [Start] is the same as clicking [Stop][Start].

CThread is used by the Ring Tone Player Project.
I have also made an example Project called Bouncer which demonstrates the usage of CThread in various ways:

Thread.h also contains a Multithreading Lock class CLock (nothing to do with clocks)!
Heres an example of its usage:
#include <vector>

template <class T>
class CLockVector : public std::vector<T>, public CLock {
public:
  CLockVector() : vector<T>() {if(!Lock.Lockable() Panic();}
  virtual ~CLockVector() {}
  void Insert(T& obj) {
    CLockedSection LockedSection(Lock);
    vector<T>::push_back(obj);
  }
};

Directory Search

Directory Searching Made Easy

These classes allow you to iterate Files and Directories
(optionally having a specified extension)
in a specified Directory.

There are two classes CDtree and CQDTree.
CDTree sorts the Directory Tree so that Directorys come before Files and all items are in name order alphabetically (case insensitive).
CQDTree is a Quick (unsorted) version.
I use Windows NT which gives sorted output (case sensitive) using CQDTree, but Win98 returns the Files in Disk Order.

CDTree which uses an AVL Binary Tree for the sorting which should be the fastest method.
For sorting is very fast but I still wanted to offer the simpler class.
I tested the sort speed using a powerful workstation with RAM disk to ignore disk access times.
The sorting took a third of the time of the rest of the process (So if the directory scan is going to take 3 minutes using the unsorted CQDTree class, it will take four minutes using the sorted CDTree class).

To deal with each File or Directory in a given Directory:
#include "DTree.h"
main() {
  CDTree DTree;
  if(DTree.GetList("V:\\Programming\\C++\\TestApps\\DirectoryTester","*.cpp")) {
    CString S;
    while(DTree.GetNext(S)) {
      bool Directory=DTree.IsDirectory();
      //Deal with it here...
} } }
The order of the search is as you would see the results in a fully expanded tree representation, top to bottom.
There is an IsLast() function to tell you if this is the last File Object in the current directory.

You can 'recursively' deal with each File or Directory from a given Path.
The algorithm is efficient, doesn't use recursion and provides extra information (like if the File you're currently dealing with is the last File Object in this Directory.
To do this you call the CDTree::FromPath method or use the appropriate constructor (as shown below).
This Method will call three event handlers that you design in a Behaviour Class derived from CDTreeBehaviour.
OnDIR is called when a Directory is found.
At this point GetCurrentDirectoryName(), GetPath() and GetDepth() are of the Directory where you are, and GetName() is of the Directory you're going into.
OnFile is called when a File is found.
At this point GetName() is of the File, and GetPath(), GetCurrentDirectoryName() and GetDepth() are of the Directory that the file is in.
OnUp is called when the search goes up a level.
At this point GetPath() is where you are, and GetCurrentDirectoryName(), GetName() and GetDepth() are of the Directory you've just finished scanning.
You need to create this small class to describe the behaviour that you want to be performed on each event; here I've created CDTreeViewer as an example.
The example produces a full directory tree listing:
+-dir1
| +-dir11
| | \-fName11
| \-dir12
|   +-fName.txt
|   \-fName12
\-dir2
  +-dir21
  | +-fName.txt
  | \-fName21
  +-dir22
  | +-Copy of fName22
  | +-fName.txt
  | \-fName22
  +-fName.txt
  \-fName2

#include "DTree.h"
#include "ioStream.h"  // For cout
#include <direct.h>    // For mkdir
#include <conio.h>     // For getch

class CDTreeViewer: public CDTreeBehaviour {
  bool Done[MAX_PATH];
public:
  CDTreeViewer(CString Path) {
    CString S;
    DWORD Length=GetFullPathName(Path,0,0,0); //Make relative paths absolute:
    GetFullPathName(Path, Length, S.GetBufferSetLength(Length), 0);
    S.ReleaseBuffer();
    cout << (const char*)(S) << endl;

    memset(Done, false, MAX_PATH);
    CDTree(Path, *this);
  }
private:
  void OnUp  (CDTreeBase& DTreeBase) {Done[DTreeBase.GetDepth()]=false;}
  void OnDIR (CDTreeBase& DTreeBase) {OnFile(DTreeBase);}
  void OnFile(CDTreeBase& DTreeBase) {
    CString S(DTreeBase.GetPath()+'\\'+DTreeBase.GetName());
    for(int i=0; i<DTreeBase.GetDepth(); ++i) cout << (Done[i] ? "  " : "| ");
    cout << (DTreeBase.IsLast() ? '\\' : '+') << '-' << (const char*)(DTreeBase.GetName()) << endl;
    if(DTreeBase.IsLast()) Done[DTreeBase.GetDepth()]=true;
  }
};

main() {
  mkdir("Test"                                                );
  mkdir("Test\\dir1"                                          );
  mkdir("Test\\dir1\\dir11"                                   );
  CFile("Test\\dir1\\fName11"               ,CFile::modeCreate);
  mkdir("Test\\dir1\\dir12"                                   );
  CFile("Test\\dir1\\dir12\\fName.txt"      ,CFile::modeCreate);
  CFile("Test\\dir1\\dir12\\fName12"        ,CFile::modeCreate);
  mkdir("Test\\dir2"                                          );
  mkdir("Test\\dir2\\dir21"                                   );
  CFile("Test\\dir2\\dir21\\fName.txt"      ,CFile::modeCreate);
  CFile("Test\\dir2\\dir21\\fName21"        ,CFile::modeCreate);
  mkdir("Test\\dir2\\dir22"                                   );
  CFile("Test\\dir2\\dir22\\Copy of fName22",CFile::modeCreate);
  CFile("Test\\dir2\\dir22\\fName.txt"      ,CFile::modeCreate);
  CFile("Test\\dir2\\dir22\\fName22"        ,CFile::modeCreate);
  CFile("Test\\dir2\\fName.txt"             ,CFile::modeCreate);
  CFile("Test\\dir2\\fName22"               ,CFile::modeCreate);

  CDTreeViewer(".");
  getch();
}
The following code saves a directory tree to a text file in a compact manner:
The top line is the start path.
Lines starting with a dot '.' specify a directory name.
Lines starting with anything other than a dot are files within the last specified directory.
Lines containing two dots mean "go up a directory".
class CDTreeSaver: public CDTreeBehaviour {
public:
  CDTreeCat(CString Path) : pFile(0), pAr(0) {
    pFile=new CFile;
    if(!pFile->Open("C:\\S.TXT",CFile::modeCreate|CFile::modeWrite)) return;
    pAr=new CArchive(pFile,CArchive::store);
    pAr->WriteString(Path+"\r\n");
    CDTree(Path, *this);
  }
  ~CDTreeCat() {delete pAr; delete pFile;}
private:
  CFile* pFile;
  CArchive* pAr;
  void OnFile(CDTreeBase& DTreeBase) {pAr->WriteString(    DTreeBase.GetName()+"\r\n");}
  void OnDIR (CDTreeBase& DTreeBase) {pAr->WriteString('.'+DTreeBase.GetName()+"\r\n");}
  void OnUp  (CDTreeBase& DTreeBase) {pAr->WriteString("..\r\n");}
};
The following projects in the Freeware section of this site demonstrate the use of DTree.h:
Zeroed File Finder
CopyTree
Automatic Picture Namer

Total File Control

Use Windows' own Move Copy Delete method

In C++ there seem to be many ways to open files, copy them, delete them...
Sometimes certain ways don't work and you end up wondering why - then it turns out to be a problem with long file names or something else rediculous.
But Windows itself uses a nice little dialog that gives a (random?) "time left estimate" and a progress bar.
Its can delete Directory Trees, Read only folders and files, and delete to the recycle bin....
So shouldn't we all be using this?
Heres a little class that wraps the Windows Shell magic.

To delete a File or Folder (which doesn't need to be empty):
  CFileIO::Delete("Test");
If you had a list of Directory Trees to delete, use a string of strings (double null terminator):
  CFileIO::Delete(CString("Test")+'\0'+"Test2"+'\0');
If you give the full path, CFileIO will delete to the Recycle Bin (unless you say:
  CFileIO::Delete("Test\0Test2\0",false);
The following code gets the full path for a file:
  CString Path;
  DWORD Length=GetFullPathName(Path,0,0,0); //Make relative paths absolute:
  GetFullPathName(Path, Length, Path.GetBufferSetLength(Length), 0);
  Path.ReleaseBuffer();
it will also Move and Copy lists of files giving the standard Windows Move/Copy Progress Bar Dialog.
Since my implementation is meant for an Application to use, there is no user feedback with regard to Read-Only files etc.
Everything that can be Moved, Deleted or Copied will be.

If, like me, you use DVD RAM drives for media, it is good to format them using NTFS because its fast and compressed...
But its also cahced, so once you've copied files to such removable media, Windows NT and above might not let you eject it until you've restarted your PC...
Unless the drive caches are flushed - and thats what the FlushDrive is for.

ResFile

Access MFC Resources as if they were MFC CFiles

CResFile allows Read-Only CFile-like access to a DATA resource.
From Visual Studio enter: [Insert Menu][Resource...][Import...][All Files (*.*)] DATA Then load the file you want to access as a Resource.
"DATA" is a Predefined Resource Type and can easily be accessed using RT_RCDATA.

Usage:
  char Buf[6];

  CResFile ResFile(nID);
  ResFile.Read(Buf,6);
  ResFile.Rewind();
or
  CResFile ResFile;
  if(ResFile.Open(nID)) {
    ResFile.Read(Buf,6);
    ResFile.Close();
  }

Directory Chooser Dialog

The Windows Directory Picker

MFC does not provide access to the directory-picking dialog as it does the other common dialogs.
You can use the ShBrowseForFolder function;
The following two functions demonstrate the simplest way to use it:
void CMyDlg::OnButton1() {
  char Dest[MAX_PATH];
  PickDir("Hello", Dest);
}

bool CMyDlg::PickDir(const char *Prompt, char * Dest) {
// Dest is assumed to be _MAX_PATH characters in length
  BROWSEINFO bi;
  ITEMIDLIST* pItemIDList;
  char Folder[_MAX_PATH];
  memset(&bi, 0, sizeof(bi));
  bi.hwndOwner=m_hWnd;
  bi.pszDisplayName=Folder;
  bi.lpszTitle=Prompt;
  if((pItemIDList=SHBrowseForFolder(&bi))!=NULL) {
     SHGetPathFromIDList(pItemIDList, Dest);
     return(true);
  }else return false;
}
There is also Callback functionality available - but most people find that confusing, so I've encapsulated it in a class (CBrowseForFolder) that should help and provided a couple of useful example classes.

CBrowseForDirectory demonstrates the usage of CBrowseForFolder and gets the user to pick a valid Directory (ie not the "Recycle Bin" or "My Computer" etc).
CBrowseForFile also demonstrates the usage of CBrowseForFolder and gets the user to tell us where a particular file is by only enabling the [OK] button when a folder containing a particular file is selected.
Look at the CBrowseForFolder class to see the virtual functions you can override to receive information,
and the functions you can use to control the Dialog Box (the ones that use SendMessage).

This file also contains a horrible little class that encapsulates the revolting code necessary to find the PIDL of a path...
You shouldn't need CItemIDList because there is already a SelectItem function that takes a path, but I've included it to show how to do it.

Icons on Controls

How to Show Icons on Controls

When you want a control to display little bitmaps next to its items you usually want them to come from your own images, or, if the items are files, you want the icons to be those that the system uses to represent the items file-type. The easiest way to get a control to use pictures of your own creation is to create a bitmap 16 pixels high and as long as you need for the number of icons you will require (I've called this IDB_ImageList). Fill the background in an unused colour (Pink is the most popular RGB(255,0,255): we will tell the system not to draw pixels we drew in this color (so pink areas will be transparent).
In the header file of your dialog class we need a CImageList:
  CImageList ImageList;
In the dialog class OnInitDialog() method add the following two lines.
  ImageList.Create(IDB_ImageList, 16, 1, RGB(255,0,255));
  MyTreeControl.SetImageList(&ImageList,TVSIL_NORMAL);
If its not a tree control you'll have to look up the appropriate SetImageList Parameters:
  MyListControl.SetImageList(&ImageList,LVSIL_SMALL);
So how do you get a control to put a File Item's Icon in a control? Well, there may be a better way, but the following is as good as I have found so far:
void SetImage(CString& Path) {
  SHFILEINFO FileInfo;
  HIMAGELIST HImageList=(HIMAGELIST)SHGetFileInfo(Path, FILE_ATTRIBUTE_NORMAL, &FileInfo, sizeof(FileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

  CImageList* pImageList=CImageList::FromHandle(HImageList);
  if(pImageList) MyTreeControl.SetImageList(pImageList,TVSIL_NORMAL);
  MyTreeControl.SetImage(FileInfo.iIcon);
}

void SetFolderImage() {
  SHFILEINFO FileInfo;
  HIMAGELIST HImageList=(HIMAGELIST)SHGetFileInfo("", FILE_ATTRIBUTE_DIRECTORY, &FileInfo, sizeof(FileInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

  CImageList* pImageList=CImageList::FromHandle(HImageList);
  if(pImageList) MyTreeControl.SetImageList(pImageList,TVSIL_NORMAL);
  MyTreeControl.SetImage(FileInfo.iIcon);
}

Modeless Dialogs

Create Dialog Boxes that run in their own Thread

If you derive your dialog class from the following tiny helper class instead of CDialog your dialog box will be "Modeless" instead of "Modal"...
class CModelessDialog : public CDialog {
public:
  CModelessDialog(                         CWnd *pParent=NULL) {}
  CModelessDialog(UINT nIDTemplate,        CWnd *pParent=NULL) {Create(nIDTemplate     , pParent);}
  CModelessDialog(LPCSTR lpszTemplateName, CWnd *pParent=NULL) {Create(lpszTemplateName, pParent);}
protected:
   virtual void OnCancel()      {DestroyWindow();}
   virtual void OnOK()          {if(UpdateData(TRUE)) DestroyWindow();}
   virtual void PostNcDestroy() {delete this;}
};
To use this, create a normal Dialog class.
Replace all occurances of the text 'CDialog' with 'CModelessDialog' in the .cpp and the .h files.
The Dialog only needs to be created to exist, but it won't be visible unless your dialog resource has its Visible flag checked: [Properties][More Styles Tab][Visible].
The code that normally goes in OnInitDlg now goes in the constructor.
To deal with the dialog before you show it, create it, deal with it, then show it.
You can leave Visible unchecked and use 'ShowWindow(SW_SHOW);' in the constructor.
Use 'OnCancel();' to end the dialog.

To stop the Dialog being opened twice, use the following code:
//In the Header file:
  static CMyDlg* Active;

//In the .cpp file:
CMyDlg* CTipDlg::Active=NULL;

//At the beginning of the constructor code MyDlg::MyDlg(:
  if(Active==NULL) Active=this;
  else {
    Active->SetActiveWindow();
    OnCancel();
    return;
  }
  ShowWindow(SW_SHOW);
  SetActiveWindow();

//At the beginning of the Destructor code MyDlg::~MyDlg():
  if(Active==this) Active=NULL;

Draw Fast Rectangles

Draw Fast Rectangles

If you're filling the background yourself: Remember to either do it in OnEraseBkgnd or to not do it at all use:
  BOOL CMyDlgOrControl::OnEraseBkgnd(CDC* pDC) {return TRUE;}
If you're filling it black or white use:
  PatBlt(Rect.left, Rect.top, Rect.Width(), Rect.Height(), BLACKNESS);
or:
  PatBlt(Rect.left, Rect.top, Rect.Width(), Rect.Height(), WHITENESS);
to fill with the current dialog background colour use:
  dc.FillSolidRect(&Rect, GetSysColor(COLOR_3DFACE)); //Draw in dialogs background colour
If you are looking to draw real-time graphics, look at the Graphics section of this site.

Use the System Font

Use the System Font

The proper way to draw text using the same font as the dialog box is:
  NONCLIENTMETRICS ncm;
  ncm.cbSize=sizeof(NONCLIENTMETRICS);
  SystemParametersInfo(SPI_GETNONCLIENTMETRICS,0,&ncm,0);
This provides a LOGFONT structure at ncm.lfStatusFont which you can modify (say by adding underline:
ncm.lfStatusFont.lfUnderline=TRUE;
) Then just use
CreateFontIndirect(&ncm.lfStatusFont);
to have the font ready for selecting into the device context.
If you don't need to alter the font in any ways your code will be simpler using one of the following methods...

If you are drawing text on a control, the font to use is the dialog's font, which can be accessed like this:
  CGdiObject*  OldFont=dc.SelectObject(GetParent()->GetFont());
then use
  dc.DrawText(...);
and finish with
  dc.SelectObject(OldFont);

If you're just wanting to use the font unchanged use:
  CGdiObject* OldFont=dc.SelectStockObject(ANSI_VAR_FONT);
then use
  dc.DrawText(...);
and finish with
  dc.SelectObject(&OldFont);
It is best to use a class to encapsulate the clean-up:
class CUseDialogFont {
  CGdiObject* OldFont;
  CDC* pDC;
public:
  CUseDialogFont(CDC* _pDC) {pDC=_pDC; OldFont=pDC->SelectStockObject(ANSI_VAR_FONT);}
 ~CUseDialogFont()          {pDC->SelectObject(&OldFont);}
};
Then in your code just use:
  CUseDialogFont Font(&dc);
That way you can 'return' at any time safe in the knowledge that the original font will be selected.

Flicker Free Drawing

Use Video Page Swapping with Device Contexts

This is a slightly optimised version of the popular CMemDC class that everyone seems to invent and re-invent.
For the fastest redraw put a bitmap in your Dialog, Control or View header:
  CBitmap Bitmap;
In the .cpp file:
#include "MemDC.h"
and then call the following just once:
  Bitmap.CreateCompatibleBitmap(pDC, Rect.Width(), Rect.Height());
If you don't have pDC use GetDC() which returns the DC of the screen.
If you're using OnPaint() use the following two lines:
  CPaintDC  PaintDC(this); // device context for painting
  CMemDC dc(PaintDC, &Bitmap);
Then draw everything to dc - and thats it!
You don't need the Bitmap - just create the CMemDC with:
  CPaintDC  PaintDC(this); // device context for painting
  CMemDC dc(PaintDC);
it'll be slower for complex animations, but fine for most Controls. The same applies to OwnerDraw Buttons, create the MemDC object as follows:
void CMemDCTesterDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) {
  CMemDC dc(lpDrawItemStruct, &Bitmap);
Theres also a constructor for Views:
void CMyView::OnDraw(CDC* pDC) {
  CMemDC dc(pDC, &Bitmap);
If you are looking to draw real-time graphics, look at the Graphics section of this site.

Progress Bars

Progress Bars made Fast and Easy!

The core of any progress bar is mapping one scale to another.
If you're copying files then the file size has to map to the number of pixels you're going to mark on the screen when the whole file has been copied.
So you need a variable to store the length of the progress bar and another to store the number of bytes to copy.
Since every redraw will want to know how much of the progress bar to draw, you also need to store the number of bytes copied so far.
To save calculating this every time a Redraw happens (assuming the progress bar hasn't moved) we can store the number of pixels to fill across the Progress Bar.
Since most progress bars are rectangular we can simply remember a CRect holding the rectangle to draw; the [right] member of CRect will be what we change as the Progress Bar moves.
Since we may also want to vary other parameters as the Progress Bar moves we should also maintain another scale that will change from 0 to 1 which we can multiply things by... I'll demonstrate this in the project.
If you're going to draw text in the status bar, the redraw gets too slow for most PCs if the Status Bar changes quickly, so you'll have to use Video Paging.
I developed what I'll be using as a demonstration project for a Dialog Application which always reports information with a 'Status Bar' (a Static Text Control).
I didn't want to alter the appearance of the Application just to report progress, and I didn't want to have anything popping up to report separately, so this example is a Static Text Control which can indicate progress when required.
So to begin, you need to create a Static Text Control on your Dialog and call it something like IDC_Status.
Use Class Wizard to create a New Class called CStatus derived from CStatic.
Subclass the control by adding:
  CStatus Status;
to your Dialog's Header file, then add:
    Status.SubclassDlgItem(IDC_Status,this);
to your Dialog's OnInitDialog() method.
Now you are ready to make the Static Control have the extra behaviour needed to be a Progress Bar.
My example CStatus uses colour to show a use for the 0 to 1 scale I talked about.
So if you're not going to download the complete project you should be aware that the example uses files from my Flicker Free and HSL Colour Sections.
If you're going to download the project be aware that the code is written to work as a Debug release only (because the file that is read is one that VC creates when compiling a Debug Release).
I chose this file because its a big file that I can guarantee will exist on all users PCs without downloading anything.
To change the file being read alter the line in StatusTestDlg.cpp:
  if(!File.Open("Debug\\StatusTest.pch", CFile::modeRead)) return;
Hopefully you'll find lots of interesting optimisations in the code!
The colour change has been made to vary from red to green, but without fading. The overall effect for fast changes is strangely more aesthetic than fading, and the redraw speed is faster.
Of course, this is still a fairly standard looking bar, and since you're drawing it all you could do anything you wanted: I've made it capable of make a circular sweep, and a colour wheel, you could make it draw frames from and animation etc.
A useful metaphor, when doing processes like file copying, is a clock: the big hand spinning once round for each file copied, and the small hand once round for all files copied.
If a square space is all that is available, this could replace two progress bars.

Setup AutoPlay CDs

Make CDs open web pages automatically!

In the root of the CD you create a text file called AutoRun.inf
This file can specify an executable file to run when the CD is inserted.
You can make an Icon from the executable file replace the CD Icon in Windows Explorer (the "ICON=Start.exe,0" means that the icon is the first icon in Start.exe).
You can also add commands that are visible if the user right-clicks the CD in Windows Explorer:
the context Menu contains the text in the shell\start line;
and if the menu entry is clicked the executable file in the shell\start\command line is run.
[autorun]
OPEN=Start.exe
ICON=Start.exe,0

shell\Start=&View PSL CD...
shell\Start\command=Start.exe
Thats wonderfully easy, until you want to give out a CD which contains a web site or at least starts from a web page...
You have to write a program (which becomes "Start.exe" which will open your web page...
If we assume the web page is in the root of the CD too and is called "index.htm" we want our Start.exe to open the default Browser and load index.htm...
Finding the default browser requires us to look up a couple of values in the registry.
HKEY_CLASSES_ROOT\.htm tells us where in the registry to get the browsers path from.
So you look up the key you are given (still within HKEY_CLASSES_ROOT) and the browser (full path) is given under "shell\open\command".
Next you need to find the URL of the file you are trying to open to pass to the Browser as a parameter.
This is found by calling GetCurrentDirectory and turning what you get into a valid URL.
All thats left to do is run the browser with the file and the easiest way (there are several) is WinExec.
So if you just want a CD to run \index.htm automatically, create a new application with
[File Menu][New...][Projects Tab][Win32 Application][Simple Win32 Applcation][Finish]
Paste in the following code and insert an Icon of your choice in the resources and you're done!
#include "stdafx.h"

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  HKEY Key;
  if(RegOpenKeyEx(HKEY_CLASSES_ROOT,".htm",0,KEY_READ,&Key)==ERROR_SUCCESS) {
    DWORD dwSize=2*MAX_PATH;
    char Browser[2*MAX_PATH];
    if(RegQueryValueEx(Key,"",NULL,NULL,(BYTE*)&Browser,&dwSize)==ERROR_SUCCESS) {
      RegCloseKey(Key);
      strcat(Browser, "\\shell\\open\\command");
      if(RegOpenKeyEx(HKEY_CLASSES_ROOT,Browser,0,KEY_READ,&Key)==ERROR_SUCCESS) {
        dwSize=2*MAX_PATH;
        if(RegQueryValueEx(Key,"",NULL,NULL,(BYTE*)&Browser,&dwSize)==ERROR_SUCCESS) {
          strcat(Browser," \"file://");
          char* ptr=Browser+dwSize+9-1; //Find the end of the string
          GetCurrentDirectory(MAX_PATH, ptr--);
          while(char c=*++ptr) if(c=='\\') *ptr='/';
          if(*(ptr-1)!='/') {
            *ptr++='/';
            *ptr=0;
          }
          strcat(Browser, "index.htm\"");
          WinExec(Browser, SW_SHOWNORMAL);
    } } }
    RegCloseKey(Key);
  }
  return 0;
}

Of course you can use the same code to open a Web Page from an Application, for example on clicking a Button:
void CMyDlg::OnButton1() {
  HKEY Key;
  if(RegOpenKeyEx(HKEY_CLASSES_ROOT,".htm",0,KEY_READ,&Key)==ERROR_SUCCESS) {
    DWORD dwSize=2*MAX_PATH;
    char Browser[2*MAX_PATH];
    if(RegQueryValueEx(Key,"",NULL,NULL,(BYTE*)&Browser,&dwSize)==ERROR_SUCCESS) {
      RegCloseKey(Key);
      strcat(Browser, "\\shell\\open\\command");
      if(RegOpenKeyEx(HKEY_CLASSES_ROOT,Browser,0,KEY_READ,&Key)==ERROR_SUCCESS) {
        dwSize=2*MAX_PATH;
        if(RegQueryValueEx(Key,"",NULL,NULL,(BYTE*)&Browser,&dwSize)==ERROR_SUCCESS) {
          strcat(Browser," \"http://rossm.net/Electronics/Computers/Software/C++/\"");
          WinExec(Browser, SW_SHOWNORMAL);
    } } }
    RegCloseKey(Key);
} }

ToolTips

Give Controls Tooltips with a few lines of code!

Start by creating a CToolTipCtrl in your dialog header file:
   CToolTipCtrl Tips;
If you don't have OnInitDialog(), use Class Wizard to add WM_INITDIALOG.
Then in the OnInitDialog() function add:
  Tips.Create(this);
  Tips.AddTool(GetDlgItem(IDC_THE_CONTROL),"Click to start transferring e-mails");
  Tips.Activate(TRUE);
To make the Tip Control work use Class Wizard to add PreTranslateMessage.
Then in the PreTranslateMessage(MSG* pMsg) function add:
  Tips.RelayEvent(pMsg);  
and thats it!
You can add more tips for more controls with further calls to AddTool.
Check out the other features on MSDN.

Hand Cursor

Use a Hand Cursor without having one in your Resources


If you want to use a hand cursor like a web browsers use when the mouse is over a link you either have to have Windows 2000 or above, or use a resource.
Download Hand.cur  The trouble with resources is that for small library files like we're offerring on this web site, the Resource is difficult to access once a Class has to work with more than one Application.
So heres a little class that is trivial to use that will give you the Hand Cursor on any version of Win32.
It steals the Cursor from a standard Windows file and uses CopyCursor (and DeleteCursor) to create a local copy.
You can see it in use in the Web Link Button and MSN Messge Window code on this page.
Download HandCursor.h 

Web Link Button

Web Link style Button Class


This class gives an (Owner Draw) CButton Resource the look and feel of a HTML Web Link (Anchor).
Additionally it behaves like a normal CButton in that Focus is maintained and pressing Return or Enter operates a button that currently has focus.
The code demonstrates logical control of the Mouse Cursor and is so similar to the MSN Messge Window code that they share the same Test application.
You just create Buttons as usual on your Dialog, then Subclass them.

MSN Message Window

Notify using MSN-style Pop-up Window Messages



This is the tidiest code I could create to give a tool-tip message window grow unobtrusively out of the Taskbar Icon tray.
All you do in your Dialog/View header is add
  #include "MsgWnd.h"
to the top and add
  CMsgWnd MsgWnd;
To the private or protected section.

In the OnInitDialog() or OnInitialUpdate() you can add any of the following lines:
  MsgWnd.SetOwner(this); //The MsgWnd will now send Notify Messages to 'this' CWnd. If you don't need to know if the user clicked the MsgWnd, then don't have this line!
  MsgWnd.SetAVI(IDR_eMailAnimation); //This isn't necessary, but it was for my application, so its here!
Then use ClassWizard to add an OnNotify handler and make it look like this:
BOOL CMsgWndDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) {
  if(MsgWnd.Clicked(lParam)) {
    SetFocus();

    MsgWnd.Show("You clicked?"); //This line is just for debug feedback

    return TRUE;
  }
  return CDialog::OnNotify(wParam, lParam, pResult);
}
There is also:
    MsgWnd.ShowDelayed("Message", 1000);
which starts showing the window after the specified number of milliseconds (showDelayed defaults to 100ms).

Click Message

Create Click Messages for your Controls

Making the MsgWnd Project made me aware that most people will only want to send a couple of messages in their applications.
In that Project I used WM_NOTIFY and SendMessage.
Here I send a WM_COMMAND PostMessage.
So if you have, for example, a Subclassed Button resource that needs to tell its Owner that it has been clicked, first add the following bools to your control's header:
  bool LButtonDown; // Keeps track of the mouse for Click Messages.
  bool MouseOver;   // true if the mouse is over the window.
In the control's constructor put:
  LButtonDown=false;
  MouseOver=false;
Now use ClassWizard to add OnMouseMove, OnLButtonDown, OnLButtonUp and make them look like this:
void CMsgWnd::OnMouseMove(UINT nFlags, CPoint point) {
  if(!MouseOver) {
    MouseOver=true;
    SetCapture();
  }else{
    CRect Rect;
    GetClientRect(Rect);
    if(Rect.PtInRect(point)) {
      MouseOver=false;
      ReleaseCapture();
    }else{
      CWnd::OnMouseMove(nFlags, point);
      return;
  } }
  RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  CWnd::OnMouseMove(nFlags, point);
}

void CMsgWnd::OnLButtonDown(UINT nFlags, CPoint point) {
  if(MouseOver) LButtonDown=true;
  else CWnd::OnLButtonDown(nFlags, point);
}

void CLinkButton::OnLButtonUp(UINT nFlags, CPoint point) {
  if(MouseOver && LButtonDown) {
    GetOwner()->PostMessage(WM_COMMAND, GetDlgCtrlID());
    MouseOver=false;
    RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
  }else CButton::OnLButtonUp(nFlags, point);
  LButtonDown=false;
}
The dialog that owns this control can now have an ON_BN_CLICKED event handler which will be fired when the Button is clicked.
If you want to have the Mouse Cursor change while over the button, look at the MsgWnd Project which has a neat way of doing this.
The same applies if you want to change the font.

System Tray Icons

Minimize your Application to the System Tray

This is a suite of classes to make it easy to create Applications that minimize to the System Tray.
In CTrayIcon clicking the icon immediately restores the Application's Main Window.
CMenuTrayIcon handles a Context Menu for the icon, so Right-Clicking the Icon makes one of your Icon Resources pop up and Double-Clicking the icon performs that menu's Default Action.
CAniTrayIcon extends CTrayIcon to animate the Icon (you give it a list of Icon Resources).
CAniMenuTrayIcon has Animated Icons and a Context Menu.

Since this class cannot maintain the Title-Bar movement animation on Minimize and Restore that the operating system normally implements you may wish to use my CWndAnimator class with this class.

CTrayIcon helps you make a basic TrayIcon application.
Create a single instance of the class after your Application's m_pMainWnd variable is set.
In CMyApp::InitInstance() (this example is for a Dialog Application):
  CMyDlg dlg;
  m_pMainWnd=&dlg;
  CTrayIcon TI("My ToolTip Text", AfxGetApp()->LoadIcon(IDR_MAINFRAME));
  dlg.DoModal();
If you want your Main Window's Task Bar Button to be hidden when the window is minimized to the System Tray you will need to add the following function:
Use ClassWizard to add an OnSysCommand handler.
void CMyDlg::OnSysCommand(UINT nID, LPARAM lParam) {
  switch(nID & 0xFFF0) {
    case SC_MINIMIZE:  if(lParam) ShowWindow(SW_HIDE); else SetForegroundWindow(); return;
    case IDM_ABOUTBOX: CAboutDlg().DoModal();    return; //This line is only for a Dialog Application with an About Box.
    default: CDialog::OnSysCommand(nID, lParam); return;
} }

CMenuTrayIcon is a CTrayIcon with a Context Menu.

Your CMyApp::InitInstance() would now have a couple of extra parameters to construct the CMenuTrayIcon.
You need to create a Menu Resource, in this case called IDR_PopUps.
The first SubMenu will be used for the System Tray Icon (You can keep all your other PopUp Menus in the same Menu Resource).
The last parameter is the ID of the Default Menu Item.
The Default Menu Item will be shown in bold text in the menu and will be what happens when the user double-clicks the icon.
  CMyDlg dlg;
  m_pMainWnd=&dlg;
  CMenuTrayIcon MTI("My ToolTip Text", AfxGetApp()->LoadIcon(IDR_MAINFRAME), IDR_PopUps, ID_ShowMe);
  dlg.DoModal();
You will also have to use ClassWizard to create handlers for each of these menu items (COMMAND and, optionally, UPDATE_COMMAND_UI (be aware that Dialog Applications don't support UPDATE_COMMAND_UI: you need CFrameWnd derived windows for that)).
To show your application, use ShowWindow(SW_RESTORE);
To close a dialog application, use CDialog::OnCancel();


CAniTrayIcon is a CTrayIcon that handles Animated Icons.

Your Application can now set a NULL Terminated Array of Icon Resource IDs and turn Animation on and off:
  CMyDlg dlg;
  m_pMainWnd=&dlg;
  CAniTrayIcon ATI("My ToolTip Text", AfxGetApp()->LoadIcon(IDR_MAINFRAME));
  static const UINT Icons[]={IDI_ICON1,IDI_ICON2,IDI_ICON3, ... ,0};
  AMTI.SetIcons(Icons);
  ATI.Animate(100); //Show one frame every 100 milliseconds.
  dlg.DoModal();
Well, that'll show you how it works, but to allow your Application to access the CAniTrayIcon::Animate and CAniTrayIcon::StopAnimating functions,
you'll need to create an instance of the class you want to use in your Application Header file,
then use the Create function when you've got the pointer to the Main Window.
You can then access the class by using AfxGetApp().
For example:
((CMyApp*)AfxGetApp())->ATI.StopAnimating();

Window Animation

Animate the Title Bar as your Application is Minimized (like Windows Explorer)

Most of this class is code to find the System Tray Location - the rest is easy.
Normally when you Minimize, Maximize, or Restore a Window you see the Window's Title Bar animate across the screen
but when you use Window Messages such as ShowWindow(SW_RESTORE); the system doesn't animate the Title Bar any more.
This class add the Window's Title Bar Animation.
It was designed to be used with the CTrayIcon class which Minimizes an Application's Main Window to the System Tray in the Task Bar.
Since the Minimize and Restore is then being done by SC_MINIMIZE and SC_RESTORE commands the animation is no longer shown for these operations.

To allow your application to animate its title bar when you Minimize and Restore (like Windows Explorer does)
Create an instance of CWndAnimator in your main window's header:
CWndAnimator WndAnimator();
Then if you are creating a Dialog Application, in OnInitDialog()
WndAnimator.SetWnd(this);
and call each animation function appropriately (this example is for a Dialog Application):
void CMyDlg::OnCancel() {WndAnimator.Close();  CDialog::OnCancel();}
void CMyDlg::OnShow  () {WndAnimator.Restore();}
void CMyDlg::OnSysCommand(UINT nID, LPARAM lParam) {
  switch(nID & 0xFFF0) {
    case IDM_ABOUTBOX: CAboutDlg().DoModal (); return;
    case SC_MINIMIZE:  WndAnimator.Minimize(); return;
    case SC_RESTORE:   if(!IsZoomed()) {WndAnimator.Restore(); return;} //Only use our animation for restoring from the TaskBar
    default: CDialog::OnSysCommand(nID, lParam); return;
} }

Play Ringtones

Let your Application play RTTTL Ringtones!

If you want your application to quickly give audible signals that are simple to specify then this could help...
Perhaps a short Trimphone ring:
In your header file include Toney.h and have an instance in your class:
CToney Toney;
and when you want to play the sound use:
Toney.Play("Trim Phone:d=16,o=5,b=350:a,b,a,b,a,b,a,4p,a,b,a,b,a,b,a,b,a.");
When the CToney is destroyed, the thread playing the sound is stopped.

You can also set things up to read a selection of RTTTL ring tones from a file.
In a dialog box create a Simple Combo Box (IDC_ToneList) and two buttons (IDC_Play, and IDC_Stop).
In your header file include Toney.h and have an instance in your class:
  CToney Toney;
In your OnInit() function put:
  Toney.LoadCombo((CComboBox*)GetDlgItem(IDC_ToneList), "RingTones.RTTTL");
this will fill a Combo Box with Ringtone Names from a file of RTTTL RingTones, one RingTone Per line.
The file may look like this:
Dream:d=8,o=4,b=220:c3,4p.,c,4p,d#3,p,d#,d#3,p,d#,p,d#3,p,f3,4p.,f,4p,g3,p,g,g3,p,a#3,p,c,p,c3,p,f5,p,c,p,c5,d#3,f5,d#,d#3,p,d#,f5,d#3,g5,f3,p,f5,p,f,p,f5,g3,g5,g,g3,p,a#3,p,c,p,c3,g5,f5,p,c,g5,c5,d#3,f5,d#,d#3,p,d#,f5,d#3,g5,f3,g,f5,p,f,g5,f5,g3,g5,g,g3,p,a#3,d#5,c,p,c3,g5,f5,c5,c,g5,c5,d#3,f5,d#,d#3,g5,d#,f5,d#3,g5,f3,g,f5,d#5,f,g5,f5,g3,g5,g,g3,f5,a#3,d#5,c,c5,c3,g5,f5,p,c,g5,c5,d#3,f5,d#,d#3,p,d#,f5,d#3,g5,f3,g,f5,p,f,g5,f5,g3,g5,g,g3,p,a#3,d#5,c,p,c3,p,f5,p,c,p,c5,d#3,f5,d#,d#3,p,d#,f5,d#3,g5,f3,p,f5,p,f,p,f5,g3,g5,g,g3,p,a#3,p,c,p,c3,4p.,c,4p,d#3,p,d#,d#3,p,d#,p,d#3,p,f3,4p.,f,4p,g3,p,g,g3,p,a#3,p,c
Ring High:d=16,o=6,b=350:b5,d,b5,d,b5,d,b5,d,d,f,d,f,d,f,d,f,f,a,f,a,f,a,f,a.
Ring Low:d=16,o=5,b=355:b4,d,b4,d,b4,d,b4,d,d,f,d,f,d,f,d,f,f,a,f,a,f,a,f,a
Scale:d=32,o=5,b=160:c,d,e,f,g,a,b,c6,b,a,g,f,e,d,c
Trim Phone:d=16,o=5,b=350:a,b,a,b,a,b,a,4p,a,b,a,b,a,b,a,b,a.
Wolf Whistle:d=16,o=5,b=900:8a4,a#4,b4,c,c#,d,d#,e,f,f#,g,g#,a,a#,b,c6,8c#6,d6,d#6,e6,f6,4p,4p,a4,a#4,b4,c,c#,d,d#,e,f,f#,g,g#,a,a#,b,a#,a,g#,g,f#,f,e,d#,d,c#,c,b4,a#4,a4
Van Halen-Eruption:d=32,o=5,b=120:c#6,16c#,e,g#,16c#,e,g#,16c#,e,g#,16c#,e,c#6,16c#,e,g#,16c#,e,g#,16c#,e,g#,16c#,e,a,16c#,e,a,16c#,e,a,16c#,e,a,16c#,e,a,16c#,e,a,16c#,e,a,16c#,e,a,16c#,d#,a,16d#,f#,a,16d#,f#,a,16d#,f#,a,16d#,f#,a,16d#,f#,a,16d#,f#,b,16d#,f#,b,16d#,f#,b,16e,g#,b,16e,g#,b,16e,g#,b,16e,g#,b,16e,g#,b,16e,g#,b,16e,g#,b,16e,g#,c6,16e,g,b,16e,g,b,16e,g,b,16e,g,b,16e,g,b,16e,g,d6,16e,g,d6,16e,f#,d6,16f#,a,d6,16f#,a,d6,16f#,a,d6,16f#,a,d6,16f#,a,d6,16f#,a,e6,16f#,a,e6,16f#,a,e6,16b,g#,e6,16b,g#,e6,16b,g#,e6,16b,g#,e6,16b,g#,e6,b,16g#,e6,b,16g#,e6,b,16g#,e6,16g#.,e6,g#,16b,e6,16b.,e6,b,16d6,e6,a#,16c#6,e6,a#,16c#6,e6,a,16c6,e6,a,16c6,e6,g#,16b,e6,g#,b,d6,e6,b,16d6,e6,b,16d6,e6,a#,16c#6,e6,a#,16c#6,e6,a,16c6,e6,a,16c6,e6,g#,16b,e6,g#,16b,d6,a,16c6,d6,a,16c6,d6,g#,16b,d6,g#,16b,d6,g,16a#,d6,g,16a#,d6,f#,a,16d6,f#,a,16c6,g,16a#,c6,g,16a#,c6,f#,16a,c6,f#,16a,c6,f,16g#,c6,f,16g#,c6,e,16g,c6,e,16g,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,e,16g,b,e,16g,b,e,16g,b,e,16g,b,e,16g,b,e,16g,b,e,16g,b,e,16g,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,e,16g,b,d#,16f#,b,4e,4a#4,4e.3
Zorba (Give it time!):d=16,o=5,b=125:16c#6,2d6,2p,c#6,2d6,2p,32e6,32d6,32c#6,2d6,2p,c#6,2d6,2p,b,2c6,2p,32d6,32c6,32b,2c6,2p,a#,2b,4p,8p,32c6,32b,32a,32g,32b,2a,2p,32a,32g,32f#,32a,1g,1p,8c#6,8d6,8d6,8d6,8d6,8d6,8d6,8d6,8c#6,8d6,8d6,8d6,8d6,8d6,e6,d6,c#6,e6,8c#6,8d6,8d6,8d6,8d6,8d6,8d6,8d6,8c#6,8d6,8d6,8d6,8d6,8d6,e6,d6,c#6,e6,8b,8c6,8c6,8c6,8c6,8c6,8c6,8c6,8b,8c6,8c6,8c6,8c6,8c6,d6,c6,b5,d6,8b,8c6,8c6,8c6,8c6,8c6,8c6,8c6,8b,8c6,8c6,8c6,8c6,8c6,8c6,8c6,c#6.,d6.,d6.,d6.,d6.,d6.,d6.,d6.,c#6.,d6.,d6.,d6.,d6.,d6.,32e6.,32d6.,32c#6.,32e6.,c#6.,d6.,d6.,d6.,d6.,d6.,d6.,d6.,c#6.,d6.,d6.,d6.,d6.,d6.,32e6.,32d6.,32c#6.,32e6.,b.,c6.,c6.,c6.,c6.,c6.,c6.,c6.,b.,c6.,c6.,c6.,c6.,c6.,32d6.,32c6.,32b5.,32d6.,b.,c6.,c6.,c6.,c6.,c6.,c6.,c6.,b.,c6.,c6.,c6.,c6.,c6.,c6.,c6.,
To play any of the tunes use the following code in the event handlers for the buttons:
void CMyDlg::OnStop() {Toney.Stop();}
void CMyDlg::OnPlay() {
  CString S;
  CComboBox* List=(CComboBox*)GetDlgItem(nID);
  List->GetLBText(List->GetCurSel(), S);
  Toney.Play(S, "RingTones.RTTTL");
}
The playing is done in a separate Thread using CThread (OnPlay doesn't need to call OnStop first, because that is done by CThread automatically).
This is available as a demo project to download:
The project contains a file with 165 ring tones in as samples.
If you have any good tones worth adding, e-mail me and I'll update everything.

If anyone thinks its worth me maintaining or updating any of the above, please e-mail me.