Click here to Skip to main content
Click here to Skip to main content

Windows Mobile Programming Tricks on the .NET Compact Framework: Part 2

, 23 Feb 2011
Rate this:
Please Sign up or sign in to vote.
The article provides and describes some useful code snippets for Windows Mobile/CE developers.

Introduction

This is the second part of the article about Windows Mobile programming tricks. The reason I created this article is that the following tricks either cannot be achieved using pure managed code or they are not easy to find out in the big twine of classes .NET CF provides. We found out in our company that these are some of the hurdles developers often need to overcome and decided to share the how-to. If you have any ideas on how to extend this project or would like to share additional how-tos, you are welcome to contact me.

I will show you how to:

  • SIM card
    • Get IMSI
  • Phone
    • Get IMEI
    • Get or set the volume of the phone ringer
  • Memory
    • Get the total physical memory
    • Get the mount of available memory
    • Get the amount of used memory
  • Device
    • Get or set the system volume
    • Soft reset the device

Get IMSI and/or IMEI

Finding out the IMSI (International Mobile Subscriber Identity) can be useful for several purposes. The first three digits are the country code. That way you can identify the country of the caller. The second two digits are the operator identification code. To get the IMSI of the mobile phone, we will use the following Platform Invokes:

internal class Tapi
{
    [DllImport("coredll")]
    public static extern int lineInitializeEx(out IntPtr lpm_hLineApp, 
      IntPtr hInstance, IntPtr lpfnCallback, string lpszFriendlyAppName, 
      out int lpdwNumDevs, ref int lpdwAPIVersion, 
      ref LINEINITIALIZEEXPARAMS lpLineInitializeExParams);

    [DllImport("coredll")]
    public static extern int lineOpen(IntPtr m_hLineApp, int dwDeviceID, 
      out IntPtr lphLine, int dwAPIVersion, int dwExtVersion, 
      IntPtr dwCallbackInstance, int dwPrivileges, 
      int dwMediaModes, IntPtr lpCallParams);

    [DllImport("coredll")]
    public static extern int lineNegotiateAPIVersion(IntPtr m_hLineApp, 
      int dwDeviceID, int dwAPILowVersion, int dwAPIHighVersion, 
      out int lpdwAPIVersion, out LINEEXTENSIONID lpExtensionId);

    [DllImport("cellcore")]
    public static extern int lineGetGeneralInfo(IntPtr hLine, byte[] bytes);

    [DllImport("cellcore")]
    public static extern int lineGetGeneralInfo(IntPtr hLine, 
           ref LINEGENERALINFO lineGenerlInfo);

    [DllImport("coredll")]
    public static extern int lineClose(IntPtr hLine);

    [DllImport("coredll")]
    public static extern int lineShutdown(IntPtr m_hLineApp);
}

public static string GetIMSIandIMEI()
{
    if (m_IMSI.Equals(String.Empty))
    {
        string manufacturer;
        string model;
        string revision;
        string imsi;
        string imei;

        PhoneInfo.Get(out manufacturer, out model, 
                      out revision, out imei, out imsi);
        m_IMSI = imsi;
        m_IMEI = imei;
    }

    return m_IMSI;
}

The key method in this code is the PhoneInfo.Get(...) method. The source code for this method is quite long. You can find it in the archive in the beginning of this article or on the web site shown at the bottom of this article. This method is also responsible for retrieving the IMEI (International Mobile Equipment Identity) of the phone. IMEI (sometimes also called serial number - which is not correct, because serial number is just one part of IMEI) uniquely identifies each mobile phone.

Get or set the volume of the phone ringer

The volume of the phone ringer is actually stored in the Windows Registry. However, for the changes to take effect, we need to call the AudioUpdateFromRegistry API function. So this is how we'll declare it:

[DllImport("coredll.dll")]
private static extern void AudioUpdateFromRegistry();

static readonly string KeyVolRegKey = 
   @"HKEY_CURRENT_USER\ControlPanel\Volume";
static readonly string KeyRingRegKey = 
   @"HKEY_CURRENT_USER\ControlPanel\SoundCategories\Ring";

The attached project contains a sample application which also provides a GUI to view or change the volume:

