How to switch on/off the speaker phone in .NETCF

A few years back, I stumbled upon this article while trying to find a solution on how to switch on/off the speaker phone. It uses a DLL found in Windows Mobile 5 (and higher) devices called ossvcs.dll. This library exposes some pretty neat API's for controlling communication related features in the device (like controlling the wireless/bluetooth radio and other cool stuff).

Here's a quick way for switching the speaker on/off in .NETCF

[DllImport("ossvcs.dll", EntryPoint = "#218")]        
static extern int SetSpeakerMode(uint mode);
 
void EnableSpeakerPhone()
{
    SetSpeakerMode(1);
}
 
void DisableSpeakerPhone()
{
    SetSpeakerMode(0);
}

Unfortunately, ossvcs.dll is not documented and might not exist in the future. But for now, it pretty much works in all devices I've tried



How to enumerate storage cards in .NETCF

In Windows Mobile, external storage cards are usually represented as the '\SD Card' or '\Storage Card' folder, this varies from device to device. A simple way to enumerate the external storage cards is to check all directories under the root directory that have the temporary attribute flag set.

Here's a quick way to do so in .NETCF:

public static List<string> GetStorageCards()
{
    var list = new List<string>();
    var root = new DirectoryInfo("\\");
    foreach (DirectoryInfo directory in root.GetDirectories()) 
    {
        if (FileAttributes.Temporary == (directory.Attributes & FileAttributes.Temporary))
            list.Add(directory.Name);
    }
    return list;
}



How to send keyboard events in .NETCF

I've seen some people ask how to how to send keyboard events in .NET Compact Framework in the community. Although the operation is pretty simple, I'll share a code snippet anyway.

const int KEYEVENTF_KEYPRESS = 0x0000;
const int KEYEVENTF_KEYUP = 0x0002;
 
[DllImport("coredll.dll")]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
 
void SendKey(Keys key)
{
    keybd_event((byte) key, 0, KEYEVENTF_KEYPRESS, 0);
    keybd_event((byte) key, 0, KEYEVENTF_KEYUP, 0);
}

The code above will send the keyboard event to currently focused window or control



Generic Bordered Control Base for .NETCF

For quite some time I've been using Google Chrome as my browser. The behavior of some of the controls are similar with Safari (probably because they use the same rendering engine). Anyway, I really liked the way that a border is drawn around the control whenever it receives focus. This inspired me to create a generic base control that draws a border around any control you use it for. The code I use is pretty much the same with my previous article, Extending the TextBox Control in .NETCF.

To accomplish this I created an abstract control that takes a generic parameter of type Control and has a default constructor. You might notice that in my override Font I check whether the control is in design time or run time. If in design time, we need to create a new Font object for the setter using the values passed. If we directly use the value passed the designer will crash, and at times Visual Studio will crash.

Here's how it can look like:



















And here's the code for the base control:

[EditorBrowsable(EditorBrowsableState.Never)]
public abstract class BorderedControlBase<T> : Control
    where T : Control, new()
{
    protected T innerControl;
 
    protected BorderedControlBase()
    {
        innerControl = new T();
        innerControl.GotFocus += delegate { OnGotFocus(EventArgs.Empty); };
        innerControl.LostFocus += delegate { OnLostFocus(EventArgs.Empty); };
        innerControl.TextChanged += delegate { OnTextChanged(EventArgs.Empty); };
        Controls.Add(innerControl);
    }
 
    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);
        innerControl.Bounds = new Rectangle(1, 1, ClientSize.Width - 2, ClientSize.Height - 2);
        Height = innerControl.Height + 2;
    }
 
    protected override void OnParentChanged(EventArgs e)
    {
        base.OnParentChanged(e);
        Invalidate();
    }
 
    protected override void OnGotFocus(EventArgs e)
    {
        base.OnGotFocus(e);
        Invalidate();
        innerControl.Focus();
    }
 
    protected override void OnLostFocus(EventArgs e)
    {
        base.OnLostFocus(e);
        Invalidate();
    }
 
    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.Clear(innerControl.Focused ? SystemColors.Highlight : BackColor);
    }
 
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        if (Environment.OSVersion.Platform != PlatformID.WinCE)
            base.OnPaint(e);
    }
 
    public override Font Font
    {
        get { return base.Font; }
        set
        {
            if (Environment.OSVersion.Platform != PlatformID.WinCE)
            {
                var font = new Font(value.Name, value.Size, value.Style);
                base.Font = innerControl.Font = font;
            }
            else 
                base.Font = innerControl.Font = value;
        }
    }
 
    public override string Text
    {
        get { return innerControl.Text; }
        set { innerControl.Text = value; }
    }
 
    public override bool Focused
    {
        get { return innerControl.Focused; }
    }
}

Now that we have this base control we can easily add borders to any control. Here's an example of how to use the the bordered control base:

public class BorderedTextBox : BorderedControlBase<TextBox> 
{
    ........
}
 
public class BorderedComboBox : BorderedControlBase<ComboBox> 
{
    ........
}

Of course you will still have to wrap all the members of the wrapped control you wish to expose to access them. Hope you find this useful. If you need the Visual Studio solution then you can grab it here.



Extending the TextBox Control in .NETCF

In this article I'm gonna extend the TextBox control. To accomplish this I will wrap the built in TextBox control in a composite control. Wrapping a control in this context means forwarding events and methods to the composite control so the parent of this control will treat it like a normal TextBox.

In this example I will demonstrate how how to display a border around the TextBox when it has focused and show how to add a property for disabling and enabling the caret.

