2383 lines
73 KiB
C++
2383 lines
73 KiB
C++
|
// --------------------------------------------------------------------------------
|
||
|
// 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);
|
||
|
}
|
||
|
}
|
||
|
}
|