Customizing Dialog Boxes and Message Boxes for Headless Systems 2/2


In the previous post we left the following question open: what if you want to link coredll to your own library with customized message and dialog boxes instead of the ‘standard’ messagedialogboxcustomize? Here’s the answer (or at least one of the possible ones):

  1. Create an empty subproject in your OS design using the ‘WCE static library’ template: we’ll call the project ‘mymessageboxcustomize’
  2. Modify the sources file changing RELEASETYPE to OAK
  3. Copy the _WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\MESSAGEDIALOGBOXCUSTOMIZE\messagedialogboxcustomize.cpp file to the subproject folder and add it to the subproject itself
  4. Build it and verify that you get mymessageboxcustomize.lib in $(_PROJECTROOT)\oak\lib
  5. Modify the %_PROJECTROOT%\oak\misc\cesysgen.bat file so it looks like
@echo off
call %_PUBLICROOT%\cebase\oak\misc\cesysgen.bat %*
REM Add our custom message box implementation
if not "%COREDLL_REPLACE_COMPONENTS%" == "" set COREDLL_REPLACE_COMPONENTS=mymessageboxcustomize %COREDLL_REPLACE_COMPONENTS%
if "%COREDLL_REPLACE_COMPONENTS%" == "" set COREDLL_REPLACE_COMPONENTS=mymessageboxcustomize
REM Remove "messagedialogboxthunk" from %COREDLL_COMPONENTS%
for %%f in (%COREDLL_COMPONENTS%) do call :RemoveMessagedialogboxthunk %%f
set COREDLL_COMPONENTS=%TEMP_COREDLL_COMPONENTS%
goto :EOF
:RemoveMessagedialogboxthunk
if /i "%1"=="messagedialogboxthunk" goto :EOF
if not "%TEMP_COREDLL_COMPONENTS%" == "" set TEMP_COREDLL_COMPONENTS=%1 %TEMP_COREDLL_COMPONENTS%
if "%TEMP_COREDLL_COMPONENTS%" == "" set TEMP_COREDLL_COMPONENTS=%1
goto :EOF

The second part of the file is the same as the previous post: it removes the standard messagedialogboxthunk library to avoid multiple definitions for MessageBox/DialogBoxIndirectParam/CreateDialogIndirectParam.

The first part takes advantage of the COREDLL_REPLACE_COMPONENTS environment variable which is handled in %_WINCEROOT%\PUBLIC\COMMON\CESYSGEN\makefile.

Now, ‘all’ you have to do is filling the stubs in messagedialogboxcustomize.cpp with your desired implementation of MessageBox/DialogBoxIndirectParam/CreateDialogIndirectParam.

Posted in Senza categoria | Leave a comment

Customizing Dialog Boxes and Message Boxes for Headless Systems 1/2


The MSDN documentation explains how to customize dialog boxes and message boxes for headless systems here http://msdn.microsoft.com/en-us/library/ee504353(v=winembedded.60).aspx.

What they say there is that you can instruct the build system to create the coredll DLL linking to the messagedialogboxcustomize component library rather than to the messagedialogboxthunk one:

  • messagedialogboxthunk is what you get if you include some kind of GWES support in your OS and it is a small layer which will forward the call to the actual implementation of MessageBox/DialogBoxIndirectParam/CreateDialogIndirectParam in GWES. 
  • messagedialogboxcustomize is built from the code in %_WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\MESSAGEDIALOGBOXCUSTOMIZE. As you see the MessageBox/DialogBoxIndirectParam/CreateDialogIndirectParam functions are basically stubs.

Following the above link, the first thing I did is modifying  %_PROJECTROOT%\oak\misc\cesysgen.bat so it looks like:

@echo off
call %_PUBLICROOT%\cebase\oak\misc\cesysgen.bat %*
set COREDLL_MESSAGEDIALOGBOXCUSTOMIZE_COMPONENT=messagedialogboxcustomize
goto :EOF

When you sysgen coredll you’ll see some warnings complaining about the fact that MessageBox/DialogBoxIndirectParam/CreateDialogIndirectParam are defined in both messagedialogboxthunk and messagedialogboxcustomize:

messagedialogboxthunk.lib(messagedialogboxthunk.obj) : warning LNK4006: MessageBoxW already defined in messagedialogboxcustomize.lib(messagedialogboxcustomize.obj); second definition ignored
messagedialogboxthunk.lib(messagedialogboxthunk.obj) : warning LNK4006: DialogBoxIndirectParamW already defined in messagedialogboxcustomize.lib(messagedialogboxcustomize.obj); second definition ignored
messagedialogboxthunk.lib(messagedialogboxthunk.obj) : warning LNK4006: CreateDialogIndirectParamW already defined in messagedialogboxcustomize.lib(messagedialogboxcustomize.obj); second definition ignored
messagedialogboxthunk.lib(messagedialogboxthunk.obj) : warning LNK4221: no public symbols found; archive member will be inaccessible

(Notice that we’re lucky enough that the we’re ignoring the definition we *want* to ignore)

Reading better the link I noticed the “Ensure that the Messagedialogboxthunk component is removed from the COREDLL_COMPONENTS environment variable” part. Of course we won’t modify the build .bat files so we do it in our %_PROJECTROOT%\oak\misc\cesysgen.bat which finally looks like:

@echo off
call %_PUBLICROOT%\cebase\oak\misc\cesysgen.bat %*
set COREDLL_MESSAGEDIALOGBOXCUSTOMIZE_COMPONENT=messagedialogboxcustomize
REM Remove "messagedialogboxthunk" from %COREDLL_COMPONENTS%
for %%f in (%COREDLL_COMPONENTS%) do call :RemoveMessagedialogboxthunk %%f
set COREDLL_COMPONENTS=%TEMP_COREDLL_COMPONENTS%
goto :EOF
:RemoveMessagedialogboxthunk
if /i "%1"=="messagedialogboxthunk" goto :EOF
if not "%TEMP_COREDLL_COMPONENTS%" == "" set TEMP_COREDLL_COMPONENTS=%1 %TEMP_COREDLL_COMPONENTS%
if "%TEMP_COREDLL_COMPONENTS%" == "" set TEMP_COREDLL_COMPONENTS=%1
goto :EOF

Notice that if you create an OS based on the small footprint device template you already have messagedialogboxcustomize in place: since no GWES support is included you’re running the following lines in %_WINCEROOT%\PUBLIC\CEBASE\OAK\MISC\winceos.bat

   if "%GWES_COMPONENTS%"=="" set __SYSGEN_MSGDLGBOXCUSTOMIZE=1
    if "%__SYSGEN_MSGDLGBOXCUSTOMIZE%"=="1" set COREDLL_MESSAGEDIALOGBOXCUSTOMIZE_COMPONENT=messagedialogboxcustomize

If you like how messagedialogboxcustomize works, you’re done, but what if you want to link coredll to your own customized messagedialogboxcustomizedbyme code without modifying %_WINCEROOT%\PUBLIC\COMMON\OAK\DRIVERS\MESSAGEDIALOGBOXCUSTOMIZE?

To be continued…

Posted in Windows Embedded CE | Leave a comment

Windows Embedded Compact 7 Documentation


In a previous post I point out that  once you install Platform Builder, in %ProgramFiles%\Windows Embedded Compact 7\Documentation you have several PDF docs about miscellaneous development topics. If you want more (or the updated version) you can check the Windows Embedded Compact 7 White Papers page. On the same site you can find even virtual labs and videos. Enjoy!

Posted in Windows Embedded Compact | Leave a comment

Checked build: the history


In a previous post I wrote about the differencies of retail, checked and debug build. You can take a look at this post by Larry Osterman for some historical background. Since you’re there you may enjoy other posts about Windows hystory and development. I really enjoyed the ‘XY years ago today’ serie Larry wrote to cheers his 25th year at MSFT.

Posted in Windows Embedded - General | Tagged , | Leave a comment

Windows Embedded Compact 7 Documentation


I do not know if everyone is aware of this, so maybe it’s worth a note. Once you install Platform Builder, in %ProgramFiles%\Windows Embedded Compact 7\Documentation you get more than 30 PDF docs about miscellaneous topics like:

  • Build system
  • Silverlight for Windows Embedded
  • BSP bring up and porting from previous Windows CE version

If you have the opportunity to take a look you’ll surely find something interesting. Enjoy!

Posted in Windows Embedded Compact | Tagged | 1 Comment

Accelerometer API


WEC7 defines a driver model and an API set for 3-axis accelerometers devices which can
be used for various purposes: orientation change, dead reckoning, image stabilization, etc.

