www.pudn.com > MailCheck_src.zip > Wakeme.cpp


/*************************************************************************** 
* Copyright (c) 1996, Microsoft Corporation 
* 
* Sample extended MAPI app with new mail notifications 
* 
* History: 
* 1 Oct 1996	Vajira Weerasekera 
* 
* This is a quick sample application that demonstrates Extended MAPI mail 
* notifications. 
* 
* Once the app is launched it will logon to MAPI and register for new mail 
* notifications, and when new mail arrives it will simply display a dialog with 
* the originator and the subject. 
* 
\***************************************************************************/ 
 
 
// Wakeme.cpp : Defines the class behaviors for the application. 
// 
 
#include "Wakeme.h" 
#include "Utils.h" 
 
#define USES_IID_IUnknown 
#define INITGUID 
#include "mkguids.h" 
 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
extern CWinApp theApp; 
 
///////////////////////////////////////////////////////////////////////////// 
// CWakemeApp 
 
///////////////////////////////////////////////////////////////////////////// 
// CWakemeApp construction 
 
CWakemeApp::CWakemeApp() 
{ 
	m_fMAPIInitialized = FALSE; 
	m_pSession = NULL; 
	m_lpDefaultStore = NULL; 
	m_lpInboxFolder = NULL; 
	m_lpIPMFolder = NULL;   
	m_lpOutboxFolder = NULL; 
	m_lpRootHierarchyTable = NULL; 
	m_lpRootFolder = NULL; 
 
	// Initialise a MAPI Session 
	HRESULT hr = MAPIInitialize(NULL); 
	 
	if (SUCCEEDED(hr)) {    
		m_fMAPIInitialized = TRUE; 
 
		ULONG ulFlags = MAPI_ALLOW_OTHERS | MAPI_USE_DEFAULT | MAPI_EXTENDED; 
		hr = (HRESULT) MAPILogonEx(NULL,  
								NULL,  
								NULL,  
								ulFlags, 
								&m_pSession ); 
	}  
	     
	if (FAILED(hr)) { 
		SCODE sc = GetScode(hr); 
			       
		if (sc != MAPI_E_USER_CANCEL) 
			MessageBox(NULL,"Cannot establish a messaging session","Error",MB_APPLMODAL); 
			          
		return; 
	} 
 
	hr = OpenMsgStore(); 
	if (FAILED(hr)) 
		return; 
 
	// Register for new mail 
	RegisterForNewMail(); 
} 
 
