|
|
// --------------------------------------------------------------------------------
// 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:[email protected]?subject=AT%26T%3dBell&[email protected]
//
// 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); } } }
|