Tuesday, July 29, 2008

LINQ - Level 100

I've been talking about LINQ recently and the more I learn, the more I write as I think it is a well cool technology that I like talking about :) But if you're starting out and not sure how to start using LINQ what do you do?

This post is level 100 so very high level and it is meant to give newcomers an overview on how to start with LINQ, ie what tools you need what version of Visual Studio, language versions supported platforms, what's supported on devices and finally some links to get started.

Visual Studio 2008

You will need to use the new language features only available in C# 3.0 and VB 9.0 which can be used with Visual Studio 2008. I have shown code examples in C# but the concepts are the same for VB.

So you'll need at least Visual Studio 2008 and target 3.5 of the framework.

Types of LINQ (all supported on the desktop)

  1. LINQ to SQL (old name DLINQ)
  2. LINQ to XML
  3. LINQ to DataSets
  4. LINQ to Entities (sometimes called LINQ to ADO.NET)
  5. LINQ to Objects
One requirement to using LINQ to Entities which is a superset of LINQ to SQL is Visual Studio 2008 SP1 beta. VS SP1 beta adds the Entity Framework support to Visual Studio. Another nice feature worth mentioning and slightly related to LINQ, is support for SQL Server 2008 via Server Explorer - which is neat.

Types of LINQ supported on the Compact Framework (v 3.5)

  1. LINQ to DataSets
  2. LINQ to Xml
  3. LINQ to Objects
Sadly no LINQ to SQL/Entities is supported as yet and there haven't been any announcements when and if it will be supported.

You can use SQL Metal to generate the .dbml file for LINQ to SQL - but this will only work for SQL Compact on the desktop not device.

Some good resources (not device specific though) can be found at:

http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx

LINQ in Action: http://linqinaction.net/

Mike Taulty: http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/category/1001.aspx

Free Vista SP1 Support until 18th March 2009

Microsoft has announced free technical support on Vista SP1 until 18th March 2009. Telephone support is available worldwide. Some countries also offer chat and email support.

To find out more see here: http://support.microsoft.com/common/international.aspx?rdpath=1&prid=11274&gprid=500921

Derive from Exception not ApplicationException

A friend of mine Steve Gregson asked me the other day what exception class you should derive from when creating custom exceptions knowing that I would answer ApplicationException. I naturally told him ApplicationException, but I was wrong.

This post talks about this very issue with an excerpt from Jeffrey Richter and the reason...TargetInvocationException...or at least one of them. The original framework design was that applications would derive from ApplicationException and the CLR would derive from class Exception. This would then enable some code higher up the chain to distinguish the difference between an application exception over a CLR exception and handle it accordingly. But as a lot of framework classes didn't follow the ApplicationException pattern it renders this class useless as it is not possible to know where the exception came from (CLR or app) higher up the chain.

Best practices for handling exceptions can be found here.

In fact Krzysztof Cwalina's blog above co-authored this book:



I happen to own the above book and I just checked, page 197 where Jeffrey talks about not to use ApplicationException class. I highly recommend the above book by the way.

So there you have it, just forget ApplicationException ever existed...

Monday, July 28, 2008

LINQ to Objects on the Compact Framework - Part 2

I wrote an article recently about LINQ to Objects on the Compact Framework here.

This post goes into a bit more detail.

There are many examples out there in the communities in how to do simple queries, stuff like sorting filtering, grouping selecting new anonymous types etc. But what if we already have a relational schema that represents a one-to-one or a one-to-many mapping class hierarchy to our database schema which contains multiple records and we want to do some processing at a very low level in the hierarchy. Consider the schema defined below:



I've modelled this using SQL Server but I could have used quite a few different tools to do this.

The schema is quite nice to work with and it would be nice to have an object model that represented this in code.

In Part 1 we modeled the Customer table although notice in the above schema we have two new columns: HomePhone and MobilePhone so we will add these to our object model as follows:
public class CustomerInfo
{
private List<OrderInfo> orders = null;


public CustomerInfo()
{
orders = new List<OrderInfo>();
}

public int CustomerId
{
get;
set;
}

public string Name
{
get;
set;
}

public string AddressLine1
{
get;
set;
}

public string AddressLine2
{
get;
set;
}

public string AddressLine3
{
get;
set;
}

public string City
{
get; set;
}

public string County
{
get;
set;
}

public string PostalCode
{
get;
set;
}

public string Country
{
get;
set;
}

public string HomePhone
{
get;
set;
}

public string MobilePhone
{
get;
set;
}

public List Orders
{
get
{
return orders;
}
set
{
orders = value;
}
}
}
As you can see we now have the two additional properties added to support the additional columns and also we have an Orders property which gives us access to all orders for each customer.

