Windows CE Database Programming using EDB

by Krishnaraj Varma on September 21, 2008

in Windows Mobile

Download the source code

Windows CE supports CEDB and EDB databases. CEDB (Property Database) is lightweight database API for Windows CE. CEDB provides storage, access and sorting records. The new EDB replaces CEDB database. The CEDB is considered as obsolete for Windows Mobile 6 onwards. EDB volumes can contain multiple databases.

An EDB database contains a number of records. Records are a collection of properties. A property in Windows CE Database can have be one of the Windows CE supported data type.

To open or create a database, we should mount the volume. A volume is a file which is specially and can contain CE database. Before using the database we have to mount the volume and after the use we should unmount the volume. After mounting it will be assigned a unique GUID and is represented as CEGUID structure. It should be noted that mounting is reference counted, each time the volume is mounted reference count is incremented and when unmounted the reference is decremented and when the count is zero it will be closed. A volume can contain multiple databases. Once a volume is mounted, we can open any database that is the volume.

To mount a volume we can use the API CeMountDBVolEx API. Syntax is defined as:

BOOL CeMountDBVolEx(PCEGUID pGuid,LPWSTR lpwszDBVol, CEVOLUMEOPTIONS* pOptions,DWORD dwFlags);

The parameter pGuid will receive the CEGUID of the mounted volume. The third parameter is a pointer to CEVOLUMEOPTIONS structure which is used to configure the database volume options such as buffer pool size, flush intervals, password, etc… After mounting the volume we create database session using the API CeCreateSession. After creating a session we can open an existing database using the API CeOpenDatabaseInSession or create a new database using the API CeCreateDatabaseWithProps. If we create the database we should still open the database in order to work.

After opening we can peform read or write operations. To read a record we can use the API CeReadRecordPropsEx. The syntax is defined as

CEOID CeReadRecordPropsEx(HANDLE hDbase,DWORD dwFlags,LPWORD, CEPROPID* prgPropID,LPBYTE* lplpBuffer,LPDWORD lpcbBuffer,HANDLE hHeap);

The dwFlags can be either 0 or CEDB_ALLOWREALLOC. The CEDB_ALLOWREALLOC flag tells the system to use the buffer specified by the lplpBuffer parameter is allocated using LocalAlloc and can reallocate if necessory. The record retrieved will be copied to the lplpBuffer. This will be an array of CEPROPVAL structure. This structure contains the data type and the data itself. The last parameter can be NULL or a handle of an application created heap. If this parameter is not NULL, the system will use this heap handle to reallocate the lplpBuffer. The CeReadRecordPropsEx returns a CEOID which represents the current row. This value is an identifier that represents the row fetched. We can use this value to seek to a particular row.

To write to the database we use the API CeWriteRecordProps and the syntax is defined as:

CEOID CeWriteRecordProps(HANDLE hDatabase, CEOID oidRecord,WORD PropID,CEPROPVAL* prgPropVal);

The past parameter prgPropVal is an array of CEPROPVAL structure which contains the actual data.

The CEPROPVAL structure is defined as:

typedef struct _CEPROPVAL{
CEPROPID propid;
WORD wLenData;
WORD wFlags;
CEVALUNION val;
} CEPROPVAL;
typedef CEPROPVAL *PCEPROPVAL;

The member propid is the identifier or data type of the property value. The higher order word can be an application defined value and low order word is one of the supported data type. The data type can be one of the folowing constants:

CEVT_BLOB
CEVT_BOOL
CEVT_FILETIME
CEVT_I2
CEVT_I4
CEVT_LPWSTR
CEVT_R8
CEVT_UI2
CEVT_UI4

These values are self explanatory. We can use a #define for a particular field such as

#define FIELD_TITLE MAKELONG(CEVT_LPWSTR,1)

The member val is a union of type CEVALUNION which defined as:

typedef union _CEVALUNION {
short iVal;
USHORT uiVal;
long lVal;
ULONG ulVal;
FILETIME filetime;
LPWSTR lpwstr;
CEBLOB blob;
BOOL boolVal;
double dblVal;
} CEVALUNION;

