Custom Points for Windows Mobile

In addition to the standard data collection points in Mobile Data Studio which can be used in projects deployed to Windows Mobile devices, the custom point property enables special points developed outside of Mobile Data Studio to be deployed for Windows Mobile. Custom points are not available for Android or Apple iOS.

Mobile Data Studio custom points are COM objects not unlike ActiveX controls, but somewhat simpler in design. They also have the unique requirement of needing to be able to operate on both the Windows Mobile device and the Windows desktop PC or server.

In order to create a custom point, code must be compiled using a language capable of creating COM objects. Mobile Data Studio custom points are written in C++, which can be compiled for both the Windows Mobile and Windows PC architectures. Visual Basic (VB) can create COM objects on the PC, but unfortunately Embedded VB can only create interpreted .VB files, which prevents it from being used for these purposes.

Please download SliderCustomPoint.zip, a package which contains a fully compilable 'Slider' project. It includes project files for Windows PC and Windows Mobile builds (Visual C++ and eMbedded Visual C++), plus the PPCCOM.h object model file. Examine the code to understand the custom point development process.

Custom points need to implement only one or two interfaces. All custom points should implement the ICustomPoint interface, which allows the point to provide standard PPCC functionality (setting properties, display on page, storage of information, etc). Additionally, most custom points implement the IPersistPropertyBag interface, which allows the custom point to store any properties it might have in the project file above and beyond the normal Mobile Data Studio properties such as Caption, ID Name, etc.

In return, Mobile Data Studio provides a reference to an ICustomPointSite interface via the ICustomPoint::SetSite() method. The ICustomPointSite interface is the access point which allows the custom point to interact with the project. At the most basic level it provides a simple means for querying the stock properties of the point, setting and querying the current value, and default handlers for most custom point functions. It can also be used to obtain a reference to the rest of the Mobile Data Studio object model through GetApplication(), GetProject(), GetPage(), GetPoint().

Default implementations for many of the methods in ICustomPoint are provided in ICustomPointSite, for example ICustomPoint::Paint() can be reflected back to ICustomPointSite::DefaultPaint(). Through this mechanism you only need to provide full implementations for the methods where the custom point provides extra functionality. Everything else can be reflected back to Mobile Data Studio to provide default actions (in this case, the default paint action simply draws the caption).

Unlike ActiveX controls, Mobile Data Studio custom points are windowless by default, so all events are passed to your implementation of ICustomPoint. ICustomPoint::GetHeight() and ICustomPoint::Paint() are the core methods used to allow the custom point to paint itself. ICustomPoint::OnTap() is called to handle stylus taps landing on the custom point. If anything more sophisticated is required, it is possible to create a windowed custom point by creating a child window on ICustomPoint::Show(), and destroying it in ICustomPoint::Hide(). The parent window handle can be retrieved from the ICustomPointSite via GetHWND().

Finally, the custom points Mobile Data Studio lists in its "Add New Point" dialog are enumerated by searching for COM objects which implement the Mobile Data Studio custom point category. The GUID for this category is {EDF7BC-0AD0-42C8-8CB4-287A-D828EE12}. Mobile Data Studio will also automatically register all DLLs it finds in its home folder upon start up, both on the Windows PC and the Windows Mobile Device. This allows custom point DLLs to be automatically registered without requiring an explicit installation step (provided they are self registering).

Note: we are always pleased to learn of Mobile Data Studio custom points developed by others, so please contact CreativityCorp to advise of your creativity. There may also be a market for your custom point amongst Windows Mobile users.

Custom Points and COM Ports

Custom points are often required to access COM ports, for example with the GPS custom point to connect to GPS hardware. COM ports are treated as special files, and are opened using regular Windows file APIs, e.g.:

// Open COM1
HANDLE hPort = CreateFile( _T("COM1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL );
// Close it again
CloseHandle( hPort );

Unlike files however, once opened, the COM port must be configured to set the desired baud rate, etc:

// Get the current port configuration
DCB pDCB;
pDCB.DCBlength = sizeof(DCB);
GetCommState( hPort, &pDCB );
// Update the configuration as desired
pDCB.BaudRate = 9600;
pDCB.fBinary = TRUE;
pDCB.fParity = FALSE;
pDCB.fOutxCtsFlow = FALSE;
pDCB.fOutxDsrFlow = FALSE;
pDCB.fDtrControl = DTR_CONTROL_ENABLE;
pDCB.fDsrSensitivity = FALSE;
pDCB.fTXContinueOnXoff = TRUE;
pDCB.fOutX = FALSE;
pDCB.fInX = FALSE;
pDCB.fErrorChar = FALSE;
pDCB.fNull = FALSE;
pDCB.fRtsControl = RTS_CONTROL_ENABLE;
pDCB.fAbortOnError = FALSE;
pDCB.ByteSize = 8;
pDCB.Parity = NOPARITY;
pDCB.StopBits = ONESTOPBIT;
// Set the new port configuration
SetCommState( hPort, &pDCB );

Default timeouts can be set using:

GetCommTimeouts() and SetCommTimeouts()

Once the port has been opened and configured, read from and write to it like a normal file. Reading and writing are blocking -- i.e. attempt to read 5 bytes, the read will block until 5 bytes have been received. Similarly, with an attempt to write 5 bytes, the write will block until the 5 bytes have been transmitted.

// Read 5 bytes into the szInput array
char szInput[5];
DWORD nRead = 0;
ReadFile( hPort, szInput, 5, &nRead, NULL );
// nRead now holds the number of bytes that were read (should be 5 here)
// Write 5 bytes from the szOutput array
char szOutput[5];
DWORD nWrote = 0;
WriteFile( hPort, szOutput, 5, &nWrote, NULL );
// nWrote now holds the number of bytes that were written (should be 5 here)