Click here to Skip to main content
15,906,626 members
Articles / Programming Languages / C++
Article

Detect and run the default mail client

Rate me:
Please Sign up or sign in to vote.
1.00/5 (2 votes)
24 Sep 2002 89.6K   933   18   13
Programatically get the default mail client using registry

Helpers

Actually these are more suitable for interfaces, but hopefully good for other objects too needing auto-deletion on getting out-of-scope.
C++
template<typename T>
class AutoDeleteHlp
{
    typedef T _Item;

    public:
        AutoDeleteHlp(T t)
        {
            m_T = t;
        }
        ~AutoDeleteHlp()
        {}
        operator T ()
        {
            return m_T;
        }
        operator T *()
        {
            return (T *)&m_T;
        }
        virtual operator bool()
        {
            return (m_T != NULL) ? true : false;
        }
        T **operator &()
        {
            return &m_T;
        }
        T *Get()
        {
            return m_T;
        }
        void Set(T t)
        {
            m_T = t;
        }

    private:
        virtual void Delete() = 0;

    protected:
        T m_T;
};

The (incomplete) registry key helper

C++
class RegKey_ : public AutoDeleteHlp<HKEY>
{
    public:
        RegKey_(HKEY hk = 0)
            : AutoDeleteHlp<HKEY>(hk)
        {}
        ~RegKey_()
        {
            Delete();
        }
        LONG Open(HKEY hKey, LPCTSTR lpSubkeyName, REGSAM regSam = KEY_READ)
        {
            return ::RegOpenKeyEx(hKey, lpSubkeyName, 0, regSam, &m_T);
        }
        LONG ReadString(LPTSTR lpString, DWORD cbData, 
          LPCTSTR lpValName = _T(""))
        {
            DWORD dwType;
            return ::RegQueryValueEx(m_T, lpValName, NULL, 
              &dwType, (LPBYTE)lpString, &cbData);
        }
        LONG Read(LPBYTE lpData, DWORD cbData, LPCTSTR lpValName = _T(""))
        {
            DWORD dwType;
            return ::RegQueryValueEx(m_T, lpValName, NULL, 
              &dwType, (LPBYTE)lpData, &cbData);
        }
    private:
        virtual void Delete()
        {
            if(m_T)
            {
                _Item hk = m_T;
                m_T = 0;

                if(::RegCloseKey(hk))
                {
                    hk = NULL;
                }
            }
        }
};

...the CreateProcess wrapper (for executing a command line):

C++
class CmdLineExec_
{
    private:
        STARTUPINFO            m_si;
        PROCESS_INFORMATION m_pi;

        TCHAR                m_lpCmdLine[_MAX_PATH + 1];

    public:
        CmdLineExec_(LPCTSTR lpCmdLine)
        {
            ZeroMemory(&m_si, sizeof(STARTUPINFO));
            ZeroMemory(&m_pi, sizeof(PROCESS_INFORMATION));

            if(lpCmdLine != NULL)
            {
                lstrcpyn(m_lpCmdLine, lpCmdLine, _MAX_PATH + 1);
            }
            else
            {
                lstrcpyn(m_lpCmdLine, _T(""), _MAX_PATH + 1);
            }
        }
        ~CmdLineExec_()
        {
            if(m_pi.hProcess)
            {
                CloseHandle(m_pi.hProcess);
            }
            if(m_pi.hThread)
            {
                CloseHandle(m_pi.hThread);
            }
        }
    public:
        BOOL Execute(DWORD *pdwLastError = NULL)
        {
            BOOL fRet = CreateProcess(NULL, (LPTSTR)m_lpCmdLine, NULL, 
                NULL, FALSE, 0, NULL, NULL, &m_si, &m_pi);
            if(pdwLastError != NULL)
            {
                *pdwLastError = GetLastError();
            }

            return fRet;
        }
};

... and finally the default mail client wrapper:

C++
class DefaultMailClient_ : public RegKey_
{
    private:
        TCHAR    m_szDefMailClient[_MAX_PATH + 1];
        BOOL    m_fValid;

    public:
        TCHAR    m_szDefMailCmd[_MAX_PATH + 1];

    public:
        DefaultMailClient_(HKEY hk = 0)
            : RegKey_(hk)
        {
            lstrcpyn(m_szDefMailClient, _T("SOFTWARE\\Clients\\Mail"),
                _MAX_PATH);
            lstrcpyn(m_szDefMailCmd, _T(""), _MAX_PATH);

            m_fValid = GetCmdLine();
        }
        ~DefaultMailClient_()
        {
            Delete();
        }