Of course now we need both the Orders class the the Products class. They look like the following:
public class OrderInfo
{
public int OrderId
{
get; set;
}

public int CustomerId
{
get; set;
}

public int ProductId
{
get; set;
}

public int Quantity
{
get; set;
}

public ProductInfo Product
{
get; set;
}
}
Notice from the above we have the Product property which gives us the product this order relates to. Now we need the product class:
public class ProductInfo
{
public int ProductId
{
get;
set;
}

public string Description
{
get;
set;
}

public decimal Cost
{
get;
set;
}
}
That's it in terms of our object model. Nothing too complex. If we wanted, we could mark each class as Serializable so that if we wanted to serialize the data into binary we could (binary serializer is not supported on the CF) this is not required for XML serialization however. I do want to show an example of serializing this too as it adds an element of coolness to this example of how powerful we can make LINQ.

So now we need some data. Normally you'd write some SQL to populate your object model as I mentioned in previous posts sadly LINQ to SQL and LINQ to ADO.NET/Entitys are not supported. So this hard work still has to be hand cranked. Although there is an ORM toolset available for the Compact Framework. You can find this here. I'd be interested in hearing from anyone their experiences of this toolset as I haven't personally tried it, yet.

As I don't have a database, I'm just going to create an object model by hand with some fictitious data that I just made up. So this code looks as follows:
 List<CustomerInfo>customersSource = new List<CustomerInfo>
{
new CustomerInfo
{
CustomerId = 1,
Name = "Joe",
City = "London",
Orders = new List()
{
new OrderInfo()
{
OrderId = 1,
CustomerId = 1,
ProductId = 1,
Quantity = 5,
Product = new ProductInfo()
{
ProductId = 1,
Cost = 23.34M,
Description = "Garden tiles"

}
},
new OrderInfo()
{
OrderId = 2,
CustomerId = 1,
ProductId = 2,
Quantity = 10,
Product = new ProductInfo()
{
ProductId = 2,
Cost = 56.12M,
Description = "Grass seed"
}
},
new OrderInfo()
{
OrderId = 3,
CustomerId = 1,
ProductId = 2,
Quantity = 1,
Product = new ProductInfo()
{
ProductId = 3,
Cost = 599.95M,
Description = "Table and chairs"
}
}
}
},
new CustomerInfo
{
CustomerId = 2,
Name = "Pete",
City = "Paris"
},
new CustomerInfo
{
CustomerId = 3,
Name = "John",
City = "New York"
},
new CustomerInfo
{
CustomerId = 4,
Name = "Pete",
City = "London"
},
new CustomerInfo
{
CustomerId = 5,
Name = "Paul",
City = "Dublin"
},
new CustomerInfo
{
CustomerId = 6,
Name = "Steve",
City = "Exeter"
},
new CustomerInfo
{
CustomerId = 7,
Name = "Clare",
City = "Norwich"
}
};
So we have 2 orders for customer Joe (id 1) and no orders for any other customer.

Suppose now that we wanted a list of customers who have placed an order. I could code somthing like the following:
var customersWithOrders = from c in customersSource
where c.Orders.Count > 0
c.Name;


foreach (string s in customersWithOrders)
{
Debug.WriteLine(string.Format("Customer {0} has an order", s));
}
The output of above looks like:
Customer Joe has an order
Orders will always be non-null because we initialize a collection of orders in the CustomerInfo class. We could have coded the above using the new feature of C# 3.0 which is anonymous types. An example of using anonymous types is as follows:
var customersWithOrders = from c in customersSource
where c.Orders.Count > 0
select new
{
c.Name
};