To draw the border I make sure that there is 1 pixel of space around the actual TextBox control. In the OnResize event of the composite control I set the bounds of the inner TextBox the bounds of the composite control minus 1 pixel on each side. If the inner TextBox is not in Multiline mode then the height of the control is forced to match its font size, if so then I resize the composite control to be 1 pixel taller. And draw the border I just clear the drawing surface with the highlight system color if it is Focused, and with white if not.

To enable and disable the caret, we add a boolean property called EnableCaret. This property is checked every time the control receives or loses focus, to call the native HideCaret() and ShowCaret(). As I demonstrated in my previous article called How to hide the TextBox caret in .NETCF

Here's how it looks like:



















And here's the code:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
namespace ExtendedTextBox
{
    public class TextBoxEx : Control
    {
        [DllImport("coredll.dll")]
        static extern bool HideCaret(IntPtr hwnd);
 
        [DllImport("coredll.dll")]
        static extern bool ShowCaret(IntPtr hwnd);
 
        private TextBox textBox;
 
        public TextBoxEx()
        {
            textBox = new TextBox();
            textBox.GotFocus += (sender, e) => OnGotFocus(EventArgs.Empty);
            textBox.LostFocus += (sender, e) => OnLostFocus(EventArgs.Empty);
            textBox.TextChanged += (sender, e) => OnTextChanged(EventArgs.Empty);
            textBox.KeyDown += (sender, e) => OnKeyDown(e);
            textBox.KeyPress += (sender, e) => OnKeyPress(e);
            textBox.KeyUp += (sender, e) => OnKeyUp(e);
            Controls.Add(textBox);
        }
 
        public bool EnabledCaret { get; set; }
 
        #region Wrapped Properties
 
        public override Font Font
        {
            get { return base.Font; }
            set
            {
                if (Environment.OSVersion.Platform != PlatformID.WinCE)
                {
                    var font = new Font(value.Name, value.Size, value.Style);
                    base.Font = textBox.Font = font;
                }
                else
                    base.Font = textBox.Font = value;
            }
        }
 
        public override string Text
        {
            get { return textBox.Text; }
            set { textBox.Text = value; }
        }
        public bool AcceptsReturn
        {
            get { return textBox.AcceptsReturn; }
            set { textBox.AcceptsReturn = value; }
        }
 
        public bool AcceptsTab
        {
            get { return textBox.AcceptsTab; }
            set { textBox.AcceptsTab = value; }
        }
 
        public bool CanUndo
        {
            get { return textBox.CanUndo; }
        }
 
        public bool Focused
        {
            get { return textBox.Focused; }
        }
 
        public new IntPtr Handle
        {
            get { return textBox.Handle; }
        }
 
        public bool HideSelection
        {
            get { return textBox.HideSelection; }
            set { textBox.HideSelection = value; }
        }
 
        public int MaxLength
        {
            get { return textBox.MaxLength; }
            set { textBox.MaxLength = value; }
        }
 
        public bool Modified
        {
            get { return textBox.Modified; }
            set { textBox.Modified = value; }
        }
 
        public bool Multiline
        {
            get { return textBox.Multiline; }
            set { textBox.Multiline = value; }
        }
 
        public char PasswordChar
        {
            get { return textBox.PasswordChar; }
            set { textBox.PasswordChar = value; }
        }
 
        public bool ReadOnly
        {
            get { return textBox.ReadOnly; }
            set { textBox.ReadOnly = value; }
        }
 
        public override Color BackColor
        {
            get { return textBox.BackColor; }
            set { textBox.BackColor = value; }
        }
 
        public ScrollBars ScrollBars
        {
            get { return textBox.ScrollBars; }
            set { textBox.ScrollBars = value; }
        }
 
        public string SelectedText
        {
            get { return textBox.SelectedText; }
            set { textBox.SelectedText = value; }
        }
 
        public int SelectionLength
        {
            get { return textBox.SelectionLength; }
            set { textBox.SelectionLength = value; }
        }
 
        public int SelectionStart
        {
            get { return textBox.SelectionStart; }
            set { textBox.SelectionStart = value; }
        }
 
        public HorizontalAlignment TextAlign
        {
            get { return textBox.TextAlign; }
            set { textBox.TextAlign = value; }
        }
 
        public int TextLength
        {
            get { return textBox.TextLength; }
        }
 
        public bool WordWrap
        {
            get { return textBox.WordWrap; }
            set { textBox.WordWrap = value; }
        }
 
        #endregion
 
        #region Wrapped Methods
 
        public void ScrollToCaret()
        {
            textBox.ScrollToCaret();
        }
 
        public void Select(int start, int length)
        {
            textBox.Select(start, length);
        }
 
        public void SelectAll()
        {
            textBox.SelectAll();
        }
 
        public void Undo()
        {
            textBox.Undo();
        }
 
        #endregion
 
        #region Overridden Methods
 
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            textBox.Bounds = new Rectangle(
                1,
                1,
                ClientSize.Width - 2,
                ClientSize.Height - 2);
            Height = textBox.Height + 2;
        }
 
        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            Invalidate();
 
            if (!EnabledCaret)
                HideCaret(Handle);
        }
 
        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            Invalidate();
 
            if (!EnabledCaret)
                ShowCaret(Handle);
        }
 
        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.Clear(textBox.Focused ? SystemColors.Highlight : Color.White);
        }
 
        protected override void OnPaintBackground(PaintEventArgs e)
        {
        }
 
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            textBox.Dispose();
        }
 
        #endregion
    }
}


Hope you find this useful. If you need the Visual Studio solution then you can grab it here.