We have to set the values based on the data type of the corresponding property such as lpwstr for type, blob for CEVT_BLOB, etc…

The sample application presented here is a simple application to manage book details such as title, ISBN, authors, description etc… You can add, delete and modify the book details. The application is compiled using Visual Studio 2008 using Windows Mobile SDK 6.

{ 1 comment }

Download the source code

Here is an application that will monitor SMS message and if the message is coming from predefined numbers then reply that SMS with some predefined text.

There are two components in this sample. MailRuleClient and DatabaseManager. The Mail Rule Client is a COM component. The Database Manager manages the database. The database stores the numbers we have to monitor, a flag which represents the actions (delete, reply message) we have to take and the Message to reply with. For the database part EDB is used instead of CEDB. For the Mail Rule Client component I took most of the code from the MailRule sample of the Windows Mobile 6 SDK. You can find sample code in the folder drive:\Program Files\Windows Mobile 6 SDK\Samples\Common\CPP\Win32\MapiRule

To monitor SMS messages there are two methods. First method is to use one of the State and Notification Broker functions like RegistryNotifyApp, RegistryNotifyWindow, etc… Upon receiving SMS message, the system will execute the application specified or send a message to specified window. If you are using RegistryNotifyApp API, our application will start with command line parameter /notify with the value name you specified in the third parameter of the API. We parse the command line and if /notify is found we read the new SMS message and reply to that.

A better approach is to use IMailRuleClient interface. This interface allows you to implement a mail rule that can process the incoming messages. There are two methods we have to implement. Initialize and ProcessMessage. A rule client is a regular COM component which is registered in the system. In addition to the registration we have to create an additional registry entry under

[HKEY_LOCAL_MACHINE\Software\Microsoft\Inbox\Svc\\Rules] = dword: 1 There is only one < TransportName> currently supported, “SMS”.

If we are our component is the first registered mail rule client, then default messaging application (tmail.exe) will launch our DLL and call the Initialize method of the IMailRuleClient. Whenever and SMS comes in, the ProcessMessage method will be called with appropriate parameters. The return value of this method determines whether system process the SMS normally.

The syntax of these methods is:

HRESULT Initialize(IMsgStore* pMsgStore, MRCACCESS* pmaDesired);
HRESULT ProcessMessage(IMsgStore* pMsgStore,ULONG cbMsg,LPENTRYID lpMsg, ULONG cbDestFolder, LPENTRYID lpDestFolder, ULONG* pulEventType, MRCHANDLED* pHandled);

The first parameter of the Initialize method is a pointer to the IMsgStore. This represents the message store of the incoming messages. The second parameter is pointer to the MRCACCESS enum which we have to fill with our desired access. Possible values can be

MRC_ACCESS_NONE
MRC_ACCESS_READ_ONLY
MRC_ACCESS_WRITE

The first parameter of the ProcessMessage method is a pointer to IMsgStore representing the message store. Second parameter is the length of the third parameter lpMsg which pointer to the ENTRYID structure which represents the message. The ENTRYID contains an identifier of an MAPI object. This is a unique identifier used by the message store and address book providers. The fourth parameter is the length of the fifth parameter which is again a pointer to the ENTRYID structure which represents the folder that contains the message. We have to fill the sixth parameter which is a ULONG pointer with appropriate bit flags. Possible flags are:

fnevObjectCreated
fnevObjectDeleted
fnevObjectModified
fnevObjectMoved
fnevObjectCopied

These flags are self explanatory and do not need any explanation. The seventh parameter is a pointer to the MRCHANDLED which we have to fill with appropriate values. Possible values are:

MRC_NOT_HANDLED
MRC_HANDLED_CONTINUE
MRC_HANDLED_DONTCONTINUE

Again these are self explanatory and explanation is not needed.

About the implementation part, when our ProcessMessage method is called first we take the IMessage pointer using the OpenEntry method of the IMsgStore that is passed in.

