Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
4/7/2010

Jim Wilson, JW Hedgehog, Inc.

November 2007

Summary

This paper describes how you can programmatically control the Device Emulator from your .NET applications using the new Device Emulator Manager API included with Microsoft® Visual Studio® 2008. This paper also demonstrates how to simplify Device Emulator Manager API programming through a few simple wrapper classes.

Download DEMAutomationWrapper.msi from the Microsoft Download Center.

Applies To

Microsoft Visual Studio 2008

Microsoft Device Emulator Manager

Microsoft Device Emulator

Microsoft Windows Mobile® 6 Professional

Microsoft Windows Mobile 6 Standard

Microsoft Windows Mobile 6 Classic

Microsoft Windows Mobile 5.0 for Pocket PC Phone Edition

Microsoft Windows Mobile 5.0 for Smartphone

Microsoft Windows Mobile 5.0 for Pocket PC

Microsoft Pocket PC 2003 SE

Microsoft Smartphone 2003 SE

Introduction

Testing is an important step in developing quality applications, and the Device Emulator is an important tool for testing Windows Mobile applications. The Device Emulator Manager allows you to interactively perform many common tasks such as starting the Device Emulator, saving the Device Emulator state, cradling the Device Emulator, and so on. The one challenge has been that the interactive nature of the Device Emulator requires that a person carry out these tasks through the Device Emulator Manager user interface, making automated testing using the Device Emulator Manager and Device Emulator difficult.

Device Emulator Manager and Device Emulator 3.0, automatically installed as part of Visual Studio 2008, eliminate this challenge through the inclusion of the Device Emulator Manager API. The Device Emulator Manager API provides programmatic access to all of the same Device Emulator management features that the Device Emulator Manager user interface provides. Using the Device Emulator Manager API, you can write desktop applications that automate starting a Device Emulator, stopping a Device Emulator, cradling a Device Emulator, and so on.

The Device Emulator Manager API provides support for .NET Framework applications, native C/C++ applications, and scripting environments such as the Microsoft Windows® Script Host. The focus of this paper is on using the Device Emulator Manager API from the .NET Framework.

Note:
For examples of using the Device Emulator Manager API from native C/C++ or scripting environments, see Automating the Device Emulator Manager Using the IDeviceEmulatorManager Interface .

This paper addresses the Device Emulator Manager API in two parts. First, the paper covers programming with Device Emulator Manager API directly as it is imported into the .NET environment.

The second part of the paper introduces wrapper classes that simplify working with the Device Emulator Manager API from .NET and give the Device Emulator Manager API a more .NET feel.

The Device Emulator Manager API

The Device Emulator Manager API is implemented as a Component Object Model (COM) In-Process Library. The .NET assembly file Microsoft.DeviceEmulatorManager.Interop.9.0.dllprovides access to the Device Emulator Manager API from managed code. The classes and interfaces of the Device Emulator Manager API appear to .NET applications just as they are implemented and do not provide any abstraction over their COM characteristics. For this reason, you’ll find that you sometimes deal directly with COM error codes, also known as HRESULTs, and COMExceptionswhen working with the API.

Note:
This paper offers one possible .NET abstraction for the Device Emulator Manager API. This abstraction is discussed in the second part of this paper.

To use the Device Emulator Manager API from .NET, you need to include a reference to the Microsoft.DeviceEmulatorManager.Interop.9.0assembly. The assembly does not appear in the Visual Studio 2008 Add Reference dialog box list of .NET assemblies; you’ll need to browse to the Microsoft.DeviceEmulatorManager.Interop.9.0.dllassembly file located in the % Program Files%\Microsoft Device Emulator\1.0 folder. All of the types in the Device Emulator Manager API are in the "Microsoft.DeviceEmulatorManager.Interop" namespace. When working with the Device Emulator Manager API, you'll also want to include a using statement (C#) or project Import (Visual Basic .NET) for the "System.Runtime.InteropServices" namespace so that you handle any COMExceptionsthat API may throw.

Note:
The Device Emulator Manager and Device Emulator are always upgraded in place and therefore overwrite the previous version. For this reason, all versions of the Device Emulator Manager and Device Emulator are located in the 1.0 folder under the % Program Files%\Microsoft Device Emulator folder irrespective of their actual version.

