GPS Programming Tips for Windows Mobile - Part 1
NETCF: Memory leak... now what??
Supporting Kiosk-Applications on Windows Mobile (Technically achievable vs. supported)
Wireless Programming on Windows Mobile: supported or not supported?
Establishing GPRS Connection on Windows CE and Windows Mobile: Sample Codes
Disable WebBrowser's Context-Menu in NETCF applications
MAPI on Windows Mobile 6: Programmatically retrieve mail BODY (sample code)
Microsoft released a HotFix for NETCF v3.5 on Windows Mobile 6.1.4 onwards, to address basic functionalities of WebBrowser control
The right approach to get a Contact’s last communication (IItem’s PIMPR_SMARTPROP)
Remote Desktop Mobile (RDP Client) disconnects after 10 minutes of inactivity
Support Boundaries for Windows Mobile Programming (Developing Drivers, for example... Or even WiFi Programming)
Miei post in italiano sul team-blog del Supporto Tecnico agli Sviluppatori
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:
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