hr = pMsgStore->OpenEntry(cbMsg,lpMsg,NULL,0,NULL,(LPUNKNOWN *)&pMsg);

Then we take the subject and sender address of the message using the code:


SizedSPropTagArray(1, sptaSubject) = {1,PR_SUBJECT};
SizedSPropTagArray(1, sptaEmail) = {1,PR_SENDER_EMAIL_ADDRESS};

hr = pMsg->GetProps((SPropTagArray*)&sptaSubject,MAPI_UNICODE,&cValues,&pspvSubject);

if (FAILED(hr))
{
return hr;
}

hr = pMsg->GetProps((SPropTagArray *)&sptaEmail,MAPI_UNICODE,&cValues,&pspvEmail);

if (FAILED(hr))
{
return hr;
}

Then we open an EDB database and check whether the address is there in the database and if there we get the message to reply with. The database contains 3 fields

Number to monitor
Bit flags representing what action to be taken and
The message body used to reply.

The database part is handled by two classes: CSMSRespondDB and CSMSRespondRecord.

Both sample workspaces are compiled using Visual Studio 2008 using Windows Mobile 6 SDK.

The handling of EDB database deserves another article and I am working on that. I will update this blog when it is finished.

Hope this gives you a simple introduction to the Message Rule clients.

{ 2 comments }

Retrieving Call History on Windows Mobile

by Krishnaraj Varma on September 18, 2008

in Windows Mobile

Download the source code

To retrieve call history use the following API functions:

PhoneOpenCallLog
PhoneSeekCallLog
PhoneGetCallLogEntry
PhoneCloseCallLog

The following code fragment shows how to retrieve call history and add to a ListCtrl:

HANDLE hCallLog = NULL;
HRESULT hResult = PhoneOpenCallLog(&hCallLog);

if(E_FAIL == hResult)
{
return;
}

DWORD dwCount = 0;

hResult = PhoneSeekCallLog(hCallLog,CALLLOGSEEK_END,0,&dwCount);

PCALLLOGENTRY pLog = NULL;
SYSTEMTIME sTime = {0};
int nItem = 0;
int nImage = 0;
CString strLog;
CString strTime;

for(DWORD dwLog=0; dwLog<=dwCount; ++dwLog)
{
pLog = new CALLLOGENTRY;
pLog->cbSize = sizeof(CALLLOGENTRY);

PhoneGetCallLogEntry(hCallLog,pLog);
FileTimeToSystemTime(&pLog->ftStartTime,&sTime);

strLog.Format(TEXT("%s"),pLog->pszName ? pLog->pszName : pLog->pszNumber);
strTime.Format(TEXT("%d-%d-%d %d:%02d"),sTime.wDay,sTime.wMonth,sTime.wYear,sTime.wHour,sTime.wMinute);

if(pLog->iom == IOM_MISSED)
nImage = 2;
else if(pLog->iom == IOM_INCOMING)
nImage = 1;
else
nImage = 0;

nItem = pList->InsertItem(dwLog,strLog,nImage);
pList->SetItemText(nItem,1,strTime);

if(pLog->pszName)
LocalFree(pLog->pszName);
if(pLog->pszNumber)
LocalFree(pLog->pszNumber);
if(pLog->pszNote)
LocalFree(pLog->pszNote);

delete pLog;
}

PhoneCloseCallLog(hCallLog);

{ 0 comments }

Listing Loaded Devices in Windows CE 5 or Above

by Krishnaraj Varma on September 18, 2008

in General,Windows Mobile

Download the source code

The APIs FindFirstDevice and FindNextDevice can be used to search for a device currently loaded in Windows CE 5.0 or above. These APIs are not available in versions prior to Windows CE 5.0. The following are the syntax:

HANDLE FindFirstDevice(DeviceSearchType searchType,LPCVOID pvSearchParam,PDEVMGR_DEVICE_INFORMATION pdi);
BOOL FindNextDevice(HANDLE h,PDEVMGR_DEVICE_INFORMATION pdi);