The device driver follows the well known MDD/PDD stream interface model: the MDD code is %_WINCEROOT%\public\COMMON\oak\drivers\accelerometer\mdd while
the PDD code is typically HW/BSP dependent(see for example %_WINCEROOT%\platform\IMX313DS\SRC\DRIVERS\ACCELEROMETER).

MSFT provides fake PDD which you can use to experience with the device and its API set: %_WINCEROOT%\public\COMMON\oak\drivers\accelerometer\pdds\mock:
for example you can use the code to emulate the accelerometer in VirtualPC including the DLL in the OS design.

There’s no rule in the makefiles to build the fake accelerometer DLL so need to build it explicitly from the command line or in VS2008;
maybe you’d like to create a DLL subproject in your OS design and include the code (Notice that if you’re building a debug version of
the DLL you need to uncomment the declaration of the dpCurSettings structure to avoid compilation errors).

To include the driver and have it loaded you need to add the relevant entries in .bib and .reg files:

MODULES
fakeaccpdd.dll      $(_FLATRELEASEDIR)\fakeaccpdd.dll     NK  SHK

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\ACC]
“Prefix”=”ACC”
“Dll”=”fakeaccpdd.dll”
“Index”=dword:1
“Order”=dword:12
; PMCLASS_GENERIC_DEVICE, Power-manageable sensor, SENSOR_TYPE_ACCELEROMETER_3D
“IClass”=multi_sz:”{A32942B7-920C-486b-B0E6-92A702A99B35}”,
“{3267CC03-F391-4fb1-BADD-36FBB8815E86}”,
“{C2FB0F5F-E2D2-4C78-BCD0-352A9582819D}”

Accelerometer API are basically a wrapper of the accelerometer device driver IOCTL’s; in addition some functions
create a thread used to communicate between the driver and your application. This API is exported by coredll provided that
you include the ‘Accelerometer Driver’ catalog item.

The following sample code demonstrate the use of the accelerometer API:

// NOTE: no error checking, do not use this code in production environment
//
#include <windows.h>
#include <accapi.h>
#include <winioctl.h> //for CTL_CODE 
#include <acc_ioctl.h> //for FILE_DEVICE_ACCELEROMETER (which is not #define'd in winioctl.h)
//From %_WINCEROOT%\public\COMMON\oak\drivers\accelerometer\pdds\mock\accelerometer.h
#define IOCTL_ACC_SEND_SAMPLE    \
    CTL_CODE(FILE_DEVICE_ACCELEROMETER, 0x4000, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_ACC_SIMULATE_ROTATE \
        CTL_CODE(FILE_DEVICE_ACCELEROMETER, 0x4001, METHOD_BUFFERED, FILE_ANY_ACCESS) 
#define ACC_NAME _T("ACC1:")
#define MAX_QUEUE_MESSAGES 10 //arbitrary value
#define RESERVED_PARM NULL
//Check the following files for details about the various struct's and enum's
//%_WINCEROOT%\public\common\oak\inc\sensor.h
//%_WINCEROOT%\public\common\oak\inc\accapi.h
//%_WINCEROOT%\public\COMMON\oak\inc\acc_ioctl.h
DWORD AccCallback(ACC_DATA* pAccData, __in_opt LPVOID plvCallbackParam);
DWORD AccMsgCallback(SENSOR_MESSAGE_TYPE msgType, LPVOID pAccData, DWORD cbSizeAccData, __in_opt LPVOID plvCallbackParam);
int _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
    LUID AccLuid;
    HSENSOR hSensor;
    MSGQUEUEOPTIONS MsgQueueopt;
 HANDLE hMsgQueue;
    ACC_DATA AccData;
    DWORD dwBytes, dwFlags, i;
    //Retrieve a handle which will be used in the other API calls
    hSensor = AccelerometerOpen(ACC_NAME, &AccLuid);
 
 /*
 Set accelerometer mode.
 Possible modes, according to the docs, are:
 ACC_CONFIG_STREAMING_DATA_MODE
 Default. Streaming data mode. The accelerometer data sample is acquired from accelerometer hardware and is constantly sent back to upper subscribers at a fixed frequency.
 ACC_CONFIG_ORIENTATION_MODE
 Orientation sensing mode. The accelerometer driver only signals the subscriber when an orientation change is detected.
 ACC_CONFIG_COMPASS_MODE
 Compass simulation mode. The accelerometer driver signals the subscriber when a small angle change is detected. This mode is designed for digital compass applications.
 ACC_CONFIG_CALIBRATION_MODE
 Device calibration mode. This mode is used for calibrating the accelerometer hardware.
 */
    AccelerometerSetMode(hSensor, ACC_CONFIG_STREAMING_DATA_MODE, RESERVED_PARM);
 /*
 This IOCTL is defined only for the fake PDD: calling it will result in a serie of sample which
 emulate a rotation on the z axis. If you do not call this IOCTL the driver will return always
    x = 0.7, y = 0.7, z = 0 (notice the '7'...). There's another custom IOCTL
 IOCTL_ACC_SEND_SAMPLE which allows you to inject specific values to the driver which will returned
 back as actual samples
 */
 DeviceIoControl(hSensor, IOCTL_ACC_SIMULATE_ROTATE, NULL, 0, NULL, 0, &dwBytes, NULL);
 //Method #1: 'manually' pass a message queue handle to the accelerometer driver and read
 //the samples from the queue
    MsgQueueopt.dwSize = sizeof(MSGQUEUEOPTIONS);
    MsgQueueopt.dwFlags = MSGQUEUE_ALLOW_BROKEN ;
    MsgQueueopt.dwMaxMessages = MAX_QUEUE_MESSAGES; 
    MsgQueueopt.cbMaxMessage = sizeof(ACC_DATA);
    MsgQueueopt.bReadAccess = TRUE;
    
    hMsgQueue = CreateMsgQueue(NULL, &MsgQueueopt);
 AccelerometerStart(hSensor, hMsgQueue);
    
    for(i=0; i<MAX_QUEUE_MESSAGES; i++)
    {
      WaitForSingleObject(hMsgQueue, INFINITE);
      
      ReadMsgQueue(hMsgQueue, &AccData, sizeof(ACC_DATA), &dwBytes, 0, &dwFlags);
   RETAILMSG(1, (_T("Accelerometer data received\r\n")));
    }
    AccelerometerStop(hSensor);
    
    CloseMsgQueue(hMsgQueue);
 //Method #2: Pass to the accelerometer driver a callback which will be called when new samples
 //are available
 AccelerometerCreateCallback(hSensor, AccCallback, NULL);
 /*Wait a bit so you can see the callback call*/
 Sleep(50);
 //According the docs, AccelerometerCreateCallback calls AccelerometerStart
 //Although it's not stated in the docs, AccelerometerCancelCallback simmetrically
 //calls AccelerometerStop
 //Note: in AccelerometerStop -called by AccelerometerCancelCallback- the message queue used
 //by the driver to sent samples and messages to the subscribers is closed: sometimes you may see 
 //'ERROR: DecodeAPI - invalid handle' due to a reader calling ReadMsgQueue on the queue which
 //has already been closed
 AccelerometerCancelCallback(hSensor);
 //Method #3:  Pass to the accelerometer driver a callback which will be called when new data
 //are available: data can be samples, orientation change, etc.
 AccelerometerCreateMsgCallback(hSensor, AccMsgCallback, NULL);
 /*Wait a bit so you can see the callback call*/
 Sleep(50);
 AccelerometerCancelCallback(hSensor);
    CloseHandle((HANDLE)hSensor);
    return 0;
}
DWORD AccCallback(ACC_DATA* pAccData, __in_opt LPVOID plvCallbackParam)
{
 RETAILMSG(1, (_T("AccCallback Callback\r\n")));
 return 0;
}
DWORD AccMsgCallback(SENSOR_MESSAGE_TYPE msgType, LPVOID pAccData, DWORD cbSizeAccData, __in_opt LPVOID plvCallbackParam)
{
 RETAILMSG(1, (_T("AccMsgCallback Callback\r\n")));
 return 0;
}

The output of a debug build will be something like:

10541593 PID:400002 TID:1bbcb2a +ACC_Open
10541599 PID:400002 TID:1bbcb2a +AccDeviceContext::AddSubscriber
10541599 PID:400002 TID:1bbcb2a -AccDeviceContext::AddSubscriber
10541599 PID:400002 TID:1bbcb2a -ACC_Open
10541600 PID:400002 TID:1bbcb2a +ACC_IOControl
10541600 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541600 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541600 PID:400002 TID:1bbcb2a -ACC_IOControl
10541600 PID:400002 TID:1bbcb2a +ACC_IOControl
10541601 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541601 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541601 PID:400002 TID:1bbcb2a -ACC_IOControl
10541601 PID:400002 TID:1bbcb2a +ACC_IOControl
10541601 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541601 PID:400002 TID:1bbcb2a +AccDeviceContext::Ioctl
10541601 PID:400002 TID:1bbcb2a fakeaccpdd PddIoctl: got IOCTL_ACC_SIM_ROTATE
10541601 PID:400002 TID:1bbcb2a -AccDeviceContext::Ioctl
10541601 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541602 PID:400002 TID:1bbcb2a -ACC_IOControl
10541602 PID:400002 TID:1bbcb2a +ACC_IOControl
10541603 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541604 PID:400002 TID:1bbcb2a +AccSubscriber::StartSensor
10541604 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541604 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541604 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541607 PID:400002 TID:141003e +AccMddProcessSample
10541607 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541608 PID:400002 TID:141003e AccSample: x=0.500000, y=0.500000, z=0.000000
10541608 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541608 PID:400002 TID:1bbcb2a -AccSubscriber::StartSensor
10541608 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541608 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541609 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541609 PID:400002 TID:141003e -AccMddProcessSample
10541609 PID:400002 TID:141003e ACC Polling thread sleeping 11ms
10541609 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541609 PID:400002 TID:1bbcb2a -ACC_IOControl
10541609 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541630 PID:400002 TID:141003e +AccMddProcessSample
10541630 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541630 PID:400002 TID:141003e AccSample: x=1.000000, y=0.000000, z=0.000000
10541630 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541631 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541631 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541631 PID:400002 TID:141003e -AccMddProcessSample
10541632 PID:400002 TID:141003e ACC Polling thread sleeping 8ms
10541632 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541653 PID:400002 TID:141003e +AccMddProcessSample
10541653 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541654 PID:400002 TID:141003e AccSample: x=0.500000, y=-0.500000, z=0.000000
10541654 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541655 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541655 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541655 PID:400002 TID:141003e -AccMddProcessSample
10541655 PID:400002 TID:141003e ACC Polling thread sleeping 5ms
10541655 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541676 PID:400002 TID:141003e +AccMddProcessSample
10541676 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541676 PID:400002 TID:141003e AccSample: x=0.000000, y=-1.000000, z=0.000000
10541677 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541677 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541678 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541678 PID:400002 TID:141003e -AccMddProcessSample
10541678 PID:400002 TID:141003e ACC Polling thread sleeping 2ms
10541679 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541701 PID:400002 TID:141003e +AccMddProcessSample
10541701 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541702 PID:400002 TID:141003e AccSample: x=-0.500000, y=-0.500000, z=0.000000
10541702 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541702 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541702 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541703 PID:400002 TID:141003e -AccMddProcessSample
10541703 PID:400002 TID:141003e ACC Polling thread sleeping 17ms
10541704 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541725 PID:400002 TID:141003e +AccMddProcessSample
10541725 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541725 PID:400002 TID:141003e AccSample: x=-1.000000, y=0.000000, z=0.000000
10541728 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541728 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541728 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541728 PID:400002 TID:141003e -AccMddProcessSample
10541728 PID:400002 TID:141003e ACC Polling thread sleeping 12ms
10541729 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541750 PID:400002 TID:141003e +AccMddProcessSample
10541750 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541751 PID:400002 TID:141003e AccSample: x=-0.500000, y=0.500000, z=0.000000
10541751 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541752 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541752 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541753 PID:400002 TID:141003e -AccMddProcessSample
10541753 PID:400002 TID:141003e ACC Polling thread sleeping 7ms
10541755 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541776 PID:400002 TID:141003e +AccMddProcessSample
10541776 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541776 PID:400002 TID:141003e AccSample: x=0.000000, y=1.000000, z=0.000000
10541776 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541777 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541777 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541777 PID:400002 TID:141003e -AccMddProcessSample
10541778 PID:400002 TID:141003e ACC Polling thread sleeping 2ms
10541778 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541802 PID:400002 TID:141003e +AccMddProcessSample
10541802 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541803 PID:400002 TID:141003e AccSample: x=0.000000, y=0.000000, z=0.000000
10541803 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541804 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541804 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541804 PID:400002 TID:141003e -AccMddProcessSample
10541804 PID:400002 TID:141003e ACC Polling thread sleeping 16ms
10541805 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541826 PID:400002 TID:141003e +AccMddProcessSample
10541826 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541826 PID:400002 TID:141003e AccSample: x=0.000000, y=1.000000, z=0.000000
10541826 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541827 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541827 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541828 PID:400002 TID:141003e -AccMddProcessSample
10541828 PID:400002 TID:141003e ACC Polling thread sleeping 12ms
10541829 PID:1bac872 TID:1bbcb2a Accelerometer data received
10541829 PID:400002 TID:1bbcb2a +ACC_IOControl
10541830 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541830 PID:400002 TID:1bbcb2a +AccSubscriber::StopSensor
10541831 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541831 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541831 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541832 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541832 PID:400002 TID:1bbcb2a -AccSubscriber::StopSensor
10541833 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541833 PID:400002 TID:1bbcb2a -ACC_IOControl
10541834 PID:400002 TID:1bbcb2a +ACC_IOControl
10541834 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541835 PID:400002 TID:1bbcb2a +AccSubscriber::StartSensor
10541835 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541835 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541836 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541836 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541837 PID:400002 TID:1bbcb2a -AccSubscriber::StartSensor
10541837 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541837 PID:400002 TID:1bbcb2a -ACC_IOControl
10541855 PID:400002 TID:141003e +AccMddProcessSample
10541855 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541855 PID:400002 TID:141003e AccSample: x=0.500000, y=0.500000, z=0.000000
10541856 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541856 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541856 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541857 PID:400002 TID:141003e -AccMddProcessSample
10541857 PID:400002 TID:141003e ACC Polling thread sleeping 3ms
10541857 PID:1bac872 TID:10cd82a AccCallback Callback
10541878 PID:400002 TID:141003e +AccMddProcessSample
10541878 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541879 PID:400002 TID:141003e AccSample: x=1.000000, y=0.000000, z=0.000000
10541879 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541879 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541879 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541879 PID:400002 TID:141003e -AccMddProcessSample
10541879 PID:400002 TID:141003e ACC Polling thread sleeping 1ms
10541880 PID:1bac872 TID:10cd82a AccCallback Callback
10541888 PID:400002 TID:1bbcb2a +ACC_IOControl
10541889 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541891 PID:400002 TID:1bbcb2a +AccSubscriber::StopSensor
10541891 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541892 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541892 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541893 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541893 PID:400002 TID:1bbcb2a -AccSubscriber::StopSensor
10541893 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541894 PID:400002 TID:1bbcb2a -ACC_IOControl
10541897 PID:400002 TID:1bbcb2a +ACC_IOControl
10541897 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541897 PID:400002 TID:1bbcb2a +AccSubscriber::StartSensor
10541897 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541897 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541897 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541898 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541898 PID:400002 TID:1bbcb2a -AccSubscriber::StartSensor
10541898 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541898 PID:400002 TID:1bbcb2a -ACC_IOControl
10541905 PID:400002 TID:141003e +AccMddProcessSample
10541905 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541906 PID:400002 TID:141003e AccSample: x=0.500000, y=-0.500000, z=0.000000
10541906 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541907 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541907 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541907 PID:400002 TID:141003e -AccMddProcessSample
10541907 PID:400002 TID:141003e ACC Polling thread sleeping 13ms
10541908 PID:1bac872 TID:108d59e AccMsgCallback Callback
10541929 PID:400002 TID:141003e +AccMddProcessSample
10541929 PID:400002 TID:141003e +AccDeviceContext::ProcessSample
10541929 PID:400002 TID:141003e AccSample: x=0.000000, y=-1.000000, z=0.000000
10541930 PID:400002 TID:141003e +AccSubscriber::NotifySample
10541930 PID:400002 TID:141003e -AccSubscriber::NotifySample
10541930 PID:400002 TID:141003e -AccDeviceContext::ProcessSample
10541930 PID:400002 TID:141003e -AccMddProcessSample
10541930 PID:400002 TID:141003e ACC Polling thread sleeping 10ms
10541930 PID:1bac872 TID:10cd82a AccMsgCallback Callback
10541957 PID:400002 TID:1bbcb2a +ACC_IOControl
10541957 PID:400002 TID:1bbcb2a +AccSubscriber::Ioctl
10541957 PID:400002 TID:1bbcb2a +AccSubscriber::StopSensor
10541957 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541958 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541958 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541959 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541959 PID:400002 TID:1bbcb2a -AccSubscriber::StopSensor
10541960 PID:400002 TID:1bbcb2a -AccSubscriber::Ioctl
10541960 PID:400002 TID:1bbcb2a -ACC_IOControl
10541961 PID:400002 TID:1bbcb2a +ACC_Close
10541961 PID:400002 TID:1bbcb2a +AccDeviceContext::RemoveSubscriber
10541962 PID:400002 TID:1bbcb2a -AccDeviceContext::RemoveSubscriber
10541962 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatedSubscriber
10541962 PID:400002 TID:1bbcb2a +AccDeviceContext::UpdatePddMode
10541962 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatePddInterval
10541963 PID:400002 TID:1bbcb2a -AccDeviceContext::UpdatedSubscriber
10541963 PID:400002 TID:1bbcb2a -ACC_Close
Posted in Windows Embedded Compact | Tagged , | Leave a comment