// Logoff from MAPI when the application is closing down 
CWakemeApp::~CWakemeApp() 
{ 
	MessageBox(NULL,"Disconnecting...","Information",MB_APPLMODAL); 
 
	// Unregister from new mail 
	if (m_bNewMailNotify) 
		UnregisterForNewMail();	 
 
	if (m_lpInboxFolder) 
		m_lpInboxFolder->Release(); 
		 
    if (m_lpIPMFolder) 
    	m_lpIPMFolder->Release(); 
     
    if (m_lpOutboxFolder) 
    	m_lpOutboxFolder->Release(); 
 
	if (m_lpRootHierarchyTable) 
		m_lpRootHierarchyTable->Release(); 
 
	if (m_lpRootFolder) 
		m_lpRootFolder->Release(); 
 
	if (m_lpDefaultStore) 
		m_lpDefaultStore->Release(); 
	 
	if (m_pSession) { 
 
		// End the MAPI session 
		HRESULT hResult = m_pSession->Logoff(0,MAPI_LOGOFF_UI,0); 
		// Release the MAPI session object 
		m_pSession->Release(); 
		if (FAILED(hResult)) 
			MessageBox(NULL,"MAPI Logoff failed !","Error",MB_APPLMODAL); 
	} 
 
   	// If we have initialized MAPI then Uninitialize it now 
   	if (m_fMAPIInitialized) { 
    	MAPIUninitialize();// Decrement MAPI reference count 
    	m_fMAPIInitialized = FALSE; 
    }	 
} 
 
 
// Open the message store object if it's not open already, and return the  
// object pointer to the caller 
// 
HRESULT CWakemeApp::OpenMsgStore() 
{ 
	ASSERT(m_pSession != NULL); 
	 
    if (m_lpDefaultStore) 
    	return ResultFromScode(SUCCESS_SUCCESS); 
 
	// Open the default message store  
	 
	ULONG       cbEntryID; 
	LPENTRYID   pEntryID; 
	    
	HRESULT hr = QueryDefaultMsgStore(&cbEntryID,&pEntryID); 
	if (FAILED(hr)) 
		return hr; 
	 
	// Now that we have the entry ID for the default message store, we can 
	// open it. 
	 
	hr = m_pSession->OpenMsgStore( NULL, 
	                                      cbEntryID, 
	                                      pEntryID, 
	                                      NULL, 
	                                      MDB_WRITE, 
	                                      &m_lpDefaultStore ); 
	if (FAILED(hr)){ 
		m_lpDefaultStore = NULL; 
		return hr; 
	}	 
	     
	// Check for the existence of an IPM_SUBTREE in this store.  
	// If one does not exist, then make one with the standard name. 
	 
	static SPropTagArray pta = { 1, {PR_IPM_SUBTREE_ENTRYID}}; 
	    
	ULONG          cValues; 
	LPSPropValue   pPropArray; 
	    
	hr = m_lpDefaultStore->GetProps(&pta,0,&cValues,&pPropArray); 
	if (FAILED(hr) || pPropArray->ulPropTag != PR_IPM_SUBTREE_ENTRYID) { 
		if (SUCCEEDED(hr)) 
	 		MAPIFreeBuffer(pPropArray); 
	 
		// Open the root folder 
	           
	    LPMAPIFOLDER pfldrRoot; 
	    ULONG ulObjType; 
	    hr = m_lpDefaultStore->OpenEntry(0,NULL,NULL,MAPI_MODIFY,&ulObjType,(LPUNKNOWN FAR *) &pfldrRoot); 
	    if (FAILED(hr)){ 
	    	m_lpDefaultStore->Release(); 
	    	m_lpDefaultStore = NULL; 
	        return hr; 
	    }     
	 
		// Create a sub-folder called 'IPM_SUBTREE' 
	         
	    LPMAPIFOLDER pfldr; 
	    hr = pfldrRoot->CreateFolder(FOLDER_GENERIC,"IPM_SUBTREE",NULL,NULL,OPEN_IF_EXISTS,&pfldr); 
	    if (FAILED(hr)) { 
	        pfldrRoot->Release(); 
	        m_lpDefaultStore->Release(); 
	        m_lpDefaultStore = NULL; 
	        return hr; 
	    } 
	 
	    pfldrRoot->Release(); 
	     
	    hr = pfldr->SaveChanges(KEEP_OPEN_READONLY); 
	    if (FAILED(hr)) { 
	        pfldr->Release(); 
	        m_lpDefaultStore->Release(); 
	        m_lpDefaultStore = NULL; 
	        return hr; 
	    } 
	         
		// Set PR_IPM_SUBTREE_ENTRYID to the entryid of this folder 
	         
	    static SPropTagArray pta = { 1, {PR_ENTRYID}}; 
	    ULONG cValues; 
	    LPSPropValue pPropArray; 
	     
	    hr = pfldr->GetProps(&pta,0,&cValues,&pPropArray); 
	    if (FAILED(hr)) { 
	        pfldr->Release(); 
	        m_lpDefaultStore->Release(); 
	        m_lpDefaultStore = NULL; 
	        return hr; 
	    } 
	     
	    // Release the newly created folder 
	    pfldr->Release(); 
	         
	    if (pPropArray->ulPropTag == PR_ENTRYID) {         
	        pPropArray->ulPropTag = PR_IPM_SUBTREE_ENTRYID; 
	        hr = m_lpDefaultStore->SetProps(1,pPropArray,NULL); 
	        if (FAILED(hr)) { 
	            MAPIFreeBuffer(pPropArray); 
	            pfldr->Release(); 
	            m_lpDefaultStore->Release(); 
	            m_lpDefaultStore = NULL; 
	            return hr; 
	        } 
	    } 
	         
	    MAPIFreeBuffer(pPropArray); 
	} else { 
	    MAPIFreeBuffer(pPropArray); 
	}     
	 
	return hr; 
 
} 
 
