How small?!

Wed, January 26, 2005, 03:26 PM under MobileAndEmbedded
Most people associate Compact Framework target devices with Pocket PCs only. This is very convenient for the developer in many ways, e.g. a screen resolution of 240x320 and the presence of a stylus are presumed in most cases.

Imagine you are targeting a device with a very small display (e.g. 105x32mm, 240x64pixels). Naturally, you need to maximise the amount of elements you can fit on a screen, to make it useful. If you take the imaginary scenario further and say that the display is *not* touchscreen (instead hardware buttons provide the only way to drive the UI), then it becomes even more obvious that the GUI controls should be as small as possible (just large enough to read and as small as you can get away with).

Imaginary scenarios interest me, so I thought I'd see how the CF (and by extension WinCE) caters for such an eventuality. The focus is on the Height of controls (Width is not only pretty much adjustable, but also not the dominant limiting factor).

Naturally the following controls are irrelevant: Panel, PictureBox and Timer.

The following controls can be resized (and where applicable their Font is changeable to accommodate the size reduction):
Button, Label, TextBox, ListBox, ProgressBar, TabControl, TrackBar, Datagrid, TreeView, ListView, HScrollBar and VScrollBar

The Toolbar does not have a Size property, but its height is controlled by the size of the images associated with it (on custom WinCE devices, not PPC!). So by adding 8x8 icons to the ImageList associated with the toolbar (or by just changing the ImageSize property), the toolbar will be high enough to fit those images - nice. Like the Toolbar, the TreeView and ListView also play nice with the image size (if there is an ImageList associated with them, otherwise like I said in the previous paragraph, the Size/Font properties also work).

Once the size and Font of controls such as ListView, ListBox and TreeView is decreased, it sticks out like a sore thumb that their scrollbars are too thick. Not a big problem, though, as this can be controlled by the following registry settings:
HKLM\System\GWE , DWORD values "cxHScr", "cyHScr", "cxVScr", "cyVScr"

Menus (MainMenu, ContextMenu and MenuItem) are resized according to their Font. However, they do not expose a Font property, so you are stuck with whatever the default Font is for the platform. You can change that through the registry:
HKLM\Menu\BarFnt , DWORD "Ht" for height , DWORD "Wt" for boldness: 700 or 400
HKLM\Menu\PopFnt same as above, but this applies to menu items rather than the menu bar

The following controls are problematic:
-DomainUpDown and NumericUpDown can have their height changed but, before you get too excited, their Font is *not* changeable and in fact attempting to assign a Font results in a NotSupportedException at runtime! Net result: these controls have, effectively, a fixed minimum height (The CF 2.0 story is the same, except now the Font property is not exposed at all).
-ComboBox and StatusBar have the reverse problem: You can change their Font but not their Height - it compiles but no runtime change is observed (The CF 2.0 story is the same, except now the Height property is not exposed at all).
-CheckBox and RadioButton shrink, but the square box and circle respectively are of fixed size!
-We saw that menus can be shrunk based on Font size, but the Menu bar *height* is not configurable.

Showing off some of the above is this screen capture

VOTE for the WinCE/NETCF teams to improve in this area.

We already saw registry settings for scrollbars and menu font, here is one more that helps (reset is required before any effect takes place for all these):
HKLM\System\GWE , DWORD "cyCap" changes the height of a windows caption/title bar. Note that, if the Font is not changed accordingly, the text will not be rendered.

For more registry entries see here. I have played with all of them on our platform and found that they are more geared for large displays rather than smaller ones. In other words, the defaults are already targetting small displays, so if you want to go smaller there isn't much there :-(

Desktop to PPC (Part B)

Tue, January 25, 2005, 03:17 PM under MobileAndEmbedded
Continuing from part A (if you haven't read it, we'll wait for you...go on then :-)

5. Take over the device
Popular desire amongst devs is to take over the device. Their app is so important that nothing else should be accessible. This is not as bad as it may sound, as in some cases the application really is the raison d'etre of the device. Every solution described seems to create more issues, so there doesn't seem to be a clean one-rule-fits-all. If you have this requirement, here are some links for you to pursue [1, 2, 3, 4, 5, 6] (in other words search for "full screen" and "kiosk")

6. File System
The storage system on PPCs is similar to the desktop, with only a couple of differences. There is no C:\ drive; everything starts at the root, so an example path is this: "\Program Files\Some Folder\MyApp.exe". More importantly, there is no concept of current directory, the implication of which is that you must always use absolute paths (like the example above). To get the directory of your NETCF app, see this. Note that the OpenFileDialog will only let you browse the "My documents" directory, so if you need to go to other places you have to create your own.