    public:
        BOOL IsValid()
        {
            return m_fValid;
        }
        BOOL Execute()
        {
            CmdLineExec_ cmdl(m_szDefMailCmd);
            return cmdl.Execute();
        }
    protected:
        BOOL GetCmdLine()
        {
            LONG retval;
            
            retval = Open(HKEY_LOCAL_MACHINE, m_szDefMailClient);
            if(retval == NO_ERROR)
            {
                DWORD cbData = _MAX_PATH;
                retval = ReadString(m_szDefMailClient, cbData);
                if(retval == NO_ERROR)
                {
                    TCHAR szCmdLine[_MAX_PATH + 1];

                    lstrcpyn(szCmdLine, _T("SOFTWARE\\Clients\\Mail\\"), 
                       _MAX_PATH + 1);
                    _tcsncat(szCmdLine, m_szDefMailClient, _MAX_PATH + 1);
                    _tcsncat(szCmdLine, _T(\\shell\\open\\command),
                       _MAX_PATH + 1);

                    RegKey_ rk;
                    if(rk.Open(HKEY_LOCAL_MACHINE, szCmdLine) == NO_ERROR)
                    {
                        retval = rk.ReadString(m_szDefMailCmd, _MAX_PATH);
                        if(retval == NO_ERROR)
                        {
                            return TRUE;
                        }
                    }
                }
            }

            return FALSE;
        }

    private:
        virtual void Delete()
        {
            if(m_T)
            {
                _Item hk = m_T;
                m_T = 0;

                if(::RegCloseKey(hk))
                {
                    hk = NULL;
                }
            }
        }
};

Calling routine

C++
void OpenDefaultMailClient()
{
    DefaultMailClient_ dmcl;
    if(dmcl.IsValid())
    {
        if(!dmcl.Execute())
        {
            MessageBox(NULL,
                _T("Could not launch the default mail client."), 
                NULL, MB_OK);
        }
    }
}
main simply calls this function:
C++
void main()
{
    OpenDefaultMailClient();
}

For convenience, the dsw and dsp files are included, and also the makefile. For a single-file project, open a console and execute :-

...> nmake /f dmcl.mak 

Conclusion

That's it. Keep it simple. Use the function instead of digging registry yourself (like I did). Tested on Windows 2000 SP3. Let me know if you have problems on other platforms.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralWindows Vista Pin
][cepick2-May-07 5:06
][cepick2-May-07 5:06 
QuestionRe: Windows Vista Pin
Member 357581824-Sep-08 1:32
Member 357581824-Sep-08 1:32 
GeneralDoesn't work with Netscape Messenger Pin
otrcomm10-Jul-04 17:07
otrcomm10-Jul-04 17:07 
I tried this with Netscape Messenger 4.7, but dmcl.IsValid() is always false.

the shell command for Netscape Messenger in the registry is "C:\Program Files\Netscape\Communicator\Program\netscape.exe" %1, but the shortcut to Netscape Messenger is "C:\Program Files\Netscape\Communicator\Program\netscape.exe" -mail.

The latter works from Run, but not the first.

I tried changing the shell command in the registry to the latter, but the code still doesn't work.

No errors, it just goes to the blackhole.

Murrah Boswell
GeneralThis is useful for non-MS mail clients Pin
Nish Nishant29-Sep-03 2:22
sitebuilderNish Nishant29-Sep-03 2:22 
Questionerror code:ERROR_SXS_ASSEMBLYNOTFOUND What is this? Pin
girishnadig18-Sep-03 6:55
girishnadig18-Sep-03 6:55 
AnswerRe: error code:ERROR_SXS_ASSEMBLYNOTFOUND What is this? Pin
Sardaukar18-Sep-03 19:54
Sardaukar18-Sep-03 19:54 
GeneralKISS Pin
Anonymous25-Sep-02 8:24
Anonymous25-Sep-02 8:24 
GeneralRe: KISS Pin
Sardaukar25-Sep-02 9:02
Sardaukar25-Sep-02 9:02 
GeneralRe: KISS Pin
Daniel Turini25-Sep-02 10:28
Daniel Turini25-Sep-02 10:28 
GeneralRe: KISS Pin
Sardaukar25-Sep-02 20:15
Sardaukar25-Sep-02 20:15 
GeneralRe: KISS Pin
Sardaukar25-Sep-02 20:21
Sardaukar25-Sep-02 20:21 
GeneralRe: KISS Pin
Andreas Saurwein26-Sep-02 1:50
Andreas Saurwein26-Sep-02 1:50 
GeneralRe: KISS Pin
Sardaukar26-Sep-02 2:47
Sardaukar26-Sep-02 2:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.