Implementing a secure socket


A recent post about SSL and Windows sockets in Windows Embedded Compact Platform Development forum reminded me that when I needed to use SSL in a Windows CE application it was very difficult to find information and sample code. On MSDN you can find basically only a page which summarize what you have to do. In this post you can see working code for estabilish a secure connection validating a certificate provided by the server. The sample assumes the certificate is installed on the device by the user using control panel rather than by the application itself (see the enrollment sample in %_WINCEROOT%\PUBLIC\COMMON\SDK\SAMPLES\ENROLL). The sample assumes several things and can undoubtly be improved: for example it does not use SO_SSL_GET_PROTOCOLS control code to determine the default protocols. 

Basically you have two functions: one ‘initializes’ SSL,  the other is the certificate validation callback which determines if the connection will be completed. Once you init the SSL related stuff and you call the connect function the callback will be invoked. If the function returns SSL_ERR_OKAY you can use send/recv functions which will automatically encode and decode data. The sample callback will return SSL_ERR_OKAY according to the options you specify in the SSL_Init:

  • do not check the server certificate at all and always return SSL_ERR_OKAY
  • succeds if in the certificate store a certificate from the same issuer as the server one can be found
  • succeds if in the certificate store the exact certificate from the server can be found
 
#include <windows.h>
#include <winsock2.h>
#include <sslsock.h>
#include <schnlsp.h>

