Blog

  • Bluetooth Library (March Edition)

    To facilitate using the library in Visual Studio 2005 Betas I have made a few minor updates to the managed Bluetooth library, new/fixed in this release:-



    • Now works under .NETCF 1.0, .NETCF 2.0, .NET 1.1 .NET 2.0 (Not tested under the .NET 1.0 desktop framework but should work).
    • On Windows CE remote name lookups are performed “on-demand” rather than during device discovery to reduce discovery time.
    • Reintroduced the BluetoothSocket helper class which provides a shortcut to create a Socket for working with Bluetooth independently of the existing BluetoothClient / BluetoothListener classes.
    • Removed OpenNETCF.dll dependency, cures deployment problems on desktop machines.

    Download the latest version here:-


    Downloads


     

  • Control and Component Designers Part Four – Events

    This is a quick addendum to part three. In that section we looked at un-hiding some properties in the standard controls which were implemented in .NETCF SP2. As well as adding Fore and Back colour support, SP2 introduced support for a few more events which were declared in the original classes but never fired. Specifically these include the keyboard events KeyDown, KeyUp and KeyPress. Just like the colour properties these can be added to our design time assembly so that we can hook these events from the designer.


    [Browsable(true),
    Category(“Key”),
    Description(“Occurs when a key is first pressed.”)]
    public new event KeyEventHandler KeyDown;


    [Browsable(true),
    Category(“Key”),
    Description(“Occurs after a user is finished pressing a key.”)]
    public new event KeyPressEventHandler KeyPress;

    [Browsable(true),
    Category(“Key”),
    Description(“Occurs when a key is released.”)]
    public new event KeyEventHandler KeyUp;


    We declare the events “new” so that they will replace the base class implementation, but as this is design time only, the code generated hooks the events that already exist in the Control class. The category and description attributes improve the grouping in the property pane.


    The last event item to cover is the DefaultEventAttribute which can be applied to a class. In our PictureBoxEx class we inherit from the standard PictureBox (Thanks to Sergey Bogdanov for submitting the code). Because I have now added a Click event to the designer (In SP2 the PictureBox supports the Click event) we can make this the default event for the class, so that when you double click on the control in the designer it will automatically rig up a handler for you and drop you into the appropriate place in the code. This makes a little more sense that the PictureBox for which the default event is ParentChanged.


    #if DESIGN
        [DefaultEvent(“Click”)]
        public class PictureBoxEx : System.Windows.Forms.PictureBox
    #else    
        public class PictureBoxEx : System.Windows.Forms.PictureBox, OpenNETCF.Windows.Forms.IWin32Window
    #endif


    Part 1 | Part 2 | Part 3 | Part 4

  • Building the Latest SDF v1.3 Source

    We get a lot of requests asking for the very latest code for the SDF since tons of exciting stuff has been added (and many issues resolved) since our v1.2 release last year specifically from users starting to work with the VS2005 betas and community previews and would like to use the SDF with these new tools. Firstly just a reminder that the SourceBrowser no longer contains a current record of the source code, which is now maintained in the Vault (Username: guest, Password: guest). From the vault you can see all the latest source files as they are checked in.


    If you need a build which you can use with VS2005 Beta you can download from:-


    http://www.peterfoot.net/files/OpenNETCF.SDF.1.3.50302.zip


    And now the big disclaimer on this build, it’s not a final v1.3 release, it’s not signed with a key pair and so cannot be installed in the GAC on devices, there is no installer, no help content. This should not be used for release purposes (just like VS2005 itself of course) and we offer no support for this build.


    Update: v1.3 is now released, see this post for instructions for using the v1.3 release version in VS2005.


    Please remember if you have any product requests, bug reports etc whether you are using the current tools or VS2005 please post them to our new bug submission page, we are grateful for any feedback to help us make v1.3 our best release yet.

  • Control and Component Designers Part Three – Extending Existing Controls

    Using these techniques it’s possible to extend existing controls and add attributes to improve their designer experience. To illustrate this I’ve taken the example of the ComboBoxEx control. This extends the ComboBox control by overriding runtime behaviour to overcome a data binding issue, and adds BeginUpdate and EndUpdate methods to improve performance when filling the list of items.


    The designer experience for the control inherits the behaviour of the ComboBox control. Since the ComboBox’s own designer excludes some designer support which the control now implements as of Service Pack 2 such as Fore and Back Colors we can add these to our designer and have the designer insert the code to set the colour. The following block of code implements these properties in the design version of the control:-


    #if DESIGN


    [Browsable(true),

    EditorBrowsable(EditorBrowsableState.Always),

    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

    public new System.Drawing.Color ForeColor

    {

    get

    {

    return base.ForeColor;

    }

    set

    {

    base.ForeColor = value;

    }

    }


    [Browsable(true),

    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]

    public new System.Drawing.Color BackColor

    {

    get

    {

    return base.BackColor;

    }

    set

    {

    base.BackColor = value;

    }

    }

    #endif


    Once built we have a combobox with color support, and because the forms designer in Visual Studio uses a standard ComboBox for drawing it already supports drawing itself with the specified colour.



     


    Part 1 | Part 2 | Part 3 | Part 4

  • Control and Component Designers Part Two – Hanging the Decorations

    How the designer interprets your components is from a mixture of reflection to actually see what properties you expose, but also attributes which allow you to override this behaviour.


    The first attributes which are required for any component to appear in the toolbox are:-


    #if DESIGN

    [ToolboxItemFilter(“NETCF”,ToolboxItemFilterType.Require),

    ToolboxItemFilter(“System.CF.Windows.Forms”, ToolboxItemFilterType.Custom)]

    #endif



    This ensures that the component only appears on the device controls toolbar and not within a desktop project. We wrap this in an if DESIGN block so that the attribute is not added to the runtime control (because the CF assemblies don’t include this attribute). The ToolboxItemFilterAttribute can be found in the System.ComponentModel namespace.


    If you build the libraries now you should be able to add these components to your toolbox. Open a new device project and open a form in the designer, right click the toolbox and select “Add/Remove Items…” then browse to the output of your project e.g. binDesigner once you have added the file and closed the dialog you should have some new entries in your toolbox:-


    In order for the properties pane to work correctly we need to do some further decorating. For most properties you’ll be dealing with fundamental types which visual studio can display automatically. It is a good practise to specify the default values for these fields, in this way if you set the properties to the default it won’t generate code to assign to the property, also the property pane displays non-default values in bold so you can quickly see which have been set to a specific value. The DefaultValueAttribute accepts an object, for example in the case of the ProcessStartInfo the FileName default is an empty string


    #if DESIGN
            [DefaultValue(“”), RecommendedAsConfigurable(true)]
    #endif
            public string FileName


    Some properties will have no meaning at design time such as the Handle property of the Process, using the BrowsableAttribute with a value of false will hide the property


    #if DESIGN

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

    #endif

    public IntPtr Handle


    The DesignerSerializationVisibility attribute ensures that this property is excluded from the data serialized to describe your component.


    If you have a property which is of type Object then the designer will have no idea what is valid to assign to this and it will appear greyed out. Some of our components and controls now include a Tag property which allows you to tag an object of any type which may contain supporting data. On the desktop this is exposed as a string, so we do the same in our designer support. At runtime you can still assign any object to this property. We also apply the BindableAttribute which tells the designer that this property may be used in data binding.


    #if DESIGN

    [Bindable(true), DefaultValue((string) null), TypeConverter(typeof(StringConverter))]

    #endif

    public object Tag

     


    Some properties will use other classes which themselves contain multiple properties. A good example is the ProcessStartInfo which is used with the Process class. In order to allow the designer to display this correctly as a nested object we apply the TypeConverterAttribute and give it a value of ExpandableObjectConverter, this allows the designer to populate the property pane with the various properties contained within it.


    #if DESIGN

    [TypeConverter(typeof(ExpandableObjectConverter))]

    #endif

    public sealed class ProcessStartInfo


    We apply the same selection of properties to define the default values for the properties within this class. Now the property pane takes on a logical nested appearance and we can setup all of these properties at design time:-


    To ensure these properties are written out in our code by the designer we need to add the DesignerSerializationVisibilityAttribute:-


    #if DESIGN

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

    #endif

    public ProcessStartInfo StartInfo


    Optionally you can specify categories and descriptions for properties and events. Depending on the user’s preferences the property pane may be shown by category or alphabetically. By default properties are added to the “Misc” category. The grey box below the actual property list will show a short description as defined by the DescriptionAttribute as used here in the BackgroundWorker class.


    #if DESIGN

    [Category(“Asynchronous”),

    Description(“Event handler to run on a different thread when the operation begins.”)]

    #endif

    public event DoWorkEventHandler DoWork;


    Part 1 | Part 2 | Part 3 | Part 4

  • Control and Component Designers Part One – Building for Design Time

    Introduction


    When developing desktop .NET forms projects the toolbox contains a number of components you can drag across to your form and setup via the designer. A component in this case is any class which inherits from System.ComponentModel.Component. Visual Studio generates the appropriate code for you, in just the same way as forms controls except your components sit in a tray below your form.


    Over the past few versions of the SDF we have steadily built up a number of components which directly match those available on the desktop, so I decided it would be great to offer exactly the same designer experience.


    There are two key points to design time controls, firstly they are compiled against the full .NET framework (since that is what Visual Studio’s form designer uses), secondly they include a number of special attributes to setup the correct behaviour of the component and the properties window.


    Setting Up the Build Process


    There are two ways to build your designer assembly, either via the command line usually by building a batch file to call the C# compiler with your code files (That’s correct no VB.NET design time controls at this stage) this article was probably the first to describe this process and is still just as relevant today. The other way is to create a desktop Class Library project type and insert your existing code files.


    This is the approach I took this time as I’ve used command line build before and fancied a change. I started with a Solution which contains all the affected SDF assemblies – OpenNETCF, OpenNETCF.Drawing, OpenNETCF.Windows.Forms and OpenNETCF.WindowsCE.Forms. OpenNETCF.Drawing exposes no designable types but is used by the two forms assemblies. Within this solution file I created 5 new desktop Class Library projects – OpenNETCF.CF, OpenNETCF.CF.Drawing, OpenNETCF.CF.Windows.Forms and OpenNETCF.CF.WindowsCE.Forms, I then removed these new projects from the solution and moved the project files (.csproj) into the respective folder with their device equivalent (note that device projects have the .csdproj extension). I then opened each of the runtime projects in a text editor and copied all the entries into the design time projects. Finally back in Visual Studio I add these new desktop projects into the same solution. Next in order to allow both sets of files to build side-by-side I create a new configuration for the project called “Designer”. Then in my default “Debug” configuration for the entire solution I set the design time projects (OpenNETCF.CF.*) to use the Designer configuration and all the runtime projects to use the Debug configuration.


    Next I go into the project properties for each of the design time libraries and set the output folder to binDesigner and set a conditional compilation constant for “DESIGN”. We have already used this constant for previous versions when adding designer support to the controls so this already makes much of the libraries “designer safe”.


    These OpenNETCF libraries include dependencies to each other so OpenNETCF.CF.Drawing requires a reference to OpenNETCF.CF, OpenNETCF.CF.Windows.Forms requires a reference to both these and so on. These references are easily added with the Add Reference dialog and switching to the Projects pane. Next each of the design time projects needs a couple of standard references to the .NETCF designer assemblies:-



    • System.CF.Design
    • System.CF.Drawing
    • System.CF.Windows.Forms

    Additionally a reference to Microsoft.CF.WindowsCE.Forms was required in OpenNETCF.CF.WindowsCE.Forms since InputPanelEx derives from InputPanel. All of these designer assemblies is found within the Visual Studio installation e.g.


    C:Program FilesMicrosoft Visual Studio .NET 2003CompactFrameworkSDKv1.0.5000Windows CEDesigner


    The advantage of going through all these hoops is that both the design time and runtime projects point to exactly the same source code and you can build both assemblies from within your visual studio solution.


     


    Designer Support


    For each component or control which is exposed to the toolbox an image is required. This should be a 16×16 bitmap with the name of the control including full namespace e.g.


    OpenNETCF.Diagnostics.Process.bmp


    This is added to the design time project as an Embedded Resource in the root of the project (otherwise folder names are added to the resource name). We could try building the solution now, and will probably come across errors.


    A quick way to simplify the process is to remove any code files which are not required by any of your designable components, alternatively you could exclude entire files or code blocks from the design time build process by encapsulating them in if blocks using the compilation constant we setup e.g.


    #if !DESIGN

    public class NativeStuffWeDontNeedAtDesignTime

    {

    }

    #endif


    Concentrating on our components you can actually be quite ruthless with this conditional compilation as long as you expose the public properties which will be displayed in the properties window in the designer. Once you have successfully built the whole solution you’ll have a full set of runtime and design time assemblies, however they are not ready just yet as with all new builds they need decorating before we can move in…


    Part 1 | Part 2 | Part 3 | Part 4

  • Alternative View of Express Products

    Thanks Bill for this excellent link – an alternative view of the Visual Studio Express products target audiences. Check it out (but don’t take too seriously!):-


    http://www.atrevido.net/blog/PermaLink.aspx?guid=fc395650-88e9-4f9a-82cc-3f1ceebdfc3f

  • Determine Current GSM Network

    This VB.NET code will work on Smartphone and Pocket PC Phone devices and return details of the current GSM operator (though it probably works on CDMA also). It relies on Alex Feinman’s excellent TAPI wrapper whish you can download here. Using the library we create a line object which we pass the handle of (line.hline) into lineGetCurrentOperator, one of the ExTAPI functions. For simplicity the structure is just passed as one big byte array then the strings are copied out from it and have trailing nulls chopped off.


    ‘gets the textual representation of the operator
    Public Function GetCurrentOperator(ByVal line As OpenNETCF.TAPI.Line) As Operator
    Dim result As Integer
    Dim nullindex As Integer

    ‘stores operator details
    Dim lo As New Operator

    Dim buff(140) As Byte

    ‘copy LINEOPERATOR_USEFIRSTAVAILABLEINDEX to struct
    BitConverter.GetBytes(-1).CopyTo(buff, 0)

    ‘call tapi method
    result = lineGetCurrentOperator(line.hLine, buff)

    If result < 0 Then
    ‘error encountered
    Throw New System.Runtime.InteropServices.ExternalException(“TAPI Error getting operator: “ + result.ToString())
    End If

    ‘index
    lo.Index = BitConverter.ToInt32(buff, 0)
    ‘get status
    lo.Status = BitConverter.ToInt32(buff, 4)
    ‘get valid fields
    lo.ValidFields = CType(BitConverter.ToInt32(buff, 8), OperatorFormat)



    ‘long name
    If (lo.ValidFields And OperatorFormat.AlphaLong) = OperatorFormat.AlphaLong Then
    lo.LongName = System.Text.Encoding.Unicode.GetString(buff, 12, 64)
    nullindex = lo.LongName.IndexOf(Chr(0))
    If nullindex > -1 Then
    lo.LongName = lo.LongName.Substring(0, nullindex)
    End If
    End If


    ‘copy short name
    If (lo.ValidFields And OperatorFormat.AlphaShort) = OperatorFormat.AlphaShort Then
    lo.ShortName = System.Text.Encoding.Unicode.GetString(buff, 76, 32)
    nullindex = lo.ShortName.IndexOf(Chr(0))
    If nullindex > -1 Then
    lo.ShortName = lo.ShortName.Substring(0, nullindex)
    End If
    End If

    ‘copy num name
    If (lo.ValidFields And OperatorFormat.Numeric) = OperatorFormat.Numeric Then
    lo.NumName = System.Text.Encoding.Unicode.GetString(buff, 108, 32)
    nullindex = lo.NumName.IndexOf(Chr(0))
    If nullindex > -1 Then
    lo.NumName = lo.NumName.Substring(0, nullindex)
    End If
    End If

    Return lo

    End Function

    Declare Function lineGetCurrentOperator Lib “cellcore.dll” (ByVal hLine As IntPtr, ByVal operator As Byte()) As Integer

    Public Class Operator

       Public Index As Integer
       Public ValidFields As OperatorFormat
       Public Status As Integer
       Public LongName As String
       Public ShortName As String
       Public NumName As String

    End Class

    _
    Public Enum OperatorFormat
       None = &H0
       AlphaShort = &H1
       AlphaLong = &H2
       Numeric = &H4
    End Enum


     

  • MEDC Worldwide Dates Announced

    The latest information on the MEDC2005 front is a list of dates and venues for the worldwide MEDC events which will follow the main MEDC conference in May. So far the following events have been announced:-



    • Korea (TBA) – 19th-20th May

    • Germany (Berlin) – 6th June

    • France (Paris) – 8th June

    • UK (Microsoft Campus) – 10th June

    • Malaysia (Kuala Lumpur) – 16th-17th June

    • Australia (Melbourne) – 20th June

    • Australia (Sydney) – 22nd June

    • China (Beijing) – 24th June

    Full details, which I expect will be regularly updated can be found here at the MEDC website.

  • FolderBrowserDialog for Windows CE

    To follow up from a recent enquiry on the newsgroup, neither .NETCF v1.0 or v2.0 include the FolderBrowserDialog component. The main reason for this is that this functionality is not implemented in all flavours of Windows CE, for example Windows Mobile (Pocket PC / Smartphone) doesn’t include support for this dialog. If your device does support this shell feature then here is a simple wrapper I wrote which wraps the SHBrowseForFolder API in a FolderBrowserDialog class, which mimics the desktop equivelent. The code is packaged with a quick three line demonstration using the dialog. This works on the CE.NET 4.1 Emulator shipped with Visual Studio 2003.


    Download InTheHand.Windows.Forms.FolderBrowserDialog.zip


    If your platform is unsupported the control will throw a PlatformNotSupportedException when you call ShowDialog(). If you want to create this kind of functionality on Windows Mobile then a good starting point is the code accompanying this article at MSDN.