Wednesday 26 August 2009

Windows Mobile 6.5 and Gestures

Having just viewed the MSDN Webcast: Developing for Windows Mobile 6.5 Devices: Using the Gesture APIs (Part 1 of 2) a link for the managed wrapper was mentioned, which is available here

Monday 24 August 2009

Windows Embedded CE and Windows Mobile Live Chat

A Windows Embedded CE and Windows Mobile Live Chat is scheduled on August 25, 2009 at 9:00 - 10:00 A.M. Pacific Time here.

Hopefully you can come along.

Saturday 15 August 2009

Toshiba TG01 and Accelerometer

I purchased the Toshiba TG01 a number of weeks ago and wanted to make programmatic use of the Accelerometer built into the device.

I knew that there would be a DLL on the device responsible for allowing access to the Accelerometer so I went about identifying this.

On the TG01 there is an application within the Settings called Adjust Motion Sensor and I thought that this application would make use of the DLL that would be available on the device. So I connected the TG01 via Active Sync and started Remote Process Viewer. I then started the Adjust Motion Sensor application and it appeared in the list of running processes, as expected.

Selecting the process from list provided me with a list of the Assemblies the application had loaded, one being the Axcon.dll.





I then wanted to copy the Axcon.dll to my development machine. The DLL is located in the \Windows directory of the device so I copied it from there.

I then opened the DLL using Notepad and was able to identify a number of possible method names as follows :-


?DTSDeregisterAcceleration@@YAKI@Z ?DTSDeregisterActionEvent@@YAKI@Z ?DTSGetAcceleration@@YAKIPAU_TS_ACCELERATION@@@Z ?DTSRegisterAcceleration@@YAKPAUHINSTANCE__@@IPAI@Z ?DTSRegisterActionEvent@@YAKPAUHWND__@@PAUHINSTANCE__@@PAI@Z ?DTSResumeSystemActionResponse@@YAKPAUHWND__@@@Z ?DTSSuspendSystemActionResponse@@YAKPAUHWND__@@@Z MwAxconEvtNotice MwAxconHoriPtSet MwAxconInitialSet MwAxconManOpTurn MwAxconParaSet MwAxconPresentGet MwAxconPresentGet2 MwAxconResume MwAxconStart MwAxconStop MwAxconSupend MwAxconTestRead MwAxconTestWrite TSDeregisterAcceleration TSDeregisterActionEvent TSGetAcceleration TSRegisterAcceleration TSRegisterActionEvent TSResumeSystemActionResponse TSSuspendSystemActionResponse

I then went another step further and loaded the DLL into Dependancy Walker which gave me the following :-

unsigned long DTSDeregisterAcceleration(unsigned int)
unsigned long DTSDeregisterActionEvent(unsigned int)
unsigned long DTSGetAcceleration(unsigned int,struct _TS_ACCELERATION *)
unsigned long DTSRegisterAcceleration(struct HINSTANCE__ *,unsigned int,unsigned int *)
unsigned long DTSRegisterActionEvent(struct HWND__ *,struct HINSTANCE__ *,unsigned int *)
unsigned long DTSResumeSystemActionResponse(struct HWND__ *)
unsigned long DTSSuspendSystemActionResponse(struct HWND__ *)
MwAxconEvtNotice
MwAxconHoriPtSet
MwAxconInitialSet
MwAxconManOpTurn
MwAxconParaSet
MwAxconPresentGet
MwAxconPresentGet2
MwAxconResume
MwAxconStart
MwAxconStop
MwAxconSupend
MwAxconTestRead
MwAxconTestWrite
TSDeregisterAcceleration
TSDeregisterActionEvent
TSGetAcceleration
TSRegisterAcceleration
TSRegisterActionEvent
TSResumeSystemActionResponse
TSSuspendSystemActionResponse

At this point I knew I had the methods of interest however the puzzling part was the structure being passed into the DTSGetAcceleration method.


I then fired an email off to Toshiba in the hope for some support in this area, however at the time of writing I am still waiting for a response.

