|
|
/*
Copyright (c) 2000 Microsoft Corporation
Module Name: smapi.cpp
Abstract: CSMapi object. Used to support our simple MAPI functions.
Revision History: created steveshi 08/23/00 */
#include "stdafx.h"
#include "Rcbdyctl.h"
#include "smapi.h"
#include "mapix.h"
#include "utils.h"
#define C_OEAPP TEXT("Outlook Express")
#define F_ISOE 0x1
#define F_ISCONFIG 0x2
#define LEN_MSOE_DLL 9 // length of "\\msoe.dll"
#define LEN_HMMAPI_DLL 11 // length of "\\hmmapi.dll"
BOOL GetMAPIDefaultProfile(TCHAR*, DWORD*);
#define E_FUNC_NOTFOUND 1000 //Userdefined error no.
// Csmapi
Csmapi::~Csmapi() { if (m_bLogonOK) Logoff(); if (m_hLib) FreeLibrary(m_hLib); }
STDMETHODIMP Csmapi::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* arr[] = { &IID_Ismapi }; for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++) { if (InlineIsEqualGUID(*arr[i],riid)) return S_OK; } return S_FALSE; }
BOOL Csmapi::IsOEConfig() { CRegKey cOE; LONG lRet; BOOL bRet = FALSE; TCHAR szBuf[MAX_PATH]; DWORD dwCount = MAX_PATH -1 ;
lRet = cOE.Open(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Account Manager"), KEY_READ); if(lRet == ERROR_SUCCESS) { lRet = cOE.QueryValue(szBuf, TEXT("Default Mail Account"), &dwCount); if (lRet == ERROR_SUCCESS) { TCHAR szActs[MAX_PATH]; CRegKey cOEAcct;
wsprintf(szActs, TEXT("Accounts\\%s"), szBuf); lRet = cOEAcct.Open((HKEY)cOE, szActs, KEY_READ); if (lRet == ERROR_SUCCESS) { bRet = TRUE; cOEAcct.Close(); } } cOE.Close(); } return bRet; }
HRESULT Csmapi::get_Reload(LONG* pVal) { if (!pVal) return E_POINTER;
HRESULT hr = S_OK; CComBSTR bstrName, bstrOldName; *pVal = 0; // assume failed for some reason;
if(m_bLogonOK) { Logoff(); } if (m_hLib) { FreeLibrary(m_hLib); m_lpfnMapiFreeBuf = NULL; m_lpfnMapiAddress = NULL; m_hLib = NULL; }
if (m_szSmapiName[0] != _T('\0')) bstrOldName = m_szSmapiName;
m_lOEFlag = 0; hr = get_SMAPIClientName(&bstrName); if (FAILED(hr) || bstrName.Length() == 0) { *pVal = 0; // failed for some reason
goto done; }
if (bstrOldName.Length() > 0 && wcscmp(bstrOldName,bstrName) != 0) { *pVal = 1; // Email client get changed.
} else { *pVal = -1; // succeed.
}
done: return S_OK; }
HRESULT Csmapi::get_SMAPIClientName(BSTR *pVal) { if (!pVal) return E_POINTER; HRESULT hr = S_OK;
CRegKey cKey; LONG lRet; DWORD dwCount = sizeof(m_szSmapiName)/sizeof(m_szSmapiName[0]) -1;
// Get default email client
if (m_hLib) // Already initialized.
goto done;
#ifndef _WIN64 // WIN32. We use only OE on Win64.
lRet = cKey.Open(HKEY_LOCAL_MACHINE, TEXT("Software\\Clients\\Mail"), KEY_READ); if (lRet != ERROR_SUCCESS) goto done;
lRet = cKey.QueryValue(m_szSmapiName, NULL, &dwCount); // get default value
if (lRet == ERROR_SUCCESS) { // Is the email client Smapi compliant?
// 1. get it's dllpath
CRegKey cMail; lRet = cMail.Open((HKEY)cKey, m_szSmapiName, KEY_READ); if (lRet == ERROR_SUCCESS) { dwCount = sizeof(m_szDllPath)/sizeof(m_szDllPath[0]) - 1; lRet = cMail.QueryValue(m_szDllPath, TEXT("DLLPath"), &dwCount); if (lRet == ERROR_SUCCESS) { LONG len = lstrlen(m_szDllPath); if ( !(len > LEN_MSOE_DLL && // no need to check OE
lstrcmpi(&m_szDllPath[len - LEN_MSOE_DLL], TEXT("\\msoe.dll")) == 0) && !(len > LEN_HMMAPI_DLL && // We don't want HMMAPI either
_tcsicmp(&m_szDllPath[len - LEN_HMMAPI_DLL], TEXT("\\hmmapi.dll")) == 0)) { HMODULE hLib = LoadLibrary(m_szDllPath); if (hLib != NULL) { if (GetProcAddress(hLib, "MAPILogon")) { m_hLib = hLib; // OK, this is the email program that we want.
} } } cMail.Close(); } } cKey.Close(); } #endif
if (m_hLib == NULL) // Need to use OE
{ m_szSmapiName[0] = TEXT('\0'); // in case OE is not available.
m_hLib = LoadOE(); }
done: *pVal = (BSTR)CComBSTR(m_szSmapiName).Copy(); return hr; }
HMODULE Csmapi::LoadOE() { LONG lRet; HKEY hKey, hSubKey; DWORD dwIndex = 0; TCHAR szName[MAX_PATH]; TCHAR szBuf[MAX_PATH]; TCHAR szDll[MAX_PATH]; DWORD dwName, dwBuf; FILETIME ft; HMODULE hLib = NULL;
lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Clients\\Mail"), 0, KEY_ENUMERATE_SUB_KEYS, &hKey); if (lRet == ERROR_SUCCESS) { dwName = sizeof(szName) / sizeof(szName[0]); while(ERROR_SUCCESS == RegEnumKeyEx(hKey, dwIndex++, // subkey index
&szName[0], // subkey name
&dwName, // size of subkey buffer
NULL, NULL, NULL, &ft)) { // get dll path.
lRet = RegOpenKeyEx(hKey, szName, 0, KEY_QUERY_VALUE, &hSubKey); if (lRet == ERROR_SUCCESS) { dwBuf = sizeof(szBuf); lRet = RegQueryValueEx(hSubKey, // handle to key
TEXT("DllPath"), NULL, NULL, (BYTE*)&szBuf[0], // data buffer
&dwBuf); if (lRet == ERROR_SUCCESS) { // is it msoe.dll?
lRet = lstrlen(szBuf); if (lRet > LEN_MSOE_DLL && lstrcmpi(&szBuf[lRet - LEN_MSOE_DLL], TEXT("\\msoe.dll")) == 0) { // Resolve environment variable.
lRet = sizeof(m_szDllPath) / sizeof(m_szDllPath[0]); dwBuf = ExpandEnvironmentStrings(szBuf, m_szDllPath, lRet); if (dwBuf > (DWORD)lRet) { // TODO: Need to handle this case
} else if (dwBuf == 0) { // TODO: Failed.
} else if ((hLib = LoadLibrary(m_szDllPath))) { lstrcpy(m_szSmapiName, szName); m_lOEFlag = F_ISOE | (IsOEConfig() ? F_ISCONFIG : 0); } break; } } RegCloseKey(hSubKey); } dwName = sizeof(szName) / sizeof(szName[0]); } RegCloseKey(hKey); } return hLib; }
HRESULT Csmapi::get_IsSMAPIClient_OE(LONG *pVal) { if (!pVal) return E_POINTER; HRESULT hr = S_OK; CComBSTR bstrTest; get_SMAPIClientName(&bstrTest); *pVal = m_lOEFlag; return hr; }
/******************************************
Func: Logon Abstract: Simple MAPI logon wrapper Params: None *******************************************/ STDMETHODIMP Csmapi::Logon(ULONG *plReg) { if (!plReg) return E_POINTER; HRESULT hr = E_FAIL; *plReg = 0; USES_CONVERSION; ULONG err = 0; // Check Win.ini MAPI == 1 ?
if (m_bLogonOK) { hr = S_OK; *plReg = 0; goto done; } // Load MAPI32.DLL
if (!m_hLib) { LONG lError; get_Reload(&lError); if (lError == 0) // failed.
{ *plReg = 1; goto done; } }
if (m_hLib != NULL) { LPMAPILOGON lpfnMapiLogon = (LPMAPILOGON)GetProcAddress(m_hLib, "MAPILogon"); if (lpfnMapiLogon == NULL) goto done;
// 1st, is there any existing session that I can use?
err = lpfnMapiLogon( 0L, NULL, NULL, 0 , 0, &m_lhSession); if (err != SUCCESS_SUCCESS) { // OK. I need a new session.
// Get default profile from registry
//
TCHAR szProfile[256]; DWORD dwCount = 255; szProfile[0]= TEXT('\0'); ::GetMAPIDefaultProfile((TCHAR*)szProfile, &dwCount);
err = lpfnMapiLogon( 0L, T2A(szProfile), NULL, MAPI_LOGON_UI , 0, &m_lhSession);
if (err != SUCCESS_SUCCESS) { PopulateAndThrowErrorInfo(err); goto done; } } // err == SUCCESS_SUCCESS
m_bLogonOK = TRUE; *plReg = 1; hr = S_OK; }
done: return hr; }
/******************************************
Func: Logoff
Abstract: Simple MAPI logoff wrapper
Params:
*******************************************/ STDMETHODIMP Csmapi::Logoff() { if (m_bLogonOK) { LPMAPILOGOFF lpfnMapiLogOff = (LPMAPILOGOFF)GetProcAddress(m_hLib, "MAPILogoff"); if (lpfnMapiLogOff) lpfnMapiLogOff (m_lhSession, 0, 0, 0);
m_bLogonOK = FALSE; }
return S_OK; }
/******************************************
Func: SendMail
Abstract: Simple MAPI MAPISendMail wrapper. It always take the attachment file from m_bstrXMLFile member variable.
Params: *plStatus: 1(Succeed)/others(Fail) *******************************************/ STDMETHODIMP Csmapi::SendMail(LONG* plStatus) { if (!plStatus) return E_POINTER; HRESULT hr = E_FAIL; ULONG err = 0; ULONG cRecip = 0; MapiRecipDesc *pMapiRecipDesc = NULL;
USES_CONVERSION;
*plStatus = 0; if (!m_bLogonOK) // Logon problem !
return S_FALSE;
LPMAPISENDMAIL lpfnMapiSendMail = (LPMAPISENDMAIL)GetProcAddress(m_hLib, "MAPISendMail"); if (lpfnMapiSendMail == NULL) return E_FAIL;
// Since we don't resolve name before, we need to resolve name here
// Even if the name list comes form AddressBook, some name list was not resolved
// in address book.
MapiFileDesc attachment = {0, // ulReserved, must be 0
0, // no flags; this is a data file
(ULONG)-1, // position not specified
W2A(m_bstrXMLFile), // pathname
NULL, //"RcBuddy.MsRcIncident", // original filename
NULL}; // MapiFileTagExt unused
// Create a blank message. Most members are set to NULL or 0 because
// MAPISendMail will let the user set them.
MapiMessage note = {0, // reserved, must be 0
W2A(m_bstrSubject), W2A(m_bstrBody), NULL, // NULL = interpersonal message
NULL, // no date; MAPISendMail ignores it
NULL, // no conversation ID
0, // no flags, MAPISendMail ignores it
NULL, // no originator, this is ignored too
cRecip, // # of recipients
NULL, //pMapiRecipDesc, // recipient array
1, // one attachment
&attachment}; // the attachment structure
//Next, the client calls the MAPISendMail function and
//stores the return status so it can detect whether the call succeeded.
err = lpfnMapiSendMail (m_lhSession, // use implicit session.
0L, // ulUIParam; 0 is always valid
¬e, // the message being sent
MAPI_DIALOG, // Use MapiMessge recipients
0L); // reserved; must be 0
if (err == SUCCESS_SUCCESS ) { *plStatus = 1; hr = S_OK; } else { PopulateAndThrowErrorInfo(err); } // remove array allocated inside BuildMapiRecipDesc with 'new' command
if (pMapiRecipDesc) delete pMapiRecipDesc;
return hr; }
/******************************************
Func: get_Subject
Abstract: Return the Subject line information.
Params: *pVal: returned string *******************************************/ STDMETHODIMP Csmapi::get_Subject(BSTR *pVal) { if (!pVal) return E_POINTER; //GET_BSTR(pVal, m_bstrSubject);
*pVal = m_bstrSubject.Copy(); return S_OK; }
/******************************************
Func: put_Subject
Abstract: Set the Subject line information.
Params: newVal: new string *******************************************/ STDMETHODIMP Csmapi::put_Subject(BSTR newVal) { m_bstrSubject = newVal; return S_OK; }
/******************************************
Func: get_Body
Abstract: Get the Body message
Params: *pVal: body message string *******************************************/ STDMETHODIMP Csmapi::get_Body(BSTR *pVal) { if (!pVal) return E_POINTER; //GET_BSTR(pVal, m_bstrBody);
*pVal = m_bstrBody.Copy(); return S_OK; }
/******************************************
Func: put_Body
Abstract: Set the Body message
Params: newVal: new body message string *******************************************/ STDMETHODIMP Csmapi::put_Body(BSTR newVal) { m_bstrBody = newVal; return S_OK; }
/******************************************
Func: get_AttachedXMLFile
Abstract: get Attachment file info.
Params: *pVal: attachment file pathname. *******************************************/ STDMETHODIMP Csmapi::get_AttachedXMLFile(BSTR *pVal) { if (!pVal) return E_POINTER; //GET_BSTR(pVal, m_bstrXMLFile);
*pVal = m_bstrXMLFile.Copy(); return S_OK; }
/******************************************
Func: put_AttachedXMLFile
Abstract: set Attachment file info.
Params: newVal: attachment file pathname. *******************************************/ STDMETHODIMP Csmapi::put_AttachedXMLFile(BSTR newVal) { m_bstrXMLFile = newVal; return S_OK; }
/* ----------------------------------------------------------- */ /* Internal Helper functions */ /* ----------------------------------------------------------- */
/******************************************
Func: MAPIFreeBuffer
Abstract: MAPIFreeBuffer wrapper.
Params: *p: buffer pointer will be deleted. *******************************************/ void Csmapi::MAPIFreeBuffer( MapiRecipDesc* p ) { if (m_lpfnMapiFreeBuf == NULL && m_hLib) { m_lpfnMapiFreeBuf = (LPMAPIFREEBUFFER)GetProcAddress(m_hLib, "MAPIFreeBuffer"); }
if (!m_lpfnMapiFreeBuf) return;
m_lpfnMapiFreeBuf(p); }
/******************************************
Func: GetMAPIDefaultProfile
Abstract: get default profile string from Registry
Params: *pProfile: profile string buffer. *pdwCount: # of char of profile string *******************************************/
BOOL GetMAPIDefaultProfile(TCHAR* pProfile, DWORD* pdwCount) { CRegKey cKey; LONG lRet; BOOL bRet = FALSE; lRet = cKey.Open(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows Messaging Subsystem\\Profiles"), KEY_READ); if (lRet == ERROR_SUCCESS) { lRet = cKey.QueryValue(pProfile, TEXT("DefaultProfile"), pdwCount); if (lRet == ERROR_SUCCESS) { bRet = TRUE; } cKey.Close(); } return bRet; }
void Csmapi::PopulateAndThrowErrorInfo(ULONG err) { UINT uID = 0;
switch (err) { case E_FUNC_NOTFOUND: uID = IDS_E_FUNC_NOTFOUND; break; case MAPI_E_FAILURE : uID = IDS_MAPI_E_FAILURE; break; case MAPI_E_INSUFFICIENT_MEMORY : uID = IDS_MAPI_E_INSUFFICIENT_MEMORY; break; case MAPI_E_LOGIN_FAILURE : uID = IDS_MAPI_E_LOGIN_FAILURE; break; case MAPI_E_TOO_MANY_SESSIONS : uID = IDS_MAPI_E_TOO_MANY_SESSIONS; break; case MAPI_E_USER_ABORT : uID = IDS_MAPI_E_USER_ABORT; break; case MAPI_E_INVALID_SESSION : uID = IDS_MAPI_E_INVALID_SESSION; break; case MAPI_E_INVALID_EDITFIELDS : uID = IDS_MAPI_E_INVALID_EDITFIELDS; break; case MAPI_E_INVALID_RECIPS : uID = IDS_MAPI_E_INVALID_RECIPS; break; case MAPI_E_NOT_SUPPORTED : uID = IDS_MAPI_E_NOT_SUPPORTED; break; case MAPI_E_AMBIGUOUS_RECIPIENT : uID = IDS_MAPI_E_AMBIGUOUS_RECIPIENT; break; case MAPI_E_ATTACHMENT_NOT_FOUND : uID = IDS_MAPI_E_ATTACHMENT_NOT_FOUND; break; case MAPI_E_ATTACHMENT_OPEN_FAILURE : uID = IDS_MAPI_E_ATTACHMENT_OPEN_FAILURE; break; case MAPI_E_BAD_RECIPTYPE : uID = IDS_MAPI_E_BAD_RECIPTYPE; break; case MAPI_E_TEXT_TOO_LARGE : uID = IDS_MAPI_E_TEXT_TOO_LARGE; break; case MAPI_E_TOO_MANY_FILES : uID = IDS_MAPI_E_TOO_MANY_FILES; break; case MAPI_E_TOO_MANY_RECIPIENTS : uID = IDS_MAPI_E_TOO_MANY_RECIPIENTS; break; case MAPI_E_UNKNOWN_RECIPIENT : uID = IDS_MAPI_E_UNKNOWN_RECIPIENT; break; default: uID = IDS_MAPI_E_FAILURE; } //Currently the hresult in the Error info structure is set to E_FAIL
Error(uID,IID_Ismapi,E_FAIL,_Module.GetResourceInstance()); }
|