// 
// Figure out the default message store. Scans the MsgStoresTable for the 
// first one with the PR_DEFAULT_STORE set to TRUE. If none found, then use 
// the first store in the table. 
// 
HRESULT CWakemeApp::QueryDefaultMsgStore(ULONG FAR *pcbEntryID,LPENTRYID FAR *ppEntryID) 
{ 
    ASSERT(m_pSession != NULL); 
     
    // Get the message store table 
     
    LPMAPITABLE ptbl; 
    HRESULT hr = m_pSession->GetMsgStoresTable(0,&ptbl); 
    if (FAILED(hr)) 
        return hr; 
 
    ULONG cRows = 0; 
    hr = ptbl->GetRowCount(0,&cRows); 
    if (FAILED(hr)) { 
        ptbl->Release(); 
        return hr; 
    } 
     
    if (cRows == 0) { 
        ptbl->Release(); 
        return ResultFromScode(MAPI_E_CALL_FAILED); 
    } 
     
    // Look for the default message store row and return it's entry ID 
         
    ULONG iRowDefault = 0xFFFF; 
    for (ULONG iRow=0;iRowSetColumns(&pta,0); 
        if (FAILED(hr)) { 
            ptbl->Release(); 
            return hr; 
        } 
 
        hr = ptbl->SeekRow(BOOKMARK_BEGINNING,iRow,NULL); 
        if (FAILED(hr)) { 
            ptbl->Release(); 
            return hr; 
        } 
 
        LPSRowSet prs; 
        hr = ptbl->QueryRows(1,0,&prs); 
        if (FAILED(hr)) { 
            ptbl->Release(); 
            return hr; 
        } 
 
        if (prs->cRows == 1 &&  
                        prs->aRow[0].lpProps->ulPropTag == PR_DEFAULT_STORE &&  
                        prs->aRow[0].lpProps->Value.b) { 
            iRowDefault = iRow; 
            FreeRowSet(MAPIFreeBuffer, prs); 
            break; 
        } 
 
        FreeRowSet(MAPIFreeBuffer, prs); 
    } 
 
    if (iRowDefault == 0xFFFF) 
        return ResultFromScode(MAPI_E_CALL_FAILED); 
     
    static SPropTagArray pta = {1, {PR_ENTRYID}}; 
    hr = ptbl->SetColumns(&pta,0); 
    if (FAILED(hr)) { 
        ptbl->Release(); 
        return hr; 
    } 
 
    hr = ptbl->SeekRow(BOOKMARK_BEGINNING,iRowDefault,NULL); 
    if (FAILED(hr)) { 
        ptbl->Release(); 
        return hr; 
    } 
 
    LPSRowSet prs; 
    hr = ptbl->QueryRows(1,0,&prs); 
    if (FAILED(hr)) { 
        ptbl->Release(); 
        return hr; 
    } 
 
    ptbl->Release(); 
 
    if (prs->cRows == 1 && prs->aRow[0].lpProps->ulPropTag == PR_ENTRYID) { 
        ULONG cb = prs->aRow[0].lpProps->Value.bin.cb; 
        LPENTRYID pEntryID; 
        SCODE sc = MAPIAllocateBuffer(cb,(LPVOID FAR *) &pEntryID); 
        if (FAILED(sc)) { 
            FreeRowSet(MAPIFreeBuffer, prs); 
            return ResultFromScode(sc); 
        } 
        memcpy(pEntryID,prs->aRow[0].lpProps->Value.bin.lpb,(size_t) cb); 
        FreeRowSet(MAPIFreeBuffer, prs); 
         
        *pcbEntryID = cb; 
        *ppEntryID = pEntryID; 
         
        return hrSuccess; 
    } 
     
    FreeRowSet(MAPIFreeBuffer, prs); 
     
    return ResultFromScode(MAPI_E_CALL_FAILED); 
} 
 
 
// Registers an AdviseSink for New Mail notification 
// 
HRESULT CWakemeApp::RegisterForNewMail() 
{ 
	ULONG       cbEntryID; 
	LPENTRYID   pEntryID; 
	LPSTR       szActualClass; 
	ULONG		ulRowCount = 0; 
	ULONG		ulObjType; 
 
	m_bNewMailNotify = FALSE; 
	 
	// Get the inbox folder object                 
	HRESULT hr = m_lpDefaultStore->GetReceiveFolder("IPM", 0, &cbEntryID, 
	                                               &pEntryID,&szActualClass ); 
	                                                    
	if (FAILED(hr) || szActualClass == NULL || strcmp(szActualClass,"IPM")) { 
	  if (SUCCEEDED(hr)) { 
	     MAPIFreeBuffer( pEntryID ); 
	     MAPIFreeBuffer( szActualClass ); 
	  } 
	  return ResultFromScode(E_FAIL); 
	}         
 
    // Get the root folder of the default message store 
    hr = m_lpDefaultStore->OpenEntry((ULONG)0, 
        NULL, 
        NULL, 
        MAPI_MODIFY|MAPI_DEFERRED_ERRORS, 
        &ulObjType, 
        (LPUNKNOWN FAR *) &m_lpRootFolder); 
    if (FAILED( hr)) 
        return ResultFromScode(E_FAIL); 
	    
	m_pNewMailSink = new CNewMailAdviseSink(this); 
	 
	//Register for notification (fnevNewMail) 
	hr = m_lpDefaultStore->Advise( cbEntryID, 
	                             pEntryID, 
	                             fnevNewMail, 
	                             m_pNewMailSink, 
	                             &m_ulNewMailConnection ); 
	                                  
	MAPIFreeBuffer( pEntryID ); 
	MAPIFreeBuffer( szActualClass ); 
	 
	if (FAILED( hr )) { 
	  m_pNewMailSink->Release(); 
	  m_pNewMailSink = NULL; 
	  return( hr );    
	} 
 
	// need to force an RPC call to the server.. 
	// without this force, the notification will NOT work. 
	// this will ensure that the Advice() call was actaully registered. 
	 
	// Get the hierarchy table for the root folder of the message store 
    hr = m_lpRootFolder->GetHierarchyTable(MAPI_DEFERRED_ERRORS, 
    	&m_lpRootHierarchyTable); 
 
    if( FAILED( hr)) 
        return ResultFromScode(E_FAIL); 
 
	hr = m_lpRootHierarchyTable->GetRowCount(TBL_NOWAIT,&ulRowCount); 
    if( FAILED( hr)) 
        return ResultFromScode(E_FAIL); 
 
	 
	m_bNewMailNotify = TRUE; 
	       
	return( hr );       
} 
 
 
// Unregisters the new mail advise sink 
// 
HRESULT CWakemeApp::UnregisterForNewMail() 
{ 
   	if (!m_bNewMailNotify) 
    	return( hrSuccess ); 
       
   	HRESULT hr = m_lpDefaultStore->Unadvise( m_ulNewMailConnection ); 
 
	if (m_pNewMailSink) 
		m_pNewMailSink->Release(); 
    
   	m_bNewMailNotify = FALSE; 
    
   	return hr;    
} 
 