Controlling the Device Emulator

The most common Device Emulator API interface you use is the IDeviceEmulatorManagerVMIDinterface. The IDeviceEmulatorManagerVMIDinterface represents an individual Device Emulator image such as Windows Mobile 5.0 Pocket PC, Pocket PC 2003 SE, or Windows Mobile 6 Standard. Using the IDeviceEmulatorManagerVMIDinterface, you can programmatically perform the actions exposed by the Device Emulator Manager user interface. Table 1 shows the IDeviceEmulatorManagerVMIDinterface methods and corresponding descriptions.

Table 1. IDeviceEmulatorManagerVMID Interface Methods

Method Description

BringToFront

Moves the Device Emulator to the foreground of the desktop display and makes the Device Emulator the active application.

ClearSaveState

Clears the Device Emulator's saved state file (.dess). The next time you start the Device Emulator, the Device Emulator will have no existing state and will start from the ROM image. The Device Emulator will therefore appear as a new device. Any software you have installed or setting changes you have made are lost.

Connect

Starts the Device Emulator.

Cradle

Puts the Device Emulator in the virtual cradle and causes the Device Emulator to connect to the desktop using Microsoft ActiveSync® (Windows XP) or Windows Mobile Device Center (Windows Vista®).

get_Name

Returns the display name of the emulator such as Windows Mobile 6 Professional Emulator or Windows Mobile 5.0 Smartphone. The display name is the same value that appears in the Device Emulator Manager user interface's list of Device Emulators.

get_State

Returns the EMULATOR_STATEenumeration value corresponding to the Device Emulator's current state. Possible values are EMU_NOT_RUNNING, EMU_RUNNING, and EMU_CRADLED. A Device Emulator is in only one state at a time.

get_VMID

Returns the Device Emulator's Virtual Machine Identifier (VMID), which is a globally unique identifier (GUID) unique to each emulator image.

GetConfiguration

Returns an XML string describing the Device Emulator's current configuration.

Reset

Performs a soft-reset or hard-reset of the Device Emulator as specified by the passed integer parameter. A non-zero parameter value specifies a soft-reset.

SetConfiguration

Sets the Device Emulator to the configuration described in the provided XML string parameter.

Shutdown

Shuts down the Device Emulator, optionally saving the Device Emulator's state as specified by the passed integer parameter. A non-zero parameter value specifies that the state should be saved.

UnCradle

Removes the Device Emulator from the virtual cradle and causes the Device Emulator to disconnect from ActiveSync (Windows XP) or Windows Mobile Device Center (Windows Vista).

Note:
The GetConfigurationand SetConfigurationmethods provide a wide variety of capabilities; a separate paper will discuss the capabilities of these functions in detail.

The following code sample demonstrates how to cradle an emulator using the IDeviceEmulatorManagerVMIDinterface.