#define SSL_OPT_NO_CHECK  0
#define SSL_OPT_ISSUER_CHECK 1
#define SSL_OPT_STRICT_CHECK 2

#define SSL_OPT_DEFAULT   SSL_OPT_STRICT_CHECK

#define DBG_ON 0

static int g_SslOptions = SSL_OPT_DEFAULT;

int
CALLBACK
SSLValidateCertHook(
   DWORD  dwType,          // in
   LPVOID pvArg,           // in
   DWORD  dwChainLen,      // in
   LPBLOB pCertChain,      // in
   DWORD dwFlags)         // in
{
 HCERTSTORE hCertStore = NULL;
 PCCERT_CONTEXT pCertInStore = NULL, pCertPassed = NULL, pPrevCertContext = NULL;
 const LPCTSTR SystemStore[] = {_T("CA"), _T("ROOT"), _T("MY")};
 unsigned int i;

 RETAILMSG(DBG_ON,(_T("+SSLValidateCertHook")));

 //The only thing we can handle
 if(dwType != SSL_CERT_X509)
  return SSL_ERR_CERT_UNKNOWN;

 //Do not check the certificate at all
 if(g_SslOptions == SSL_OPT_NO_CHECK)
  return SSL_ERR_OKAY;

 //Get a context struct from the certificate blob
 pCertPassed = CertCreateCertificateContext(X509_ASN_ENCODING,pCertChain->pBlobData,pCertChain->cbSize);

 if(!pCertPassed)
  return SSL_ERR_FAILED;

 //Check for a matching certificate in the stores
 for (i=0; i<(sizeof(SystemStore)/sizeof(SystemStore[0])); i++)
 {
  //open the store
  hCertStore = CertOpenSystemStore((HCRYPTPROV)NULL,SystemStore[i]);

  if(!hCertStore)
   continue;

  RETAILMSG(DBG_ON,(_T("Opened %s"), SystemStore[i]));

  pPrevCertContext = NULL;

  do
  {
   //Find a certificate from the same issuer
   pCertInStore = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING,
    0, CERT_FIND_ISSUER_NAME,&pCertPassed->pCertInfo->Issuer,pPrevCertContext);

   if(pCertInStore)
   {
    RETAILMSG(DBG_ON,(_T("Find certificate with the correct issuer")));

    //It's enough if we have a certificate from te same issuer
    if(g_SslOptions == SSL_OPT_ISSUER_CHECK)
    {
     CertFreeCertificateContext(pCertInStore);
     CertCloseStore(hCertStore,0);
     CertFreeCertificateContext(pCertPassed);
     return SSL_ERR_OKAY;
    }
    else if(g_SslOptions == SSL_OPT_STRICT_CHECK)
    {
     //Compare (exact match) the certificate with the one we have found
     if(CertCompareCertificate(X509_ASN_ENCODING,pCertInStore->pCertInfo,pCertPassed->pCertInfo))
     {
      RETAILMSG(DBG_ON,(_T("Find a certificate *exact match*")));
      CertFreeCertificateContext(pCertInStore);
      CertCloseStore(hCertStore,0);
      CertFreeCertificateContext(pCertPassed);
      return SSL_ERR_OKAY;
     }
    }
   }

   pPrevCertContext = pCertInStore;
  }
  while(pCertInStore);

  CertCloseStore(hCertStore,0);
 }

 if(pCertInStore)
  CertFreeCertificateContext(pCertInStore);

 if(hCertStore)
  CertCloseStore(hCertStore,0);

 if(pCertPassed)
  CertFreeCertificateContext(pCertPassed);

 RETAILMSG(DBG_ON,(_T("-SSLValidateCertHook")));

 return SSL_ERR_NO_CERT;
}