foreach (var s in customersWithOrders)
{
Debug.WriteLine(string.Format("Customer {0} has an order", s.Name));
}
We could extend the anonymous type to include more information such as which city the customer is from:
var customersWithOrders = from c in customersSource
where c.Orders.Count > 0
select new
{
c.Name,
c.City
};
foreach (var s in customersWithOrders)
{
Debug.WriteLine(string.Format("Customer {0} from city {1} has an order",
s.Name, s.City));
}
We could also just select the customer like so:
var customersWithOrders =  from c in customersSource
where c.Orders.Count > 0
select c;
foreach (var s in customersWithOrders)
{
Debug.WriteLine(string.Format
("Customer {0} from city {1} country {2} has an order",
s.Name, s.City, s.Country));
}
The type is in fact a CustomerInfo object. It is implicitly inferred at runtime. The output of the above looks like the following:
Customer Joe from city London country  has an order
Notice how the country is blank, why is this? Go back to where we create our object model - we never intialized the Country property. In fact, as we are using auto-implemented properties the property will in fact be null. Cleverly though the code doesn't blow up because the above is in fact a bug.

You could from the var above do this:
CustomerInfo cust = customersWithOrders.First();
Which would give us our first CustomerInfo object found in the collection. The var is in this case an IEnumerable and First is an extension method on IEnumerable. There are many extension methods on IEnumerable which I will show examples of how to use lambda expressions in queries.

So far we have seen very simple queries. Now what if we wanted to do something more complex like find out which customers have placed orders totaling more than £100.00.

We use a new feature of C# 3.0 called lambda expressions to do this which makes our code very short and easy to read. Lambda expressions are much like anonymous methods as introduced with C# 2.0. There are plenty of resources out in the community that talk about lambda expressions in depth. In fact whenever you use LINQ - for example in the simple examples above the compiler will be creating lambda expression calculations in the background, seemlessly. Of course you can explicitly use them yourself to add extra power.

The code to achieve the above could look like the following:
var customersWithOrdersOver100 = from c in customersSource
where c.Orders.Sum(o => o.Product.Cost) > 100
select c.Name;
foreach (var s in customersWithOrdersOver100)
{
Debug.WriteLine(string.Format("Customer {0} has an order over £100.00", s));
}
The output of the above looks like:
Customer Joe has an order over £100.00
Here we have used extension method Sum on the IEnumerable interface then using lambda expression we are able to execute the query.

How cool is that, in just 3 lines of code - that is the impressive thing here.

That's it for this post, but in my next post Part 3 I talk about some more things you can do with LINQ.

Tuesday, July 22, 2008

LINQ to Objects on the Compact Framework - Part 1

I wrote an article recently about writing comparer classes to sort data on the CF because LINQ to SQL is not supported on the Compact Framework. I did forget to mention LINQ to Objects which *is* supported on the Compact Framework and of course adds so much more power than writing a comparer class.

So just as in the previous article we have a simple customer object:
public class CustomerInfo
{
public int CustomerId
{
get;
set;
}

public string Name
{
get;
set;
}

public string AddressLine1
{
get;
set;
}

public string AddressLine2
{
get;
set;
}

public string AddressLine3
{
get;
set;
}

public string City
{
get;
set;
}

public string County
{
get;
set;
}

public string PostalCode
{
get;
set;
}

public string Country
{
get;
set;
}
}
So instead of writing all that comparer logic, instead we can use LINQ to Objects as follows:
[MTAThread]
static void Main()
{
List<CustomerInfo> customersSource = new List<CustomerInfo>
{
new CustomerInfo {CustomerId = 1, Name = "Joe", City = "London"},
new CustomerInfo {CustomerId = 2, Name = "Pete", City = "Paris"},
new CustomerInfo {CustomerId = 3, Name = "John", City = "New York"},
new CustomerInfo {CustomerId = 4, Name = "Pete", City = "London"},
new CustomerInfo {CustomerId = 5, Name = "Paul", City = "Dublin"},
new CustomerInfo {CustomerId = 6, Name = "Steve", City = "Exeter"},
new CustomerInfo {CustomerId = 7, Name = "Clare", City = "Norwich"}
};

List<CustomerInfo> customersAscending =
(from c in customersSource
orderby c.City ascending
select c).ToList();

List<CustomerInfo> customersDescending =
(from c in customersSource
orderby c.City descending
select c).ToList();

Debug.WriteLine("Before sort");
DisplayCollection(customersSource);
Debug.WriteLine("");

Debug.WriteLine("After sort - Ascending");
DisplayCollection(customersAscending);
Debug.WriteLine("");
Debug.WriteLine("After sort - Descending");
DisplayCollection(customersDescending);

}

