Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Detect and run the default mail client

0.00/5 (No votes)
24 Sep 2002 1  
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.
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

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):

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:

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

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:
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