int
SSLInit(
 SOCKET s,
 int SslOptions
)
{
 DWORD optval = SO_SEC_SSL;
    SSLVALIDATECERTHOOK hook;
    SSLPROTOCOLS protocolsToUse;
    int ret;

 RETAILMSG(DBG_ON,(_T("+SSLInit (opt:%i)"),SslOptions));

 g_SslOptions = SslOptions;//WSAIoctl cannot handle the pointer copy, use a global variable

 if( setsockopt(s, SOL_SOCKET, SO_SECURE, (LPSTR)&optval,sizeof(optval)) ==
  SOCKET_ERROR)
 {
  RETAILMSG(DBG_ON,(_T("setsockopt SO_SECURE failed")));
  goto SSLInit_Error;
 }

 hook.HookFunc = SSLValidateCertHook;
    hook.pvArg = NULL; //WSAIoctl cannot handle the pointer copy, use a global variable

 if(WSAIoctl(s, SO_SSL_SET_VALIDATE_CERT_HOOK,
        &hook, sizeof(SSLVALIDATECERTHOOK),
        NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
 {
  RETAILMSG(DBG_ON,(_T("SO_SSL_SET_VALIDATE_CERT_HOOK failed")));
  goto SSLInit_Error;
 }

 //specify TLS1 protocol

 protocolsToUse.dwCount = 1;
 protocolsToUse.ProtocolList[0].dwFlags = 0;
 protocolsToUse.ProtocolList[0].dwProtocol = SSL_PROTOCOL_TLS1;
 protocolsToUse.ProtocolList[0].dwVersion = 0;

 if( WSAIoctl( s, SO_SSL_SET_PROTOCOLS,
  (LPVOID)&protocolsToUse, sizeof(protocolsToUse),
  NULL, 0, NULL, NULL, NULL ) == SOCKET_ERROR)
 {
  RETAILMSG(DBG_ON,(_T("SO_SSL_SET_PROTOCOLS failed")));
  goto SSLInit_Error; 
 }

 return 0;

SSLInit_Error:

 ret = WSAGetLastError();

 RETAILMSG(DBG_ON,(_T("-SSLInit error %i"),ret));

    return ret;
}
Posted in Windows Embedded CE, Windows Embedded Compact | Tagged , , | Leave a comment