public static void DisplayCollection(List<CustomerInfo> customers)
{
foreach (CustomerInfo customer in customers)
{
Debug.WriteLine(string.Format("Name: {0}, City: {1}",
customer.Name, customer.City));
}
}
Output of the above looks like the following:
Before sort
Name: Joe, City: London
Name: Pete, City: Paris
Name: John, City: New York
Name: Pete, City: London
Name: Paul, City: Dublin
Name: Steve, City: Exeter
Name: Clare, City: Norwich
After sort - Ascending
Name: Paul, City: Dublin
Name: Steve, City: Exeter
Name: Joe, City: London
Name: Pete, City: London
Name: John, City: New York
Name: Clare, City: Norwich
Name: Pete, City: Paris
After sort - Descending
Name: Pete, City: Paris
Name: Clare, City: Norwich
Name: John, City: New York
Name: Joe, City: London
Name: Pete, City: London
Name: Steve, City: Exeter
Name: Paul, City: Dublin
So exactly the same results as both the IComparer and LINQ to SQL examples.

Of course LINQ is a little bit more powerful than traditional IComparer code in that we can filter data without having to write much code or go back to the database - which is quite powerful.

What if we wanted to show customers from London. We could write a query as:
 List<CustomerInfo> customersFromLondon = 
(from c in customersSource
where c.City == "London"
select c).ToList();
Debug.WriteLine(string.Format("Customers from london: {0} customers
found", customersFromLondon.Count.ToString()));
DisplayCollection(customersFromLondon);
The output of the above is as follows:
Customers from london: 2 customers found
Name: Joe, City: London
Name: Pete, City: London
Bearing in mind these examples are only 1 dimensional objects, you can see the power when we have related objects. I will show some more complex examples in another post.

We can also do wildcard filtering such as show me customers that name begins with 'J':

List<CustomerInfo> customersNameStartsWithj =
(from c in customersSource
where c.Name.StartsWith("J")
select c).ToList();
Debug.WriteLine(string.Format("Customer that name begins with the letter 'J': {0}
customers found", customersNameStartsWithj.Count.ToString()));
DisplayCollection(customersNameStartsWithj);
The output of this is as follows:
Customer that name begins with the letter 'J': 2 customers found
Name: Joe, City: London
Name: John, City: New York
Which gives us two results as with have a John and a Joe in our list of data.

Typically though, that list would normally have been returned from a data layer in your application and instead of going back to the database to filter, sort etc, you'd use LINQ instead which will improve performance no-end. This is also quite powerful if you are retrieving your data from a remote server, you wouldn't want to do another round trip to filter or sort results.

The really exciting thing about all this code is that it will run against your existing custo strongly typed collections and that is very powerful.

UPDATE: See part 2 of this series here.

Sunday, July 20, 2008

Building my Windows Vista Ultimate machine

***Not related to mobility or in fact anything else technical but I'd thought I'd post my experience here for any hardware geek readers out there! :)

I decided recently to build a Windows Vista machine to use on my network LAN at home and I thought I'd share my experiences here. This should have been a fairly simple task but turned out to be a bit of a nightmare but I finally got through it..... in the end.

The spec of this machine is as follows:

Motherboard: Gigabyte GA-P35-DQ6 (New Intel P35 chipset)
Processor: Intel Core 2 Duo E8200 2.66GHz (45nm) (not overclocked, not yet anyway)
Memory: Corsair 2GB DDR2 800 MHz/PC2-6400 XMS2 Non-ECC
HDD: Samsung Spinpoint 500GB
CD/DVD Drive: HP 1040d
Case: Coolermaster Elite 330 with Coolermaster eXtreme Power 460w PSU
Monitor: Samsung SyncMaster 2032BW (20" LCD)
Wireless: Netgear WG311T 108mbps Wireless PCI
Graphics: NVIDIA GeForce 8500 (512mb)
Sound: On board 8 channel (not bad at all for on-board)
Keyboard: KeySonic 2.4Ghz Wireless Compact Keyboard with Integrated Touchpad
Mouse: Acme laser something....need to get a decent mouse.
Web cam: Microsoft LifeCam 6000
Media Centre Support: Microsoft OEM Media Centre Remote Control (for controlling Media Centrer Extender - XBox 360)
OS: Windows Vista Ultimate 64-bit SP1

The good the bad and the ugly:

1. Ugly: The first thing was to check the monitor didn't have any dead pixels. So I simply hooked this upto my ancient laptop, luckily the ancient laptop has a VGA port and the cool Samsung supports VGA! Now did the monitor have any dead pixels,Guess what, it did. This is unusal for Samsung, they have a zero dead pixel policy even though PC World told me otherwise! Having said this PC world replaced the deal pixel monitor with no problems.

2. Ugly: When the last component arrived from ebuyer the Coolermaster Elite 330 with the processor I was finally ready to build this machine. After several hours of putting it all together it failed to boot, just wouldn't turn on. I figured it might be a lack of power because the board is a bit of a beast. So I hooked up the additional 2x4 12v power connector in hope the board will have enough power from the PSU. And it turned on! but it just kept on rebooting. You could hear the HDD kick in, fans etc and before any output was displayed on the screen it would reboot as if it was in an endless loop.

After a bit of diagnostics, I found out there was a CMOS checksum error, so I decided to try and short (reset) the CMOS to see if that fixed the problem. It didn't, sadly. The motherboard was then sent back to the supplier for repair as I bought this motherboard more than 6 months earlier I didn't get a new one. I just hadn't had the time to built it.

The fixed motherboard arrived while I was away around 2 weeks later so I was quite excited that I might have a working board and moments away from a running system as these days building PC's is much easier than they used to be. So lets start again!


The board waiting to be unpacked.


It's a very nice looking board.

1. In the picture above, I've added the CPU and the memory (memory in dual mode as the board supports it). The stock fan was very difficult to install. Today these fans come with these springy type mounts that click into place. They no longer just stick onto of the CPU as they need very tight contact with the CPU to disperse as much heat as possible - multi-core CPUs run very hot. Getting all mounts through the motherboard was quite a task! You also need some conducting lube to help with heat flow.


The case with the side off, ready for the board to be inserted

The case comes with a 120mm stock fan to draw heat from the CPU. It doesn't have any BIOS regulator as it doesn't connect to the motherboard so there is no way to control the speed of it. This is unlike the CPU fan. All we have to do is hook it up to one of the power cables.


The 120mm fan extracing heat from the CPU and the north bridge

We do not have to install the PSU as it comes pre-installed.

2. Before we insert the board we will need to install the HDD so it makes it easier to get it in before we install the motherboard.

This case (Coolermaster Elite 330) contains the quick release drive sockets so we do not have to use a screwdriver - this feature I really liked. The case has another similar features for expansion cards. But to be honest, I used screws in addition to using the quick release gadget in the case as it didn't seem to secure the cards well enough in place for my likeing.


Samsung Spinpoint 500Gb HD501LJ


Hard drive installed

3. Now its time to install the CD ROM drive. Before we do this we need to prepare a bay for the drive to be installed.


The front of the case and the blank removed


The drive inserted - HP 1040d

The drive will not be flush against the case here, it will be flush againt the front of the case which is why it's sticking out a bit.

4. Now we need to hook up the IDE and power cables to the drive as it's an IDE drive.





5. Now we can install the motherboard into the case.


Board inserted

Now we have the board inserted. The GA-P35-DQ6 is an ATX board so just fits without the hard disk drive touching any part of the board.

6. Now its time to install the graphics card.


NVIDIA GeForce 8500 (512mb)

This graphics won't run a games like Crysis or COD4 on full graphics but I didn't build it for gaming, my xbox is for gaming.


Graphics installed into PCI-E x16 slot also the SATA HDD hooked up to the board

The case would support a much larger card such as the 8800 series without problems.

7. Now install the wireless NIC card.


Netgear WG311T


NIC card installed into the motherboard

8. Now we need to put the front of the case on.



9. We now need to install the external SATA blanking plate into the case and hook it up to the board. This enables us to plug in external HDD drives without somesort of caddy case.


The plate to install


The plate installed into the board

10. We will need to install additional USB ports. I do not have any photos of doing this but it's a simple case of installing a plate and screwing it into place and hooking it up to the motherboard.

11. There are a couple of finishing touches required to complete this build. Hooking up the USB the headphone and MIC ports available on the front of the case to the board. Note in the picture below, we have one spare 2.5" bay. This can either be a floppy drive, or a compact flash multiple support card reader which I will probebly buy as this feature would be very useful.



12. Hook up the monitor to the graphics card (DVI support).


The card also supports VGA and S-Video

You can see in the above picture the additional USB ports we installed. 12 in total!


The DVI cable in the back of the monitor

13. Bluetooth support. I will use my bluetooth card - a gift from Microsoft :) This is a simple case of plugging it into one of the spare USB ports.




14. Installing the webcam. Again this is a simple case of plugging it into a spare USB port.



Microsoft LifeCam 6000

And that is it. Finished. All that is required now is installation of all the software!


The finished article


Samsung SyncMaster 2032BW (20" LCD)



A couple of points to make. 2 GB of RAM is not enough. Vista sits idle using around 50% load on 2GB so as soon as you start hammering it, remote desktop sessions, Visual Studio etc the memory usage increases upto around 70% which is when Vista becomes a little unstable. I have ordered some more memory to cope with this.

The board supports dual memory too which helps on throughput. I don't recommend the KeySonic wireless 2.4 Ghz keyboard as it seems to disconnect on inactivity which then requires extra key presses to "wake it up".

The next machine I am building is a Windows Server 2008 box, I will post my experience of that here!

Friday, July 18, 2008

Opera Mobile 9.5 beta 1 for WM5/6



I just downloaded and installed the web browser available from Opera Software, Opera Mobile 9.5 beta 1 and I think it's a work of art!

It supports full screen browsing, panning, zooming and you can save pages to your device.

It has a nice UI too, completly custom designed.


Portrait mode

Double tapping the screen zooms in so you can read the text more clearly:

Zoomed in

You can simply touch and drag the screen with the stylus or finger you have TouchFLO style devices.

Notice how it groups HTML paragraphs for easier reading, neat.

Gesture features:



Toolbar features:


Note this is a beta product so there are some known issues however for the very short amount of time I have been using it it seems to be fairly stable.

A list of know issues are as follows:

Known issues

  • ActiveX is disabled — Flash plugins and embedded video streaming do not work.
  • Custom IME’s (like HTC’s IME) will be buggy at best, not working at worst.
  • Not multilingual build — Only English is supported. Problems with other languages (and input methods) are not unexpected.
  • Installation on memory cards may cause problems.
  • Text wraps in overview mode.
  • Main testing has been done on English HTC devices (Touch Diamond, Touch Pro, Touch, Touch Dual, Touch Cruise, TyTN and Wizard) and Samsung i900.
  • We have got reports from some users that this build will disable the phones sounds/notifications.
Get it from here.

Thursday, July 17, 2008

Implementing the gradient fade look and feel Windows Mobile

You will notice on Windows Mobile (and pre WM) many core applications, Outlook, excel etc use a horizontal fade from right to left and normally the system Control colour combined with white generally.

An example of this is as follows:



An example of an application I've written looks like the following:



The above is a custom owner drawn list with of course no items. Here is the code to achieve the gradient background effect:
gOffScreen.FillRectangle(
new SolidBrush(Color.White),
0, 0, Convert.ToInt32(20 * grfx.DpiY / DESIGNPOINTSPERINCH), Height);
Rectangle rc = this.ClientRectangle;
rc.X = Convert.ToInt32(20 * grfx.DpiY / DESIGNPOINTSPERINCH);
rc.Width = Convert.ToInt32(rc.Width - 20 * grfx.DpiY / DESIGNPOINTSPERINCH);

NativeMethods.TRIVERTEX[] tva = new NativeMethods.TRIVERTEX[2];
tva[0] = new NativeMethods.TRIVERTEX(rc.X, rc.Y, Color.White);
tva[1] = new NativeMethods.TRIVERTEX(rc.Right,
rc.Bottom, SystemColors.Control);
NativeMethods.GRADIENT_RECT[] gra = new NativeMethods.GRADIENT_RECT[]
{
new NativeMethods.GRADIENT_RECT(0, 1)
};
//Get the hDC from the Graphics object.
IntPtr hdc = gOffScreen.GetHdc();
//P/Invoke to GradientFill.
NativeMethods.GradientFill(
hdc,
tva,
(uint)tva.Length,
gra,
(uint)gra.Length,
(uint)NativeMethods.GRADIENT_FILL_RECT_H);
//Release the hDC from the Graphics object.
gOffScreen.ReleaseHdc(hdc);
Where grfx is an instance of the Graphics object for this drawing surface and DESIGNPOINTSPERINCH is the design time DPI - normally 92. And the gOffScreen is a bitmap as we are using double buffering.

The unmanaged declarations look like the following:
public const int GRADIENT_FILL_RECT_H = 0x00000000;
public const int GRADIENT_FILL_RECT_V = 0x00000001;
public struct GRADIENT_RECT
{
public uint LowerRight;
public uint UpperLeft;
public GRADIENT_RECT(uint ul, uint lr);
}
[DllImport("coredll.dll", SetLastError = true,
EntryPoint = "GradientFill")]
public extern static bool GradientFill(IntPtr hdc,
TRIVERTEX[] pVertex,
uint dwNumVertex,
GRADIENT_RECT[] pMesh,
uint dwNumMesh,
uint dwMode);
There is an MSDN article for this subject here: http://msdn.microsoft.com/en-us/library/ms229655(VS.80).aspx

Wednesday, July 09, 2008

Students - Imagine Cup 2009 is now open!



Now open for registration.
http://imaginecup.com/Default.aspx

To learn more about the imagine cup see here.

Locking Keyboard and Screen on Windows Mobile

There was a question in the community today regarding locking the keyboard and screen. I thought this was a good question so decided to write an article about how to do it.

There is a very simple solution to this problem so long as the device supports locking the device, which is on most WM5 and later devices. This code should work on CE devices also. Simply P/Invoke the keybd_event procedure passing hex 0x85.

For a list of key codes see here: http://msdn.microsoft.com/en-us/library/bb431750.aspx

So I have knocked up a very simple application with one button which locks the device:


Click to show a larger image

When we click the Lock button you'll notice the menubar soft input 1 changes to read Unlock and the device is completely inaccessible, tapping even the start menu will not work apart from soft input 1:


Click to show a larger image

Clicking Unlock shows this screen:


Click to show a larger image

Of course clicking Unlock in the middle of the screen returns to you're app.

This approach can be used for many different features, check out the list of codes above. A simple way of achieving many features of the device.

The code looks like the following:
[DllImport("coredll.dll", EntryPoint = "keybd_event", SetLastError = true)]
internal static extern void keybd_event(byte bVk, byte bScan,
int dwFlags, int dwExtraInfo);

private void lockDevice_Click(object sender, EventArgs e)
{
keybd_event(0x85, 0,0,0);
}

Tuesday, July 08, 2008

Locking down Windows Mobile - code example

I wrote an article some time ago regarding locking down Windows Mobile here. Someone emailed me to ask how do we go about creating a zero-byte file to "hide" the app as this is the only real way to lock down Windows Moble devices at present other than removing shortcuts etc as mentioned in the above post.

It is relatively simple to create a zero-byte file we simple write something like the following would stop Internet Explorer Mobile from running:
StreamWriter sw = null;
try
{
StringBuilder sb = new StringBuilder();
sw = new StreamWriter(@"\Windows\iexplore.exe");
}
catch (Exception)
{
//Custom handling logic.
throw;
}
finally
{
if (sw != null)
{
sw.Flush();
sw.Close();
}
}
Although the code will prevent loading of the Internet Explorer Mobile - our objective here, it's a little ugly in that an error message will appear before the end user which isn't pretty as end users don't tend to like error messages :)

A nicer approach is to handle the shortcuts so the end user can't get to the application in the first place. It is recomended to still create a zero-byte file as if we do not lock down file explorer, the user could be smart and try and load the app from within file explorer.

Be sure to kill the process before creating a zero-byte file:
 Kill("iexplore.exe");
Of course the cleaner way would be to send WM_CLOSE to the app if it is a Windows base program and wait for a response. However the code for a Kill method might look something like the following:
private bool Kill(string program)
{
bool result = false;
try
{
ProcessEntry[] runningProcesses = ProcessEntry.GetProcesses();
//Check if the system we are about to remove is running or not.
foreach (ProcessEntry process in runningProcesses)
{
if (Path.GetFileName(program).ToLower() ==
Path.GetFileName(process.ExeFile).ToLower())
{
process.Kill();
result = true;
break;
}
}
}
catch
{
result = false;
}
return result;
}
Note the above method uses the OpenNETCF Diagnostic library to get a collection of running programs.

In order to handle shortcuts in terms of whether we need to remove them or re-add them and delete the zero-byte file, we can code something like the following:
//We check both locations for shortcuts, the programs menu and the start menu.
string ieShortcutStartMenuFilePath =
@"\Windows\Start Menu\Internet Explorer.lnk";
string ieShortcutProgramsFilePath =
@"\Windows\Start Menu\Programs\Internet Explorer.lnk";
FileInfo ieShortcutProgramsFile =
new FileInfo(ieShortcutProgramsFilePath);
FileInfo ieShortcutStartMenuFile =
new FileInfo(ieShortcutStartMenuFilePath);

if (ieGranted)
{
//Then access to Microsoft Pocket Internet Explorer is granted.
if (!ieShortcutProgramsFile.Exists && !ieShortcutStartMenuFile.Exists)
{
StreamWriter sw = null;
try
{
StringBuilder sb = new StringBuilder();
if (WindowsMobile5)
{
//WM5 and onwards - default to start menu.
sw = new StreamWriter(ieShortcutStartMenuFilePath);
sw.Write("21#\"\\Windows\\iexplore.exe");
}
else
{
//PPC 2003 - default to Programs folder.
sw = new StreamWriter(ieShortcutProgramsFilePath);
sw.Write("21#:MSPIE");
}
}
catch (Exception)
{
//Handle error
throw;
}
finally
{
if (sw != null)
{
sw.Flush();
sw.Close();
}
}

//We now need to delete the zero byte file, if found.
System.IO.FileInfo ieFile = new FileInfo(@"\Windows\iexplore.exe");
if (ieFile.Exists)
{
//This file should always exist!!!
if (ieFile.Length == 0)
{
try
{
File.Delete(@"\Windows\iexplore.exe");
}
catch (Exception)
{
//Handle exception.
throw;
}
}
else
{
//Then access to Microsoft Internet Explorer is denied.
try
{
//Set the shortcut's file attributes
//to archive to ensure we can delete it.
if (ieShortcutProgramsFile.Exists)
{
ieShortcutProgramsFile.Attributes = FileAttributes.Archive;
ieShortcutProgramsFile.Delete();
}
}
catch (Exception)
{
//Handle exception.
throw;
}

try
{
//Set the shortcut's file attributes to
//archive to ensure we can delete it.
if (ieShortcutStartMenuFile.Exists)
{
ieShortcutStartMenuFile.Attributes = FileAttributes.Archive;
ieShortcutStartMenuFile.Delete();
}
}
catch (Exception)
{
//Handle exception.
throw;
}
}
}
}
There are a couple of points to make with the code above. Notice we are refering to two different locations as to where the shortcut (.lnk) might live, either the Start Menu or in the Programs group. This is because is varies, there is no set standard as to where we might find it. Also notice naming differences on older devices PPC 2003 to that of WM5/6.x.

Don't you just love mobility :)

Microsoft Visual Studio SP1 (Beta) does not apply, or is blocked by another...

I mentioned recently the availability of Visual Studio 2008 SP1 Beta here.

If you try to install this you might get the following error if Silverlight Tools Beta 1 is installed on your machine:

"Microsoft Visual Studio 2008 SP1 (Beta) does not apply, or is blocked by another condition on your system. Please click the link below for more details".



To fix this, simply uninstall the Silverlight Tools Beta 1 package.

See the release notes for this SP here.

When you do finally get this installed, one of the upgrade features of VS 2008 is the ADO.NET Entity Framework for LINQ to Entity support - very cool. I will be talking about this soon...