Copy Code
void CradleEmulator(IDeviceEmulatorManagerVMID theEmulator)
{
	if (theEmulator != null)
		throw new ArgumentException("Must provide a valid
reference");
	EMULATOR_STATE state = theEmulator.get_State();
	if (state == EMULATOR_STATE.EMU_NOT_RUNNING)
		theEmulator.Connect(); // start emulator
	if (state != EMULATOR_STATE.EMU_CRADLED)
		theEmulator.Cradle(); // cradle to start ActiveSync
	else
		theEmulator.BringToFront();
}

To cradle the emulator, the emulator must already be running; therefore, the preceding sample code gets the emulator state by calling the get_Statemethod and then checks to see if the current state indicates that the emulator is not running. If this is the case, the program starts the emulator by calling the Connectmethod. The program then checks the emulator state to see if the emulator is already cradled. If necessary, the program then cradles the emulator by calling the Cradlemethod; cradling the emulator initiates the emulator's connection to ActiveSync (Windows XP) or Windows Mobile Device Center (Windows Vista). If the emulator is already cradled, the program gives the emulator focus by calling the BringToFrontmethod.

Understanding the Device Emulator Manager Hierarchy

The beauty of the Device Emulator Manager API is that interacting with and controlling a Device Emulator is quite easy. To work with any of the Device Emulators you must first navigate through the Device Emulator Manager hierarchy.

The Device Emulator Manager hierarchy is divided into three layers. At the highest level are the categories. Categories are used to group Windows Mobile Software Development Kits (SDKs). Each SDK contains a list of Device Emulators. To locate a specific Device Emulator, you need to traverse the layers of the hierarchy above it.

Note:
The next several sections discuss the details of programmatically working with the COM-style features of the Device Emulator Manager API hierarchy. You are encouraged to read these sections to get a better understanding of the API. However, if you have only limited time available you may want to jump ahead to the A Device Emulator Manager Wrappersection, which discusses a simplified Device Emulator Manager API programming model.

To get started with the Device Emulator Manager API, you must first create an instance of the Device Emulator Manager. You do this by creating an instance of the DeviceEmulatorManagerClassclass. This class encapsulates the COM component that represents the Device Emulator Manager. When working with the Device Emulator Manager, you can use the DeviceEmulatorManagerClassclass directly or use the IDeviceEmulatorManagerinterface. Both the class and the interface provide all of the same methods. For consistency with the interface-based nature of COM, this paper uses the interface as shown in the following code sample.

Copy Code
IDeviceEmulatorManager _emulatorManager;
_emulatorManager = new DeviceEmulatorManagerClass();

Working with the Category List

Once you have a reference to the Device Emulator Manager, you can start working with the first level of the hierarchy, the categories. Two points that you should be aware of when iterating through the list of categories are the multifaceted nature of the IDeviceEmulatorManagerinterface and the way the IDeviceEmulatorManagerinterface indicates the end of the list. First, the multifaceted nature of the IDeviceEmulatorManagerinterface. The IDeviceEmulatorManagerinterface plays three distinct roles: the Device Emulator Manager, the enumerator over the list of categories, and the current category in the list. When working with the individual interface methods you'll want to be certain that you understand to which of these three identities the specific method applies. The other point is the way that the IDeviceEmulatorManager.MoveNextmethod indicates that there are no more categories left, which is to throw a COMException. The following sample demonstrates aspects of both points.

Copy Code
void ListDEMCategoryMembers(IDeviceEmulatorManager emulatorManager)
{
	const int END_OF_DATA = -2147024637;
	string categoryName;
	emulatorManager.Reset(); // Ensure that at beginning of
categories

	try
	{
		while (true)
		{
			categoryName = emulatorManager.get_Name();
			Console.WriteLine(categoryName);
			ListDEMSdkMembers(emulatorManager); // SDKs for this
category

			_mulatorManager.MoveNext();
	}
}
	catch (COMException ex)
	{
		if (ex.ErrorCode != END_OF_DATA)
			throw ex;
}
} 

As mentioned previously, the IDeviceEmulatorManagerinterface represents multiple roles. You can see in the preceding sample code that the IDeviceEmulatorManagerreference, emulatorManager, exposes the methods Reset, MoveNext, and get_Name. The first two methods allow you to work with the category enumerator. The Resetmethod positions the emulatorManagerreference at the beginning of the category list; the MoveNextmethod advances the emulatorManagerreference to the next category in the list. The get_Namemethod returns the name of category at the emulatorManager's current position in the category list thereby representing the current category. This code sample does not show any of the IDeviceEmulatorManagermethods that represent the Device Emulator Manager role, however upcoming code samples will. Similar multi-role behavior is repeated in the IEnumManagerSDKsinterface discussed in the next section.

With regard to the way that the MoveNextmethod indicates that no categories remain, notice that the loop iterating over the category list uses a truevalue as the exit condition for the whileloop. Using a truevalue within the loop condition often indicates an endless loop, but not in this case. As you can see, the whileloop is contained within the tryportion of a try/ catchblock. The way this code is written, the only way to exit the whileloop is for one of the Device Emulator Manager API methods to throw an exception. In fact, that is how the MoveNextmethod exits the loop.

Being written as a COM component, the Device Emulator Manager API uses numeric codes known as HRESULTs to indicate the success or failure of each method call; in most cases a zero-value HRESULT indicates success. In addition to success or failure, HRESULTs can also indicate a state change such as reaching the end of a list. In the case of the MoveNextmethod, this is exactly what happens.

When the call to the MoveNextmethod causes the emulatorManagerto advance beyond the end of the category list, the MoveNextmethod returns a specific HRESULT value (-2147024637) to the COM layer to indicate that no further data exists in the category list. The .NET Interoperability layer interprets the non-zero HRESULT value as an error and translates the HRESULT into a COMException. With this being the case, the .NET Interoperability layer will always raise a COMExceptionwhen reaching the end of the category list; the preceding code catches the exception outside of the whileloop and checks the COMExceptionHRESULT. When the HRESULT is the expected end-of-data value the program continues normally, otherwise the COMExceptionis re-thrown. The Device Emulator Manager SDK enumerator and Device Emulator enumerator indicate the end-of-data in this same way.

Working with the SDK List

Working with the SDK list is very similar to working with the category list. Each category has its own list of SDKs; therefore, each category has a separate SDK enumerator. The Device Emulator Manager API exposes each SDK enumerator through the IEnumManagerSDKsinterface. You access the SDK enumerator for a specific category through the IDeviceEmulatorManager.EnumerateSDKsmethod for that category. Similar to the IDeviceEmulatorManagerinterface, the IEnumManagerSDKsinterface plays multiple roles acting as both the SDK list enumerator and the current SDK in the list.

The following code sample demonstrates how to iterate over the list of SDKs for a particular category. The method in this sample code is called once for each iteration of the loop within the ListDEMCategoryMembersmethod shown in the previous sample code.

Copy Code
void ListDEMSdkMembers(IDeviceEmulatorManager emulatorManager)
{
	const int END_OF_DATA = -2147024637;
	string sdkName;
	IEnumManagerSDKs sdkEnum = emulatorManager.EnumerateSDKs();
	sdkEnum.Reset();

	try
	{
		while (true)
		{
			sdkName = sdkEnum.get_Name();
			Console.WriteLine("\t"+sdkName);
			ListDEMEmulators(sdkEnum);
			sdkEnum.MoveNext();
	}
}
	catch (COMException ex)
	{
		if (ex.ErrorCode != END_OF_DATA &&
			ex.ErrorCode !=
DeviceEmulatorManagerErrorCodes.E_ENUMSDK_NOT_LOADED)
			throw ex;
}
}

Just as was the case in the earlier sample code for iterating over the category list, the Device Emulator Manager API indicates the end of the SDK list through a COMExceptionwith an HRESULT value of -2147024637. In addition to the catchblock handling the end of the SDK list HRESULT, this code sample includes a check for an additional HRESULT. This additional HRESULT check handles the case of a category that contains no SDKs.

The Device Emulator Manager API is implemented such that the Resetmethod positions the enumerator at the first item in the list and you cannot call the MoveNextmethod until you no longer need the first list item, because the call to the MoveNextmethod immediately advances the enumerator to the next member in the list. What this means is that there is no method call you can make that will indicate that the list is empty (in other words a category with no SDKs). The only way to know that the SDK list is empty is to call one of the methods that represent the current list item, such as the get_Namemethod. When you call the get_Namemethod when no SDK is available, the method returns an HRESULT value that corresponds to the constant DeviceEmulatorManagerErrorCodes.E_ENUMSDK_NOT_LOADED, which the .NET Interoperability layer translates into a COMExceptioncontaining this same HRESULT. Like when reaching the end of the list, the program catches the COMExceptionand checks that the HRESULT has the expected value, if not, the COMExceptionis re-thrown.

Working with the Emulator List

The IEnumVMIDsinterface represents the list enumerator for the Device Emulators within an SDK. Working with the emulator list is very much like working with the SDK list. The following code sample demonstrates how to iterate over the list of Device Emulators. The method shown in this code sample, ListDEMEmulators, is called once for each iteration of the loop within the ListDEMSdkMembersmethod shown in the previous sample code.

Copy Code
void ListDEMEmulators(IEnumManagerSDKs sdkEnum)
{
	string emulatorName;
	IDeviceEmulatorManagerVMID theEmulator;
	IEnumVMIDs vmidEnum = sdkEnum.EnumerateVMIDs();
	vmidEnum.Reset();

	try
	{
		while (true)
		{
			theEmulator = vmidEnum.GetVMID();
			emulatorName = theEmulator.get_Name();
			Console.WriteLine(emulatorName);
			vmidEnum.MoveNext();
	}
}
	catch (COMException ex)
	{
		if (ex.ErrorCode != END_OF_DATA &&
			ex.ErrorCode !=
DeviceEmulatorManagerErrorCodes.E_ENUMVMID_INVALID_VMID &&
					ex.ErrorCode !=
DeviceEmulatorManagerErrorCodes.E_ENUMVMID_NOT_LOADED)
			throw ex;
}
}

One minor difference in looping through the Device Emulator list as compared to the SDK list is the error codes you must handle in the case of an empty list. When working with the SDK list, the enumerator always returns DeviceEmulatorManagerErrorCodes.E_ENUMSDK_NOT_LOADED, whereas the Device Emulator enumerator indicates an empty list by returning DeviceEmulatorManagerErrorCodes.E_ENUMVMID_INVALID_VMIDin some cases and DeviceEmulatorManagerErrorCodes.E_ENUMVMID_NOT_LOADEDin others. For this reason, the catchblock must check for both of these HRESULTs in addition to the end-of-data HRESULT.

Unlike the IDeviceEmulatorManagerand IEnumManagerSDKsinterfaces, which each represent both their list enumerator and the current item in their list, the IEnumVMIDsinterface represents only the Device Emulator list enumerator. To access an individual Device Emulator enumerator, you use the IDeviceEmulatorManagerVMIDinterface. Through this interface you can access not only the emulator name but gain full control of the Device Emulator including all of the capabilities shown earlier in the Controlling the Device Emulatorsection of this paper.

Accessing a Device Emulator

The Device Emulator Manager API does not provide any facility for directly accessing a Device Emulator; you loop through the layers of the hierarchy to find a particular Device Emulator. For this reason, one of the most important facilities to have for the Device Emulator Manager API is a Findmethod. To create a Findmethod you combine the category, SDK, and Device Emulator iteration code from the previous three code samples adding a condition in the Device Emulator iteration code to locate the Device Emulator of interest by matching its name.

A complete implementation of a Device Emulator Manager API Findmethod is available at Windows Mobile Device Emulator Programmability - Just Needs a Find-Emulator Function .

Monitoring for Changes

The information in the Device Emulator Manager hierarchy can change for a variety reasons: a user installs or uninstalls a SDK, a user creates or deletes an emulator configuration, an application creates or deletes an emulator configuration, and so on. The Device Emulator Manager API provides notification of such changes through a Win32® synchronization event object.

You should monitor for changes in the Device Emulator Manager hierarchy to be aware of any new items but more importantly to avoid any unexpected issues that may occur as a result of the removal of one of the Device Emulator Manager objects.

To monitor for changes in the Device Emulator Manager hierarchy, you must create a named Win32 synchronization event object and pass the name of event object to the IDeviceEmulatorManager.RegisterRefreshEventmethod. You must then launch a thread that blocks on the event. If any changes in Device Emulator Manager hierarchy occur, the Device Emulator Manager will signal the synchronization event. The following code sample demonstrates how to monitor for a change in the Device Emulator Manager hierarchy.

Copy Code
const string refreshEventName = "MyApplication.Refresh";
EventWaitHandle _refreshEvent;
Thread _refreshEventThread;
volatile bool _shutDownRequested = false; 
private void SetupEventListener(IDeviceEmulatorManager emulatorMgr)
{
	// Create the event
	_refreshEvent = 
	new EventWaitHandle(false, EventResetMode.AutoReset,
refreshEventName);
	// Start thread to monitor for changes
	_shutDownRequested = false;
	_refreshEventThread = new Thread(RefreshEventMonitor);
	_refreshEventThread.Start();
	// Notify Device Emulator Manager API of event name
	emulatorMgr.RegisterRefreshEvent(refreshEventName);
}

void RefreshEventMonitor()
{
	while (!_shutDownRequested)
	{
		bool signaled = _refreshEvent.WaitOne();
		if (signaled && !_shutDownRequested)
			// hierarchy has changed
}
}

private void ShutdownEventListener(IDeviceEmulatorManager
emulatorMgr)
{
   // Tell Device Emulator Manager that we're done listening
	emulatorMgr.UnRegisterRefreshEvent();
   // Bring down thread monitoring the refresh event
	_shutDownRequested = true;
	_refreshEvent.Set();
	_refreshEventThread.Join();
   // Release event
	_refreshEvent.Close();
}

The code that actually monitors for changes to the Device Emulator Manager hierarchy is in the RefreshEventMonitormethod. This method runs on a thread separate from the main application. Anytime the synchronization event signals, RefreshEventMonitorperforms the appropriate action to deal with the Device Emulator Manager hierarchy changes. Each instance of the DeviceEmulatorManagerClassand the related Device Emulator Manager classes cache the list of objects in the Device Emulator Manager hierarchy; therefore, most applications should call the IDeviceEmulatorManager.Refreshmethod to update this cached list. Other actions may include re-reading the contents of the Device Emulator Manager hierarchy, updating any cached references your program holds to one of the Device Emulator Manager objects, and so on. When these actions are complete, the RefreshEventMonitormethod then goes back to monitoring for changes.

Note:
Because the function monitoring the refresh synchronization event runs on a thread separate from the main application thread, use caution if you call the IDeviceEmulatorManager.Refreshmethod from this thread, as the update to the Device Emulator Manager hierarchy may cause problems with code using the hierarchy on the main application thread. For information on synchronizing activities between threads, C# developers should see Thread Synchronization from C# Programming Guide; Visual Basic .NET developers should see Thread Synchronization from Visual Basic Language concepts.

The RefreshEventMonitorcontinues monitoring for changes until the class-level field, _shutDownRequested, is set to true. Notice that the _shutDownRequestedfield is declared with the volatilekeyword; this is necessary because the thread that modifies the field value is separate from the thread that reads the field value. Without the volatilemodifier, the thread monitoring for refresh events may cache the value of the _shutDownRequestedfield, possibly causing the thread to miss the main application thread's change to the field value.

The code to start the process of monitoring for changes to the Device Emulator Manager hierarchy is contained in the SetupEventListenermethod. This method starts by creating a named Win32 synchronization AutoResetevent object. As an AutoResetsynchronization event, the synchronization event guarantees that the RefreshEventMonitormethod will carry out exactly one iteration of the whileloop; the next time the RefreshEventFunctioncalls the _refreshEvent.WaitOnemethod, the thread is guaranteed to block again. The event name can be any value you like but should be a value that is not likely to collide with event names that other programs may use.

Note:
For information on working with threads using AutoReset and ManualReset events, see EventWaitHandle, AutoResetEvent, and ManualResetEvent and Managed Threading in the MSDN® library.

Once the program creates the synchronization event, the program then goes on to start the thread on which the RefreshEventMonitormethod runs. Finally, the program informs the Device Emulator Manager API of the name of the event to signal if the Device Emulator Manager hierarchy changes.

When the program no longer needs to monitor the Device Emulator Manager API for changes, most likely just before the application exits, the ShutdownEventListenermethod takes care of the details. The ShutdownEventListenermethod first calls the IDeviceEmulatorManager.UnRegisterRefreshEventmethod to inform the Device Emulator Manager API that the program no longer needs to be notified of changes. The method then shuts down the RefreshEventMontorthread and releases the synchronization event.

A Device Emulator Manager Wrapper

The Device Emulator Manager API is very powerful but it does require you to work directly with the COM behavior of the API. Encapsulating these details and wrapping the API in a way more consistent with .NET would simplify working with the API. For example, much of the details of working with the category, SDK, and Device Emulator lists would be much simpler if they were exposed as .NET collections. Similarly, handling Device Emulator Manager hierarchy refresh notifications would be much easier if exposed as a traditional .NET event.

To make working with the Device Emulator Manager API a little more .NET friendly, this paper includes a set of classes that encapsulate the features of the API and expose them in more of a .NET fashion.

Working with Categories, SDKs, and Device Emulators

One of the things that can sometimes be confusing is that the Device Emulator Manager API interfaces do not always differentiate between a list of objects and the individual objects in the list. For example, the IDeviceEmulatorManagerinterface represents the Device Emulator Manager, the list of categories, and an individual category. The wrapper avoids this confusion by providing individual classes for each object. Table 2 shows the list of classes and their descriptions.

Table 2. Classes for the Device Emulator Manager Objects

Type Description

DeviceEmulatorManagerEx

Represents the Device Emulator Manager. Encapsulates the Device Emulator Manager features of the IDeviceEmulatorManagerinterface.

DeviceEmulatorCategory

Represents an individual category. Encapsulates those features of the IDeviceEmulatorManagerinterface that represent a single category.

DeviceEmulatorSdk

Represents an individual SDK. Encapsulates those features of the IEnumManagerSDKsinterface that represent a single SDK.

DeviceEmulator

Represents an individual Device Emulator. Provides the same features as the IDeviceEmulatorManagerVMIDinterface.

With the exception of the DeviceEmulatorclass, the classes in Table 2 are relatively simple. In general they expose a Nameproperty and a collection representing the next level of the hierarchy.

Working with Collections

As mentioned earlier in this paper, the most significant issue in working with the Device Emulator Manager API is that the hierarchy of lists is exposed in a COM-style representation rather than as .NET collections. The logical thing to do is provide .NET collections for each level of the lists in the hierarchy. Table 3 shows the collection classes.

Table 3. Collection Classes for the Device Emulator Manager Lists

Collection Description

DeviceEmulatorCategoryCollection

Represents a list of categories. Encapsulates the category enumeration features of the IDeviceEmulatorManagerinterface.

DeviceEmulatorSdkCollection

Represents a list of SDKs. Encapsulates the enumeration features of the IEnumManagerSDKsinterface.

DeviceEmulatorCollection

Represents a list of Device Emulators. Encapsulates enumeration features of the IEnumVMIDsinterface.

With the collection classes defined, each of the wrapper classes in the Device Emulator Manager hierarchy can expose the list of objects in the next level of the hierarchy as a simple collection property. Table 4 shows the collection properties for each of the wrapper classes.

Table 4. Collection Properties

Class and Property Description

DeviceEmulatorManagerEx.Categories

List of Device Emulator Manager categories.

DeviceEmulatorCategory.Sdks

List of SDKs for this category.

DeviceEmulatorSdk.DeviceEmulators

List of emulators for this SDK.

Using the collection properties, iterating through the entire hierarchy becomes very simple. The following code sample writes out the Device Emulator Manager hierarchy.

Copy Code
DeviceEmulatorManagerEx demManagerEx = new
DeviceEmulatorManagerEx();
foreach (DeviceEmulatorCategory category in
demManagerEx.Categories)
{
	Console.WriteLine(category.Name);
	foreach (DeviceEmulatorSdk sdk in category.Sdks)
	{
		Console.WriteLine("\t" + sdk.Name);
		foreach (DeviceEmulator deviceEmulator in
sdk.DeviceEmulators)
	 {
			Console.WriteLine("\t\t" + deviceEmulator.Name);
	}
}
}

The 13 lines in this sample code do the same thing as the 78 lines in the second, third, forth, and fifth code samples from this paper combined.

Locating Members of the Hierarchy

One of the most common reasons that you will likely iterate over the Device Emulator Manager hierarchy is to locate an item within the hierarchy. Although the wrapper classes simplify the process of iterating over the Device Emulator Manager hierarchy, the better solution is to allow you to directly access the specific item of interest.

Note:
Each of the samples in this section and the following section makes the assumption that there is an existing DeviceEmulatorManagerExvariable named demManagerEx.

To make locating a Device Emulator easier, the DeviceEmulatorManagerExclass provides a FindEmulatormethod. The FindEmulatormethod allows you to locate a Device Emulator using either its name of VMID. The following sample code demonstrates using the FindEmulatormethod to locate the Windows Mobile 6 Professional Emulator; the sample code then demonstrates using the returned DeviceEmulatorreference to start the emulator if it is not running.

Copy Code
DeviceEmulator wm6Pro = 
  demManagerEx.FindEmulator("Windows Mobile 6 Professional Emulator
");
if (wm6Pro != null)
{
	if (wm6Pro.State == EMULATOR_STATE.EMU_NOT_RUNNING)
		wm6Pro.Connect();
}

To simplify locating items at any layer in the hierarchy, each of the collections provides a string-based indexer. To use the indexer simply pass the string name of the item of interest.

Note:
The collections all inherit from the ReadOnlyCollection<T>class, which provides an integer-based indexer that allows you to access the members of the collection by numeric position such as 0, 1, and so on.

The following sample code demonstrates using an indexer to locate the DataStore category.

Copy Code
DeviceEmulatorCategory dataStore =
demManager.Categories["DataStore"];

The following sample code demonstrates using indexers to locate the Windows Mobile 6 Professional SDK within the DataStore category.

Copy Code
DeviceEmulatorSdk wm6ProSdk = 
  demManager.Categories["DataStore"].Sdks["Windows Mobile 6
Professional SDK"];

The following sample code demonstrates using indexers to locate the Windows Mobile 6 Professional Emulator within the Windows Mobile 6 Professional SDK within the DataStore category.

Copy Code
DeviceEmulator wm6Pro = 
  demManager.Categories["DataStore"].Sdks["Windows Mobile 6
Professional SDK"].DeviceEmulators["Windows Mobile 6 Professional
Emulator"];
Note:
In the case of locating a specific emulator, one would generally use the DeviceEmulatorManagerEx.FindEmulatormethod rather than a sequence of indexers.

Monitoring for Changes with the Device Emulator Manager Wrapper

The DeviceEmulatorManagerExclass makes Device Emulator Manager hierarchy change notifications available as a standard .NET event through the RefreshRequiredevent. The event type is MethodInvokerand therefore requires that your event handler accept no parameters and has no return value. The threading and synchronization event handling details that the Device Emulator Manager API requires for change notifications is encapsulated in the DeviceEmulatorManagerExclass.

The DeviceEmulatorManagerExclass monitors for changes to the Device Emulator Manager hierarchy on a thread separate from the main application thread and therefore calls your event handler on this same thread. As a result, you should use caution when interacting with the user interface; always use Control.Invokeor Control.BeginInvoke.

Note:
You should always call the Disposemethod on the DeviceEmulatorManagerExclass. The Disposemethod handles the details of terminating the thread that monitors for Device Emulator Manager hierarchy changes. If you forget to call the Disposemethod, you may find that your application appears to stop responding during the application exit process.

Like the IDeviceEmulatorManagerinterface, the DeviceEmulatorManagerExclass includes a Refreshmethod to update the internal cache of Device Emulator Manager objects and hierarchies. Because the DeviceEmulatorManagerEx.RefreshRequiredevent signals your event handler on a thread separate from the main application thread, calling the Refreshmethod from your RefreshRequiredevent handler requires the same caution as described in the earlier IDeviceEmulatorManager.Refreshdiscussion.

Conclusion

The Device Emulator Manager API provides the features necessary to perform automated application testing with the Device Emulators. Using the Device Emulator Manager API, you can programmatically manage the entire life cycle of the Device Emulators allowing you to easily create reproducible tests.

The API provides complete support for .NET applications, native C/C++ applications, and scripting environments; although the COM nature of the API may sometimes seem awkward, these issues can easily be eliminated with some basic wrapper classes. Using the wrapper classes provided with this paper, you can take advantage of the powerful features provided by the Device Emulator Manager API and do so with just a few lines of code.

See Also

Author Bio

Jim Wilson is president of JW Hedgehog, Inc. (http://www.jwhh.com) a New Hampshire–based consulting firm specializing in solutions, content creation, and mentoring for the Windows Mobile platform. Jim has worked extensively with the .NET Framework and .NET Compact Framework since the original beta release of each; he has over 20 years experience in the software industry including more than 14 years experience with relational database programming including SQL Server and SQL Server Compact Edition. Jim writes frequently for MSDN and has developed mobility curriculums for two of the industry’s leading technology training organizations, DevelopMentor and PluralSight. Jim speaks regularly at Tech Ed, the Professional Developer's Conference (PDC), VSLive, and the Mobility & Embedded DevCon. You will find Jim online at http://pluralsight.com/blogs/jimw.