I posted a question on the Modaco forums (http://www.modaco.com/content/toshiba-tg01-tg01-modaco-com/290257/tg01-sdk/) however it seemed I had reached a dead end at this point.

I just happened to check back on the forum last night and found that a thread had been started regarding the G-Sensor in the TG01 (http://www.modaco.com/content/toshiba-tg01-tg01-modaco-com/291274/g-sensor-in-tg01-emu-dev/)

Scrolling through this thread I found that a PDF document had been posted regarding the Driver Interface Specification.

I would like to point out that an attempt had been made to contact Toshiba regarding this however no response was given.

I downloaded the PDF document and begain reading. The document contained exactly the information I had been previously lacking therefore this morning I went about creating a C# managed wrapper for the methods exposed via Axcon.DLL.

Having done a bit of P/Invoking in the past I soon was able to call the required methods, passing in the correct data types and thanks to the document, able to retrieve G-Sensor data, based on the definition of the structure mentioned early.

There were two sections to the document. One was getting the G-Sensor data and the other was getting action events. These action events were things such as Shake, Rotate, Tilt, etc. The interesting thing about the action events were that when registring the event, a Handle was required for the Window that was to recieve the action events. I managed to intercept the messages being sent from the Action Event using the NativeWindow class as specified here (http://blog.opennetcf.com/ayakhnin/CategoryView,category,NativeWindow.aspx). I managed to intercept a Shake event however my main focus was on the G-Sensor data.

Having got back an X, Y and Z value from the method call DTSGetAcceleration, I then went about trying to intergrate this into the HTCSensorSDK sample as specified here (http://blog.enterprisemobile.com/2008/07/using-htc-diamonds-sensor-sdk-from-managed-code/)

With the Toshiba you had to "manually" query the G-Sensor data using the DTSGetAcceleration method.

After a short while I had managed to integrate the TG01 G-Sensor data into the sample and was able to get the ball rolling around the screen, there seems to be a slight issue with this however I am yet to figure that out.

So I have now got the wrapper I had wanted all those weeks ago and hopefully this information and sample code will help others integrate the G-Sensor data with their applications and games.

Toshiba - Please note I have only taken the unofficial route with this due to the lack of response from yourselfs. My intentions are only to help provide the relevant information to others so that they can make use of the hardware provided in the TG01.

G-Sensor Code :-

public struct _TS_ACCELERATION
{
public short x;
public short y;
public short z;
public _FILETIME time;
}

public struct _FILETIME
{
Int32 dwLowDateTime; /* low 32 bits */
Int32 dwHighDateTime; /* high 32 bits */
}

[DllImport("CoreDll.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(IntPtr ModuleName);

[DllImport("CoreDll.dll", SetLastError = true)]
public static extern Int32 GetModuleFileName(IntPtr hModule, StringBuilder ModuleName, Int32 cch);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSRegisterAcceleration(IntPtr hModule, UInt32 uPeriod, out UInt32 puID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSDeregisterAcceleration(UInt32 uID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSGetAcceleration(UInt32 uID, ref _TS_ACCELERATION accel);

G-Sensor Code Usage :-

// Registrying
// Firstly get the module handle for the application
IntPtr modulehandle = GetModuleHandle(IntPtr.Zero);
// Secondly registry the Acceleration providing the module handle above, the interval at which the data will be updated and the Request Id which is used when getting the G-Sensor data
TSRegisterAcceleration(modulehandle, (UInt32)100, out puId);

// Getting G-Sensor Data
// puId is the Request Id from above and acc is the reference to the_TS_ACCELERATION structure - This method can be called in a while loop or timer tick
TSGetAcceleration(puId, ref acc);

// Deregistry
// puId is the Request Id from above
TSDeregisterAcceleration(puId);

Action Events Code :-


[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSRegisterActionEvent(IntPtr hWnd, IntPtr hModule, out UInt32 puID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSDeregisterActionEvent(uint uID);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSSuspendSystemActionResponse(IntPtr hWnd);

[DllImport("Axcon.dll", SetLastError = true)]
public static extern Int32 TSResumeSystemActionResponse(IntPtr hWnd);


Action Events Code Usage - In conjuction with the NativeWindow project above :-

// The control that will receive the Action Events Windows Messages
MyAccControl myAccControl = new MyAccControl(this.Handle, this.listBox1);
// Register the Action Events using the Handle of the control above, the module handle and the puId
TSRegisterActionEvent(myAccControl.Handle, modulehandle, out puId);

Snippet of Code used to determine orientation of device :-

if (acc.z > 0)
{
if (acc.z > 800)
{
this.listBox1.Items.Add("Device Face Up Flat");
}
}
else
{
if (0 - acc.z > 800)
{
this.listBox1.Items.Add("Device Face Down Flat");
}
}
if (acc.y > 0)
{
if (acc.y > 800)
{
this.listBox1.Items.Add("Device Rotated Right");
}
}
else
{
if (0 - acc.y > 800)
{
this.listBox1.Items.Add("Device Rotated Left");
}
}
if (acc.x > 0)
{
if (acc.x > 800)
{
this.listBox1.Items.Add("Device Standing Up ");
}
}
else
{
if (0 - acc.x > 800)
{
this.listBox1.Items.Add("Device Upside Down");
}
}

Tuesday 4 August 2009

Bing Maps and Windows Mobile Part 4

I knew of the following Device How Do I video (Display Virtual Earth Maps inside a PictureBox Control? - http://msdn.microsoft.com/en-gb/netframework/dd920289.aspx) and after looking at the code, it provided the missing piece in the jig saw from the original article I was working from (http://msdn.microsoft.com/en-us/library/dd483215.aspx).

The missing pieces were a few calls to a number of the specified properties as below :-

pushpin.Location.LatitudeSpecified = true;
pushpin.Location.LongitudeSpecified = true;
mapUriOptions.ZoomLevelSpecified = true;

I now get a nice map as expected. It is slightly unusual that you set the property's value and then have to state that the value was specified, you would think that by just setting the value in the first place then you would have specified the value. It is also strange that these specified properties were not listed in the code from the MSDN article.

So the code as posted previously should now look like the following :-

private string GetMapUri(double latitude, double longitude, int zoom, string mapStyle, int width, int height)
{
Pushpin[] pins = new Pushpin[1];
Pushpin pushpin = new Pushpin();
pushpin.Location = new WindowsMobileBingMapsTester.net.virtualearth.dev.staging1.Location();
pushpin.Location.Latitude = latitude;
pushpin.Location.LatitudeSpecified = true;
pushpin.Location.Longitude = longitude;
pushpin.Location.LongitudeSpecified = true;
pushpin.IconStyle = "2";
pins[0] = pushpin;
MapUriRequest mapUriRequest = new MapUriRequest();
// Set credentials using a valid Bing Maps Token
mapUriRequest.Credentials = new WindowsMobileBingMapsTester.net.virtualearth.dev.staging1.Credentials();
mapUriRequest.Credentials.Token = GetClientToken();
// Set the location of the requested image
mapUriRequest.Pushpins = pins;
// Set the map style and zoom level
MapUriOptions mapUriOptions = new MapUriOptions();
switch (mapStyle.ToUpper())
{
case "HYBRID":
mapUriOptions.Style = MapStyle.AerialWithLabels;
break;
case "ROAD":
mapUriOptions.Style = MapStyle.Road;
break;
case "AERIAL":
mapUriOptions.Style = MapStyle.Aerial;
break;
default:
mapUriOptions.Style = MapStyle.Road;
break;
}
mapUriOptions.ZoomLevel = zoom;
mapUriOptions.ZoomLevelSpecified = true;
// Set the size of the requested image to match the size of the image control
mapUriOptions.ImageSize = new WindowsMobileBingMapsTester.net.virtualearth.dev.staging1.SizeOfint();
mapUriOptions.ImageSize.Height = height;
mapUriOptions.ImageSize.Width = width;
mapUriOptions.ImageSize.HeightSpecified = true;
mapUriOptions.ImageSize.WidthSpecified = true;
mapUriRequest.Options = mapUriOptions;
int width1 = mapUriRequest.Options.ImageSize.Width;
ImageryService imageryService = new ImageryService();
MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);
return mapUriResponse.Uri;
}

Monday 3 August 2009

Bing Maps and Windows Mobile Part 3

Using the method GetMapUri from here http://msdn.microsoft.com/en-us/library/dd483215.aspx I was able to retrieve a URL, however I have been unable to see a map yet, just a nice grey square with part of the words "Staging" on it. This was using both my home address and 1 Microsoft Way, as suggested in the article.

One point to note is that when running the GetMapUri method, the line
MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest); complained with an soap exception regarding the width of the mapUriOptions.ImageSize object not be set (The argument value must be between 80 and 900.Parameter name: Options.ImageSize.WidthActual value was 0.). I found that the following two statements also need to be added to prevent this exception :-
mapUriOptions.ImageSize.HeightSpecified = true;
mapUriOptions.ImageSize.WidthSpecified = true;

With these properties set, the code executes successfully, however I am presented with the grey square as previously mentioned.

Reusing the Token has had little effect.

I will post the code that I have, however I'm unsure why I am not getting a map :-


private string GetMapUri(double latitude, double longitude, int zoom, string mapStyle, int width, int height)
{
Pushpin[] pins = new Pushpin[1];
Pushpin pushpin = new Pushpin();
pushpin.Location = new WindowsMobileBingMapsTester.net.virtualearth.dev.staging1.Location();
pushpin.Location.Latitude = latitude;
pushpin.Location.Longitude = longitude;
pushpin.IconStyle = "2";
pins[0] = pushpin;
MapUriRequest mapUriRequest = new MapUriRequest();
// Set credentials using a valid Bing Maps Token
mapUriRequest.Credentials = new WindowsMobileBingMapsTester.net.virtualearth.dev.staging1.Credentials();
mapUriRequest.Credentials.Token = GetClientToken();
// Set the location of the requested image
mapUriRequest.Pushpins = pins;
// Set the map style and zoom level
MapUriOptions mapUriOptions = new MapUriOptions();
switch (mapStyle.ToUpper())
{
case "HYBRID":
mapUriOptions.Style = MapStyle.AerialWithLabels;
break;
case "ROAD":
mapUriOptions.Style = MapStyle.Road;
break;
case "AERIAL":
mapUriOptions.Style = MapStyle.Aerial;
break;
default:
mapUriOptions.Style = MapStyle.Road;
break;
}
mapUriOptions.ZoomLevel = zoom;
// Set the size of the requested image to match the size of the image control
mapUriOptions.ImageSize = new WindowsMobileBingMapsTester.net.virtualearth.dev.staging1.SizeOfint();
mapUriOptions.ImageSize.Height = height;
mapUriOptions.ImageSize.Width = width;
mapUriOptions.ImageSize.HeightSpecified = true;
mapUriOptions.ImageSize.WidthSpecified = true;
mapUriRequest.Options = mapUriOptions;
int width1 = mapUriRequest.Options.ImageSize.Width;
ImageryService imageryService = new ImageryService();
MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);
return mapUriResponse.Uri;
}

My usage :-


WindowsMobileBingMapsTester.net.virtualearth.dev.staging.GeocodeLocation currentLocation = GeocodeAddress("1 Microsoft Way, Redmond, WA");
this.webBrowser1.Url = new Uri(GetMapUri(currentLocation.Latitude, currentLocation.Longitude, 17, "HYBRID", 220, 220));

Bing Maps and Windows Mobile Part 2

After waiting about an hour and a half I tried to add the Common web service again and after entering the correct credentials (Account Id rather than Account Name) I was able to add the reference.

I build the project and found a number of errors, namely due to the copy and paste from the original article, however after these were resolve the project built and deployed to the Windows Mobile 5 emulator.

I kept things simple by entering my home address and wanting to get out the Latitude and Longitude. Having entered only my house number and street, the code ran through however no locations were found. I then entered my complete address and I was able to get out a
GeocodeLocation object which allowed me to display a label with the two properties on it.

The following is the code I have currently, I will then look at downloading a map, bear in mind that you have to sign up for a developer account and the credentials you have to enter in both the dialog and the code are unique to yourself and have been removed in the posted code :-


private string GetClientToken()
{
CommonService commonService = new CommonService();
commonService.Url = "https://staging.common.virtualearth.net/find-30/common.asmx";
commonService.Credentials =
new System.Net.NetworkCredential("[ACCOUNTID]", "[ACCOUNTPASSWORD]");
// Create the TokenSpecification object to pass to GetClientToken.
TokenSpecification tokenSpec = new TokenSpecification();
//Use the currently exposed public IP for the page.
tokenSpec.ClientIPAddress = "[IPADDRESS]";
// The maximum allowable token duration is 480 minutes (8 hours).
// The minimum allowable duration is 15 minutes.
tokenSpec.TokenValidityDurationMinutes = 480;
// Now get a token from the Bing Maps Token Service.
return commonService.GetClientToken(tokenSpec);
}


private GeocodeLocation GeocodeAddress(string address)
{
GeocodeRequest geocodeRequest = new GeocodeRequest();
// Set the credentials using a valid Bing Maps token
geocodeRequest.Credentials = new Credentials();
geocodeRequest.Credentials.Token = GetClientToken();
// Set the full address query
geocodeRequest.Query = address;
// Set the options to only return high confidence results
ConfidenceFilter[] filters = new ConfidenceFilter[1];
filters[0] = new ConfidenceFilter();
filters[0].MinimumConfidence = Confidence.High;
GeocodeOptions geocodeOptions = new GeocodeOptions();
geocodeOptions.Filters = filters;
geocodeRequest.Options = geocodeOptions;
// Make the geocode request
GeocodeService geocodeService = new GeocodeService();
GeocodeResponse geocodeResponse = geocodeService.Geocode(geocodeRequest);
if (geocodeResponse.Results.Length > 0)
if (geocodeResponse.Results[0].Locations.Length > 0)
return geocodeResponse.Results[0].Locations[0];
return null;
}

And calling code :-

GeocodeLocation currentLocation = GeocodeAddress("[MY ADDRESS HERE]");
if (currentLocation != null)
{
this.label1.Text = "Lat: " + currentLocation.Latitude.ToString();
this.label1.Text += " Long : " + currentLocation.Longitude.ToString();
}

More to follow...

Bing Maps and Windows Mobile Part 1

Eric Lam had blogged about the Bing Maps Web Services SDK 1.0 (http://ericlam.spaces.live.com/blog/cns!5D73BE0B4076E647!4408.entry), so I decided to sign up for a developer account to have a play with the SDK.

After receiving the email I was instructed to sign in to Bing Maps CSS to create a password for my account. Having done this I then went about trying to get something up and running.

After browsing through the documentation, there was a link to the Developing a Mobile Application Using Bing Maps Web Services article (http://msdn.microsoft.com/en-us/library/dd483215.aspx), I thought this is exactly what I was looking for (I wanted to Geocode an address and then display a map inside a Smart Device project).

I started reading this article and it soon turned out that it was very much focused on developing a ASP.NET page that a Windows Mobile device could access, this wasn't exactly what I was looking for, but would be a useful resource in achieving my goal.

So I set about adding the first web reference (ASMX) for being able to setup a Client Token. I was then prompted for my Username and Password however it was going to take a couple of hours for my account to be fully activated so I went on to the next section, the Bing Maps Web Services.

The service URLs had an extension of SVC (WCF), I had never used WCF before so this was going to be a new experience. As the article was aimed at creating a ASP.NET page then Adding A Service Reference wouldn't be a problem, however you do not get this option for a Smart Device project.

After a little more searching I realised I had to generate the Proxy classes. I thought I needed to use the svcutil.exe tool, I went ahead and generated the proxy classes, added them to my Smart Device project and then built, I was then faced with a number of build errors. I then remembered that there was a NETCF version of this tool (netcfsvcutil.exe), so I then attempted to generate the proxy classes using this tool. The tool ran through to completion however did not produce any proxy classes.

I then did a bit more searching and found the following piece of documentation Bing Maps Web Services Metadata (http://msdn.microsoft.com/en-us/library/cc966738.aspx). This provided the metadata URLs which I could then add as references to my Smart Device project.

I now have all four Bing Map Web Services added to my project, I am now just waiting for my account to be activated to be able to add the Common web service and then generate a Client Token.

More details to follow...