// Implementation of IUnknown methods 
// 
HRESULT CNewMailAdviseSink::QueryInterface(REFIID riid,LPVOID FAR* ppvObj) 
{ 
    if( riid == IID_IUnknown){ 
        *ppvObj = this; 
        AddRef(); 
        return hrSuccess; 
    } 
     
   return ResultFromScode(E_NOINTERFACE); 
} 
 
ULONG CNewMailAdviseSink::AddRef() 
{ 
   return ++m_cRef; 
} 
 
ULONG CNewMailAdviseSink::Release() 
{ 
   if (--m_cRef == 0) { 
      delete this; 
      return 0; 
   } 
     
   return m_cRef; 
} 
 
// Ha! a new mail msg just came in... 
// 
ULONG CNewMailAdviseSink::OnNotify(ULONG cNotif,LPNOTIFICATION lpNotify) 
{ 
    static SizedSPropTagArray(2, pta) = {2, {PR_SENDER_NAME,   
                                    PR_SUBJECT}};  
	 
	HRESULT hr; 
	ULONG ulObjType; 
	LPMESSAGE lpNewMessage; 
	 
	ULONG          cValues; 
	LPSPropValue   pPropArray; 
 
	// Quick sanity chek to see if we got really called back for newmail ? 
	if (lpNotify) { 
		if (lpNotify->ulEventType == fnevNewMail){ 
 
			// Open the new message 
			hr = m_pParent->m_lpDefaultStore->OpenEntry( 
							lpNotify->info.newmail.cbEntryID, 
							lpNotify->info.newmail.lpEntryID, 
							NULL, 
							MAPI_MODIFY|MAPI_DEFERRED_ERRORS, 
							&ulObjType, 
							(LPUNKNOWN FAR *) &lpNewMessage); 
			if (FAILED( hr)) 
				return 1; 
 
			// Get the message details 
 
			hr = lpNewMessage->GetProps((LPSPropTagArray)&pta,0,&cValues,&pPropArray); 
			 
			// release the new message 
			lpNewMessage->Release(); 
			 
			if (FAILED( hr)) 
				return 1; 
 
			CString s; 
			s.LoadString(IDS_MAIL); 
 
			m_pParent->dlg.m_from = pPropArray[0].Value.lpszA; 
			m_pParent->dlg.m_subject = pPropArray[1].Value.lpszA; 
			m_pParent->dlg.m_legend = s; 
			m_pParent->dlg.UpdateData(FALSE); 
 
			m_pParent->dlg.TraySetToolTip((LPCTSTR)s); 
			m_pParent->dlg.TraySetIcon(IDI_MAIL); 
			m_pParent->dlg.TrayUpdate(); 
 
			Beep(440, 200); 
 
			return 0; 
 
		} // if 
	} // if 
 
	 
	MessageBox(NULL,"Who is waking me up ?","Error",MB_APPLMODAL); 
 
	return 0; 
}