And this is the property we will use to adjust the volume:

public static int PhoneRingVolume
{
    set
    {
        long volumeValue;
        switch (value)
        {
            case 0:
                volumeValue = 0;
                break;
            case 1:
                volumeValue = (long)858993459;
                break;
            case 2:
                volumeValue = (long)1717986918;
                break;
            case 3:
            default:
                volumeValue = (long)-1717986919;
                break;
            case 4:
                volumeValue = (long)-858993460;
                break;
            case 5:
                volumeValue = (long)-1;
                break;

        }

        Registry.SetValue(KeyVolRegKey, "Ringer", volumeValue, 
                          RegistryValueKind.QWord);
        Registry.SetValue(KeyRingRegKey, "InitVol", 
                         (uint)value, RegistryValueKind.DWord);
        AudioUpdateFromRegistry();
    }
    get
    {
        switch (Convert.ToInt64((Registry.GetValue(KeyVolRegKey, 
                                 "Ringer", 2576980377))))
        {
            case 0:
                return 0;
            case 858993459:
                return 1;

            case 1717986918:
                return 2;

            case 3435973836:
            case -858993460:
                return 4;

            case 4294967295:
            case -1:
                return 5;

            case -1717986919:
            default:
                return 3;
        }
    }
}

Get information about the device memory

Being able to find out how much memory is available to us is very valuable if we want to create stable and well-performing applications. Let's say we know the minimum memory requirements of our application. If the total physical memory is less than our requirements, we can close the application and inform the user that the amount of memory is insufficient. This is certainly a better approach than trying to run the application and then finishing it with an out of memory exception. We will use this code:

public class MemoryStatus
{
    private struct MEMORYSTATUS
    {
        public uint Length;
        public uint MemoryLoad;
        public uint TotalPhys;
        public uint AvailPhys;
        public uint TotalPageFile;
        public uint AvailPageFile;
        public uint TotalVirtual;
        public uint AvailVirtual;
    }

    [DllImport("coredll.dll", EntryPoint = "GlobalMemoryStatus", SetLastError = true)]
    private static extern void GlobalMemoryStatus(ref MEMORYSTATUS lpBuffer);

    /// <summary>
    /// Retrieves information about the system's current available physical memory.
    /// </summary>
    /// <returns>Available memory in mega bytes.</returns>
    public static float GetAvailableMemory()
    {
        MEMORYSTATUS mem = new MEMORYSTATUS();
        GlobalMemoryStatus(ref mem);

        return (float)mem.AvailPhys / 1048576.0f;
    }

    /// <summary>
    /// Retrieves information about the system's current usage of physical memory.
    /// </summary>
    /// <param name="aTotalMem">Total memory in mega bytes.</param>
    /// <param name="anUsedMem">Used memory in mega bytes.</param>
    /// <param name="aFreeMem">Available memory in mega bytes.</param>
    public static void GetAvailableMemory(out float aTotalMem, 
           out float anUsedMem, out float aFreeMem)
    {
        MEMORYSTATUS mem = new MEMORYSTATUS();
        GlobalMemoryStatus(ref mem);

        aTotalMem = (float)mem.TotalPhys / 1048576.0f;
        aFreeMem = (float)mem.AvailPhys / 1048576.0f;
        anUsedMem = aTotalMem - aFreeMem;
    }
}

The attached sample project shows how to use this code to display memory information:

Get or set the system volume

The system volume is the volume level at which the Operating System plays the system sounds (e.g., if the user taps a screen or types on the keyboard). If you want to provide a user interface in your application for the user to change the system volume, you will probably use this code:

///<summary> 
/// Specifies the volume levels.
/// </summary>
public enum Volumes : int
{
    OFF = 0,
    LOW = 858993459,
    NORMAL = 1717986918,
    MEDIUM = -1717986919,
    HIGH = -858993460,
    VERY_HIGH = -1
}


/// <summary>
/// Allows you to change the volume on Windows Mobile.
/// </summary>
public class VolumeControl
{
    [DllImport("coredll.dll", SetLastError = true)]
    internal static extern int waveOutSetVolume(IntPtr device, int volume);

