Determining the type of a device at runtime

There are times when it is useful for an application to know on what type of device it is running.  An application may wish to modify it's user interface depending on device type (suppress button controls on SmartPhone devices, for example), or may be part of a test harness and have a need to log the type of device on which testing was performed.

On Win32 platforms, including Windows CE, the function SystemParametersInfo provides a mechanism to get and set system-wide parameters on a device.  The data returned by SystemParametersInfo (via the pvParam argument) can vary in type.  Depending on the system parameter you request, the function can return a string, an integer, a structure, etc.  This makes it a difficult function to call from managed code.  We can make it using SystemParametersInfo easier by writing type safe wrappers for the specific system parameters of interest.  Today's discussion will do just that for SPI_GETPLATFORMTYPE.

The snippet below shows a simple wrapper function which calls SystemParametersInfo to request the device (platform) type.

//--------------------------------------------------------------------- //THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY //KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE //IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A //PARTICULAR PURPOSE. //---------------------------------------------------------------------/// <summary>/// Get the device (platform) type of the device/// </summary>/// <param name="szDeviceType">/// The string to hold the device type/// </param>/// <param name="length">/// The length of the string (szDeviceType)/// </param>/// <returns>/// True if the device type was successfully retrieved, false otherwise)/// </returns>BOOL GetDeviceType(WCHAR* szDeviceType, DWORD length){    // TODO: Add parameter validation code here.     return SystemParametersInfo(SPI_GETPLATFORMTYPE,                                 length * sizeof(WCHAR),  // buffer size (length * character size)                                szDeviceType,            // output buffer                                 0); }

As you can see, the wrapper is very simple.  The code forwards the arguments from the wrapper function to SystemParametersInfo and sends the results directly back to the caller.  This wrapper is type safe and much easier to call from managed code.

My managed application can now easily determine the type of the device.  Please note that for this example, the name of the DLL containing the above function is devicetype.dll and that the above "as is" banner also applies.

using System;using System.Runtime.InteropServices;using System.Text;using System.Windows.Forms;class DeviceType{    // P/Invoke definition    [DllImport("devicetype.dll", SetLastError=true)]    private extern static Boolean GetDeviceType(StringBuilder deviceTypeName,                                                 Int32 length);    /// <summary>    /// Application entry point    /// </summary>    public static void Main()    {        String message = "Unknown";        try        {            // create a string builder and specify its capacity            StringBuilder deviceType = new StringBuilder(256);            // call our wrapper function            Boolean success = GetDeviceType(deviceType,                                             deviceType.Capacity);            if(success)            {                message = deviceType.ToString();            }        }        catch(Exception ex)        {            message = String.Format("GetDeviceType failed with exception: {0}",                                     ex.GetType().ToString());        }        // display our findings        MessageBox.Show(message, "Device Type Check");    }}

Running this example on a SmartPhone device displays a message box containing "SmartPhone" and a Pocket PC device displays "Pocket PC".  If desired, your application can use this information to customize its behavior.

Please note: Since we need to allow native code do modify the string, we must use a StringBuilder in our P/Invoke signature. 

Enjoy!
-- DK

Disclaimer(s):
This posting is provided "AS IS" with no warranties, and confers no rights.