You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
8.6 KiB
341 lines
8.6 KiB
/*****************************************************************************\
|
|
FILE: ACEmail.cpp
|
|
|
|
DESCRIPTION:
|
|
This file implements AutoComplete for Email Addresses.
|
|
|
|
BryanSt 3/1/2000
|
|
Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
|
|
\*****************************************************************************/
|
|
|
|
#include "priv.h"
|
|
#include <atlbase.h> // USES_CONVERSION
|
|
#include "util.h"
|
|
#include "objctors.h"
|
|
#include <comdef.h>
|
|
|
|
#include "MailBox.h"
|
|
|
|
#define MAX_EMAIL_MRU_SIZE 100
|
|
|
|
|
|
|
|
class CACLEmail
|
|
: public IEnumString
|
|
, public IACList
|
|
{
|
|
public:
|
|
//////////////////////////////////////////////////////
|
|
// Public Interfaces
|
|
//////////////////////////////////////////////////////
|
|
|
|
// *** IUnknown ***
|
|
virtual STDMETHODIMP_(ULONG) AddRef(void);
|
|
virtual STDMETHODIMP_(ULONG) Release(void);
|
|
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
|
|
|
|
// *** IEnumString ***
|
|
virtual STDMETHODIMP Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched);
|
|
virtual STDMETHODIMP Skip(ULONG celt) {return E_NOTIMPL;}
|
|
virtual STDMETHODIMP Reset(void);
|
|
virtual STDMETHODIMP Clone(IEnumString **ppenum) {return E_NOTIMPL;}
|
|
|
|
// *** IACList ***
|
|
virtual STDMETHODIMP Expand(LPCOLESTR pszExpand) {return E_NOTIMPL;}
|
|
|
|
private:
|
|
// Constructor / Destructor (protected so we can't create on stack)
|
|
CACLEmail(LPCTSTR pszMRURegKey);
|
|
~CACLEmail(void);
|
|
|
|
HRESULT AddEmail(IN LPCWSTR pszEmailAddress);
|
|
|
|
// Instance creator
|
|
friend HRESULT CACLEmail_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT void ** ppvObj);
|
|
friend HRESULT AddEmailToAutoComplete(IN LPCWSTR pszEmailAddress);
|
|
|
|
// Private variables
|
|
DWORD m_cRef; // COM reference count
|
|
DWORD m_nMRUIndex; // Current Index into MRU
|
|
|
|
DWORD m_dwRunMRUIndex; // Index into the Run MRU.
|
|
DWORD m_dwRunMRUSize;
|
|
HANDLE m_hMRURun;
|
|
};
|
|
|
|
|
|
|
|
|
|
//===========================
|
|
// *** IEnumString Interface ***
|
|
//===========================
|
|
HRESULT CACLEmail::Reset(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
m_nMRUIndex = 0;
|
|
m_dwRunMRUIndex = 0;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CACLEmail::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szMRUEntry[MAX_URL_STRING+1];
|
|
LPWSTR pwzMRUEntry = NULL;
|
|
|
|
*pceltFetched = 0;
|
|
if (!celt)
|
|
return S_OK;
|
|
|
|
if (!rgelt)
|
|
return S_FALSE;
|
|
|
|
*rgelt = 0;
|
|
if (m_dwRunMRUIndex >= m_dwRunMRUSize)
|
|
hr = S_FALSE; // No more.
|
|
else
|
|
{
|
|
if (m_hMRURun && EnumMRUList(m_hMRURun, m_dwRunMRUIndex++, szMRUEntry, ARRAYSIZE(szMRUEntry)) > 0)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
DWORD cchSize = lstrlen(szMRUEntry)+1;
|
|
//
|
|
// Allocate a return buffer (caller will free it).
|
|
//
|
|
pwzMRUEntry = (LPOLESTR)CoTaskMemAlloc(cchSize * sizeof(pwzMRUEntry[0]));
|
|
if (pwzMRUEntry)
|
|
{
|
|
//
|
|
// Convert the display name into an OLESTR.
|
|
//
|
|
#ifdef UNICODE
|
|
StrCpyN(pwzMRUEntry, szMRUEntry, cchSize);
|
|
#else // ANSI
|
|
MultiByteToWideChar(CP_ACP, 0, szMRUEntry, -1, pwzMRUEntry, cchSize);
|
|
#endif // ANSI
|
|
rgelt[0] = pwzMRUEntry;
|
|
*pceltFetched = 1;
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================
|
|
// *** IUnknown Interface ***
|
|
//===========================
|
|
STDMETHODIMP CACLEmail::QueryInterface(REFIID riid, LPVOID *ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CACLEmail, IEnumString),
|
|
QITABENT(CACLEmail, IACList),
|
|
{ 0 },
|
|
};
|
|
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|
|
|
|
|
|
ULONG CACLEmail::AddRef(void)
|
|
{
|
|
m_cRef++;
|
|
return m_cRef;
|
|
}
|
|
|
|
|
|
ULONG CACLEmail::Release(void)
|
|
{
|
|
ASSERT(m_cRef > 0);
|
|
|
|
m_cRef--;
|
|
|
|
if (m_cRef > 0)
|
|
{
|
|
return m_cRef;
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//===========================
|
|
// *** Class Methods ***
|
|
//===========================
|
|
HRESULT CACLEmail::AddEmail(IN LPCWSTR pszEmailAddress)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (-1 == AddMRUStringW(m_hMRURun, pszEmailAddress))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
CACLEmail::CACLEmail(LPCTSTR pszMRURegKey)
|
|
{
|
|
DllAddRef();
|
|
|
|
// Require object to be in heap and Zero-Inited
|
|
ASSERT(!m_nMRUIndex);
|
|
ASSERT(!m_dwRunMRUIndex);
|
|
ASSERT(!m_hMRURun);
|
|
|
|
MRUINFO mi = {
|
|
sizeof(MRUINFO),
|
|
MAX_EMAIL_MRU_SIZE,
|
|
MRU_CACHEWRITE,
|
|
HKEY_CURRENT_USER,
|
|
SZ_REGKEY_EMAIL_MRU,
|
|
NULL // NOTE: use default string compare
|
|
// since this is a GLOBAL MRU
|
|
};
|
|
|
|
m_hMRURun = CreateMRUList(&mi);
|
|
if (m_hMRURun)
|
|
m_dwRunMRUSize = EnumMRUList(m_hMRURun, -1, NULL, 0);
|
|
|
|
m_cRef = 1;
|
|
}
|
|
|
|
|
|
CACLEmail::~CACLEmail()
|
|
{
|
|
if (m_hMRURun)
|
|
FreeMRUList(m_hMRURun);
|
|
|
|
DllRelease();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************\
|
|
DESCRIPTION:
|
|
This function create an instance of the AutoComplete
|
|
List "MRU". This will point to either the MRU for
|
|
a browser or for a non-browser (Start->Run or
|
|
the AddressBar in the Taskbar or floating) depending
|
|
on the pszMRU parameter.
|
|
\****************************************************/
|
|
HRESULT CACLEmail_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT void ** ppvObj)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
CACLEmail *paclSF = new CACLEmail(NULL);
|
|
if (paclSF)
|
|
{
|
|
hr = paclSF->QueryInterface(riid, ppvObj);
|
|
paclSF->Release();
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT AddEmailToAutoComplete(IN LPCWSTR pszEmailAddress)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
CACLEmail *paclSF = new CACLEmail(NULL);
|
|
if (paclSF)
|
|
{
|
|
hr = paclSF->AddEmail(pszEmailAddress);
|
|
paclSF->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
#define SZ_REGKEY_AUTOCOMPLETE_TAB TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete")
|
|
#define SZ_REGVALUE_AUTOCOMPLETE_TAB TEXT("Always Use Tab")
|
|
#define BOOL_NOT_SET 0x00000005
|
|
DWORD _UpdateAutoCompleteFlags(void)
|
|
{
|
|
DWORD dwACOptions = 0;
|
|
|
|
if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, /*default:*/FALSE))
|
|
{
|
|
dwACOptions |= ACO_AUTOAPPEND;
|
|
}
|
|
|
|
if (SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, /*default:*/TRUE))
|
|
{
|
|
dwACOptions |= ACO_AUTOSUGGEST;
|
|
}
|
|
|
|
// Windows uses the TAB key to move between controls in a dialog. UNIX and other
|
|
// operating systems that use AutoComplete have traditionally used the TAB key to
|
|
// iterate thru the AutoComplete possibilities. We need to default to disable the
|
|
// TAB key (ACO_USETAB) unless the caller specifically wants it. We will also
|
|
// turn it on
|
|
static BOOL s_fAlwaysUseTab = BOOL_NOT_SET;
|
|
if (BOOL_NOT_SET == s_fAlwaysUseTab)
|
|
s_fAlwaysUseTab = SHRegGetBoolUSValue(SZ_REGKEY_AUTOCOMPLETE_TAB, SZ_REGVALUE_AUTOCOMPLETE_TAB, FALSE, FALSE);
|
|
|
|
if (s_fAlwaysUseTab)
|
|
dwACOptions |= ACO_USETAB;
|
|
|
|
return dwACOptions;
|
|
}
|
|
|
|
|
|
// TODO: Move this functionality to SHAutoComplete when it's ready.
|
|
STDAPI AddEmailAutoComplete(HWND hwndEdit)
|
|
{
|
|
IUnknown * punkACL = NULL;
|
|
DWORD dwACOptions = _UpdateAutoCompleteFlags();
|
|
HRESULT hr = CACLEmail_CreateInstance(NULL, IID_PPV_ARG(IUnknown, &punkACL));
|
|
|
|
if (punkACL) // May fail on low memory.
|
|
{
|
|
IAutoComplete2 * pac;
|
|
|
|
// Create the AutoComplete Object
|
|
hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAutoComplete2, &pac));
|
|
if (SUCCEEDED(hr)) // May fail because of out of memory
|
|
{
|
|
if (SHPinDllOfCLSID(&CLSID_ACListISF) &&
|
|
SHPinDllOfCLSID(&CLSID_AutoComplete))
|
|
{
|
|
hr = pac->Init(hwndEdit, punkACL, NULL, NULL);
|
|
pac->SetOptions(dwACOptions);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
pac->Release();
|
|
}
|
|
|
|
punkACL->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|