7. Memory Constraint
An obvious difference with PPC devices is the limited memory that is available. When the device runs into low memory situations, it will start closing open windows (this is not minimising, it is real closing). If you get in such a scenario, some people advise to try hooking into the WM_HIBERNATE/WM_CLOSE windows msg; I advise you to revisit your architecture and not consume so much memory in the first place. Measure and set the expected memory your app requires to run smoothly, and if it doesn't get that on a device, it simply means the environment does not meet your criteria. You should, of course, be cleaning up resources in the Form.Closing events in any case. For more on memory problems see Memory Problems FAQ

8. Deployment
Deployment is quite different on devices than to the PC and all links you need on this topic are already provided here

9. Question: "How do I take advantage of my existing desktop .NET code?"
Answer: Share the code

If you are using the NETCF for targetting a device other than PPC (like me), you cannot make any of the above statements without knowing the specifics of the device (all custom CE-based devices are different). In this MSDN article, you can see some of the differences between PPC projects and WinCE projects in VS.NET 2003. I may do an entry on the topic too, at some point in the future.

MSN Messenger

Tue, January 25, 2005, 02:59 AM under Random
I haven't gone off topic in a while and today this pushed me to do so. The moral of Ian's story (although he doesn't state it like that) is do not change your main email account in Passport if you are using messenger. Reason I found the post interesting is because I was considering doing exactly that and now I am put off for good. Maybe it will be fixed in Messenger 7.0

You are using the BETA of 7.0, right? If you are not here are two reasons to do so (apart from the fact that it has been very stable for me in the past week):
1. Ability to sign in invisible
2. In addition to typing messages you can also handwrite them

Desktop to PPC (Part A)

Mon, January 24, 2005, 03:16 PM under MobileAndEmbedded
With the Compact Framework making programming for devices so easy, there is an increasing number of desktop developers making the move to CF development (or at least getting their feet wet). They face the challenges of a .NET Framework that is missing whole areas (e.g. Remoting, COM Interop, ASP.NET) and has every interface trimmed down (e.g. the Thread has only 2 public instance members) - it is not called the *Compact* Framework for nothing. Many of my blog entries focus on exactly that: the differences between the full and compact frameworks and sometimes how to bridge the gap.

However, another difference is the actual operating system or platform. This bites the developer even more if they are not daily users of a Pocket PC (which is the target of 95% of the NETCF developers). The situation described has as a consequence a lot of questions in the CF newsgroup, so I will try to address some of these in this entry and point to it in the future (as an FAQ).

1. Input methods
PPCs do not have a mouse or a keyboard (for the few devices that have, keyboard events are supported by some NETCF controls since Service Pack 2). The lack of a mouse is catered by a touch screen and the use of a stylus (mouse events are not supported in most controls and you may need to create your own control; help for custom controls is here, here and here). Right-click context menus are simulated by tap-and-hold (made possible by the aygshell.dll that is part of the PPC platform). There is a Soft Input Panel (SIP), which is a software keyboard that can pop up on the screen. To interact with it, you must reference Microsoft.WindowsCE.Forms.dll and drag the InputPanel control onto your form. To show it, you call InputPanel1.Enabled = true, typically in the GotFocus event of a TextBox (and set it to false in the LostFocus). To detect when it is up or down, you can track the InputPanel.EnabledChanged event. Note that hand-in-hand with the InputPanel is the MainMenu control that your form must have - even if it doesn't use it (!)

2. Form/Dialog size
Forms and dialogs on the PPC are always full screen (the only exception to that rule is the built-in MessageBox). There are known workarounds, but it seems that they hurt more than they help, so my advice is to stick with full screen dialogs and design for that approach from day 1. Try to design the UI so the user never gets the impression they are interacting with more than one screen; use multiple hidden panels on one form and swap them in/out as appropriate.

3. App/Form closing
The design guidelines for the PPC are clear: Applications do not exit/close, instead they minimise. This aids in the concept of a device that is always on (and the apps are always available, without waiting for them to load each time). For NETCF apps, setting the Form1.MinimizeBox to true will display the X button in the top right, whereas MinimizeBox=false will instead show a little OK button in the top right. Clicking an X minimizes the form, whereas clicking an OK closes the form and by extension the application if the form is the application's main form. Note that minimising is not identical to the desktop, i.e. all that happens to the window is that it is pushed to the back of the stack of open windows on the PPC. To programmatically know when a smart minimize occurs, you should hook into the Form1.Deactivate event (which is supported even though designer support is missing).

4. Moving between applications
Following from points 2 & 3 above, you might wonder how you switch between applications. There are various ways: By closing (minimising really) windows, you can reach the desired one OR you can use the top-right Start menu (Windows icon) OR open the Start->Settings->System->Memory->Running Programs screen. The "Running Programs List" displays all the open windows (minimised or not) and allows you to switch between them. This presents a problem in a scenario where your app has Form_A opening Form_B and you only expect the user to get back to Form_A after closing Form_B; they can also go to Form_A by using the "Running Programs List"! The workaround is to only show in the list the active form and to do that you must set the caption (Form1.Text) of other forms to String.Empty (""). By the way, if you are having trouble bringing your application to the front programmatically, read that.

In my opinion, these are the top 4 gotchas for desktop devs moving to the PPC platform. Look forward to the next 4 or 5 in part B.

Blog link of the week 03

Sun, January 23, 2005, 01:20 PM under Links
By now you know about the yesfollow OR the chance to bid for an hour's consultancy with payment going to the victims... I will also remind you that the next installment of the training we mentioned last week is out - of particular interest the talk about progressive API...

Instead, go give a piece of your mind about default Form instances in VB (why would they listen now when they didn't before is a different matter)

I've already given a piece of my mind on the Class Designer in the past but I am still interested in new Beta 2 features.

Semaphore

Sat, January 22, 2005, 10:34 AM under MobileAndEmbedded
We looked at the implementation of EventWaitHandle for the NETCF 1.0 & 2.0

Here, I offer an implementation of Semaphore (another new Whidbey class inheriting from WaitHandle). If you are looking for it (e.g. in your Object Browser), note that unlike every other System.Threading class, it is in System.dll (and not mscorlib) (!)

Get the C# version from OpenNETCF (like most of my other contributions, in 1.3), and the VB version is available right now: Semaphore.vb

EventWaitHandle

Wed, January 19, 2005, 02:39 PM under MobileAndEmbedded
We looked at the absense of a nice class from NETCF (today & tomorrow). Here I will offer an implementation of the .NET 2.0 EventWaitHandle for the NETCF.

The C# version is over at the SDF, and the VB version is right here

Take note of inheritance limitations as described before, and obviously I have omitted parts of the interface that do not apply on WinCE. Finally, if you only wanted the class for CF 1.0 or just for CF 2.0, there are changes you can apply to the implementation - as it stands, it works on both :-)

WaitHandle

Tue, January 18, 2005, 02:21 PM under MobileAndEmbedded
As part of some restructuring for my app, I had to dig into the abstract System.Threading.WaitHandle class. As you'd expect, this is different on NETCF to the Full Fx, and both have changed with Whidbey (based on November CTP).

NETCF 1.0 vs .NET 1.1
The CF version does not provide the WaitAll or WaitAny methods; it only provides the basic parameterless overload of WaitOne. Comparing the total number of members (fields, properties, methods) regardless of scope, we find the CF version having half the members than the Full Fx (13 vs 26).

.NET 1.1 vs .NET 2.0
The main addition we'll get is the public static SignalAndWait methods (3 overloads). The class grows by 9 members in total. The other change is the replacement of the Handle type. Instead of using an IntPtr, it is now of the newly introduced SafeWaitHandle (of the new Microsoft.Win32.SafeHandles namespace)

NETCF 1.0 vs NETCF 2.0The WaitHandle in CF 2.0 brings no changes compared to CF 1.0 apart from implementing the IDisposable.Dispose method (that the Full Fx classes do in all versions).

Getting to the point
So why am I looking at this class? Well actually, I am not interested in the class itself; it is the derived classes that are interesting, and to understand an object's behaviour you must understand its parents. In .NET 1.1 and NETCF 1.0 the public inheritance relationship is:
Figure A
WaitHandle : MarshalByRefObject
|-> Mutex
|-> AutoResetEvent
|-> ManualResetEvent

In .NET 2.0 this changes with the introduction of a new class (and the one that interests me) EventWaitHandle:
Figure B
WaitHandle : MarshalByRefObject
|-> Mutex
|-> EventWaitHandle
|-> AutoResetEvent
|-> ManualResetEvent
|->Semaphore

EventWaitHandle is not supported in CF 2.0 and, in fact, the whole inheritance hierarchy remains the same in CF 2.0 as it is today (i.e. Figure A). Ignoring Semaphore for the time being (maybe a subject of a future post), I would have urged you to go vote but the inclusion of EventWaitHandle to NETCF has already been postponed.

The main use of this class would be for creating named events which play a prominent role in Inter-Process Communication on WinCE.

Next time we'll look at wrapping the pinvokes required to offer a class that exposes the same interface as EventWaitHandle (unfortunately, though, it cannot fit in the same inheritance hierarchy as the desktop, i.e. we cannot change the existing Compact Framework XXXXResetEvent classes to inherit from the EventWaitHandle we introduce, rather than the WaitHandle that they do).

ObfuscationAttribute

Mon, January 17, 2005, 10:11 AM under Whidbey | VisualStudio
This is the title of a blog post that immediately got my attention. I had to dig further, so here is the process.

Look at the attribute with a decompiler:
[AttributeUsage(AttributeTargets.Delegate | (AttributeTargets.Parameter | 

(AttributeTargets.Interface | (AttributeTargets.Event |
(AttributeTargets.Field | (AttributeTargets.Property |
(AttributeTargets.Method | (AttributeTargets.Enum |
(AttributeTargets.Struct | (AttributeTargets.Class |
AttributeTargets.Assembly))))))))),
AllowMultiple=true, Inherited=false), ComVisible(true)]
public sealed class ObfuscationAttribute : Attribute {
// Constructor
public ObfuscationAttribute();

// Properties
public bool ApplyToMembers;
public bool Excludet
public string Feature;
public bool StripAfterObfuscation;

// Fields
private bool mApplyToMembers;
private bool mExclude;
private string mFeature;
private bool mStripAfterObfuscation;
}

If you think drilling deeper will tell you anything, don't hold your breath; the properties are plain accessors for the fields and this is the ctor:
public ObfuscationAttribute(){

mStrip = true;
mExclude = true;
mApplyToMembers = true;
mFeature = "all";
}

OK, so the class itself doesn't unveil the mystery, but maybe applying it to one of our methods and then examining that will:
[System.Reflection.Obfuscation()]

public int ObfuscateThisPlease() {
int j = 6;
int i = 5 + j;
return (j - i);
}

.method public hidebysig instance int32 ObfuscateThisPlease() cil managed
{
.custom instance void [mscorlib]ObfuscationAttribute::.ctor()=(01 00 00 00)
// Code size 10 (0xa)
.maxstack 2
.locals init ([0] int32 j,
[1] int32 i)
IL_0000: ldc.i4.6
IL_0001: stloc.0
IL_0002: ldc.i4.5
IL_0003: ldloc.0
IL_0004: add
IL_0005: stloc.1
IL_0006: ldloc.0
IL_0007: ldloc.1
IL_0008: sub
IL_0009: ret
} // end of method Program::ObfuscateThisPlease

Nada. Tzifos. Nothing. At this point there is only one thing left to do: RTFM, and all is revealed:
"Instructs obfuscation tools to take the specified actions for an assembly, type, or member."

Well I bet, like me, you guys (and gals) were hoping System.Reflection.ObfuscationAttribute would be a pseudo-custom attribute rather than just a marker for 3rd party tools, but not every journey leads to a treasure :-(

I guess I could be applying it to all my privates automatically since, as we know, custom attributes cost absolutely nothing, until you explicitly reflect on them.

(Just to get this out of my system: I think the term Attribute is an unfortunate choice by the .NET designers. "Annotation", "decoration", "declaration", “metadata” or anything else would have not only conveyed the purpose better, but would also not clash with the UML's existing use of the keyword "attribute" to mean fields/data_members of a class)

Blog link of the week 02

Sun, January 16, 2005, 12:00 PM under Links
On Friday (I almost broke my pattern and posted BLOTW then), Brad Adams announced a free .NET training series on Class Library design, kicking off with "Setting the Stage". I must admit it really does set the scene and there isn't any technical info in this one, but it does make me unable to wait for the next ones (make sure you read slides 11-14 for MSFT's business model as per BillG)! Definitely one for your bookmarks.

If you are after a quick WinForms tip, Cathi Gero has a cool one. Not only I've always liked the AutoTab feature as an end user, but as a developer I was not aware before of the highly configurable Control.SelectNextControl method.

And the lighter side of Project Management