If successful the FindFirstDevice returns a device handle which can be used for subsequent FineNextDevice. The first parameter is the device type which can be one of the following:

DeviceSearchByLegacyName
DeviceSearchByDeviceName
DeviceSearchByBusName
DeviceSearchByGuid
DeviceSearchByParent

The second parameter is the additional search parameter which depends of the device type specified. To search all devices we can use “*” as the search parameter. The third parameter is a pointer to DEVMGR_DEVICE_INFORMATION structure which will be filled with the details of the devices found.

The FindNextDevice returns TRUE if there are more devices to find otherwise returns FALSE. The first parameter is the HANDLE returned by the FindFirstDevice and second parameter is a pointer to the DEVMGR_DEVICE_INFORMATION structure.

The following code enumerate all devices and add the details to a ListCtrl.

HANDLE hDevice = NULL;
DeviceSearchType eSearchType = DeviceSearchByLegacyName;
DEVMGR_DEVICE_INFORMATION sInfo = {0};

sInfo.dwSize = sizeof(DEVMGR_DEVICE_INFORMATION);
hDevice = FindFirstDevice(eSearchType,TEXT("*"),&sInfo);

int nItem = 0;
int nListItem = 0;

if(INVALID_HANDLE_VALUE == hDevice)
return;

BOOL bContinue = TRUE;

while(bContinue)
{
nListItem = pList->InsertItem(nItem,sInfo.szLegacyName);

pList->SetItemText(nItem,1,sInfo.szDeviceName);
pList->SetItemText(nItem,2,sInfo.szDeviceKey);
pList->SetItemText(nItem,3,sInfo.szBusName);

++nItem;

bContinue = FindNextDevice(hDevice,&sInfo);
}

FindClose(hDevice);

{ 0 comments }

Listing Processor Features on Windows Mobile 5 or Above

by Krishnaraj Varma on September 17, 2008

in Windows Mobile

Download the source code

We can use IsProcessorFeaturePresent to retrieve processor features the syntax of the API is:

BOOL IsProcessorFeaturePresent(DWORD dwProcessorFeature);

The dwProcessorFeature is the feature we want to check whether it is supported or not. There are different #defines in Winnt.h header file. These #defines depends on the processor being compiled. If you are using compiling for ARM processor you will get all the #defines of ARM processor. I compiled it for ARM processor. The other #defines are copied from Winnt.h to Features.h header file.

{ 0 comments }

Remote Application Start in Windows CE

by Krishnaraj Varma on September 16, 2008

in General,Windows Mobile

Download the source code

CeStartProcess API can be used to start an application in Windows CE machine from a remote PC. To start an application first initialize RAPI using CeRapiInit or CeRapiInitEx and call this API with the name of the application. The sample application also uses CeGetSystemInfo and CeGetVersionEx APIs to get the system information and version.

{ 0 comments }

How to soft reset Windows Mobile programmatically

by Krishnaraj Varma on September 14, 2008

in Windows Mobile

We can use the API SetSystemPowerState to reset the Windows Mobile device. The following code resets the device.

#include
#include

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
if(IDYES == MessageBox(NULL,TEXT("Are you sure to reset the device?"),TEXT("Reset"),MB_YESNO | MB_ICONQUESTION))
{
SetSystemPowerState(NULL,POWER_STATE_RESET,0);
}
return (int)0;
}

We can use following values instead of POWER_STATE_RESET
POWER_STATE_ON
POWER_STATE_OFF
POWER_STATE_CRITICAL
POWER_STATE_BOOT
POWER_STATE_IDLE
POWER_STATE_SUSPEND
POWER_STATE_RESET

The last parameter can be 0, POWER_FORCE or POWER_DUMPDW. The POWER_FORCE parameter indicates the state change is urgent, and the POWER_DUMPDW will generate Dr. Watson report.

Please note that some of the power state may not work in all the platforms. Different platforms may restrict the use of some of the power states

{ 0 comments }

Getting Network Adapter Information in Windows Mobile

