Over a million developers have joined DZone.

Windows Phone Native Series - ExitApplication, PlaySystemSound, GetSystemInformation

DZone's Guide to

Windows Phone Native Series - ExitApplication, PlaySystemSound, GetSystemInformation

· Mobile Zone ·
Free Resource

As a continuation of the Windows Phone Native series, I decided to add some very basic methods to the native wrapper I am working with. It acts as an extension to the stock SDK and is able to invoke capabilities that are not (yet) exposed through managed APIs.

NOTE: I am making the assumption that you are already following my series and have the basics ready to extend the project. If not, head over here and read the introduction article.


So let's say you want to exit the application. There is the standard Exit method that can be implemented by adding a reference to Microsoft.Xna.Framework. It is a generally accepted practice not to use it in Silverlight applications, when there are more acceptable methods, like cleaning the backstack. However, for research purposes, I should mention that there is also a way to natively exit an application, and even associate an exit code with it. Take a look at this method:

STDMETHODIMP CNativeAPI::ExitApplication()

	return S_OK;

Simply by invoking the exit method, I am able to terminate my own application. All that needs to be done additionaly is adding the proper declarations in the IDL and the header files.


Moving on, you now want to play the system beep sound. There is the MessageBeep function, that in a standard Windows OS has multiple possible variations, like  MB_ICONINFORMATION, MB_ICONWARNING or MB_OK. In this case, there is only one standard sound (there should be more, given that this data is parameterized in Guide.BeginShowMessageBox) that can be passed through an uint value. So the method is quite simple:

STDMETHODIMP CNativeAPI::PlaySystemSound(UINT sound)
	BOOL result = MessageBeep(sound);

	if (result)
		return S_OK;
		return 0x80070000 | ::GetLastError();

You might be asking - why am I asking the user to add a uint value when there is only one sound available? The MessageBeep method itself doesn't work without a parameter. Therefore, hardcoding a value will not make much sense, since OS settings might eventually change.


This is a function that is called to return information about the CPU the OS is running on. It relies on a SYSTEM_INFO struct that contains the associated DWORD and WORD values. Here is a quick and dirty approach to read the system data:

STDMETHODIMP CNativeAPI::GetSystemInformation(SYSTEM_DATA* retData)

	sysData.AllocationGranularity = data.dwAllocationGranularity;
	sysData.NumberOfProcessors = data.dwNumberOfProcessors;
	sysData.PageSize = data.dwPageSize;
	sysData.OEMID = data.dwOemId;
	sysData.ProcessorType = data.dwProcessorType;
	sysData.ActiveProcessorMask = data.dwActiveProcessorMask;
	sysData.ProcessorLevel = data.wProcessorLevel;
	sysData.ProcessorRevision = data.wProcessorRevision;
	sysData.ProcessorArchitecture = data.wProcessorArchitecture;
	*retData = sysData;

	return S_OK;

You can see that there is also the so-called SYSTEM_DATA struct. It is a custom implemenation that I introduced for readability and portability reasons. It is declared in the IDL file that is associated with the main library. Just like this:

typedef struct _SYSTEM_DATA {
	DWORD PageSize;
	DWORD ActiveProcessorMask;
	DWORD NumberOfProcessors;
	DWORD ProcessorType;
	DWORD AllocationGranularity;
	WORD ProcessorLevel;
	WORD ProcessorRevision;
	WORD ProcessorArchitecture;

Once I invoke GetSystemInfo, I simply "transport" the data to a new struct. The same struct will be used in managed code. Given that the methods are declared correctly on the native side and the DLL compiles correctly, the managed snippet will now be composed of three parts. 

The class declaration:

[ComImport, ClassInterface(ClassInterfaceType.None), Guid("8848DEB3-66B6-4AE3-A6F6-4A9C2F6595A5")]
public class CNativeAPI

The interface declaration:

[ComImport, Guid("57C3A135-837D-486F-93E3-BF878F61892B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INativeAPI
    [return: MarshalAs(UnmanagedType.BStr)]
    string GetDeviceDriverInformation();

    void PlaySystemSound(uint sound);

    void ExitApplication();

    // Mainly CPU information.
    // ProcessorType
    // 2577 - STRONGARM
    // ProcessorLevel
    // 5 - ARMV5 (http://msdn.microsoft.com/en-us/library/ee488780.aspx)
    // Apparently the same applies to the OEM identificator.
    SYSTEM_DATA GetSystemInformation();

The struct declaration for GetSystemInformation:

public  struct SYSTEM_DATA 
    public uint PageSize;
    public uint ActiveProcessorMask;
    public uint NumberOfProcessors;
    public uint ProcessorType;
    public uint AllocationGranularity;
    public ushort ProcessorLevel;
    public ushort ProcessorRevision;
    public uint OEMID;
    public ushort ProcessorArchitecture;

You can simply invoke the informational call with a snippet similar to this:

SYSTEM_DATA data = NativeAPIHook.GetSystemInformation();

Since the values you will be getting are integers, you need to look up their meaning in the official MSDN documentation for Windows CE and Mobile, given that those are constants and are not self-explanatory (e.g. NumberOfProcessors will return 1).


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}