I've discussed about the “wrong” approach in a previous post of mine, where I also talked about why using PIMPR_SMARTPROP to retrieve the info about the last way a Windows Mobile-device user communicated with a given contact. Recently 2 MSDN Forums users asked for help about this (“How to get the information of a selected phonecall number?” and “How to read LastNumber in contact”) and therefore I wanted to invest some time for the Community, hoping this may help others as well! (and also to play with POOM, since managed APIs wrapped so many properties making POOM _quite_ obsolete…)
Before spreading the code, let me state a thing: the SmartProp property is not set for a contact until the first time the user
explicitly changes the default contact method, or it is otherwise explicitly set by an application. I noticed this when coding this sample, and later I understood that this is the expected behavior.
Ehy, remember that this is not production code: this is for testing\didactic purposes only… indeed the code is simply meant to dump out to a text-file only the First Name, Last Name and the string representing the last way user communicated with the selected contact. The code doesn’t even use the IPOutlookItemCollection::Find to get a specific contact, as this was not the goal here. Yet, I think it was worth sharing as it is, so that who wants can customize it… enjoy!!
NOTES:
- PIMPR_SMARTPROP is a property of the IItem, not of the IContact: that’s why for example the old POOM NETCF sample code didn’t contain it. So what we need is to retrieve the collection of Contacts and handle them as IItem.
- Once you have all the contacts as a collection (IPOutlookItemCollection), you can’t directly retrieve each item – even if IItem implements IDispatch, the right way is the one for example mentioned by my colleague Xiaoyun Li here, i.e. invoke IPOutlookItemCollection::Item by passing a IContact as IDispatch, then call IContact::get_Oid to retrieve the unique OID and finally use this with IPOutlookApp2::GetItemFromOidEx (see function DumpOutToText below).
- At this point you have an IItem object and can query its properties in the usual old way, considering that PIMPR_SMARTPROP will return the property id (e.g. PIMPR_MOBILE_TELEPHONE_NUMBER, PIMPR_SMS, etc); all the propIDs that can be returned as smart prop are listed in the documentation here.
- For each returned property, remember to check if it was really found (.wFlags != CEDB_PROPNOTFOUND) and if it’s of the expected data type (.propid == CEVT_LPWSTR).
If you know of any smarter way I’ll be more than welcome on continuing this saga about PIMPR_SMARTPROP…
#include "stdafx.h" #include <pimstore.h> // ************************************************************************** // Globals IPOutlookApp2 * g_polApp = NULL; IUnknown * g_pUnknown = NULL; LPCTSTR g_pszFilename = TEXT("contacts.txt"); // ************************************************************************** //Functions HRESULT InitPoom(void); HRESULT GetPoomFolder(int nFolder, IFolder ** ppFolder); HRESULT FillFileWithContacts(void); HRESULT DumpOutToText(IPOutlookItemCollection * pItemCol); HRESULT WriteItemSmartProp(IItem *pItem); HRESULT Log(LPTSTR szLog); HRESULT LogToFile(LPTSTR szLog, LPCTSTR pszFilename); // ************************************************************************** //MAIN int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = E_FAIL; //Initialize POOM hr = InitPoom(); CHR(hr); //Fill file with Contacts hr = FillFileWithContacts(); CHR(hr); //Success MessageBox(NULL, TEXT("Done"), TEXT("Test"), MB_OK); Exit: return 0; } // ************************************************************************** //InitPoom HRESULT InitPoom(void) { HRESULT hr = E_FAIL; hr = CoInitializeEx(NULL, 0); CHR(hr); hr = CoCreateInstance(CLSID_Application, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&g_pUnknown); CHR(hr); hr = g_pUnknown->QueryInterface(IID_IPOutlookApp, (void**)&g_polApp); CHR(hr); hr = g_polApp->Logon(NULL); CHR(hr); //success hr = S_OK; Exit: RELEASE_OBJ(g_polApp); return hr; } // ************************************************************************** //FillFileWithContacts HRESULT FillFileWithContacts(void) { HRESULT hr = E_FAIL; IFolder * pCurrFldr = NULL; IPOutlookItemCollection * pItemCol = NULL; // Get the Contacts folder and its items hr = GetPoomFolder(olFolderContacts, &pCurrFldr); CHR(hr); if (SUCCEEDED(pCurrFldr->get_Items(&pItemCol))) { //Dump out First Name, Last Name, SMARTPROP for each item hr = DumpOutToText(pItemCol); CHR(hr); } //success hr = S_OK; Exit: RELEASE_OBJ(pItemCol); RELEASE_OBJ(pCurrFldr); return hr; } // ************************************************************************** //GetPoomFolder HRESULT GetPoomFolder(int nFolder, IFolder ** ppFolder) { HRESULT hr = E_FAIL; if (SUCCEEDED(g_polApp->GetDefaultFolder(nFolder, ppFolder))) { hr = S_OK; } return hr; } // ************************************************************************** //DumpOutToText HRESULT DumpOutToText(IPOutlookItemCollection * pItemCol) { HRESULT hr = E_FAIL; IContact * pContact = NULL; IItem * pItem = NULL; CEOID oid = 0; int cItems = 0; //Count contacts pItemCol->get_Count(&cItems); for (int i = 1; i <= cItems; i++) { //get the item as a IContact if (SUCCEEDED(pItemCol->Item (i, reinterpret_cast<IDispatch**>(&pContact)))) { //convert the IContact into a IItem... if (SUCCEEDED(pContact->get_Oid((long*)&oid))) { //... by using the Oid if (SUCCEEDED(g_polApp->GetItemFromOidEx(oid, 0, &pItem))) { //Write item's properties to file hr = WriteItemSmartProp(pItem); RELEASE_OBJ(pItem); CHR(hr); } } } } //success hr = S_OK; Exit: return hr; } // ************************************************************************** //GetItemSmartProp HRESULT WriteItemSmartProp(IItem *pItem) { HRESULT hr = E_FAIL; int cProps = 20; CEPROPID rgPropId[20] = {0}; CEPROPVAL *prgPropvalUser = NULL; ULONG cbBuffer = 0; // FROM http://msdn.microsoft.com/en-us/library/bb415504.aspx // The Smart Property (PIMPR_SMARTPROP) is the Contact property that contains the property ID of the default communication mode. rgPropId[0] = PIMPR_FIRST_NAME; //type: CEVT_LPWSTR rgPropId[1] = PIMPR_LAST_NAME; //type: CEVT_LPWSTR rgPropId[2] = PIMPR_SMARTPROP; //type: CEVT_UI4 //all of the following are of type: CEVT_LPWSTR rgPropId[3] = PIMPR_IM2_ADDRESS; rgPropId[4] = PIMPR_ASSISTANT_TELEPHONE_NUMBER; rgPropId[5] = PIMPR_BUSINESS_TELEPHONE_NUMBER; rgPropId[6] = PIMPR_BUSINESS2_TELEPHONE_NUMBER; rgPropId[7] = PIMPR_CAR_TELEPHONE_NUMBER; rgPropId[8] = PIMPR_COMPANY_TELEPHONE_NUMBER; rgPropId[9] = PIMPR_EMAIL1_ADDRESS; rgPropId[10] = PIMPR_EMAIL2_ADDRESS; rgPropId[11] = PIMPR_EMAIL3_ADDRESS; rgPropId[12] = PIMPR_HOME_TELEPHONE_NUMBER; rgPropId[13] = PIMPR_HOME2_TELEPHONE_NUMBER; rgPropId[14] = PIMPR_IM1_ADDRESS; rgPropId[15] = PIMPR_IM3_ADDRESS; rgPropId[16] = PIMPR_MOBILE_TELEPHONE_NUMBER; rgPropId[17] = PIMPR_PAGER_NUMBER; rgPropId[18] = PIMPR_RADIO_TELEPHONE_NUMBER; rgPropId[19] = PIMPR_SMS; //FROM: http://msdn.microsoft.com/en-us/library/ms859378.aspx // Allocate memory, then get item properties cbBuffer = 0; hr = pItem->GetProps(rgPropId, 0, cProps, &prgPropvalUser, &cbBuffer, NULL); if(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) { prgPropvalUser = (CEPROPVAL *) LocalAlloc(0, cbBuffer); } // cbBuffer is set to the number of bytes required to hold the data. hr = pItem->GetProps(rgPropId, 0, cProps, (CEPROPVAL **)&prgPropvalUser, &cbBuffer, NULL); //better error-checking to do here... if(FAILED(hr) || 0 == cbBuffer) { goto Exit; } if(prgPropvalUser[0].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[0].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[0].val.lpwstr); Log(TEXT("\t")); } } if(prgPropvalUser[1].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[1].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[1].val.lpwstr); Log(TEXT("\t")); } } if(prgPropvalUser[2].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[2].propid) == CEVT_UI4) { switch (prgPropvalUser[2].val.ulVal) { case PIMPR_IM2_ADDRESS: if(prgPropvalUser[3].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[3].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[3].val.lpwstr); } } break; case PIMPR_ASSISTANT_TELEPHONE_NUMBER: if(prgPropvalUser[4].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[4].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[4].val.lpwstr); } } break; case PIMPR_BUSINESS_TELEPHONE_NUMBER: if(prgPropvalUser[5].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[5].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[5].val.lpwstr); } } break; case PIMPR_BUSINESS2_TELEPHONE_NUMBER: if(prgPropvalUser[6].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[6].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[6].val.lpwstr); } } break; case PIMPR_CAR_TELEPHONE_NUMBER: if(prgPropvalUser[7].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[7].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[7].val.lpwstr); } } break; case PIMPR_COMPANY_TELEPHONE_NUMBER: if(prgPropvalUser[8].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[8].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[8].val.lpwstr); } } break; case PIMPR_EMAIL1_ADDRESS: if(prgPropvalUser[9].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[9].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[9].val.lpwstr); } } break; case PIMPR_EMAIL2_ADDRESS: if(prgPropvalUser[10].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[10].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[10].val.lpwstr); } } break; case PIMPR_EMAIL3_ADDRESS: if(prgPropvalUser[11].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[11].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[11].val.lpwstr); } } break; case PIMPR_HOME_TELEPHONE_NUMBER: if(prgPropvalUser[12].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[12].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[12].val.lpwstr); } } break; case PIMPR_HOME2_TELEPHONE_NUMBER: if(prgPropvalUser[13].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[13].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[13].val.lpwstr); } } break; case PIMPR_IM1_ADDRESS: if(prgPropvalUser[14].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[14].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[14].val.lpwstr); } } break; case PIMPR_IM3_ADDRESS: if(prgPropvalUser[15].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[15].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[15].val.lpwstr); } } break; case PIMPR_MOBILE_TELEPHONE_NUMBER: if(prgPropvalUser[16].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[16].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[16].val.lpwstr); } } break; case PIMPR_PAGER_NUMBER: if(prgPropvalUser[17].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[17].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[17].val.lpwstr); } } break; case PIMPR_RADIO_TELEPHONE_NUMBER: if(prgPropvalUser[18].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[18].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[18].val.lpwstr); } } break; case PIMPR_SMS: if(prgPropvalUser[19].wFlags!=CEDB_PROPNOTFOUND) { if(LOWORD(prgPropvalUser[19].propid) == CEVT_LPWSTR) { Log(prgPropvalUser[19].val.lpwstr); } } break; } //switch } } Log(TEXT("\r\n")); //success hr = S_OK; Exit: LocalFree(prgPropvalUser); return hr; }
// ************************************************************************** // Log HRESULT Log(LPTSTR szLog) { HRESULT hr = E_FAIL; hr = LogToFile(szLog, g_pszFilename); CHR(hr); Exit: return hr; } // ************************************************************************** // LogToFile // Writes szLog into the file named pszFilename HRESULT LogToFile(LPTSTR szLog, LPCTSTR pszFilename) { HRESULT hr = E_FAIL; //Open the handle to the file (and create it if it doesn't exist HANDLE hFile = CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) goto Exit; //Set the pointer at the end so that we can append szLog DWORD dwFilePointer = SetFilePointer(hFile, 0, NULL, FILE_END); if (0xFFFFFFFF == dwFilePointer) goto Exit; //Write to the file DWORD dwBytesWritten = 0; BOOL bWriteFileRet = WriteFile(hFile, szLog, wcslen(szLog) * 2, &dwBytesWritten, NULL); if (!bWriteFileRet) goto Exit; //Flush the buffer BOOL bFlushFileBuffersRet = FlushFileBuffers(hFile); if (!bFlushFileBuffersRet) goto Exit; //Success hr = S_OK; Exit: if (NULL != hFile) CloseHandle(hFile); return hr; }
Cheers,
~raffaele
PingBack from http://www.anith.com/?p=42550