by Krishnaraj Varma on September 14, 2008

in Windows Mobile

Download the source code

The API GetAdaptersInfo or GetAdaptersAddresses can be used to get Network Adapter information. We can retrieve information like Adapter Name, Description, IP Address, Mask, DNS, etc… Here is a sample application that use GetAdapterInfo API to retrieve network information. The application screen looks like this:
Adapterinfo 225x300
The application retrieves this information and displays it in an owner draw list box.

{ 0 comments }

Remote Display For Windows Mobile 5 or above

by Krishnaraj Varma on September 14, 2008

in Windows Mobile

Download the source code

As I already posted here, ActiveSync IP address 169.254.2.1/169.254.2.2 can be used to create socket based application. Here is an application that makes use of this; this application displays the Windows Mobile desktop on a remote computer. You can also take the screen shots. The screen can be saved to JPEG or PNG files, these are the only supported picture formats now. But you can extent this by creating an output plug-in DLL.

There are two components in this application, Mobile Server which runs on the mobile device and Client Component which runs on the PC. The mobile server listens on port 8082 which is configurable. The client application connects to this server.

When connected to the mobile server, client application sends MS_CMD_SCREENSHOT command every 100 milliseconds and receives the screen data in compressed form. The client uncompresses the data and displays it on the screen. The mobile server application received commands from the client and based on the command it receives sends the data to the client. As of now the only command supported is MS_CMD_SCREENSHOT which sends the screen data. The command structure is defined as


typedef struct __MS_CMD_TAG__
{
int nCommand;
int nDataSize;
}MS_CMD

The nCommand member specifies the command and nDataSize member specifies the size of additional data in bytes. This member is reserved for future use and is not used now.

The screen data format is:


typedef struct __MS_SCREEN_DATA_TAG__
{
int nWidth;
int nHeight;
int nBPP;
int nLineWidth;
int nCompressedSize;
int nDataSize;
}MS_SCREEN_DATA

The nWidth, nHeight members are width and height of the screen data respectively. The nBPP member is the bits-per-pixel of the screen data. The nLineWidth member is the length of the scan line of the screen data. nCompressedSize represents the compressed data. nDataSize is the uncompressed size.

The compressed data is send after the sending the MS_SCREEN_DATA structure, so the total size of the data will be nCompressedData + sizeof(MS_SCREEN_DATA).

The client application uses Output Plug-in for saving the screen shots. There are two output plug-in now, JPEG plug-in and PNG plug-in. You can extend this by creating Output Plug-in. The plug-in exports only one function GetPluginInterface which returns a pointer to IOutputPlugin which is defined as:


class COutputPlugin
{
public:
virtual LPCTSTR GetFileName() = 0;
virtual LPCTSTR GetPluginName() = 0;
virtual LPCTSTR GetDescription() = 0;
virtual long GetVersion() = 0;
virtual LPCTSTR GetFilterString() = 0;
virtual LPCTSTR GetExtension() = 0;

virtual int SaveImage(const char* lpszFile,BITMAPINFO* pInfo,BYTE* pBytes) = 0;
virtual void Release() = 0;
};

typedef COutputPlugin IOutputPlugin;

The class is simply and self-explanatory.

The application works well on my HTC TyTN II mobile and is not tested on any other mobile. Also this application will not work with the Emulator.

{ 0 comments }

Very Simple Notepad for Windows Mobile

by Krishnaraj Varma on September 12, 2008

in Windows Mobile

Download the source and setup cab

This is a very simple notepad application for Windows Mobile 5 or above. There are some commercial and free notepad application available which are far more feature rich. But they don’t come with source code. This one comes with full source code.

There is only one point of interest in this application, Font Dialog. Windows Mobile doesn’t have any default font dialog. But we can use EnumFontFamiliesEx to enumerate fonts. The font dialog in this application use the above API to enumerate the installed fonts.

{ 0 comments }

Disclaimer: This is a personal weblog. The information in this weblog is provided “AS IS” with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion.