Windows2003-3790/inetcore/outlookexpress/mailnews/shell/instance.cpp

2383 lines
73 KiB
C++
Raw Normal View History

2001-01-01 00:00:00 +01:00
// --------------------------------------------------------------------------------
// INSTANCE.CPP
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "instance.h"
#include "acctutil.h"
#include "inetcfg.h"
#include <storfldr.h>
#include "zmouse.h"
#include "migrate.h"
#include <notify.h>
#include "conman.h"
#include "browser.h"
#include "note.h"
#include "reutil.h"
#include "spengine.h"
#include "addrobj.h"
#include "statnery.h"
#include "thumb.h"
#include "imagelst.h"
#include "url.h"
#include "secutil.h"
#include "shlwapip.h"
#include "ruleutil.h"
#include "newfldr.h"
#include "envfact.h"
#include "storutil.h"
#include "multiusr.h"
#include "newsstor.h"
#include "storutil.h"
#include <storsync.h>
#include "cleanup.h"
#include <grplist2.h>
#include <newsutil.h>
#include <sync.h>
#include "menures.h"
#include "shared.h"
#include "acctcach.h"
#include <inetreg.h>
#include <mapiutil.h>
#include "useragnt.h"
#include "demand.h"
#include <ieguidp.h>
static DWORD g_dwAcctAdvise = 0xffffffff;
DWORD g_dwHideMessenger = BL_DEFAULT;
extern BOOL g_fMigrationDone;
extern UINT GetCurColorRes(void);
// --------------------------------------------------------------------------------
// Forward Decls
// --------------------------------------------------------------------------------
void SimpleMAPICleanup(void); // smapi.cpp
BOOL DemandLoadMSOEACCT(void);
BOOL DemandLoadMSOERT2(void);
BOOL DemandLoadINETCOMM(void);
// --------------------------------------------------------------------------------
// Init Common Control Flags
// --------------------------------------------------------------------------------
#define ICC_FLAGS (ICC_WIN95_CLASSES|ICC_DATE_CLASSES|ICC_PAGESCROLLER_CLASS|ICC_USEREX_CLASSES|ICC_COOL_CLASSES|ICC_NATIVEFNTCTL_CLASS)
#ifdef DEBUG
// --------------------------------------------------------------------------------
// INITSOURCEINFO
// --------------------------------------------------------------------------------
typedef struct tagINITSOURCEINFO *LPINITSOURCEINFO;
typedef struct tagINITSOURCEINFO {
LPSTR pszSource;
DWORD cRefs;
LPINITSOURCEINFO pNext;
} INITSOURCEINFO;
static LPINITSOURCEINFO g_InitSourceHead=NULL;
#endif // DEBUG
// --------------------------------------------------------------------------------
// MAKEERROR
// --------------------------------------------------------------------------------
#define MAKEERROR(_pInfo, _nPrefixIds, _nErrorIds, _nReasonIds, _pszExtra1) \
{ \
(_pInfo)->nTitleIds = idsAthena; \
(_pInfo)->nPrefixIds = _nPrefixIds; \
(_pInfo)->nErrorIds = _nErrorIds; \
(_pInfo)->nReasonIds = _nReasonIds; \
(_pInfo)->nHelpIds = IDS_ERROR_START_HELP; \
(_pInfo)->pszExtra1 = _pszExtra1; \
(_pInfo)->ulLastError = GetLastError(); \
}
// --------------------------------------------------------------------------------
// CoStartOutlookExpress
// --------------------------------------------------------------------------------
MSOEAPI CoStartOutlookExpress(DWORD dwFlags, LPCWSTR pwszCmdLine, INT nCmdShow)
{
// Tracing
TraceCall("CoStartOutlookExpress");
// Verify that we have an outlook express object
Assert(g_pInstance);
// E_OUTOFMEMORY
if (NULL == g_pInstance)
{
// We should show an error, but the liklyhood of this happening is almost zero
return TraceResult(E_OUTOFMEMORY);
}
// Run...
return g_pInstance->Start(dwFlags, pwszCmdLine, nCmdShow);
}
// --------------------------------------------------------------------------------
// CoCreateOutlookExpress
// --------------------------------------------------------------------------------
MSOEAPI CoCreateOutlookExpress(IUnknown *pUnkOuter, IUnknown **ppUnknown)
{
// Locals
HRESULT hr=S_OK;
// Trace
TraceCall("CoCreateOutlookExpress");
// Invalid Arg
Assert(NULL != ppUnknown && NULL == pUnkOuter);
// No global object yet ?
AssertSz(g_pInstance, "This gets created in dllmain.cpp DllProcessAttach.");
// Lets not crash
if (NULL == g_pInstance)
{
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
// AddRef that badboy
g_pInstance->AddRef();
// Return the Innter
*ppUnknown = SAFECAST(g_pInstance, IOutlookExpress *);
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::COutlookExpress
// --------------------------------------------------------------------------------
COutlookExpress::COutlookExpress(void)
{
// Trace
TraceCall("COutlookExpress::COutlookExpress");
// Init Members
m_cRef = 1;
m_hInstMutex = NULL;
m_fPumpingMsgs = FALSE;
m_cDllRef = 0;
m_cDllLock = 0;
m_cDllInit = 0;
m_dwThreadId = GetCurrentThreadId();
m_fSwitchingUsers = FALSE;
m_szSwitchToUsername = NULL;
m_hwndSplash = NULL;
m_pSplash = NULL;
m_fIncremented = FALSE;
m_hTrayIcon = 0;
// Init Thread Safety
InitializeCriticalSection(&m_cs);
}
// --------------------------------------------------------------------------------
// COutlookExpress::~COutlookExpress
// --------------------------------------------------------------------------------
COutlookExpress::~COutlookExpress(void)
{
// Trace
TraceCall("COutlookExpress::~COutlookExpress");
// We should have been un-inited
Assert(0 == m_cDllInit && 0 == m_cDllRef && 0 == m_cDllLock);
// Free the mutex
SafeCloseHandle(m_hInstMutex);
// Kill CritSect
DeleteCriticalSection(&m_cs);
if(m_hTrayIcon)
{
DestroyIcon(m_hTrayIcon);
}
// Free the switch to if necessary
if (m_szSwitchToUsername)
MemFree(m_szSwitchToUsername);
}
// --------------------------------------------------------------------------------
// COutlookExpress::QueryInterface
// --------------------------------------------------------------------------------
STDMETHODIMP COutlookExpress::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("COutlookExpress::QueryInterface");
// check params
if (ppv == NULL)
return TrapError(E_INVALIDARG);
// Find IID
if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
else if (IID_IOutlookExpress == riid)
*ppv = (IOutlookExpress *)this;
else
{
*ppv = NULL;
hr = TraceResult(E_NOINTERFACE);
goto exit;
}
// AddRef It
((IUnknown *)*ppv)->AddRef();
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::AddRef
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) COutlookExpress::AddRef(void)
{
TraceCall("COutlookExpress::AddRef");
return InterlockedIncrement(&m_cRef);
}
// --------------------------------------------------------------------------------
// COutlookExpress::Release
// --------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) COutlookExpress::Release(void)
{
TraceCall("COutlookExpress::Release");
LONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
delete this;
return (ULONG)cRef;
}
// --------------------------------------------------------------------------------
// COutlookExpress::LockServer
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::LockServer(BOOL fLock)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("COutlookExpress::LockServer");
if (TRUE == fLock)
{
InterlockedIncrement(&m_cDllLock);
}
else
{
InterlockedDecrement(&m_cDllLock);
}
// Trace
//TraceInfo(_MSG("Lock: %d, CoIncrementInit Count = %d, Reference Count = %d, Lock Count = %d", fLock, m_cDllInit, m_cDllRef, m_cDllLock));
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// COutlookExpress::DllAddRef
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::DllAddRef(void)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("COutlookExpress::DllAddRef");
// Thread Safety
if (InterlockedIncrement(&m_cDllRef) <= 0)
{
// refcount already below zero
hr = S_FALSE;
}
// Trace
//TraceInfo(_MSG("CoIncrementInit Count = %d, Reference Count = %d, Lock Count = %d", m_cDllInit, m_cDllRef, m_cDllLock));
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::DllRelease
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::DllRelease(void)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("COutlookExpress::DllRelease");
// Thread Safety
if (InterlockedDecrement(&m_cDllRef) < 0)
{
// refcount already below zero
hr = S_FALSE;
}
// Trace
//TraceInfo(_MSG("CoIncrementInit Count = %d, Reference Count = %d, Lock Count = %d", m_cDllInit, m_cDllRef, m_cDllLock));
// Done
return hr;
}
// --------------------------------------------------------------------------------
// _CheckForJunkMail
// --------------------------------------------------------------------------------
void _CheckForJunkMail()
{
HKEY hkey;
DWORD dw=0, cb;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegRoot, 0, KEY_QUERY_VALUE, &hkey))
{
cb = sizeof(dw);
RegQueryValueEx(hkey, c_szRegJunkMailOn, 0, NULL, (LPBYTE)&dw, &cb);
if (dw)
g_dwAthenaMode |= MODE_JUNKMAIL;
RegCloseKey(hkey);
}
}
// --------------------------------------------------------------------------------
// COutlookExpress::Start
// --------------------------------------------------------------------------------
STDMETHODIMP COutlookExpress::Start(DWORD dwFlags, LPCWSTR pwszCmdLine, INT nCmdShow)
{
// Locals
HRESULT hr=S_OK;
MSG msg;
HWND hwndTimeout;
HINITREF hInitRef=NULL;
BOOL fErrorDisplayed=FALSE;
LPWSTR pwszFree=NULL;
LPWSTR pwszCmdLineDup = NULL;
// Stack
TraceCall("COutlookExpress::Start");
// Make sure OLE is initialized on the thread
OleInitialize(NULL);
// Duplicate It
IF_NULLEXIT(pwszCmdLineDup = PszDupW(pwszCmdLine));
// pwszCmdLineDup will change, remember the allocated block
pwszFree = pwszCmdLineDup;
//We want to process the switches set the mode flags before we call CoIncrementInit
_ProcessCommandLineFlags(&pwszCmdLineDup, dwFlags);
// AddRef the Dll..
hr = CoIncrementInit("COutlookExpress", dwFlags, pwszCmdLine, &hInitRef);
if (FAILED(hr))
{
fErrorDisplayed = TRUE;
TraceResult(hr);
goto exit;
}
// Process the Command Line..
IF_FAILEXIT(hr = ProcessCommandLine(nCmdShow, pwszCmdLineDup, &fErrorDisplayed));
// No splash screen
CloseSplashScreen();
// Do a CoDecrementInit
IF_FAILEXIT(hr = CoDecrementInit("COutlookExpress", &hInitRef));
// No need for a Message Pump ?
if (S_OK == DllCanUnloadNow() || FALSE == ISFLAGSET(dwFlags, MSOEAPI_START_MESSAGEPUMP))
goto exit;
// Start the message Pump
EnterCriticalSection(&m_cs);
// Do we already have a pump running ?
if (TRUE == m_fPumpingMsgs)
{
LeaveCriticalSection(&m_cs);
goto exit;
}
// We are going to pump
m_fPumpingMsgs = TRUE;
// Thread Safety
LeaveCriticalSection(&m_cs);
SetSwitchingUsers(FALSE);
// Message Loop
while (GetMessageWrapW(&msg, NULL, 0, 0) && ((m_cDllInit > 0) || !SwitchingUsers()))
{
CNote *pNote = GetTlsGlobalActiveNote();
// Ask it to translate an accelerator
if (g_pBrowser && g_pBrowser->TranslateAccelerator(&msg) == S_OK)
continue;
// Hand message off to the active note, but ignore init window msgs and ignore per-task msgs where hwnd=0
if (msg.hwnd != g_hwndInit && IsWindow(msg.hwnd))
{
pNote = GetTlsGlobalActiveNote();
// Give it to the active note if a note has focus, call it's XLateAccelerator...
if (pNote && pNote->TranslateAccelerator(&msg) == S_OK)
continue;
}
// Get Timeout Window for this thread
hwndTimeout = (HWND)TlsGetValue(g_dwTlsTimeout);
// Check for Is modeless timeout dialog window message
if (hwndTimeout && TRUE == IsDialogMessageWrapW(hwndTimeout, &msg))
continue;
// If Still not processed
TranslateMessage(&msg);
DispatchMessageWrapW(&msg);
}
// We are no longer pumping messages
EnterCriticalSection(&m_cs);
m_fPumpingMsgs = FALSE;
LeaveCriticalSection(&m_cs);
if(SwitchingUsers())
{
HrCloseWabWindow();
while (PeekMessageWrapW(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageWrapW(&msg);
}
MU_ResetRegRoot();
}
exit:
// Free command line copy
SafeMemFree(pwszFree);
// Do a CoDecrementInit
CoDecrementInit("COutlookExpress", &hInitRef);
// No splash screen
CloseSplashScreen();
// Is there an error ?
if (FALSE == fErrorDisplayed && FAILED(hr) &&
hrUserCancel != hr &&
MAPI_E_USER_CANCEL != hr)
{
REPORTERRORINFO rError={0};
MAKEERROR(&rError, 0, IDS_ERROR_UNKNOWN, 0, NULL);
_ReportError(g_hLocRes, hr, 0, &rError);
}
//Bug #101360 - (erici) OleInitialize created a window, this destroys it.
OleUninitialize();
// Done
return (SwitchingUsers() ? S_RESTART_OE : hr);
}
// --------------------------------------------------------------------------------
// COutlookExpress::_ReportError
// --------------------------------------------------------------------------------
BOOL COutlookExpress::_ReportError(
HINSTANCE hInstance, // Dll Instance
HRESULT hrResult, // HRESULT of the error
LONG lResult, // LRESULT from like a registry function
LPREPORTERRORINFO pInfo) // Report Error Information
{
// Locals
TCHAR szRes[255],
szMessage[1024],
szTitle[128];
// INit
*szMessage = '\0';
// Is there a prefix
if (pInfo->nPrefixIds)
{
// Load the string
LoadString(hInstance, pInfo->nPrefixIds, szMessage, ARRAYSIZE(szMessage));
}
// Error ?
if (pInfo->nErrorIds)
{
// Are there extras in this error string
if (NULL != pInfo->pszExtra1)
{
// Locals
TCHAR szTemp[255];
// Load and format
LoadString(hInstance, pInfo->nErrorIds, szTemp, ARRAYSIZE(szTemp));
// Format the string
wnsprintf(szRes, ARRAYSIZE(szRes), szTemp, pInfo->pszExtra1);
}
// Load the string
else
{
// Load the error string
LoadString(hInstance, pInfo->nErrorIds, szRes, ARRAYSIZE(szRes));
}
// Add to szMessage
StrCatBuff(szMessage, g_szSpace, ARRAYSIZE(szMessage));
StrCatBuff(szMessage, szRes, ARRAYSIZE(szMessage));
}
// Reason ?
if (pInfo->nReasonIds)
{
// Load the string
LoadString(hInstance, pInfo->nReasonIds, szRes, ARRAYSIZE(szRes));
// Add to szMessage
StrCatBuff(szMessage, g_szSpace, ARRAYSIZE(szMessage));
StrCatBuff(szMessage, szRes, ARRAYSIZE(szMessage));
}
// Load the string
LoadString(hInstance, pInfo->nHelpIds, szRes, ARRAYSIZE(szRes));
// Add to szMessage
StrCatBuff(szMessage, g_szSpace, ARRAYSIZE(szMessage));
StrCatBuff(szMessage, szRes, ARRAYSIZE(szMessage));
// Append Error Results
if (lResult != 0 && E_FAIL == hrResult && pInfo->ulLastError)
wnsprintf(szRes, ARRAYSIZE(szRes), "(%d, %d)", lResult, pInfo->ulLastError);
else if (lResult != 0 && E_FAIL == hrResult && 0 == pInfo->ulLastError)
wnsprintf(szRes, ARRAYSIZE(szRes), "(%d)", lResult);
else if (pInfo->ulLastError)
wnsprintf(szRes, ARRAYSIZE(szRes), "(0x%08X, %d)", hrResult, pInfo->ulLastError);
else
wnsprintf(szRes, ARRAYSIZE(szRes), "(0x%08X)", hrResult);
// Add to szMessage
StrCatBuff(szMessage, g_szSpace, ARRAYSIZE(szMessage));
StrCatBuff(szMessage, szRes, ARRAYSIZE(szMessage));
// Get the title
LoadString(hInstance, pInfo->nTitleIds, szTitle, ARRAYSIZE(szTitle));
// Show the error message
MessageBox(NULL, szMessage, szTitle, MB_OK | MB_SETFOREGROUND | MB_ICONEXCLAMATION);
// Done
return TRUE;
}
#ifdef DEAD
// --------------------------------------------------------------------------------
// COutlookExpress::_ValidateDll
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::_ValidateDll(LPCSTR pszDll, BOOL fDemandResult, HMODULE hModule,
HRESULT hrLoadError, HRESULT hrVersionError, LPREPORTERRORINFO pError)
{
// Locals
HRESULT hr=S_OK;
PFNGETDLLMAJORVERSION pfnGetVersion;
// Tracing
TraceCall("COutlookExpress::_ValidateDll");
// We must load these here in order to show errors and not crash - Load MSOERT2.DLL
if (FALSE == fDemandResult)
{
MAKEERROR(pError, IDS_ERROR_PREFIX1, IDS_ERROR_MISSING_DLL, IDS_ERROR_REASON2, pszDll);
hr = TraceResult(hrLoadError);
goto exit;
}
// Try to get the current verion
else
{
// Get Version Proc Address
pfnGetVersion = (PFNGETDLLMAJORVERSION)GetProcAddress(hModule, STR_GETDLLMAJORVERSION);
// Not the Correct Version
if (NULL == pfnGetVersion || OEDLL_VERSION_CURRENT != (*pfnGetVersion)())
{
MAKEERROR(pError, IDS_ERROR_PREFIX1, IDS_ERROR_BADVER_DLL, IDS_ERROR_REASON2, pszDll);
hr = TraceResult(hrVersionError);
goto exit;
}
}
exit:
// Done
return hr;
}
#endif // DEAD
// --------------------------------------------------------------------------------
// COutlookExpress::CoIncrementInitDebug
// --------------------------------------------------------------------------------
#ifdef DEBUG
HRESULT COutlookExpress::CoIncrementInitDebug(LPCSTR pszSource, DWORD dwFlags,
LPCWSTR pwszCmdLine, LPHINITREF phInitRef)
{
// Locals
BOOL fFound=FALSE;
LPINITSOURCEINFO pCurrent;
// Trace
TraceCall("COutlookExpress::CoIncrementInitDebug");
// Invalid Args
Assert(pszSource);
// Thread Safety
EnterCriticalSection(&m_cs);
// Find Source
for (pCurrent = g_InitSourceHead; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
// Is this It ?
if (lstrcmpi(pszSource, pCurrent->pszSource) == 0)
{
// Increment Reference Count
pCurrent->cRefs++;
// Found
fFound = TRUE;
// Done
break;
}
}
// Not Found, lets add one
if (FALSE == fFound)
{
// Set pCurrent
pCurrent = (LPINITSOURCEINFO)ZeroAllocate(sizeof(INITSOURCEINFO));
Assert(pCurrent);
// Set pszSource
pCurrent->pszSource = PszDupA(pszSource);
Assert(pCurrent->pszSource);
// Set cRefs
pCurrent->cRefs = 1;
// Set Next
pCurrent->pNext = g_InitSourceHead;
// Set Head
g_InitSourceHead = pCurrent;
}
// Thread Safety
LeaveCriticalSection(&m_cs);
// Call the Actual CoIncrementInit
return(CoIncrementInitImpl(dwFlags, pwszCmdLine, phInitRef));
}
#endif // DEBUG
// --------------------------------------------------------------------------------
// COutlookExpress::CoIncrementInitImpl
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::CoIncrementInitImpl(DWORD dwFlags, LPCWSTR pwszCmdLine, LPHINITREF phInitRef)
{
// Locals
HRESULT hr=S_OK;
DWORD dw;
RECT rc={0};
HWND hwndDesk;
DWORD dwSize;
INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_FLAGS };
CImnAdviseAccount *pImnAdviseAccount=NULL;
WNDCLASSW wcW;
WNDCLASS wc;
DWORD dwType, dwVal, cb;
REPORTERRORINFO rError={0};
LONG lResult=0;
LPCWSTR pwszInitWndClass;
BOOL fReleaseMutex=FALSE;
BOOL fResult;
CHAR szFolder[MAX_PATH];
IF_DEBUG(DWORD dwTickStart=GetTickCount());
// Tracing
TraceCall("COutlookExpress::CoIncrementInitImpl");
// Make sure OLE is initialized on the thread
OleInitialize(NULL);
// Thread Safety
EnterCriticalSection(&m_cs);
if (!SwitchingUsers() && !m_fIncremented)
{
SetQueryNetSessionCount(SESSION_INCREMENT_NODEFAULTBROWSERCHECK);
m_fIncremented = TRUE;
}
// Increment Reference Count
m_cDllInit++;
// Set phInitRef
if (phInitRef)
*phInitRef = (HINITREF)((ULONG_PTR)m_cDllInit);
// First-Time Reference
if (m_cDllInit > 1)
{
LeaveCriticalSection(&m_cs);
return S_OK;
}
// Leave CS (This code always runs on the same primary thread
LeaveCriticalSection(&m_cs);
if (FAILED(hr = MU_Init(ISFLAGSET(dwFlags, MSOEAPI_START_DEFAULTIDENTITY))))
goto exit;
// Is there more than one identity?
g_fPluralIDs = 1 < MU_CountUsers();
if (!MU_Login(GetDesktopWindow(), FALSE, NULL))
{
hr = hrUserCancel;
goto exit;
}
// Create the instance mutex
if (NULL == m_hInstMutex)
{
m_hInstMutex = CreateMutex(NULL, FALSE, STR_MSOEAPI_INSTANCEMUTEX);
if (NULL == m_hInstMutex)
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_CREATE_INSTMUTEX, IDS_ERROR_REASON1, NULL);
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
}
// Release m_hInstMutex if it is currently owned by this thread, allow new instances to start.
if (FALSE == ISFLAGSET(dwFlags, MSOEAPI_START_INSTANCEMUTEX))
{
// Lets grab the mutex ourselves
WaitForSingleObject(m_hInstMutex, INFINITE);
}
// Release the mutex
fReleaseMutex = TRUE;
// Must init thread on primary instnance thread
// If the thread id is zero, then we have uninitialized everything.
// Which means we need to re-initialize everything
if (0 == m_dwThreadId)
{
m_dwThreadId = GetCurrentThreadId();
}
AssertSz(m_dwThreadId == GetCurrentThreadId(), "We are not doing first CoIncrementInit on the thread in which g_pInstance was created on.");
// Set g_dwAthenaMode
_CheckForJunkMail();
// Get MimeOle IMalloc Interface
if (NULL == g_pMoleAlloc)
{
hr = MimeOleGetAllocator(&g_pMoleAlloc);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_MIMEOLE_ALLOCATOR, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
}
// Set OE5 mode for INetcomm.
MimeOleSetCompatMode(MIMEOLE_COMPAT_MLANG2);
// Create the Database Session Object
if (NULL == g_pDBSession)
{
hr = CoCreateInstance(CLSID_DatabaseSession, NULL, CLSCTX_INPROC_SERVER, IID_IDatabaseSession, (LPVOID *)&g_pDBSession);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_OPEN_STORE, IDS_ERROR_REASON1, NULL);
goto exit;
}
}
// all migration and upgrade happens in here now.
hr = MigrateAndUpgrade();
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
// Only if there is a command line...
if (pwszCmdLine)
{
LPSTR pszCmdLine = NULL;
// If this returns S_OK, we have launched the first-run ICW exe and we need to go away.
// this is consistent with IE and forces the user to deal with the ICW before partying with us.
IF_NULLEXIT(pszCmdLine = PszToANSI(CP_ACP, pwszCmdLine));
hr = NeedToRunICW(pszCmdLine);
MemFree(pszCmdLine);
if (hr == S_OK)
{
hr = hrUserCancel;
goto exit;
}
// If that failed, time to show an error message
else if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_FIRST_TIME_ICW, IDS_ERROR_REASON2, NULL);
hr = TraceResult(hr);
goto exit;
}
}
// Create WNDCLASS for Primary Outlook Express hidden window
if (ISFLAGSET(dwFlags, MSOEAPI_START_APPWINDOW))
pwszInitWndClass = STRW_MSOEAPI_INSTANCECLASS;
else
pwszInitWndClass = STRW_MSOEAPI_IPSERVERCLASS;
// Register the init window
if (FALSE == GetClassInfoWrapW(g_hInst, pwszInitWndClass, &wcW))
{
ZeroMemory(&wcW, sizeof(wcW));
wcW.lpfnWndProc = COutlookExpress::InitWndProc;
wcW.hInstance = g_hInst;
wcW.lpszClassName = pwszInitWndClass;
if (FALSE == RegisterClassWrapW(&wcW))
{
// In this case, we are in an error condition so don't care if PszToANSI fails.
LPSTR pszInitWndClass = PszToANSI(CP_ACP, pwszInitWndClass);
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_REG_WNDCLASS, IDS_ERROR_REASON1, pszInitWndClass);
MemFree(pszInitWndClass);
hr = TraceResult(E_FAIL);
goto exit;
}
}
// Create the OutlookExpressHiddenWindow
if (NULL == g_hwndInit)
{
g_hwndInit = CreateWindowExWrapW(WS_EX_TOPMOST, pwszInitWndClass, pwszInitWndClass,
WS_POPUP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
NULL, NULL, g_hInst, NULL);
if (NULL == g_hwndInit)
{
// In this case, we are in an error condition so don't care if PszToANSI fails.
LPSTR pszInitWndClass = PszToANSI(CP_ACP, pwszInitWndClass);
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_REG_WNDCLASS, IDS_ERROR_REASON1, pszInitWndClass);
MemFree(pszInitWndClass);
hr = TraceResult(E_FAIL);
goto exit;
}
}
// CoIncrementInit Global Options Manager
if (FALSE == InitGlobalOptions(NULL, NULL))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_INIT_GOPTIONS, IDS_ERROR_REASON1, NULL);
hr = TraceResult(E_FAIL);
goto exit;
}
// Prompt the user for a store location, if we don't have one already
hr = InitializeLocalStoreDirectory(NULL, FALSE);
if (hrUserCancel == hr || FAILED(hr))
{
// If not user cancel, then must be another error
if (hrUserCancel != hr)
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_INITSTORE_DIRECTORY, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
}
// Done
goto exit;
}
// This needs to stay in since the Intl guys want a way to work around people who aren't going to upgrade to the latest ATOK11.
if (ISFLAGSET(dwFlags, MSOEAPI_START_SHOWSPLASH) && 0 == DwGetOption(OPT_NO_SPLASH)
&& ((g_dwAthenaMode & MODE_OUTLOOKNEWS) != MODE_OUTLOOKNEWS))
{
// Create me a splash screen
hr = CoCreateInstance(CLSID_IESplashScreen, NULL, CLSCTX_INPROC_SERVER, IID_ISplashScreen, (LPVOID *)&m_pSplash);
// If that worked, heck, lets show it
if (SUCCEEDED(hr))
{
HDC hdc = GetDC(NULL);
m_pSplash->Show(g_hLocRes, ((GetDeviceCaps(hdc, BITSPIXEL) > 8) ? idbSplashHiRes : idbSplash256), idbSplashLoRes, &m_hwndSplash);
ReleaseDC(NULL, hdc);
}
// Trace
else
TraceResultSz(hr, "CoCreateInstance(CLSID_IESplashScreen, ...) failed, but who cares.");
// Everything is good
hr = S_OK;
}
cb = sizeof(dw);
if (ERROR_SUCCESS != SHGetValue(HKEY_LOCAL_MACHINE, c_szRegFlat, c_szHideMessenger, &dwType, (LPBYTE)&dw, &cb))
dw = 0xffffffff;
cb = sizeof(dwVal);
if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, c_szRegFlat, c_szHideMessenger, &dwType, (LPBYTE)&dwVal, &cb))
dwVal = 0xffffffff;
if (dw != 0xffffffff && dwVal != 0xffffffff)
g_dwHideMessenger = max(dw, dwVal);
else if (dw != 0xffffffff)
g_dwHideMessenger = dw;
else if (dwVal != 0xffffffff)
g_dwHideMessenger = dwVal;
else
g_dwHideMessenger = BL_DEFAULT;
// IntelliMouse support
g_msgMSWheel = RegisterWindowMessage(TEXT(MSH_MOUSEWHEEL));
AssertSz(g_msgMSWheel, "RegisterWindowMessage for the IntelliMouse failed, we can still continue.");
// Create WNDCLASS for ThumbNail
if (FALSE == GetClassInfo(g_hLocRes, WC_THUMBNAIL, &wc))
{
ZeroMemory(&wc, sizeof(wc));
wc.lpfnWndProc = ThumbNailWndProc;
wc.hInstance = g_hLocRes;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = WC_THUMBNAIL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
if (FALSE == RegisterClass(&wc))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_REG_WNDCLASS, IDS_ERROR_REASON1, WC_THUMBNAIL);
hr = TraceResult(E_FAIL);
goto exit;
}
}
// Get the desktop Window
hwndDesk = GetDesktopWindow();
AssertSz(hwndDesk, "GetDesktopWindow returned NULL. We should be ok, I hope.");
if (hwndDesk)
{
// Get the size of the desktop window
GetWindowRect(hwndDesk, &rc);
// sungr: following is a hack to avoid the fullscreen app detection hack that user does to modify the top-most state of the tray.
rc.left += 20;
rc.top += 20;
rc.bottom -= 20;
rc.right -= 20;
}
// Test to see if we should move the store
cb = ARRAYSIZE(szFolder);
if (ERROR_SUCCESS == AthUserGetValue(NULL, c_szNewStoreDir, &dwType, (LPBYTE)szFolder, &cb))
{
DWORD dwMoveStore = 0;
DWORD cb = sizeof(dwMoveStore);
AthUserGetValue(NULL, c_szMoveStore, NULL, (LPBYTE)&dwMoveStore, &cb);
if (SUCCEEDED(RelocateStoreDirectory(g_hwndInit, szFolder, (dwMoveStore != 0))))
{
AthUserDeleteValue(NULL, c_szNewStoreDir);
AthUserDeleteValue(NULL, c_szMoveStore);
}
}
// CoIncrementInit Common Controls Library
InitCommonControlsEx(&icex);
// Create account manger
if (NULL == g_pAcctMan)
{
hr = AcctUtil_CreateAccountManagerForIdentity(PGUIDCurrentOrDefault(), &g_pAcctMan);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_CREATE_ACCTMAN, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
pImnAdviseAccount = new CImnAdviseAccount();
if (NULL == pImnAdviseAccount)
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_ALLOC_ACCTADVISE, IDS_ERROR_REASON1, NULL);
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
hr = pImnAdviseAccount->Initialize();
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_INIT_ACCTADVISE, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
// Register Advise sink
Assert(g_dwAcctAdvise == 0xffffffff);
hr = g_pAcctMan->Advise(pImnAdviseAccount, &g_dwAcctAdvise);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_ADVISE_ACCTMAN, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
}
// Create the rules manager
if (NULL == g_pRulesMan)
{
hr = HrCreateRulesManager(NULL, (IUnknown **)&g_pRulesMan);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, idsErrorCreateRulesMan, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
// CoIncrementInit the account manager
hr = g_pRulesMan->Initialize(0);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, idsErrorInitRulesMan, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
}
// Create the global connection manager
if (NULL == g_pConMan)
{
g_pConMan = new CConnectionManager();
if (NULL == g_pConMan)
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_ALLOC_CONMAN, IDS_ERROR_REASON1, NULL);
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
// CoIncrementInit the Connection Manager
hr = g_pConMan->HrInit(g_pAcctMan);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_INIT_CONMAN, IDS_ERROR_REASON1, NULL);
TraceResult(hr);
goto exit;
}
}
// Initialize the HTTP user agent
InitOEUserAgent(TRUE);
// Create the Spooler Object
if (NULL == g_pSpooler)
{
hr = CreateThreadedSpooler(NULL, &g_pSpooler, TRUE);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_CREATE_SPOOLER, IDS_ERROR_REASON1, NULL);
hr = TraceResult(hr);
goto exit;
}
}
// Create the Font Cache Object
if (NULL == g_lpIFontCache)
{
hr = CoCreateInstance(CLSID_IFontCache, NULL, CLSCTX_INPROC_SERVER, IID_IFontCache, (LPVOID *)&g_lpIFontCache);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_CREATE_FONTCACHE, IDS_ERROR_REASON1, NULL);
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
hr = g_lpIFontCache->Init(MU_GetCurrentUserHKey(), c_szRegInternational, 0);
Assert(SUCCEEDED(hr));
}
// Create the Global Store Object
hr = InitializeStore(dwFlags);
if (FAILED(hr))
{
MAKEERROR(&rError, IDS_ERROR_PREFIX1, IDS_ERROR_OPEN_STORE, IDS_ERROR_REASON1, NULL);
goto exit;
}
DoNewsgroupSubscribe();
if (NULL == g_pSync)
{
g_pSync = new COfflineSync;
if (NULL == g_pSync)
{
hr = TraceResult(E_OUTOFMEMORY);
goto exit;
}
hr = g_pSync->Initialize();
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
}
// Start Background Compaction in XX Seconds
if (DwGetOption(OPT_BACKGROUNDCOMPACT))
SideAssert(SUCCEEDED(StartBackgroundStoreCleanup(30)));
// CoIncrementInit Drag Drop Information
if (0 == CF_FILEDESCRIPTORA)
{
CF_FILEDESCRIPTORA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
CF_FILEDESCRIPTORW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
CF_FILECONTENTS = RegisterClipboardFormat(CFSTR_FILECONTENTS);
CF_HTML = RegisterClipboardFormat(CFSTR_HTML);
CF_INETMSG = RegisterClipboardFormat(CFSTR_INETMSG);
CF_OEFOLDER = RegisterClipboardFormat(CFSTR_OEFOLDER);
CF_SHELLURL = RegisterClipboardFormat(CFSTR_SHELLURL);
CF_OEMESSAGES = RegisterClipboardFormat(CFSTR_OEMESSAGES);
CF_OESHORTCUT = RegisterClipboardFormat(CFSTR_OESHORTCUT);
}
// Get the current default codepage
cb = sizeof(dwVal);
if (ERROR_SUCCESS == SHGetValue(MU_GetCurrentUserHKey(), c_szRegInternational, REGSTR_VAL_DEFAULT_CODEPAGE, &dwType, &dwVal, &cb))
g_uiCodePage = (UINT)dwVal;
// CoIncrementInit the Wab on first run
cb = sizeof(dwVal);
if (ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, c_szNewWABKey, c_szFirstRunValue, &dwType, &dwVal, &cb))
HrInitWab(TRUE);
//This call could fail if the registry gets trashed, but do we want an error box?
//According to takos, no...we do not.
HGetDefaultCharset(NULL);
exit:
// Is there an error ?
if (hrUserCancel != hr && ISFLAGSET(dwFlags, MSOEAPI_START_SHOWERRORS) && (FAILED(hr) || ERROR_SUCCESS != lResult))
{
// If ulError is zero, lets set it to a default
if (0 == rError.nErrorIds)
MAKEERROR(&rError, 0, IDS_ERROR_UNKNOWN, 0, NULL);
// Report the Error
_ReportError(g_hLocRes, hr, lResult, &rError);
}
// Release the mutex and signal the caller initialization is done
if (fReleaseMutex)
SideAssert(FALSE != ReleaseMutex(m_hInstMutex));
// Trace
//TraceInfo(_MSG("CoIncrementInit Count = %d, Reference Count = %d, Lock Count = %d", m_cDllInit, m_cDllRef, m_cDllLock));
// Cleanup
SafeRelease(pImnAdviseAccount);
// If we failed, decrement the reference count
if (FAILED(hr))
{
CloseSplashScreen();
CoDecrementInit("COutlookExpress", phInitRef);
}
else
Assert(g_pAcctMan);
// Time To Crank
TraceInfo(_MSG("Startup Time: %d", GetTickCount() - dwTickStart));
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::CloseSplashScreen
// --------------------------------------------------------------------------------
void COutlookExpress::CloseSplashScreen(void)
{
// Kill the splash screen
if (m_pSplash)
{
m_pSplash->Dismiss();
m_pSplash->Release();
m_pSplash = NULL;
// HACKHACKHACK
// This is needed because the splash screen might still be around after we
// free up OLE.
if (FALSE != IsWindow(m_hwndSplash))
{
SendMessage(m_hwndSplash, WM_CLOSE, 0, 0);
}
}
}
// --------------------------------------------------------------------------------
// COutlookExpress::CoDecrementInitDebug
// --------------------------------------------------------------------------------
#ifdef DEBUG
HRESULT COutlookExpress::CoDecrementInitDebug(LPCSTR pszSource, LPHINITREF phInitRef)
{
// Locals
BOOL fFound=FALSE;
LPINITSOURCEINFO pCurrent;
LPINITSOURCEINFO pPrevious=NULL;
// Trace
TraceCall("COutlookExpress::CoDecrementInitDebug");
// Invalid Args
Assert(pszSource);
// Do I need to do this
if (NULL == phInitRef || NULL != *phInitRef)
{
// Thread Safety
EnterCriticalSection(&m_cs);
// Find Source
for (pCurrent = g_InitSourceHead; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
// Is this It ?
if (lstrcmpi(pszSource, pCurrent->pszSource) == 0)
{
// Increment Reference Count
pCurrent->cRefs--;
// Found
fFound = TRUE;
// No More Reference Counts ?
if (0 == pCurrent->cRefs)
{
// Previous ?
if (pPrevious)
pPrevious->pNext = pCurrent->pNext;
else
g_InitSourceHead = pCurrent->pNext;
// Free pszSource
g_pMalloc->Free(pCurrent->pszSource);
// Free pCurrent
g_pMalloc->Free(pCurrent);
}
// Done
break;
}
// Set Previous
pPrevious = pCurrent;
}
// Not Found, lets add one
Assert(fFound);
// TraceInfoTag
TraceInfoTag(TAG_INITTRACE, "********** CoDecrementInit **********");
// Find Source
for (pCurrent = g_InitSourceHead; pCurrent != NULL; pCurrent = pCurrent->pNext)
{
// TraceInfoTag
TraceInfoTag(TAG_INITTRACE, _MSG("Source: %s, Refs: %d", pCurrent->pszSource, pCurrent->cRefs));
}
// Thread Safety
LeaveCriticalSection(&m_cs);
}
// Call Actual
return(CoDecrementInitImpl(phInitRef));
}
#endif // DEBUG
// --------------------------------------------------------------------------------
// COutlookExpress::CoDecrementInitImpl
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::CoDecrementInitImpl(LPHINITREF phInitRef)
{
// Locals
HRESULT hr=S_OK;
// Stack
TraceCall("COutlookExpress::CoDecrementInitImpl");
// If *phInitRef = NULL, then we should no do the CoDecrementInit
if (phInitRef && NULL == *phInitRef)
{
hr = S_OK;
goto exit;
}
// We must de-init on the same thread that we were created on...
if (m_dwThreadId != GetCurrentThreadId() && g_hwndInit && IsWindow(g_hwndInit))
{
// Thunk the shutdown to the correct thread
hr = (HRESULT) SendMessage(g_hwndInit, ITM_SHUTDOWNTHREAD, 0, (LPARAM)phInitRef);
}
else
{
// Forward everything off to the main function
hr = _CoDecrementInitMain(phInitRef);
}
if (!SwitchingUsers() && m_fIncremented && (m_cDllInit == 0))
{
SetQueryNetSessionCount(SESSION_DECREMENT);
m_fIncremented = FALSE;
}
// Uninitialize Ole
OleUninitialize();
exit:
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::_CoDecrementInitMain
//
// NOTE: We assume that we already have the critical section before this call
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::_CoDecrementInitMain(LPHINITREF phInitRef)
{
// Stack
TraceCall("COutlookExpress::_CoDecrementInitMain");
// If *phInitRef = NULL, then we should no do the CoDecrementInit
if (phInitRef && NULL == *phInitRef)
return S_OK;
// Thread Safety
EnterCriticalSection(&m_cs);
// This should never happen. It could only happen if g_hwndInit was NULL.
AssertSz(m_dwThreadId == GetCurrentThreadId(), "We are not doing the last CoDecrementInit on the thread in which g_pInstance was created on.");
// Release
Assert(m_cDllInit);
m_cDllInit--;
// Not hit zero yet ?
if (m_cDllInit > 0)
{
LeaveCriticalSection(&m_cs);
goto exit;
}
// Leave Critical Section
LeaveCriticalSection(&m_cs);
// Validate
Assert(NULL == g_InitSourceHead);
// Take ownership of the mutex to block people from creating new insts while shutting down
WaitForSingleObject(m_hInstMutex, INFINITE);
// Cleanup the Trident data for this thread
//g_hLibMAPI
if (g_hlibMAPI)
{
FreeLibrary(g_hlibMAPI);
g_hlibMAPI = 0;
}
// Make sure we remove our new mail notification from the tray
UpdateTrayIcon(TRAYICONACTION_REMOVE);
// Close Background Compaction
SideAssert(SUCCEEDED(CloseBackgroundStoreCleanup()));
// Kill the Spooler
if (g_pSpooler)
{
CloseThreadedSpooler(g_pSpooler);
g_pSpooler = NULL;
}
// de-init the http user agent
InitOEUserAgent(FALSE);
// A bunch of de-init things
FInitRichEdit(FALSE);
Note_Init(FALSE);
Envelope_FreeGlobals();
// Make sure next identity can migrate
g_fMigrationDone = FALSE;
// De-initialize Multilanguage menu
DeinitMultiLanguage();
// Deinit Stationery
if (g_pStationery)
{
// Save the current list
g_pStationery->SaveStationeryList();
// Release the object
SideAssert(0 == g_pStationery->Release());
// Lets not free it again
g_pStationery = NULL;
}
// Release the font cache
SafeRelease(g_lpIFontCache);
// Simple MAPI Cleanup
#ifndef WIN16
SimpleMAPICleanup();
#endif
// Kill the Wab
HrInitWab(FALSE);
/*
We shouldn't have to do this anymore. This should be handled by IE when we decrement the session count
#ifndef WIN16 // No RAS support in Win16
if (g_pConMan && g_pConMan->IsRasLoaded() && g_pConMan->IsConnected())
g_pConMan->Disconnect(g_hwndInit, TRUE, FALSE, TRUE);
#endif
*/
// Image Lists
FreeImageLists();
// Kill the account manager
if (g_pAcctMan)
{
CleanupTempNewsAccounts();
if (g_dwAcctAdvise != 0xffffffff)
{
g_pAcctMan->Unadvise(g_dwAcctAdvise);
g_dwAcctAdvise = 0xffffffff;
}
g_pAcctMan->Release();
g_pAcctMan = NULL;
}
Assert(g_dwAcctAdvise == 0xffffffff);
SafeRelease(g_pSync);
#ifndef WIN16 // No RAS support in Win16
SafeRelease(g_pConMan);
#endif
// Kill the rules manager
SafeRelease(g_pRulesMan);
// Take down the password cache
DestroyPasswordList();
// free the account data cache
FreeAccountPropCache();
// MIMEOLE Allocator
SafeRelease(g_pMoleAlloc);
// Kill g_hwndInit
if (g_hwndInit)
{
SendMessage(g_hwndInit, WM_CLOSE, (WPARAM) 0, (LPARAM) 0);
g_hwndInit = NULL;
}
// Kill the store
SafeRelease(g_pStore);
SafeRelease(g_pLocalStore);
SafeRelease(g_pDBSession);
// Global options
DeInitGlobalOptions();
// Run register window classes
UnregisterClass(c_szFolderWndClass, g_hInst);
UnregisterClassWrapW(STRW_MSOEAPI_INSTANCECLASS, g_hInst);
UnregisterClassWrapW(STRW_MSOEAPI_IPSERVERCLASS, g_hInst);
UnregisterClass(c_szFolderViewClass, g_hInst);
UnregisterClass(c_szBlockingPaintsClass, g_hInst);
UnregisterClass(WC_THUMBNAIL, g_hInst);
// Break Message Loop in RunShell if we are pumping messages and not switching identities
if (m_fPumpingMsgs && !m_fSwitchingUsers)
PostQuitMessage(0);
else
PostMessage(NULL, ITM_IDENTITYMSG, 0, 0);
MU_Shutdown();
// Relase the startup/shutdown mutex
ReleaseMutex(m_hInstMutex);
// Make sure mark this initialization thread as dead
m_dwThreadId = 0;
exit:
// We must have decremented succesfully
if (phInitRef)
*phInitRef = NULL;
// Trace
//TraceInfo(_MSG("_CoDecrementInitMain Count = %d, Reference Count = %d, Lock Count = %d", m_cDllInit, m_cDllRef, m_cDllLock));
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// COutlookExpress::ActivateWindow
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::ActivateWindow(HWND hwnd)
{
// If hwnd is minimized, retstore it
if (IsIconic(hwnd))
ShowWindow(hwnd, SW_RESTORE);
// If the window is not enabled, set it to the foreground
if (IsWindowEnabled(hwnd))
SetForegroundWindow(hwnd);
// Otherwise, I have no clue what this does
else
{
SetForegroundWindow(GetLastActivePopup(hwnd));
MessageBeep(MB_OK);
return S_FALSE;
}
// Done
return S_OK;
}
// --------------------------------------------------------------------------------
// COutlookExpress::SetSwitchingUsers
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::SetSwitchingUsers(BOOL bSwitching)
{
// Set the mode to whatever was passed in
m_fSwitchingUsers = bSwitching;
// if we are switching, we need to enter the mutex so that
// another process won't get started
if (bSwitching)
WaitForSingleObject(m_hInstMutex, INFINITE);
return S_OK;
}
// --------------------------------------------------------------------------------
// COutlookExpress::SetSwitchingUsers
// --------------------------------------------------------------------------------
void COutlookExpress::SetSwitchToUser(TCHAR *lpszUserName)
{
ULONG cchUserName = 0;
if (m_szSwitchToUsername)
{
MemFree(m_szSwitchToUsername);
m_szSwitchToUsername = NULL;
}
cchUserName = lstrlen(lpszUserName) + 1;
MemAlloc((void **)&m_szSwitchToUsername, cchUserName);
if (m_szSwitchToUsername)
{
StrCpyN(m_szSwitchToUsername, lpszUserName, cchUserName);
}
}
// --------------------------------------------------------------------------------
// COutlookExpress::BrowseToObject
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::BrowseToObject(UINT nCmdShow, FOLDERID idFolder)
{
// Locals
HRESULT hr=S_OK;
HWND hwnd;
// Trace
TraceCall("COutlookExpress::BrowseToObject");
// Do we already have a global browser object ?
if (g_pBrowser)
{
// Get its Window
if (SUCCEEDED(g_pBrowser->GetWindow(&hwnd)))
{
// Activate that Window
IF_FAILEXIT(hr = ActivateWindow(hwnd));
}
// Tell the browser to browse to this object
IF_FAILEXIT(hr = g_pBrowser->BrowseObject(idFolder, 0));
}
// Otherwise, we need to create a new browser object
else
{
// We should always be on the correct thread here
if (m_dwThreadId == GetCurrentThreadId())
{
// Create a new browser object
IF_NULLEXIT(g_pBrowser = new CBrowser);
// CoIncrementInit It
IF_FAILEXIT(hr = g_pBrowser->HrInit(nCmdShow, idFolder));
}
// Otherwise, we need to thunk across to the init thread to make this happen.
// This can happen when the Finder.cpp does a BrowseToObject to open a messgae's container
else
{
// Thunk with a message
Assert(g_hwndInit && IsWindow(g_hwndInit));
IF_FAILEXIT(hr = (HRESULT)SendMessage(g_hwndInit, ITM_BROWSETOOBJECT, (WPARAM)nCmdShow, (LPARAM)idFolder));
}
}
exit:
// Done
return hr;
}
void COutlookExpress::_ProcessCommandLineFlags(LPWSTR *ppwszCmdLine, DWORD dwFlags)
{
Assert(ppwszCmdLine != NULL);
DWORD Mode = 0;
if (*ppwszCmdLine != NULL)
{
// '/mailonly'
if (0 == StrCmpNIW(*ppwszCmdLine, c_wszSwitchMailOnly, lstrlenW(c_wszSwitchMailOnly)))
{
SetStartFolderType(FOLDER_LOCAL);
Mode |= MODE_MAILONLY;
*ppwszCmdLine = *ppwszCmdLine + lstrlenW(c_wszSwitchMailOnly);
}
// '/newsonly'
else if (0 == StrCmpNIW(*ppwszCmdLine, c_wszSwitchNewsOnly, lstrlenW(c_wszSwitchNewsOnly)))
{
SetStartFolderType(FOLDER_NEWS);
Mode |= MODE_NEWSONLY;
*ppwszCmdLine = *ppwszCmdLine + lstrlenW(c_wszSwitchNewsOnly);
}
// '/outnews'
else if (0 == StrCmpNIW(*ppwszCmdLine, c_wszSwitchOutNews, lstrlenW(c_wszSwitchOutNews)))
{
SetStartFolderType(FOLDER_NEWS);
Mode |= MODE_OUTLOOKNEWS;
*ppwszCmdLine = *ppwszCmdLine + lstrlenW(c_wszSwitchOutNews);
}
}
if (!(dwFlags & MSOEAPI_START_ALREADY_RUNNING))
{
g_dwAthenaMode |= Mode;
}
}
// --------------------------------------------------------------------------------
// COutlookExpress::ProcessCommandLine
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::ProcessCommandLine(INT nCmdShow, LPWSTR pwszCmdLine, BOOL *pfErrorDisplayed)
{
// Locals
HRESULT hr=S_OK;
LPWSTR pwszArgs;
FOLDERID idFolder=FOLDERID_ROOT;
HWND hwnd=NULL;
IF_DEBUG(DWORD dwTickStart=GetTickCount());
// Trace
TraceCall("COutlookExpress::ProcessCommandLine");
// Invalid Arg
Assert(pfErrorDisplayed);
// Do we have a command line
if (NULL == pwszCmdLine)
return S_OK;
// Goto Next Switch
if (*pwszCmdLine == L' ')
pwszCmdLine++;
// '/mailurl:'
if (0 == StrCmpNIW(pwszCmdLine, c_wszSwitchMailURL, lstrlenW(c_wszSwitchMailURL)))
{
SetStartFolderType(FOLDER_LOCAL);
pwszArgs = pwszCmdLine + lstrlenW(c_wszSwitchMailURL);
IF_FAILEXIT(hr = _HandleMailURL(pwszArgs, pfErrorDisplayed));
}
// '/newsurl:'
else if (0 == StrCmpNIW(pwszCmdLine, c_wszSwitchNewsURL, lstrlenW(c_wszSwitchNewsURL)))
{
SetStartFolderType(FOLDER_NEWS);
pwszArgs = pwszCmdLine + lstrlenW(c_wszSwitchNewsURL);
IF_FAILEXIT(hr = _HandleNewsURL(nCmdShow, pwszArgs, pfErrorDisplayed));
}
// '/eml:'
else if (0 == StrCmpNIW(pwszCmdLine, c_wszSwitchEml, lstrlenW(c_wszSwitchEml)))
{
pwszArgs = pwszCmdLine + lstrlenW(c_wszSwitchEml);
IF_FAILEXIT(hr = _HandleFile(pwszArgs, pfErrorDisplayed, FALSE));
}
// '/nws:'
else if (0 == StrCmpNIW(pwszCmdLine, c_wszSwitchNws, lstrlenW(c_wszSwitchNws)))
{
pwszArgs = pwszCmdLine + lstrlenW(c_wszSwitchNws);
IF_FAILEXIT(hr = _HandleFile(pwszArgs, pfErrorDisplayed, TRUE));
}
// Otherwise, decide where to start a browser at...
else
{
// Handle '/news'
if (0 == StrCmpNIW(pwszCmdLine, c_wszSwitchNews, lstrlenW(c_wszSwitchNews)))
{
// This sets g_dwIcwFlags
SetStartFolderType(FOLDER_NEWS);
if (g_pBrowser)
g_pBrowser->GetWindow(&hwnd);
hr = ProcessICW(hwnd, FOLDER_NEWS, TRUE);
if (hr != S_OK)
goto exit;
// Get Default News SErver
GetDefaultServerId(ACCT_NEWS, &idFolder);
}
// Handle '/mail /defclient'
else if (0 == StrCmpNIW(pwszCmdLine, c_wszSwitchMail, lstrlenW(c_wszSwitchMail)) ||
0 == StrCmpNIW(pwszCmdLine, c_wszSwitchDefClient, lstrlenW(c_wszSwitchDefClient)))
{
// Locals
FOLDERINFO Folder;
FOLDERID idStore;
// This sets g_dwIcwFlags
SetStartFolderType(FOLDER_LOCAL);
if (g_pBrowser)
g_pBrowser->GetWindow(&hwnd);
hr = ProcessICW(hwnd, FOLDER_LOCAL, TRUE);
if (hr != S_OK)
goto exit;
// Get store ID of default account
if (FAILED(GetDefaultServerId(ACCT_MAIL, &idStore)))
idStore = FOLDERID_LOCAL_STORE;
// Get Inbox Id
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idStore, FOLDER_INBOX, &Folder)))
{
idFolder = Folder.idFolder;
g_pStore->FreeRecord(&Folder);
}
}
// No switches
else
{
// default launch
// - if there is already a browser, just activate it
// - else if the option is set, select default inbox
// - else select the root (pidl = NULL)
if (g_pBrowser && SUCCEEDED(g_pBrowser->GetWindow(&hwnd)))
{
ActivateWindow(hwnd);
goto exit;
}
else if (DwGetOption(OPT_LAUNCH_INBOX) && (FALSE == ISFLAGSET(g_dwAthenaMode, MODE_NEWSONLY)))
{
// Locals
FOLDERINFO Folder;
FOLDERID idStore;
// This sets g_dwIcwFlags
SetStartFolderType(FOLDER_LOCAL);
// Get store ID of default account
if (FAILED(GetDefaultServerId(ACCT_MAIL, &idStore)))
idStore = FOLDERID_LOCAL_STORE;
// Get Inbox Id
if (SUCCEEDED(g_pStore->GetSpecialFolderInfo(idStore, FOLDER_INBOX, &Folder)))
{
idFolder = Folder.idFolder;
g_pStore->FreeRecord(&Folder);
}
}
}
// Browe to this new object, I assume if pidl=null, we browse to the root
IF_FAILEXIT(hr = BrowseToObject(nCmdShow, idFolder));
}
exit:
/*
// Cleanup
SafeMemFree(pszFree);
*/
// Trace
TraceInfo(_MSG("Process Command Line Time: %d milli-seconds", GetTickCount() - dwTickStart));
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::_HandleFile
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::_HandleFile(LPWSTR pwszCmd, BOOL *pfErrorDisplayed, BOOL fNews)
{
// Locals
HRESULT hr=S_OK;
INIT_MSGSITE_STRUCT initStruct;
DWORD dwCreateFlags = OENCF_SENDIMMEDIATE;
if (fNews)
dwCreateFlags |= OENCF_NEWSFIRST;
// Stack
TraceCall("COutlookExpress::_HandleFile");
// Invalid Arg
Assert(pfErrorDisplayed);
// Invalid Arg
if (NULL == pwszCmd || L'\0' == *pwszCmd)
{
hr = TraceResult(E_INVALIDARG);
goto exit;
}
// Does the file exist ?
if (FALSE == PathFileExistsW(pwszCmd))
{
// Locals
REPORTERRORINFO rError={0};
// Set hr
hr = TraceResult(MSOEAPI_E_FILE_NOT_FOUND);
// Duplicate It
LPSTR pszCmd = PszToANSI(CP_ACP, pwszCmd);
if (pszCmd)
{
// Make the rror
MAKEERROR(&rError, 0, IDS_ERROR_FILE_NOEXIST, 0, pszCmd);
rError.nHelpIds = 0;
// Show an error
*pfErrorDisplayed = _ReportError(g_hLocRes, hr, 0, &rError);
// Cleanup
MemFree(pszCmd);
}
// Done
goto exit;
}
initStruct.dwInitType = OEMSIT_FAT;
initStruct.pwszFile = pwszCmd;
hr = CreateAndShowNote(OENA_READ, dwCreateFlags, &initStruct);
exit:
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::_HandleNewsArticleURL
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::_HandleNewsArticleURL(LPSTR pszServerIn, LPSTR pszArticle, UINT uPort, BOOL fSecure, BOOL *pfErrorDisplayed)
{
HRESULT hr=S_OK;
CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
LPSTR psz = NULL,
pszBuf = NULL;
IImnAccount *pAccount=NULL;
INIT_MSGSITE_STRUCT initStruct;
LPMIMEMESSAGE pMsg = NULL;
Assert(pszServerIn);
// Stack
TraceCall("COutlookExpress::_HandleNewsArticleURL");
// Invalid Arg
Assert(pfErrorDisplayed);
// If a server was specified, then try to create a temp account for it
if (FALSE == FIsEmptyA(pszServerIn) && SUCCEEDED(CreateTempNewsAccount(pszServerIn, uPort, fSecure, &pAccount)))
{
// Get the Account name
IF_FAILEXIT(hr = pAccount->GetPropSz(AP_ACCOUNT_ID, szAccountId, ARRAYSIZE(szAccountId)));
}
// Otherwise, use the default news server
else
{
// If a server wasn't specified, then use the default account
IF_FAILEXIT(hr = GetDefaultNewsServer(szAccountId, ARRAYSIZE(szAccountId)));
}
// Bug #10555 - The URL shouldn't have <> around the article ID, but some lameoids probably will do it anyway, so deal with it.
if (FALSE == IsDBCSLeadByte(*pszArticle) && '<' != *pszArticle)
{
ULONG cchArticle;
cchArticle = lstrlen(pszArticle) + 4;
if (!MemAlloc((void **)&pszBuf, cchArticle))
{
hr = E_OUTOFMEMORY;
goto exit;
}
wnsprintf(pszBuf, cchArticle, TEXT("<%s>"), pszArticle);
psz = pszBuf;
}
else
{
psz = pszArticle;
}
hr = HrDownloadArticleDialog(szAccountId, psz, &pMsg);
if (S_OK == (hr))
{
Assert(pMsg != NULL);
initStruct.dwInitType = OEMSIT_MSG;
initStruct.pMsg = pMsg;
initStruct.folderID = FOLDERID_INVALID;
hr = CreateAndShowNote(OENA_READ, OENCF_NEWSFIRST, &initStruct);
}
else
{
// No errors if the user cancel'ed on purpose.
if (HR_E_USER_CANCEL_CONNECT == hr || HR_E_OFFLINE == hr)
hr = S_OK;
else
{
AthMessageBoxW(g_hwndInit, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsNewsTaskArticleError), 0, MB_OK|MB_SETFOREGROUND);
hr = S_OK;
}
}
exit:
// Cleanup
MemFree(pszBuf);
ReleaseObj(pAccount);
ReleaseObj(pMsg);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::_HandleNewsURL
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::_HandleNewsURL(INT nCmdShow, LPWSTR pwszCmd, BOOL *pfErrorDisplayed)
{
// Locals
HWND hwnd;
HRESULT hr=S_OK;
LPSTR pszCmd=NULL,
pszServer=NULL,
pszGroup=NULL,
pszArticle=NULL;
UINT uPort=(UINT)-1;
BOOL fSecure;
FOLDERID idFolder;
TCHAR szRes[CCHMAX_STRINGRES],
szError[MAX_PATH + CCHMAX_STRINGRES];
// Stack
TraceCall("COutlookExpress::_HandleNewsURL");
// Invalid Arg
Assert(pfErrorDisplayed);
Assert(pwszCmd != NULL);
Assert(*pwszCmd != 0);
// Since this is a URL, then don't need to worry about UNICODE
IF_NULLEXIT(pszCmd = PszToANSI(CP_ACP, pwszCmd));
// Un-escape the Url
UrlUnescapeInPlace(pszCmd, 0);
// Figure out if the URL is valid and what type of URL it is.
hr = URL_ParseNewsUrls(pszCmd, &pszServer, &uPort, &pszGroup, &pszArticle, &fSecure);
if ((hr == INET_E_UNKNOWN_PROTOCOL || hr == INET_E_INVALID_URL) &&
LoadString(g_hLocRes, idsErrOpenUrlFmt, szRes, ARRAYSIZE(szRes)))
{
// if bad url format, warn user and return S_OK as we handled it
// Outlook Express could not open the URL '%.100s' because it is not a recognized format.
// we clip the URL to 100 chars, so it easily fits in the MAX_PATH buffer
wnsprintf(szError, ARRAYSIZE(szError), szRes, pszCmd, lstrlen(pszCmd)>100?g_szEllipsis:c_szEmpty);
AthMessageBox(g_hwndInit, MAKEINTRESOURCE(idsAthena), szError, 0, MB_OK|MB_SETFOREGROUND);
return S_OK;
}
IF_FAILEXIT(hr);
// Compute the correct port number
if (uPort == -1)
uPort = fSecure ? DEF_SNEWSPORT : DEF_NNTPPORT;
// If we have an article, HandleNewsArticleURL
if (pszArticle)
{
// Launch a read note onto the article id
IF_FAILEXIT(hr = _HandleNewsArticleURL(pszServer, pszArticle, uPort, fSecure, pfErrorDisplayed));
}
// Otheriwse, create a PIDL and browse to that pidl (its a newsgroup)
else
{
// Locals
FOLDERID idFolder;
if (pszServer == NULL)
{
// If we have a browser, the its hwnd so that ICW has a parent
if (g_pBrowser)
g_pBrowser->GetWindow(&hwnd);
else
hwnd = NULL;
// Run the ICW if necessary
hr = ProcessICW(hwnd, FOLDER_NEWS, TRUE);
if (hr != S_OK)
goto exit;
}
// Create a PIDL for this newsgroup URL
if (SUCCEEDED(hr = GetFolderIdFromNewsUrl(pszServer, uPort, pszGroup, fSecure, &idFolder)))
{
// Browse to that object
IF_FAILEXIT(hr = BrowseToObject(nCmdShow, idFolder));
}
}
exit:
// Cleanup
SafeMemFree(pszCmd);
SafeMemFree(pszServer);
SafeMemFree(pszGroup);
SafeMemFree(pszArticle);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::_HandleMailURL
//
// PURPOSE: Provides an entry point into Thor that allows us to be
// invoked from a URL. The pszCmdLine paramter must be a
// valid Mail URL or nothing happens.
//
// --------------------------------------------------------------------------------
HRESULT COutlookExpress::_HandleMailURL(LPWSTR pwszCmdLine, BOOL *pfErrorDisplayed)
{
// Locals
HRESULT hr=S_OK;
LPMIMEMESSAGE pMsg=NULL;
INIT_MSGSITE_STRUCT initStruct;
TCHAR szRes[CCHMAX_STRINGRES],
szError[MAX_PATH + CCHMAX_STRINGRES];
LPSTR pszCmdLine = NULL;
// Stack
TraceCall("COutlookExpress::_HandleMailURL");
// Invalid Arg
Assert(pfErrorDisplayed);
// No command line
if (NULL == pwszCmdLine || L'\0' == *pwszCmdLine)
{
hr = TraceResult(E_INVALIDARG);
goto exit;
}
// Since this is a URL, then don't need to worry about UNICODE
IF_NULLEXIT(pszCmdLine = PszToANSI(CP_ACP, pwszCmdLine));
// Create a Message Object
IF_FAILEXIT(hr = HrCreateMessage(&pMsg));
// NOTE: no URLUnescape in this function - it must be done in URL_ParseMailTo to handle
// URLs of the format:
//
// mailto:foo@bar.com?subject=AT%26T%3dBell&cc=me@too.com
//
// so that the "AT%26T" is Unescaped into "AT&T=Bell" *AFTER* the "subject=AT%26T%3dBell&" blob is parsed.
hr = URL_ParseMailTo(pszCmdLine, pMsg);
if ((hr == INET_E_UNKNOWN_PROTOCOL || hr == INET_E_INVALID_URL) &&
LoadString(g_hLocRes, idsErrOpenUrlFmt, szRes, ARRAYSIZE(szRes)))
{
// if bad url format, warn user and return S_OK as we handled it
// Outlook Express could not open the URL '%.100s' because it is not a recognized format.
// we clip the URL to 100 chars, so it easily fits in the MAX_PATH buffer
wnsprintf(szError, ARRAYSIZE(szError), szRes, pszCmdLine, lstrlen(pszCmdLine)>100?g_szEllipsis:c_szEmpty);
AthMessageBox(g_hwndInit, MAKEINTRESOURCE(idsAthena), szError, 0, MB_OK|MB_SETFOREGROUND);
return S_OK;
}
IF_FAILEXIT(hr);
initStruct.dwInitType = OEMSIT_MSG;
initStruct.pMsg = pMsg;
initStruct.folderID = FOLDERID_INVALID;
hr = CreateAndShowNote(OENA_COMPOSE, OENCF_SENDIMMEDIATE, &initStruct);
exit:
// Cleanup
SafeRelease(pMsg);
MemFree(pszCmdLine);
// Done
return hr;
}
// --------------------------------------------------------------------------------
// COutlookExpress::InitWndProc
// --------------------------------------------------------------------------------
LRESULT EXPORT_16 CALLBACK COutlookExpress::InitWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
// Locals
BOOL fRet;
HRESULT hr;
// Delegate to the Account Manager
if (g_pAcctMan && g_pAcctMan->ProcessNotification(msg, wp, lp) == S_OK)
return TRUE;
// Handle the Message
switch(msg)
{
case WM_ENDSESSION:
// if we get forced down by window, we don't exit clean, so deinit global opt it not called. We obviously don't have a mailbomb so clear the regkey.
SetDwOption(OPT_ATHENA_RUNNING, FALSE, NULL, 0);
break;
case WM_SETTINGCHANGE:
Assert (g_lpIFontCache);
if (g_lpIFontCache)
{
if (!wp || SPI_SETNONCLIENTMETRICS == wp || SPI_SETICONTITLELOGFONT == wp)
g_lpIFontCache->OnOptionChange();
}
break;
case ITM_WAB_CO_DECREMENT:
Wab_CoDecrement();
return 0;
case ITM_BROWSETOOBJECT:
return (LRESULT)g_pInstance->BrowseToObject((UINT)wp, (FOLDERID)lp);
case ITM_SHUTDOWNTHREAD:
return (LRESULT)g_pInstance->_CoDecrementInitMain((LPHINITREF)lp);
case ITM_POSTCOPYDATA:
if (lp)
{
g_pInstance->Start(MSOEAPI_START_ALREADY_RUNNING, (LPCWSTR)lp, SW_SHOWNORMAL);
MemFree((LPWSTR)lp);
}
break;
case WM_COPYDATA:
{
// Locals
COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT *)lp;
// Command-line
if (pCopyData->dwData == MSOEAPI_ACDM_CMDLINE)
{
// #25238: On Win95, OLE get's pissed if we syncronously do stuff on the
// WM_COPYDATA. On the most part it works, but if we show an error and pump messages
// then some messages get run out of sequence and we deadlock between msimn.exe and
// iexplore.exe. Now we post to ourselves as we don't care about the HRESULT anyway
// we free the duped string on the post
PostMessage(hwnd, ITM_POSTCOPYDATA, 0, (LPARAM)PszDupW((LPCWSTR)pCopyData->lpData));
return 0;
}
// Notification Thunk
else if (pCopyData->dwData == MSOEAPI_ACDM_NOTIFY)
{
// Locals
NOTIFYDATA rNotify;
LRESULT lResult=0;
// Crack the notification
if (SUCCEEDED(CrackNotificationPackage(pCopyData, &rNotify)))
{
// Otherwise, its within this process...
if (ISFLAGSET(rNotify.dwFlags, SNF_SENDMSG))
lResult = SendMessage(rNotify.hwndNotify, rNotify.msg, rNotify.wParam, rNotify.lParam);
else
PostMessage(rNotify.hwndNotify, rNotify.msg, rNotify.wParam, rNotify.lParam);
// Done
return lResult;
}
// Problems
else
Assert(FALSE);
}
}
break;
case MVM_NOTIFYICONEVENT:
g_pInstance->_HandleTrayIconEvent(wp, lp);
return (0);
}
// Delegate to default window procedure
return DefWindowProc(hwnd, msg, wp, lp);
}
HRESULT COutlookExpress::UpdateTrayIcon(TRAYICONACTION type)
{
NOTIFYICONDATA nid;
HWND hwnd = NULL;
ULONG i;
TraceCall("COutlookExpress::UpdateTrayIcon");
EnterCriticalSection(&m_cs);
// Make sure we have the init window around first
if (!g_hwndInit)
goto exit;
// Set up the struct
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
nid.uCallbackMessage = MVM_NOTIFYICONEVENT;
if(m_hTrayIcon)
{
//Bug #86366 - (erici) Fixes leak. Don't create a new ICON each time COutlookExpress::UpdateTrayIcon is called.
nid.hIcon = m_hTrayIcon;
}
else
{
nid.hIcon = (HICON) LoadImage(g_hLocRes, MAKEINTRESOURCE(idiNewMailNotify), IMAGE_ICON, 16, 16, 0);
}
nid.hWnd = g_hwndInit;
LoadString(g_hLocRes, idsNewMailNotify, nid.szTip, sizeof(nid.szTip));
if (TRAYICONACTION_REMOVE == type)
{
Shell_NotifyIcon(NIM_DELETE, &nid);
}
// Add
if (TRAYICONACTION_ADD == type)
{
Shell_NotifyIcon(NIM_ADD, &nid);
}
g_pBrowser->WriteUnreadCount();
exit:
LeaveCriticalSection(&m_cs);
return (S_OK);
}
void COutlookExpress::_HandleTrayIconEvent(WPARAM wParam, LPARAM lParam)
{
HWND hwnd;
if (lParam == WM_LBUTTONDBLCLK)
{
if (g_pBrowser)
{
g_pBrowser->GetWindow(&hwnd);
if (IsIconic(hwnd))
ShowWindow(hwnd, SW_RESTORE);
SetForegroundWindow(hwnd);
PostMessage(hwnd, WM_COMMAND, ID_GO_INBOX, 0);
}
}
}