    [DllImport("coredll.dll", SetLastError = true)]
    internal static extern int waveOutGetVolume(IntPtr device, ref int volume);

    public static Volumes Volume
    {
        get
        {
            int v = (int)0;

            waveOutGetVolume(IntPtr.Zero, ref v);

            switch (v)
            {
                case (int)Volumes.OFF:
                    return Volumes.OFF;

                case (int)Volumes.LOW:
                    return Volumes.LOW;

                case (int)Volumes.NORMAL:
                    return Volumes.NORMAL;

                case (int)Volumes.MEDIUM:
                    return Volumes.MEDIUM;

                case (int)Volumes.HIGH:
                    return Volumes.HIGH;

                case (int)Volumes.VERY_HIGH:
                    return Volumes.VERY_HIGH;

                default:
                    return Volumes.OFF;
            }
        }
        set
        {
            waveOutSetVolume(IntPtr.Zero, (int)value);
        }
    }
}

Perform a soft reset

Performing a soft reset can be useful sometimes, especially after making changes to the system which only show up after the reset. We can call this routine to perform the soft reset of the user's device so that the changes take effect immediately. We should never ever forget though to ask the user first whether they agree with the soft reset. Resetting the device without asking is considered very rude and can cause loss of data for the user as well.

///<summary> 
/// Represents a functionality to reset the whole device.
/// </summary>
public class ResetDevice
{
    private const uint FILE_DEVICE_HAL = 0x00000101;
    private const uint METHOD_BUFFERED = 0;
    private const uint FILE_ANY_ACCESS = 0;

    private static uint CTL_CODE(uint DeviceType, 
            uint Function, uint Method, uint Access)
    {
        return ((DeviceType << 16) | (Access << 14) | 
                (Function << 2) | Method);
    }

    [DllImport("Coredll.dll")]
    private extern static uint KernelIoControl
    (
        uint dwIoControlCode,
        IntPtr lpInBuf,
        uint nInBufSize,
        IntPtr lpOutBuf,
        uint nOutBufSize,
        ref uint lpBytesReturned
    );

    /// <summary>
    /// Reset device.
    /// </summary>
    /// <returns></returns>
    public static uint ResetPocketPC()
    {
        uint bytesReturned = 0;
        uint IOCTL_HAL_REBOOT = CTL_CODE(FILE_DEVICE_HAL, 15,
          METHOD_BUFFERED, FILE_ANY_ACCESS);
        return KernelIoControl(IOCTL_HAL_REBOOT, IntPtr.Zero, 0,
          IntPtr.Zero, 0, ref bytesReturned);
    }
}

Conclusion

This concludes the second part of the article. All the source code along with a sample application can be downloaded at the beginning of this article or from the Bee Mobile web site at http://beemobile4.net/?mod=products&action=det&id=3. The whole source code is part of Bee Mobile's Free Utils project. The goal of Free Utils project is to put together source code which shows how to overcome some typical hurdles of Windows Mobile / Windows CE development in the .NET Compact Framework environment.

The first part of this article is available here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Vladimir Gregor(Beemobile)
G&M Dynamics, s.r.o.
Slovakia Slovakia
I work for Bee Mobile.
 
Web site: http://beemobile4.net
Facebook site: http://facebook.com/BeeMobile
YouTube Channel: http://youtube.com/beemobile4dotnet
Follow on   Twitter

Comments and Discussions

 
QuestionTested with MC 55 Pinmemberkhinezw20-Sep-11 22:44 
AnswerRe: Tested with MC 55 PinmemberVladimir Gregor(Beemobile)21-Sep-11 1:57 
GeneralRe: Tested with MC 55 Pinmemberkhinezw21-Sep-11 17:49 
GeneralRe: Tested with MC 55 PinmemberVladimir Gregor(Beemobile)21-Sep-11 23:18 
GeneralRe: Tested with MC 55 Pinmemberkhinezw27-Sep-11 17:43 
GeneralRe: Tested with MC 55 PinmemberVladimir Gregor(Beemobile)28-Sep-11 4:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140902.1 | Last Updated 23 Feb 2011
Article Copyright 2011 by Vladimir Gregor(Beemobile)
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid