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
Have you ever played with EDB? I hadn’t… till the moment when I thought that what I needed was not implemented by the POOM and therefore I had to play with the “Contacts Database” contained in pim.vol... Unfortunately I understood only later that I was wrong… And luckily this was precisely the same query raised by in the MSDN Forum ‘How to get the information of a selected phonecall number?’ which I answered having fresh mind on the topic.
Basically when opening a Contact summary card, you can see 2 info:
So why on the earth did I mess up with EDB Functions against the “Contacts Database”? Purely because I wasn’t aware of such ad-hoc property!! And I ended up with a code that I want to share in case anyone is approaching to EDB Functions on Windows Mobile as it shows some basic functionalities… as usual it’s provided as-is for didactic purposes and doesn’t contain enough error-check for example.
DWORD dwError = ERROR_SUCCESS; CEGUID guid; DWORD dwBufSize, dwIndex; BOOL fOk = FALSE; HANDLE hSession, hDatabase; WORD wNumProps; CEOID oid = 0, ceoid; TCHAR szBuffer[MAXBUFFERSIZE] = {0}; PCEPROPVAL lpProp; //Used for CEVT_STREAM: HANDLE hStream; DWORD cbStream; LPBYTE pBuffer; DWORD cbActualRead; //1- Mount DB if (!CeMountDBVolEx(&guid, TEXT("\\pim.vol"), NULL, OPEN_ALWAYS)) { dwError = GetLastError(); goto Exit; } //2- Open Session hSession = CeCreateSession(&guid); if (hSession == INVALID_HANDLE_VALUE) { dwError = GetLastError(); goto Exit; } //3- Open Database hDatabase = CeOpenDatabaseInSession(hSession, &guid, &oid, TEXT("Contacts Database"), NULL, 0, NULL); if (hDatabase == INVALID_HANDLE_VALUE) { dwError = GetLastError(); goto Exit; } //4- Iterate through records (there are other ways apart from waiting for ERROR_SEEK...) dwIndex = 0; BOOL bFound = FALSE; while (!bFound) { //4.1- Set index into db ceoid = CeSeekDatabaseEx(hDatabase, CEDB_SEEK_BEGINNING, dwIndex, 0, NULL); if (ceoid == 0) { dwError = GetLastError(); goto Exit; } //4.2- Read records at index wNumProps = 0; ceoid = CeReadRecordPropsEx(hDatabase, CEDB_ALLOWREALLOC, &wNumProps, NULL, (LPBYTE*)&lpProp, &dwBufSize, NULL); if (ceoid == 0) { dwError = GetLastError(); //if (dwError == 122) //ERR_INSUFFICIENT_BUFFER //e.g. increase buffer and re-try goto Exit; } //4.3- Iterate through columns for( int i = 0; i < wNumProps; i++ ) { //4.4- switch based on datatype (http://msdn.microsoft.com/en-us/library/aa917573.aspx) switch( TypeFromPropID(lpProp[i].propid) ) { case CEVT_I2: _stprintf(szBuffer, _T("%d\t %d\t %s: %s"), dwIndex, i, _T("Data Type"), _T("CEVT_I2") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%d \r\n"), lpProp[i].val.iVal ); OutputDebugString(szBuffer); break; case CEVT_UI2: _stprintf(szBuffer, _T("%d\t %d\t %s: %s"), dwIndex, i, _T("Data Type"), _T("CEVT_UI2") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%d \r\n"), lpProp[i].val.uiVal ); OutputDebugString(szBuffer); break; case CEVT_I4: _stprintf(szBuffer, _T("%d\t %d\t %s: %s"), dwIndex, i, _T("Data Type"), _T("CEVT_I4") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%d \r\n"), lpProp[i].val.lVal ); OutputDebugString(szBuffer); break; case CEVT_UI4: _stprintf(szBuffer, _T("%d\t %d\t %s: %s"), dwIndex, i, _T("Data Type"), _T("CEVT_UI4") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%d \r\n"), lpProp[i].val.ulVal ); OutputDebugString(szBuffer); break; case CEVT_LPWSTR: _stprintf(szBuffer, _T("%d\t %d\t %s: %s\t"), dwIndex, i, _T("Data Type"), _T("CEVT_LPWSTR") ); OutputDebugString(szBuffer); OutputDebugString(lpProp[i].val.lpwstr); OutputDebugString(_T("\r\n")); break; case CEVT_BLOB: _stprintf(szBuffer, _T("%d\t %d\t %s: %s \r\n"), dwIndex, i, _T("Data Type"),_T("CEVT_BLOB") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%s: %li \r\n"), _T("Size in bytes"), lpProp[i].val.blob.dwCount ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%s: 0x%x \r\n"), _T("Buffer Address") ,lpProp[i].val.blob.lpb ); OutputDebugString(szBuffer); break; case CEVT_BOOL: _stprintf(szBuffer, _T("%d\t %d\t %s: %s \r\n"), dwIndex, i, _T("Data Type"),_T("CEVT_BOOL") ); OutputDebugString(szBuffer); break; case CEVT_R8: _stprintf(szBuffer, _T("%d\t %d\t %s: %s \r\n"), dwIndex, i, _T("Data Type"),_T("CEVT_R8") ); OutputDebugString(szBuffer); break; case CEVT_STREAM: _stprintf(szBuffer, _T("%d\t %d\t %s: %s \r\n"), dwIndex, i, _T("Data Type"),_T("CEVT_STREAM") ); OutputDebugString(szBuffer); //OPEN STREAM hStream = CeOpenStream(hDatabase, lpProp[i].propid, GENERIC_READ); cbStream = sizeof(hStream); if (hStream == INVALID_HANDLE_VALUE ) { dwError = GetLastError(); goto Exit; } //SET SEEK POSITION AT BEGINNING if (!CeStreamSeek(hStream, 0, STREAM_SEEK_SET, NULL)) { dwError = GetLastError(); goto Exit; } //READ STREAM pBuffer = new BYTE[cbStream]; if (!CeStreamRead(hStream, pBuffer, cbStream, &cbActualRead)) { dwError = GetLastError(); delete [] pBuffer; goto Exit; } _stprintf(szBuffer, _T("\tSTREAM: %s\r\n"), (LPTSTR)(pBuffer)); OutputDebugString(szBuffer); break; case CEVT_RECID: _stprintf(szBuffer, _T("%d\t %d\t %s: %s \r\n"), dwIndex, i, _T("Data Type"),_T("CEVT_RECID") ); OutputDebugString(szBuffer); break; case CEVT_AUTO_I4: _stprintf(szBuffer, _T("%d\t %d\t %s: %s"), dwIndex, i, _T("Data Type"),_T("CEVT_AUTO_I4") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%d \r\n"), lpProp[i].val.lVal ); OutputDebugString(szBuffer); break; case CEVT_AUTO_I8: _stprintf(szBuffer, _T("%d\t %d\t %s: %s"), dwIndex, i, _T("Data Type"),_T("CEVT_AUTO_I8") ); OutputDebugString(szBuffer); _stprintf(szBuffer, _T("\t%d \r\n"), lpProp[i].val.lVal ); OutputDebugString(szBuffer); break; default: _stprintf(szBuffer, _T("%d\t %d\t %s: %s \r\n"), dwIndex, i, _T("Data Type"),_T("Unknown") ); OutputDebugString(szBuffer); //lpProp[i].val ?? break; } //switch } //for //move to next record dwIndex++; } //while //5- Unmount db if (!CeUnmountDBVol(&guid)) { dwError = GetLastError(); goto Exit; } Exit: if (NULL != hDatabase) CloseHandle(hDatabase); if (NULL != hSession) CloseHandle(hSession); if (dwError == ERROR_SEEK) dwError = ERROR_SUCCESS; //ERROR_SEEK is expected to exit the while loop return dwError;
Cheers,
~raffaele
PingBack from http://asp-net-hosting.simplynetdev.com/the-wrong-approach-to-get-a-contact%e2%80%99s-last-communication-edb/
I've discussed about the “wrong” approach in a previous post of mine , where I also talked about why
One advantage of this over managed WindowsMobile.PocketOutlook is speed. When dealing with a large collection of contacts the managed library slows to a crawl.